Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
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 combobox.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/control/combobox.cxx

/home/maarten/src/libreoffice/core/vcl/source/control/combobox.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 <vcl/toolkit/combobox.hxx>
21
22#include <set>
23
24#include <comphelper/string.hxx>
25#include <vcl/toolkit/lstbox.hxx>
26#include <vcl/commandevent.hxx>
27#include <vcl/event.hxx>
28#include <vcl/settings.hxx>
29#include <vcl/uitest/uiobject.hxx>
30#include <sal/log.hxx>
31
32#include <listbox.hxx>
33#include <controldata.hxx>
34#include <comphelper/lok.hxx>
35#include <tools/json_writer.hxx>
36
37namespace {
38
39struct ComboBoxBounds
40{
41 Point aSubEditPos;
42 Size aSubEditSize;
43
44 Point aButtonPos;
45 Size aButtonSize;
46};
47
48}
49
50struct ComboBox::Impl
51{
52 ComboBox & m_rThis;
53 VclPtr<Edit> m_pSubEdit;
54 VclPtr<ImplListBox> m_pImplLB;
55 VclPtr<ImplBtn> m_pBtn;
56 VclPtr<ImplListBoxFloatingWindow> m_pFloatWin;
57 sal_uInt16 m_nDDHeight;
58 sal_Unicode m_cMultiSep;
59 bool m_isDDAutoSize : 1;
60 bool m_isSyntheticModify : 1;
61 bool m_isKeyBoardModify : 1;
62 bool m_isMatchCase : 1;
63 sal_Int32 m_nMaxWidthChars;
64 sal_Int32 m_nWidthInChars;
65 Link<ComboBox&,void> m_SelectHdl;
66
67 explicit Impl(ComboBox & rThis)
68 : m_rThis(rThis)
69 , m_nDDHeight(0)
70 , m_cMultiSep(0)
71 , m_isDDAutoSize(false)
72 , m_isSyntheticModify(false)
73 , m_isKeyBoardModify(false)
74 , m_isMatchCase(false)
75 , m_nMaxWidthChars(0)
76 , m_nWidthInChars(-1)
77 {
78 }
79
80 void ImplInitComboBoxData();
81 void ImplUpdateFloatSelection();
82 ComboBoxBounds calcComboBoxDropDownComponentBounds(
83 const Size &rOutSize, const Size &rBorderOutSize) const;
84
85 DECL_LINK( ImplSelectHdl, LinkParamNone*, void )static void LinkStubImplSelectHdl(void *, LinkParamNone*); void
ImplSelectHdl(LinkParamNone*)
;
86 DECL_LINK( ImplCancelHdl, LinkParamNone*, void )static void LinkStubImplCancelHdl(void *, LinkParamNone*); void
ImplCancelHdl(LinkParamNone*)
;
87 DECL_LINK( ImplDoubleClickHdl, ImplListBoxWindow*, void )static void LinkStubImplDoubleClickHdl(void *, ImplListBoxWindow
*); void ImplDoubleClickHdl(ImplListBoxWindow*)
;
88 DECL_LINK( ImplClickBtnHdl, void*, void )static void LinkStubImplClickBtnHdl(void *, void*); void ImplClickBtnHdl
(void*)
;
89 DECL_LINK( ImplPopupModeEndHdl, FloatingWindow*, void )static void LinkStubImplPopupModeEndHdl(void *, FloatingWindow
*); void ImplPopupModeEndHdl(FloatingWindow*)
;
90 DECL_LINK( ImplSelectionChangedHdl, sal_Int32, void )static void LinkStubImplSelectionChangedHdl(void *, sal_Int32
); void ImplSelectionChangedHdl(sal_Int32)
;
91 DECL_LINK( ImplAutocompleteHdl, Edit&, void )static void LinkStubImplAutocompleteHdl(void *, Edit&); void
ImplAutocompleteHdl(Edit&)
;
92 DECL_LINK( ImplListItemSelectHdl , LinkParamNone*, void )static void LinkStubImplListItemSelectHdl(void *, LinkParamNone
*); void ImplListItemSelectHdl(LinkParamNone*)
;
93};
94
95
96static void lcl_GetSelectedEntries( ::std::set< sal_Int32 >& rSelectedPos, const OUString& rText, sal_Unicode cTokenSep, const ImplEntryList* pEntryList )
97{
98 if (rText.isEmpty())
99 return;
100
101 sal_Int32 nIdx{0};
102 do {
103 const sal_Int32 nPos = pEntryList->FindEntry(comphelper::string::strip(rText.getToken(0, cTokenSep, nIdx), ' '));
104 if ( nPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
105 rSelectedPos.insert( nPos );
106 } while (nIdx>=0);
107}
108
109ComboBox::ComboBox(vcl::Window *const pParent, WinBits const nStyle)
110 : Edit( WindowType::COMBOBOX )
111 , m_pImpl(new Impl(*this))
112{
113 m_pImpl->ImplInitComboBoxData();
114 ImplInit( pParent, nStyle );
115 SetWidthInChars(-1);
116}
117
118ComboBox::~ComboBox()
119{
120 disposeOnce();
121}
122
123void ComboBox::dispose()
124{
125 m_pImpl->m_pSubEdit.disposeAndClear();
126
127 VclPtr< ImplListBox > pImplLB = m_pImpl->m_pImplLB;
128 m_pImpl->m_pImplLB.clear();
129 pImplLB.disposeAndClear();
130
131 m_pImpl->m_pFloatWin.disposeAndClear();
132 m_pImpl->m_pBtn.disposeAndClear();
1
Calling 'VclPtr::disposeAndClear'
133 Edit::dispose();
134}
135
136void ComboBox::Impl::ImplInitComboBoxData()
137{
138 m_pSubEdit.disposeAndClear();
139 m_pBtn = nullptr;
140 m_pImplLB = nullptr;
141 m_pFloatWin = nullptr;
142
143 m_nDDHeight = 0;
144 m_isDDAutoSize = true;
145 m_isSyntheticModify = false;
146 m_isKeyBoardModify = false;
147 m_isMatchCase = false;
148 m_cMultiSep = ';';
149 m_nMaxWidthChars = -1;
150 m_nWidthInChars = -1;
151}
152
153void ComboBox::ImplCalcEditHeight()
154{
155 sal_Int32 nLeft, nTop, nRight, nBottom;
156 GetBorder( nLeft, nTop, nRight, nBottom );
157 m_pImpl->m_nDDHeight = static_cast<sal_uInt16>(m_pImpl->m_pSubEdit->GetTextHeight() + nTop + nBottom + 4);
158 if ( !IsDropDownBox() )
159 m_pImpl->m_nDDHeight += 4;
160
161 tools::Rectangle aCtrlRegion( Point( 0, 0 ), Size( 10, 10 ) );
162 tools::Rectangle aBoundRegion, aContentRegion;
163 ImplControlValue aControlValue;
164 ControlType aType = IsDropDownBox() ? ControlType::Combobox : ControlType::Editbox;
165 if( GetNativeControlRegion( aType, ControlPart::Entire,
166 aCtrlRegion,
167 ControlState::ENABLED,
168 aControlValue,
169 aBoundRegion, aContentRegion ) )
170 {
171 const long nNCHeight = aBoundRegion.GetHeight();
172 if (m_pImpl->m_nDDHeight < nNCHeight)
173 m_pImpl->m_nDDHeight = sal::static_int_cast<sal_uInt16>(nNCHeight);
174 }
175}
176
177void ComboBox::ImplInit( vcl::Window* pParent, WinBits nStyle )
178{
179 bool bNoBorder = ( nStyle & WB_NOBORDER ) != 0;
180 if ( !(nStyle & WB_DROPDOWN) )
181 {
182 nStyle &= ~WB_BORDER;
183 nStyle |= WB_NOBORDER;
184 }
185 else
186 {
187 if ( !bNoBorder )
188 nStyle |= WB_BORDER;
189 }
190
191 Edit::ImplInit( pParent, nStyle );
192 SetBackground();
193
194 // DropDown ?
195 WinBits nEditStyle = nStyle & ( WB_LEFT | WB_RIGHT | WB_CENTER );
196 WinBits nListStyle = nStyle;
197 if( nStyle & WB_DROPDOWN )
198 {
199 m_pImpl->m_pFloatWin = VclPtr<ImplListBoxFloatingWindow>::Create( this );
200 if (!IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Focus))
201 m_pImpl->m_pFloatWin->RequestDoubleBuffering(true);
202 m_pImpl->m_pFloatWin->SetAutoWidth( true );
203 m_pImpl->m_pFloatWin->SetPopupModeEndHdl( LINK(m_pImpl.get(), ComboBox::Impl, ImplPopupModeEndHdl)::tools::detail::makeLink( ::tools::detail::castTo<ComboBox
::Impl *>(m_pImpl.get()), &ComboBox::Impl::LinkStubImplPopupModeEndHdl
)
);
204
205 m_pImpl->m_pBtn = VclPtr<ImplBtn>::Create( this, WB_NOLIGHTBORDER | WB_RECTSTYLE );
206 ImplInitDropDownButton( m_pImpl->m_pBtn );
207 m_pImpl->m_pBtn->SetMBDownHdl( LINK( m_pImpl.get(), ComboBox::Impl, ImplClickBtnHdl )::tools::detail::makeLink( ::tools::detail::castTo<ComboBox
::Impl *>(m_pImpl.get()), &ComboBox::Impl::LinkStubImplClickBtnHdl
)
);
208 m_pImpl->m_pBtn->Show();
209
210 nEditStyle |= WB_NOBORDER;
211 nListStyle &= ~WB_BORDER;
212 nListStyle |= WB_NOBORDER;
213 }
214 else
215 {
216 if ( !bNoBorder )
217 {
218 nEditStyle |= WB_BORDER;
219 nListStyle &= ~WB_NOBORDER;
220 nListStyle |= WB_BORDER;
221 }
222 }
223
224 m_pImpl->m_pSubEdit.set( VclPtr<Edit>::Create( this, nEditStyle ) );
225 m_pImpl->m_pSubEdit->EnableRTL( false );
226 SetSubEdit( m_pImpl->m_pSubEdit );
227 m_pImpl->m_pSubEdit->SetPosPixel( Point() );
228 EnableAutocomplete( true );
229 m_pImpl->m_pSubEdit->Show();
230
231 vcl::Window* pLBParent = this;
232 if (m_pImpl->m_pFloatWin)
233 pLBParent = m_pImpl->m_pFloatWin;
234 m_pImpl->m_pImplLB = VclPtr<ImplListBox>::Create( pLBParent, nListStyle|WB_SIMPLEMODE|WB_AUTOHSCROLL );
235 m_pImpl->m_pImplLB->SetPosPixel( Point() );
236 m_pImpl->m_pImplLB->SetSelectHdl( LINK(m_pImpl.get(), ComboBox::Impl, ImplSelectHdl)::tools::detail::makeLink( ::tools::detail::castTo<ComboBox
::Impl *>(m_pImpl.get()), &ComboBox::Impl::LinkStubImplSelectHdl
)
);
237 m_pImpl->m_pImplLB->SetCancelHdl( LINK(m_pImpl.get(), ComboBox::Impl, ImplCancelHdl)::tools::detail::makeLink( ::tools::detail::castTo<ComboBox
::Impl *>(m_pImpl.get()), &ComboBox::Impl::LinkStubImplCancelHdl
)
);
238 m_pImpl->m_pImplLB->SetDoubleClickHdl( LINK(m_pImpl.get(), ComboBox::Impl, ImplDoubleClickHdl)::tools::detail::makeLink( ::tools::detail::castTo<ComboBox
::Impl *>(m_pImpl.get()), &ComboBox::Impl::LinkStubImplDoubleClickHdl
)
);
239 m_pImpl->m_pImplLB->SetSelectionChangedHdl( LINK(m_pImpl.get(), ComboBox::Impl, ImplSelectionChangedHdl)::tools::detail::makeLink( ::tools::detail::castTo<ComboBox
::Impl *>(m_pImpl.get()), &ComboBox::Impl::LinkStubImplSelectionChangedHdl
)
);
240 m_pImpl->m_pImplLB->SetListItemSelectHdl( LINK(m_pImpl.get(), ComboBox::Impl, ImplListItemSelectHdl)::tools::detail::makeLink( ::tools::detail::castTo<ComboBox
::Impl *>(m_pImpl.get()), &ComboBox::Impl::LinkStubImplListItemSelectHdl
)
);
241 m_pImpl->m_pImplLB->Show();
242
243 if (m_pImpl->m_pFloatWin)
244 m_pImpl->m_pFloatWin->SetImplListBox( m_pImpl->m_pImplLB );
245 else
246 m_pImpl->m_pImplLB->GetMainWindow()->AllowGrabFocus( true );
247
248 ImplCalcEditHeight();
249
250 SetCompoundControl( true );
251}
252
253WinBits ComboBox::ImplInitStyle( WinBits nStyle )
254{
255 if ( !(nStyle & WB_NOTABSTOP) )
256 nStyle |= WB_TABSTOP;
257 if ( !(nStyle & WB_NOGROUP) )
258 nStyle |= WB_GROUP;
259 return nStyle;
260}
261
262void ComboBox::EnableAutocomplete( bool bEnable, bool bMatchCase )
263{
264 m_pImpl->m_isMatchCase = bMatchCase;
265
266 if ( bEnable )
267 m_pImpl->m_pSubEdit->SetAutocompleteHdl( LINK(m_pImpl.get(), ComboBox::Impl, ImplAutocompleteHdl)::tools::detail::makeLink( ::tools::detail::castTo<ComboBox
::Impl *>(m_pImpl.get()), &ComboBox::Impl::LinkStubImplAutocompleteHdl
)
);
268 else
269 m_pImpl->m_pSubEdit->SetAutocompleteHdl( Link<Edit&,void>() );
270}
271
272bool ComboBox::IsAutocompleteEnabled() const
273{
274 return m_pImpl->m_pSubEdit->GetAutocompleteHdl().IsSet();
275}
276
277IMPL_LINK_NOARG(ComboBox::Impl, ImplClickBtnHdl, void*, void)void ComboBox::Impl::LinkStubImplClickBtnHdl(void * instance,
void* data) { return static_cast<ComboBox::Impl *>(instance
)->ImplClickBtnHdl(data); } void ComboBox::Impl::ImplClickBtnHdl
(__attribute__ ((unused)) void*)
278{
279 m_rThis.CallEventListeners( VclEventId::DropdownPreOpen );
280 m_pSubEdit->GrabFocus();
281 if (!m_pImplLB->GetEntryList()->GetMRUCount())
282 ImplUpdateFloatSelection();
283 else
284 m_pImplLB->SelectEntry( 0 , true );
285 m_pBtn->SetPressed( true );
286 m_rThis.SetSelection( Selection( 0, SELECTION_MAX9223372036854775807L ) );
287 m_pFloatWin->StartFloat( true );
288 m_rThis.CallEventListeners( VclEventId::DropdownOpen );
289
290 m_rThis.ImplClearLayoutData();
291 if (m_pImplLB)
292 m_pImplLB->GetMainWindow()->ImplClearLayoutData();
293}
294
295IMPL_LINK_NOARG(ComboBox::Impl, ImplPopupModeEndHdl, FloatingWindow*, void)void ComboBox::Impl::LinkStubImplPopupModeEndHdl(void * instance
, FloatingWindow* data) { return static_cast<ComboBox::Impl
*>(instance)->ImplPopupModeEndHdl(data); } void ComboBox
::Impl::ImplPopupModeEndHdl(__attribute__ ((unused)) FloatingWindow
*)
296{
297 if (m_pFloatWin->IsPopupModeCanceled())
298 {
299 if (!m_pImplLB->GetEntryList()->IsEntryPosSelected(
300 m_pFloatWin->GetPopupModeStartSaveSelection()))
301 {
302 m_pImplLB->SelectEntry(m_pFloatWin->GetPopupModeStartSaveSelection(), true);
303 bool bTravelSelect = m_pImplLB->IsTravelSelect();
304 m_pImplLB->SetTravelSelect( true );
305 m_rThis.Select();
306 m_pImplLB->SetTravelSelect( bTravelSelect );
307 }
308 }
309
310 m_rThis.ImplClearLayoutData();
311 if (m_pImplLB)
312 m_pImplLB->GetMainWindow()->ImplClearLayoutData();
313
314 m_pBtn->SetPressed( false );
315 m_rThis.CallEventListeners( VclEventId::DropdownClose );
316}
317
318IMPL_LINK(ComboBox::Impl, ImplAutocompleteHdl, Edit&, rEdit, void)void ComboBox::Impl::LinkStubImplAutocompleteHdl(void * instance
, Edit& data) { return static_cast<ComboBox::Impl *>
(instance)->ImplAutocompleteHdl(data); } void ComboBox::Impl
::ImplAutocompleteHdl(Edit& rEdit)
319{
320 Selection aSel = rEdit.GetSelection();
321
322 {
323 OUString aFullText = rEdit.GetText();
324 OUString aStartText = aFullText.copy( 0, static_cast<sal_Int32>(aSel.Max()) );
325 sal_Int32 nStart = m_pImplLB->GetCurrentPos();
326
327 if ( nStart == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
328 nStart = 0;
329
330 sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
331 if (!m_isMatchCase)
332 {
333 // Try match case insensitive from current position
334 nPos = m_pImplLB->GetEntryList()->FindMatchingEntry(aStartText, nStart, true);
335 if ( nPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
336 // Try match case insensitive, but from start
337 nPos = m_pImplLB->GetEntryList()->FindMatchingEntry(aStartText, 0, true);
338 }
339
340 if ( nPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
341 // Try match full from current position
342 nPos = m_pImplLB->GetEntryList()->FindMatchingEntry(aStartText, nStart, false);
343 if ( nPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
344 // Match full, but from start
345 nPos = m_pImplLB->GetEntryList()->FindMatchingEntry(aStartText, 0, false);
346
347 if ( nPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
348 {
349 OUString aText = m_pImplLB->GetEntryList()->GetEntryText( nPos );
350 Selection aSelection( aText.getLength(), aStartText.getLength() );
351 rEdit.SetText( aText, aSelection );
352 }
353 }
354}
355
356IMPL_LINK_NOARG(ComboBox::Impl, ImplSelectHdl, LinkParamNone*, void)void ComboBox::Impl::LinkStubImplSelectHdl(void * instance, LinkParamNone
* data) { return static_cast<ComboBox::Impl *>(instance
)->ImplSelectHdl(data); } void ComboBox::Impl::ImplSelectHdl
(__attribute__ ((unused)) LinkParamNone*)
357{
358 bool bPopup = m_rThis.IsInDropDown();
359 bool bCallSelect = false;
360 if (m_pImplLB->IsSelectionChanged() || bPopup)
361 {
362 OUString aText;
363 if (m_rThis.IsMultiSelectionEnabled())
364 {
365 aText = m_pSubEdit->GetText();
366
367 // remove all entries to which there is an entry, but which is not selected
368 sal_Int32 nIndex = 0;
369 while ( nIndex >= 0 )
370 {
371 sal_Int32 nPrevIndex = nIndex;
372 OUString aToken = aText.getToken( 0, m_cMultiSep, nIndex );
373 sal_Int32 nTokenLen = aToken.getLength();
374 aToken = comphelper::string::strip(aToken, ' ');
375 sal_Int32 nP = m_pImplLB->GetEntryList()->FindEntry( aToken );
376 if ((nP != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF))) && (!m_pImplLB->GetEntryList()->IsEntryPosSelected(nP)))
377 {
378 aText = aText.replaceAt( nPrevIndex, nTokenLen, "" );
379 nIndex = nIndex - nTokenLen;
380 sal_Int32 nSepCount=0;
381 if ((nPrevIndex+nSepCount < aText.getLength()) && (aText[nPrevIndex+nSepCount] == m_cMultiSep))
382 {
383 nIndex--;
384 ++nSepCount;
385 }
386 aText = aText.replaceAt( nPrevIndex, nSepCount, "" );
387 }
388 aText = comphelper::string::strip(aText, ' ');
389 }
390
391 // attach missing entries
392 ::std::set< sal_Int32 > aSelInText;
393 lcl_GetSelectedEntries( aSelInText, aText, m_cMultiSep, m_pImplLB->GetEntryList() );
394 sal_Int32 nSelectedEntries = m_pImplLB->GetEntryList()->GetSelectedEntryCount();
395 for ( sal_Int32 n = 0; n < nSelectedEntries; n++ )
396 {
397 sal_Int32 nP = m_pImplLB->GetEntryList()->GetSelectedEntryPos( n );
398 if ( !aSelInText.count( nP ) )
399 {
400 if (!aText.isEmpty() && (aText[aText.getLength()-1] != m_cMultiSep))
401 aText += OUStringChar(m_cMultiSep);
402 if ( !aText.isEmpty() )
403 aText += " "; // slightly loosen
404 aText += m_pImplLB->GetEntryList()->GetEntryText( nP ) +
405 OUStringChar(m_cMultiSep);
406 }
407 }
408 aText = comphelper::string::stripEnd( aText, m_cMultiSep );
409 }
410 else
411 {
412 aText = m_pImplLB->GetEntryList()->GetSelectedEntry( 0 );
413 }
414
415 m_pSubEdit->SetText( aText );
416
417 Selection aNewSelection( 0, aText.getLength() );
418 if (m_rThis.IsMultiSelectionEnabled())
419 aNewSelection.Min() = aText.getLength();
420 m_pSubEdit->SetSelection( aNewSelection );
421
422 bCallSelect = true;
423 }
424
425 // #84652# Call GrabFocus and EndPopupMode before calling Select/Modify, but after changing the text
426 bool bMenuSelect = bPopup && !m_pImplLB->IsTravelSelect() && (!m_rThis.IsMultiSelectionEnabled() || !m_pImplLB->GetSelectModifier());
427 if (bMenuSelect)
428 {
429 m_pFloatWin->EndPopupMode();
430 m_rThis.GrabFocus();
431 }
432
433 if ( bCallSelect )
434 {
435 m_isKeyBoardModify = !bMenuSelect;
436 m_pSubEdit->SetModifyFlag();
437 m_isSyntheticModify = true;
438 m_rThis.Modify();
439 m_isSyntheticModify = false;
440 m_rThis.Select();
441 m_isKeyBoardModify = false;
442 }
443}
444
445bool ComboBox::IsSyntheticModify() const
446{
447 return m_pImpl->m_isSyntheticModify;
448}
449
450bool ComboBox::IsModifyByKeyboard() const
451{
452 return m_pImpl->m_isKeyBoardModify;
453}
454
455IMPL_LINK_NOARG( ComboBox::Impl, ImplListItemSelectHdl, LinkParamNone*, void )void ComboBox::Impl::LinkStubImplListItemSelectHdl(void * instance
, LinkParamNone* data) { return static_cast<ComboBox::Impl
*>(instance)->ImplListItemSelectHdl(data); } void ComboBox
::Impl::ImplListItemSelectHdl(__attribute__ ((unused)) LinkParamNone
*)
456{
457 m_rThis.CallEventListeners( VclEventId::DropdownSelect );
458}
459
460IMPL_LINK_NOARG(ComboBox::Impl, ImplCancelHdl, LinkParamNone*, void)void ComboBox::Impl::LinkStubImplCancelHdl(void * instance, LinkParamNone
* data) { return static_cast<ComboBox::Impl *>(instance
)->ImplCancelHdl(data); } void ComboBox::Impl::ImplCancelHdl
(__attribute__ ((unused)) LinkParamNone*)
461{
462 if (m_rThis.IsInDropDown())
463 m_pFloatWin->EndPopupMode();
464}
465
466IMPL_LINK( ComboBox::Impl, ImplSelectionChangedHdl, sal_Int32, nChanged, void )void ComboBox::Impl::LinkStubImplSelectionChangedHdl(void * instance
, sal_Int32 data) { return static_cast<ComboBox::Impl *>
(instance)->ImplSelectionChangedHdl(data); } void ComboBox
::Impl::ImplSelectionChangedHdl(sal_Int32 nChanged)
467{
468 if (!m_pImplLB->IsTrackingSelect())
469 {
470 if (!m_pSubEdit->IsReadOnly() && m_pImplLB->GetEntryList()->IsEntryPosSelected(nChanged))
471 m_pSubEdit->SetText(m_pImplLB->GetEntryList()->GetEntryText(nChanged));
472 }
473}
474
475IMPL_LINK_NOARG(ComboBox::Impl, ImplDoubleClickHdl, ImplListBoxWindow*, void)void ComboBox::Impl::LinkStubImplDoubleClickHdl(void * instance
, ImplListBoxWindow* data) { return static_cast<ComboBox::
Impl *>(instance)->ImplDoubleClickHdl(data); } void ComboBox
::Impl::ImplDoubleClickHdl(__attribute__ ((unused)) ImplListBoxWindow
*)
476{
477 m_rThis.DoubleClick();
478}
479
480void ComboBox::ToggleDropDown()
481{
482 if( !IsDropDownBox() )
483 return;
484
485 if (m_pImpl->m_pFloatWin->IsInPopupMode())
486 m_pImpl->m_pFloatWin->EndPopupMode();
487 else
488 {
489 m_pImpl->m_pSubEdit->GrabFocus();
490 if (!m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount())
491 m_pImpl->ImplUpdateFloatSelection();
492 else
493 m_pImpl->m_pImplLB->SelectEntry( 0 , true );
494 CallEventListeners( VclEventId::DropdownPreOpen );
495 m_pImpl->m_pBtn->SetPressed( true );
496 SetSelection( Selection( 0, SELECTION_MAX9223372036854775807L ) );
497 m_pImpl->m_pFloatWin->StartFloat( true );
498 CallEventListeners( VclEventId::DropdownOpen );
499 }
500}
501
502void ComboBox::Select()
503{
504 ImplCallEventListenersAndHandler( VclEventId::ComboboxSelect, [this] () { m_pImpl->m_SelectHdl.Call(*this); } );
505}
506
507void ComboBox::DoubleClick()
508{
509 ImplCallEventListenersAndHandler( VclEventId::ComboboxDoubleClick, [] () {} );
510}
511
512bool ComboBox::IsAutoSizeEnabled() const { return m_pImpl->m_isDDAutoSize; }
513
514void ComboBox::EnableAutoSize( bool bAuto )
515{
516 m_pImpl->m_isDDAutoSize = bAuto;
517 if (m_pImpl->m_pFloatWin)
518 {
519 if (bAuto && !m_pImpl->m_pFloatWin->GetDropDownLineCount())
520 {
521 // Adapt to GetListBoxMaximumLineCount here; was on fixed number of five before
522 AdaptDropDownLineCountToMaximum();
523 }
524 else if ( !bAuto )
525 {
526 m_pImpl->m_pFloatWin->SetDropDownLineCount( 0 );
527 }
528 }
529}
530
531void ComboBox::SetDropDownLineCount( sal_uInt16 nLines )
532{
533 if (m_pImpl->m_pFloatWin)
534 m_pImpl->m_pFloatWin->SetDropDownLineCount( nLines );
535}
536
537void ComboBox::AdaptDropDownLineCountToMaximum()
538{
539 // Adapt to maximum allowed number.
540 // Limit for LOK as we can't render outside of the dialog canvas.
541 if (comphelper::LibreOfficeKit::isActive())
542 SetDropDownLineCount(11);
543 else
544 SetDropDownLineCount(GetSettings().GetStyleSettings().GetListBoxMaximumLineCount());
545}
546
547sal_uInt16 ComboBox::GetDropDownLineCount() const
548{
549 sal_uInt16 nLines = 0;
550 if (m_pImpl->m_pFloatWin)
551 nLines = m_pImpl->m_pFloatWin->GetDropDownLineCount();
552 return nLines;
553}
554
555void ComboBox::setPosSizePixel( long nX, long nY, long nWidth, long nHeight,
556 PosSizeFlags nFlags )
557{
558 if( IsDropDownBox() && ( nFlags & PosSizeFlags::Size ) )
559 {
560 Size aPrefSz = m_pImpl->m_pFloatWin->GetPrefSize();
561 if ((nFlags & PosSizeFlags::Height) && (nHeight >= 2*m_pImpl->m_nDDHeight))
562 aPrefSz.setHeight( nHeight-m_pImpl->m_nDDHeight );
563 if ( nFlags & PosSizeFlags::Width )
564 aPrefSz.setWidth( nWidth );
565 m_pImpl->m_pFloatWin->SetPrefSize( aPrefSz );
566
567 if (IsAutoSizeEnabled())
568 nHeight = m_pImpl->m_nDDHeight;
569 }
570
571 Edit::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
572}
573
574void ComboBox::Resize()
575{
576 Control::Resize();
577
578 if (m_pImpl->m_pSubEdit)
579 {
580 Size aOutSz = GetOutputSizePixel();
581 if( IsDropDownBox() )
582 {
583 ComboBoxBounds aBounds(m_pImpl->calcComboBoxDropDownComponentBounds(aOutSz,
584 GetWindow(GetWindowType::Border)->GetOutputSizePixel()));
585 m_pImpl->m_pSubEdit->SetPosSizePixel(aBounds.aSubEditPos, aBounds.aSubEditSize);
586 m_pImpl->m_pBtn->SetPosSizePixel(aBounds.aButtonPos, aBounds.aButtonSize);
587 }
588 else
589 {
590 m_pImpl->m_pSubEdit->SetSizePixel(Size(aOutSz.Width(), m_pImpl->m_nDDHeight));
591 m_pImpl->m_pImplLB->setPosSizePixel(0, m_pImpl->m_nDDHeight,
592 aOutSz.Width(), aOutSz.Height() - m_pImpl->m_nDDHeight);
593 if ( !GetText().isEmpty() )
594 m_pImpl->ImplUpdateFloatSelection();
595 }
596 }
597
598 // adjust the size of the FloatingWindow even when invisible
599 // as KEY_PGUP/DOWN is being processed...
600 if (m_pImpl->m_pFloatWin)
601 m_pImpl->m_pFloatWin->SetSizePixel(m_pImpl->m_pFloatWin->CalcFloatSize());
602}
603
604bool ComboBox::IsDropDownBox() const { return m_pImpl->m_pFloatWin != nullptr; }
605
606void ComboBox::FillLayoutData() const
607{
608 mpControlData->mpLayoutData.reset( new vcl::ControlLayoutData );
609 AppendLayoutData( *m_pImpl->m_pSubEdit );
610 m_pImpl->m_pSubEdit->SetLayoutDataParent( this );
611 ImplListBoxWindow* rMainWindow = m_pImpl->m_pImplLB->GetMainWindow();
612 if (m_pImpl->m_pFloatWin)
613 {
614 // dropdown mode
615 if (m_pImpl->m_pFloatWin->IsReallyVisible())
616 {
617 AppendLayoutData( *rMainWindow );
618 rMainWindow->SetLayoutDataParent( this );
619 }
620 }
621 else
622 {
623 AppendLayoutData( *rMainWindow );
624 rMainWindow->SetLayoutDataParent( this );
625 }
626}
627
628void ComboBox::StateChanged( StateChangedType nType )
629{
630 Edit::StateChanged( nType );
631
632 if ( nType == StateChangedType::ReadOnly )
633 {
634 m_pImpl->m_pImplLB->SetReadOnly( IsReadOnly() );
635 if (m_pImpl->m_pBtn)
636 m_pImpl->m_pBtn->Enable( IsEnabled() && !IsReadOnly() );
637 }
638 else if ( nType == StateChangedType::Enable )
639 {
640 m_pImpl->m_pSubEdit->Enable( IsEnabled() );
641 m_pImpl->m_pImplLB->Enable( IsEnabled() && !IsReadOnly() );
642 if (m_pImpl->m_pBtn)
643 m_pImpl->m_pBtn->Enable( IsEnabled() && !IsReadOnly() );
644 Invalidate();
645 }
646 else if( nType == StateChangedType::UpdateMode )
647 {
648 m_pImpl->m_pImplLB->SetUpdateMode( IsUpdateMode() );
649 }
650 else if ( nType == StateChangedType::Zoom )
651 {
652 m_pImpl->m_pImplLB->SetZoom( GetZoom() );
653 m_pImpl->m_pSubEdit->SetZoom( GetZoom() );
654 ImplCalcEditHeight();
655 Resize();
656 }
657 else if ( nType == StateChangedType::ControlFont )
658 {
659 m_pImpl->m_pImplLB->SetControlFont( GetControlFont() );
660 m_pImpl->m_pSubEdit->SetControlFont( GetControlFont() );
661 ImplCalcEditHeight();
662 Resize();
663 }
664 else if ( nType == StateChangedType::ControlForeground )
665 {
666 m_pImpl->m_pImplLB->SetControlForeground( GetControlForeground() );
667 m_pImpl->m_pSubEdit->SetControlForeground( GetControlForeground() );
668 }
669 else if ( nType == StateChangedType::ControlBackground )
670 {
671 m_pImpl->m_pImplLB->SetControlBackground( GetControlBackground() );
672 m_pImpl->m_pSubEdit->SetControlBackground( GetControlBackground() );
673 }
674 else if ( nType == StateChangedType::Style )
675 {
676 SetStyle( ImplInitStyle( GetStyle() ) );
677 m_pImpl->m_pImplLB->GetMainWindow()->EnableSort( ( GetStyle() & WB_SORT ) != 0 );
678 }
679 else if( nType == StateChangedType::Mirroring )
680 {
681 if (m_pImpl->m_pBtn)
682 {
683 m_pImpl->m_pBtn->EnableRTL( IsRTLEnabled() );
684 ImplInitDropDownButton( m_pImpl->m_pBtn );
685 }
686 m_pImpl->m_pSubEdit->CompatStateChanged( StateChangedType::Mirroring );
687 m_pImpl->m_pImplLB->EnableRTL( IsRTLEnabled() );
688 Resize();
689 }
690}
691
692void ComboBox::DataChanged( const DataChangedEvent& rDCEvt )
693{
694 Control::DataChanged( rDCEvt );
695
696 if ( !((rDCEvt.GetType() == DataChangedEventType::FONTS) ||
697 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
698 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
699 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))) )
700 return;
701
702 if (m_pImpl->m_pBtn)
703 {
704 m_pImpl->m_pBtn->SetSettings( GetSettings() );
705 ImplInitDropDownButton( m_pImpl->m_pBtn );
706 }
707 Resize();
708 m_pImpl->m_pImplLB->Resize(); // not called by ComboBox::Resize() if ImplLB is unchanged
709
710 SetBackground(); // due to a hack in Window::UpdateSettings the background must be reset
711 // otherwise it will overpaint NWF drawn comboboxes
712}
713
714bool ComboBox::EventNotify( NotifyEvent& rNEvt )
715{
716 bool bDone = false;
717 if ((rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
718 && (rNEvt.GetWindow() == m_pImpl->m_pSubEdit)
719 && !IsReadOnly())
720 {
721 KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
722 sal_uInt16 nKeyCode = aKeyEvt.GetKeyCode().GetCode();
723 switch( nKeyCode )
724 {
725 case KEY_UP:
726 case KEY_DOWN:
727 case KEY_PAGEUP:
728 case KEY_PAGEDOWN:
729 {
730 m_pImpl->ImplUpdateFloatSelection();
731 if ((nKeyCode == KEY_DOWN) && m_pImpl->m_pFloatWin
732 && !m_pImpl->m_pFloatWin->IsInPopupMode()
733 && aKeyEvt.GetKeyCode().IsMod2())
734 {
735 CallEventListeners( VclEventId::DropdownPreOpen );
736 m_pImpl->m_pBtn->SetPressed( true );
737 if (m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount())
738 m_pImpl->m_pImplLB->SelectEntry( 0 , true );
739 SetSelection( Selection( 0, SELECTION_MAX9223372036854775807L ) );
740 m_pImpl->m_pFloatWin->StartFloat( false );
741 CallEventListeners( VclEventId::DropdownOpen );
742 bDone = true;
743 }
744 else if ((nKeyCode == KEY_UP) && m_pImpl->m_pFloatWin
745 && m_pImpl->m_pFloatWin->IsInPopupMode()
746 && aKeyEvt.GetKeyCode().IsMod2())
747 {
748 m_pImpl->m_pFloatWin->EndPopupMode();
749 bDone = true;
750 }
751 else
752 {
753 bDone = m_pImpl->m_pImplLB->ProcessKeyInput( aKeyEvt );
754 }
755 }
756 break;
757
758 case KEY_RETURN:
759 {
760 if ((rNEvt.GetWindow() == m_pImpl->m_pSubEdit) && IsInDropDown())
761 {
762 m_pImpl->m_pImplLB->ProcessKeyInput( aKeyEvt );
763 bDone = true;
764 }
765 }
766 break;
767 }
768 }
769 else if ((rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS) && m_pImpl->m_pFloatWin)
770 {
771 if (m_pImpl->m_pFloatWin->HasChildPathFocus())
772 m_pImpl->m_pSubEdit->GrabFocus();
773 else if (m_pImpl->m_pFloatWin->IsInPopupMode() && !HasChildPathFocus(true))
774 m_pImpl->m_pFloatWin->EndPopupMode();
775 }
776 else if( (rNEvt.GetType() == MouseNotifyEvent::COMMAND) &&
777 (rNEvt.GetCommandEvent()->GetCommand() == CommandEventId::Wheel) &&
778 (rNEvt.GetWindow() == m_pImpl->m_pSubEdit) )
779 {
780 MouseWheelBehaviour nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
781 if ( ( nWheelBehavior == MouseWheelBehaviour::ALWAYS )
782 || ( ( nWheelBehavior == MouseWheelBehaviour::FocusOnly )
783 && HasChildPathFocus()
784 )
785 )
786 {
787 bDone = m_pImpl->m_pImplLB->HandleWheelAsCursorTravel(*rNEvt.GetCommandEvent(), *this);
788 }
789 else
790 {
791 bDone = false; // don't eat this event, let the default handling happen (i.e. scroll the context)
792 }
793 }
794 else if ((rNEvt.GetType() == MouseNotifyEvent::MOUSEBUTTONDOWN)
795 && (rNEvt.GetWindow() == m_pImpl->m_pImplLB->GetMainWindow()))
796 {
797 m_pImpl->m_pSubEdit->GrabFocus();
798 }
799
800 return bDone || Edit::EventNotify( rNEvt );
801}
802
803void ComboBox::SetText( const OUString& rStr )
804{
805 CallEventListeners( VclEventId::ComboboxSetText );
806
807 Edit::SetText( rStr );
808 m_pImpl->ImplUpdateFloatSelection();
809}
810
811void ComboBox::SetText( const OUString& rStr, const Selection& rNewSelection )
812{
813 CallEventListeners( VclEventId::ComboboxSetText );
814
815 Edit::SetText( rStr, rNewSelection );
816 m_pImpl->ImplUpdateFloatSelection();
817}
818
819void ComboBox::Modify()
820{
821 if (!m_pImpl->m_isSyntheticModify)
822 m_pImpl->ImplUpdateFloatSelection();
823
824 Edit::Modify();
825}
826
827void ComboBox::Impl::ImplUpdateFloatSelection()
828{
829 if (!m_pImplLB || !m_pSubEdit)
830 return;
831
832 // move text in the ListBox into the visible region
833 m_pImplLB->SetCallSelectionChangedHdl( false );
834 if (!m_rThis.IsMultiSelectionEnabled())
835 {
836 OUString aSearchStr( m_pSubEdit->GetText() );
837 sal_Int32 nSelect = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
838 bool bSelect = true;
839
840 if (m_pImplLB->GetCurrentPos() != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)))
841 {
842 OUString aCurrent = m_pImplLB->GetEntryList()->GetEntryText(
843 m_pImplLB->GetCurrentPos());
844 if ( aCurrent == aSearchStr )
845 nSelect = m_pImplLB->GetCurrentPos();
846 }
847
848 if ( nSelect == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
849 nSelect = m_pImplLB->GetEntryList()->FindEntry( aSearchStr );
850 if ( nSelect == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
851 {
852 nSelect = m_pImplLB->GetEntryList()->FindMatchingEntry( aSearchStr, 0, true );
853 bSelect = false;
854 }
855
856 if( nSelect != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
857 {
858 if (!m_pImplLB->IsVisible(nSelect))
859 m_pImplLB->ShowProminentEntry( nSelect );
860 m_pImplLB->SelectEntry( nSelect, bSelect );
861 }
862 else
863 {
864 nSelect = m_pImplLB->GetEntryList()->GetSelectedEntryPos( 0 );
865 if( nSelect != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
866 m_pImplLB->SelectEntry( nSelect, false );
867 m_pImplLB->ResetCurrentPos();
868 }
869 }
870 else
871 {
872 ::std::set< sal_Int32 > aSelInText;
873 lcl_GetSelectedEntries(aSelInText, m_pSubEdit->GetText(), m_cMultiSep, m_pImplLB->GetEntryList());
874 for (sal_Int32 n = 0; n < m_pImplLB->GetEntryList()->GetEntryCount(); n++)
875 m_pImplLB->SelectEntry( n, aSelInText.count( n ) != 0 );
876 }
877 m_pImplLB->SetCallSelectionChangedHdl( true );
878}
879
880sal_Int32 ComboBox::InsertEntry(const OUString& rStr, sal_Int32 const nPos)
881{
882 assert(nPos >= 0 && COMBOBOX_MAX_ENTRIES > m_pImpl->m_pImplLB->GetEntryList()->GetEntryCount())(static_cast <bool> (nPos >= 0 && (((sal_Int32
) 0x7FFFFFFF) - 1) > m_pImpl->m_pImplLB->GetEntryList
()->GetEntryCount()) ? void (0) : __assert_fail ("nPos >= 0 && COMBOBOX_MAX_ENTRIES > m_pImpl->m_pImplLB->GetEntryList()->GetEntryCount()"
, "/home/maarten/src/libreoffice/core/vcl/source/control/combobox.cxx"
, 882, __extension__ __PRETTY_FUNCTION__))
;
883
884 sal_Int32 nRealPos;
885 if (nPos == COMBOBOX_APPEND(((sal_Int32) 0x7FFFFFFF)))
886 nRealPos = nPos;
887 else
888 {
889 const sal_Int32 nMRUCount = m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount();
890 assert(nPos <= COMBOBOX_MAX_ENTRIES - nMRUCount)(static_cast <bool> (nPos <= (((sal_Int32) 0x7FFFFFFF
) - 1) - nMRUCount) ? void (0) : __assert_fail ("nPos <= COMBOBOX_MAX_ENTRIES - nMRUCount"
, "/home/maarten/src/libreoffice/core/vcl/source/control/combobox.cxx"
, 890, __extension__ __PRETTY_FUNCTION__))
;
891 nRealPos = nPos + nMRUCount;
892 }
893
894 nRealPos = m_pImpl->m_pImplLB->InsertEntry( nRealPos, rStr );
895 nRealPos -= m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount();
896 CallEventListeners( VclEventId::ComboboxItemAdded, reinterpret_cast<void*>(nRealPos) );
897 return nRealPos;
898}
899
900sal_Int32 ComboBox::InsertEntryWithImage(
901 const OUString& rStr, const Image& rImage, sal_Int32 const nPos)
902{
903 assert(nPos >= 0 && COMBOBOX_MAX_ENTRIES > m_pImpl->m_pImplLB->GetEntryList()->GetEntryCount())(static_cast <bool> (nPos >= 0 && (((sal_Int32
) 0x7FFFFFFF) - 1) > m_pImpl->m_pImplLB->GetEntryList
()->GetEntryCount()) ? void (0) : __assert_fail ("nPos >= 0 && COMBOBOX_MAX_ENTRIES > m_pImpl->m_pImplLB->GetEntryList()->GetEntryCount()"
, "/home/maarten/src/libreoffice/core/vcl/source/control/combobox.cxx"
, 903, __extension__ __PRETTY_FUNCTION__))
;
904
905 sal_Int32 nRealPos;
906 if (nPos == COMBOBOX_APPEND(((sal_Int32) 0x7FFFFFFF)))
907 nRealPos = nPos;
908 else
909 {
910 const sal_Int32 nMRUCount = m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount();
911 assert(nPos <= COMBOBOX_MAX_ENTRIES - nMRUCount)(static_cast <bool> (nPos <= (((sal_Int32) 0x7FFFFFFF
) - 1) - nMRUCount) ? void (0) : __assert_fail ("nPos <= COMBOBOX_MAX_ENTRIES - nMRUCount"
, "/home/maarten/src/libreoffice/core/vcl/source/control/combobox.cxx"
, 911, __extension__ __PRETTY_FUNCTION__))
;
912 nRealPos = nPos + nMRUCount;
913 }
914
915 nRealPos = m_pImpl->m_pImplLB->InsertEntry( nRealPos, rStr, rImage );
916 nRealPos -= m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount();
917 CallEventListeners( VclEventId::ComboboxItemAdded, reinterpret_cast<void*>(nRealPos) );
918 return nRealPos;
919}
920
921void ComboBox::RemoveEntryAt(sal_Int32 const nPos)
922{
923 const sal_Int32 nMRUCount = m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount();
924 assert(nPos >= 0 && nPos <= COMBOBOX_MAX_ENTRIES - nMRUCount)(static_cast <bool> (nPos >= 0 && nPos <=
(((sal_Int32) 0x7FFFFFFF) - 1) - nMRUCount) ? void (0) : __assert_fail
("nPos >= 0 && nPos <= COMBOBOX_MAX_ENTRIES - nMRUCount"
, "/home/maarten/src/libreoffice/core/vcl/source/control/combobox.cxx"
, 924, __extension__ __PRETTY_FUNCTION__))
;
925 m_pImpl->m_pImplLB->RemoveEntry( nPos + nMRUCount );
926 CallEventListeners( VclEventId::ComboboxItemRemoved, reinterpret_cast<void*>(nPos) );
927}
928
929void ComboBox::Clear()
930{
931 if (!m_pImpl->m_pImplLB)
932 return;
933 m_pImpl->m_pImplLB->Clear();
934 CallEventListeners( VclEventId::ComboboxItemRemoved, reinterpret_cast<void*>(-1) );
935}
936
937Image ComboBox::GetEntryImage( sal_Int32 nPos ) const
938{
939 if (m_pImpl->m_pImplLB->GetEntryList()->HasEntryImage(nPos))
940 return m_pImpl->m_pImplLB->GetEntryList()->GetEntryImage( nPos );
941 return Image();
942}
943
944sal_Int32 ComboBox::GetEntryPos( const OUString& rStr ) const
945{
946 sal_Int32 nPos = m_pImpl->m_pImplLB->GetEntryList()->FindEntry( rStr );
947 if ( nPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
948 nPos -= m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount();
949 return nPos;
950}
951
952OUString ComboBox::GetEntry( sal_Int32 nPos ) const
953{
954 const sal_Int32 nMRUCount = m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount();
955 if (nPos < 0 || nPos > COMBOBOX_MAX_ENTRIES(((sal_Int32) 0x7FFFFFFF) - 1) - nMRUCount)
956 return OUString();
957
958 return m_pImpl->m_pImplLB->GetEntryList()->GetEntryText( nPos + nMRUCount );
959}
960
961sal_Int32 ComboBox::GetEntryCount() const
962{
963 if (!m_pImpl->m_pImplLB)
964 return 0;
965 return m_pImpl->m_pImplLB->GetEntryList()->GetEntryCount() - m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount();
966}
967
968bool ComboBox::IsTravelSelect() const
969{
970 return m_pImpl->m_pImplLB->IsTravelSelect();
971}
972
973bool ComboBox::IsInDropDown() const
974{
975 // when the dropdown is dismissed, first mbInPopupMode is set to false, and on the next event iteration then
976 // mbPopupMode is set to false
977 return m_pImpl->m_pFloatWin && m_pImpl->m_pFloatWin->IsInPopupMode() && m_pImpl->m_pFloatWin->ImplIsInPrivatePopupMode();
978}
979
980bool ComboBox::IsMultiSelectionEnabled() const
981{
982 return m_pImpl->m_pImplLB->IsMultiSelectionEnabled();
983}
984
985void ComboBox::SetSelectHdl(const Link<ComboBox&,void>& rLink) { m_pImpl->m_SelectHdl = rLink; }
986
987void ComboBox::SetEntryActivateHdl(const Link<Edit&,bool>& rLink)
988{
989 if (!m_pImpl->m_pSubEdit)
990 return;
991 m_pImpl->m_pSubEdit->SetActivateHdl(rLink);
992}
993
994Size ComboBox::GetOptimalSize() const
995{
996 return CalcMinimumSize();
997}
998
999long ComboBox::getMaxWidthScrollBarAndDownButton() const
1000{
1001 long nButtonDownWidth = 0;
1002
1003 vcl::Window *pBorder = GetWindow( GetWindowType::Border );
1004 ImplControlValue aControlValue;
1005 tools::Rectangle aContent, aBound;
1006
1007 // use the full extent of the control
1008 tools::Rectangle aArea( Point(), pBorder->GetOutputSizePixel() );
1009
1010 if ( GetNativeControlRegion(ControlType::Combobox, ControlPart::ButtonDown,
1011 aArea, ControlState::NONE, aControlValue, aBound, aContent) )
1012 {
1013 nButtonDownWidth = aContent.getWidth();
1014 }
1015
1016 long nScrollBarWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
1017
1018 return std::max(nScrollBarWidth, nButtonDownWidth);
1019}
1020
1021Size ComboBox::CalcMinimumSize() const
1022{
1023 Size aSz;
1024
1025 if (!m_pImpl->m_pImplLB)
1026 return aSz;
1027
1028 if (!IsDropDownBox())
1029 {
1030 aSz = m_pImpl->m_pImplLB->CalcSize( m_pImpl->m_pImplLB->GetEntryList()->GetEntryCount() );
1031 aSz.AdjustHeight(m_pImpl->m_nDDHeight );
1032 }
1033 else
1034 {
1035 aSz.setHeight( Edit::CalcMinimumSizeForText(GetText()).Height() );
1036
1037 if (m_pImpl->m_nWidthInChars!= -1)
1038 aSz.setWidth(m_pImpl->m_nWidthInChars * approximate_digit_width());
1039 else
1040 aSz.setWidth(m_pImpl->m_pImplLB->GetMaxEntryWidth());
1041 }
1042
1043 if (m_pImpl->m_nMaxWidthChars != -1)
1044 {
1045 long nMaxWidth = m_pImpl->m_nMaxWidthChars * approximate_char_width();
1046 aSz.setWidth( std::min(aSz.Width(), nMaxWidth) );
1047 }
1048
1049 if (IsDropDownBox())
1050 aSz.AdjustWidth(getMaxWidthScrollBarAndDownButton() );
1051
1052 ComboBoxBounds aBounds(m_pImpl->calcComboBoxDropDownComponentBounds(
1053 Size(0xFFFF, 0xFFFF), Size(0xFFFF, 0xFFFF)));
1054 aSz.AdjustWidth(aBounds.aSubEditPos.X()*2 );
1055
1056 aSz.AdjustWidth(ImplGetExtraXOffset() * 2 );
1057
1058 aSz = CalcWindowSize( aSz );
1059 return aSz;
1060}
1061
1062Size ComboBox::CalcAdjustedSize( const Size& rPrefSize ) const
1063{
1064 Size aSz = rPrefSize;
1065 sal_Int32 nLeft, nTop, nRight, nBottom;
1066 static_cast<vcl::Window*>(const_cast<ComboBox *>(this))->GetBorder( nLeft, nTop, nRight, nBottom );
1067 aSz.AdjustHeight( -(nTop+nBottom) );
1068 if ( !IsDropDownBox() )
1069 {
1070 long nEntryHeight = CalcBlockSize( 1, 1 ).Height();
1071 long nLines = aSz.Height() / nEntryHeight;
1072 if ( nLines < 1 )
1073 nLines = 1;
1074 aSz.setHeight( nLines * nEntryHeight );
1075 aSz.AdjustHeight(m_pImpl->m_nDDHeight );
1076 }
1077 else
1078 {
1079 aSz.setHeight( m_pImpl->m_nDDHeight );
1080 }
1081 aSz.AdjustHeight(nTop+nBottom );
1082
1083 aSz = CalcWindowSize( aSz );
1084 return aSz;
1085}
1086
1087Size ComboBox::CalcBlockSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const
1088{
1089 // show ScrollBars where appropriate
1090 Size aMinSz = CalcMinimumSize();
1091 Size aSz;
1092
1093 // height
1094 if ( nLines )
1095 {
1096 if ( !IsDropDownBox() )
1097 aSz.setHeight( m_pImpl->m_pImplLB->CalcSize( nLines ).Height() + m_pImpl->m_nDDHeight );
1098 else
1099 aSz.setHeight( m_pImpl->m_nDDHeight );
1100 }
1101 else
1102 aSz.setHeight( aMinSz.Height() );
1103
1104 // width
1105 if ( nColumns )
1106 aSz.setWidth( nColumns * approximate_char_width() );
1107 else
1108 aSz.setWidth( aMinSz.Width() );
1109
1110 if ( IsDropDownBox() )
1111 aSz.AdjustWidth(getMaxWidthScrollBarAndDownButton() );
1112
1113 if ( !IsDropDownBox() )
1114 {
1115 if ( aSz.Width() < aMinSz.Width() )
1116 aSz.AdjustHeight(GetSettings().GetStyleSettings().GetScrollBarSize() );
1117 if ( aSz.Height() < aMinSz.Height() )
1118 aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
1119 }
1120
1121 aSz.AdjustWidth(ImplGetExtraXOffset() * 2 );
1122
1123 aSz = CalcWindowSize( aSz );
1124 return aSz;
1125}
1126
1127long ComboBox::GetDropDownEntryHeight() const
1128{
1129 return m_pImpl->m_pImplLB->GetEntryHeight();
1130}
1131
1132void ComboBox::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const
1133{
1134 long nCharWidth = GetTextWidth(OUString(u'x'));
1135 if ( !IsDropDownBox() )
1136 {
1137 Size aOutSz = m_pImpl->m_pImplLB->GetMainWindow()->GetOutputSizePixel();
1138 rnCols = (nCharWidth > 0) ? static_cast<sal_uInt16>(aOutSz.Width()/nCharWidth) : 1;
1139 rnLines = static_cast<sal_uInt16>(aOutSz.Height()/GetDropDownEntryHeight());
1140 }
1141 else
1142 {
1143 Size aOutSz = m_pImpl->m_pSubEdit->GetOutputSizePixel();
1144 rnCols = (nCharWidth > 0) ? static_cast<sal_uInt16>(aOutSz.Width()/nCharWidth) : 1;
1145 rnLines = 1;
1146 }
1147}
1148
1149void ComboBox::Draw( OutputDevice* pDev, const Point& rPos, DrawFlags nFlags )
1150{
1151 m_pImpl->m_pImplLB->GetMainWindow()->ApplySettings(*pDev);
1152
1153 Point aPos = pDev->LogicToPixel( rPos );
1154 Size aSize = GetSizePixel();
1155 vcl::Font aFont = m_pImpl->m_pImplLB->GetMainWindow()->GetDrawPixelFont( pDev );
1156
1157 pDev->Push();
1158 pDev->SetMapMode();
1159 pDev->SetFont( aFont );
1160 pDev->SetTextFillColor();
1161
1162 // Border/Background
1163 pDev->SetLineColor();
1164 pDev->SetFillColor();
1165 bool bBorder = (GetStyle() & WB_BORDER);
1166 bool bBackground = IsControlBackground();
1167 if ( bBorder || bBackground )
1168 {
1169 tools::Rectangle aRect( aPos, aSize );
1170 // aRect.Top() += nEditHeight;
1171 if ( bBorder )
1172 {
1173 ImplDrawFrame( pDev, aRect );
1174 }
1175 if ( bBackground )
1176 {
1177 pDev->SetFillColor( GetControlBackground() );
1178 pDev->DrawRect( aRect );
1179 }
1180 }
1181
1182 // contents
1183 if ( !IsDropDownBox() )
1184 {
1185 long nOnePixel = GetDrawPixel( pDev, 1 );
1186 long nTextHeight = pDev->GetTextHeight();
1187 long nEditHeight = nTextHeight + 6*nOnePixel;
1188 DrawTextFlags nTextStyle = DrawTextFlags::VCenter;
1189
1190 // First, draw the edit part
1191 Size aOrigSize(m_pImpl->m_pSubEdit->GetSizePixel());
1192 m_pImpl->m_pSubEdit->SetSizePixel(Size(aSize.Width(), nEditHeight));
1193 m_pImpl->m_pSubEdit->Draw( pDev, aPos, nFlags );
1194 m_pImpl->m_pSubEdit->SetSizePixel(aOrigSize);
1195
1196 // Second, draw the listbox
1197 if ( GetStyle() & WB_CENTER )
1198 nTextStyle |= DrawTextFlags::Center;
1199 else if ( GetStyle() & WB_RIGHT )
1200 nTextStyle |= DrawTextFlags::Right;
1201 else
1202 nTextStyle |= DrawTextFlags::Left;
1203
1204 if ( nFlags & DrawFlags::Mono )
1205 {
1206 pDev->SetTextColor( COL_BLACK );
1207 }
1208 else
1209 {
1210 if ( !IsEnabled() )
1211 {
1212 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1213 pDev->SetTextColor( rStyleSettings.GetDisableColor() );
1214 }
1215 else
1216 {
1217 pDev->SetTextColor( GetTextColor() );
1218 }
1219 }
1220
1221 tools::Rectangle aClip( aPos, aSize );
1222 pDev->IntersectClipRegion( aClip );
1223 sal_Int32 nLines = static_cast<sal_Int32>( nTextHeight > 0 ? (aSize.Height()-nEditHeight)/nTextHeight : 1 );
1224 if ( !nLines )
1225 nLines = 1;
1226 const sal_Int32 nTEntry = IsReallyVisible() ? m_pImpl->m_pImplLB->GetTopEntry() : 0;
1227
1228 tools::Rectangle aTextRect( aPos, aSize );
1229
1230 aTextRect.AdjustLeft(3*nOnePixel );
1231 aTextRect.AdjustRight( -(3*nOnePixel) );
1232 aTextRect.AdjustTop(nEditHeight + nOnePixel );
1233 aTextRect.SetBottom( aTextRect.Top() + nTextHeight );
1234
1235 // the drawing starts here
1236 for ( sal_Int32 n = 0; n < nLines; ++n )
1237 {
1238 pDev->DrawText( aTextRect, m_pImpl->m_pImplLB->GetEntryList()->GetEntryText( n+nTEntry ), nTextStyle );
1239 aTextRect.AdjustTop(nTextHeight );
1240 aTextRect.AdjustBottom(nTextHeight );
1241 }
1242 }
1243
1244 pDev->Pop();
1245
1246 // Call Edit::Draw after restoring the MapMode...
1247 if ( IsDropDownBox() )
1248 {
1249 Size aOrigSize(m_pImpl->m_pSubEdit->GetSizePixel());
1250 m_pImpl->m_pSubEdit->SetSizePixel(GetSizePixel());
1251 m_pImpl->m_pSubEdit->Draw( pDev, rPos, nFlags );
1252 m_pImpl->m_pSubEdit->SetSizePixel(aOrigSize);
1253 // DD-Button ?
1254 }
1255}
1256
1257void ComboBox::SetUserDrawHdl(const Link<UserDrawEvent*, void>& rLink)
1258{
1259 m_pImpl->m_pImplLB->SetUserDrawHdl(rLink);
1260}
1261
1262void ComboBox::SetUserItemSize( const Size& rSz )
1263{
1264 m_pImpl->m_pImplLB->GetMainWindow()->SetUserItemSize( rSz );
1265}
1266
1267void ComboBox::EnableUserDraw( bool bUserDraw )
1268{
1269 m_pImpl->m_pImplLB->GetMainWindow()->EnableUserDraw( bUserDraw );
1270}
1271
1272bool ComboBox::IsUserDrawEnabled() const
1273{
1274 return m_pImpl->m_pImplLB->GetMainWindow()->IsUserDrawEnabled();
1275}
1276
1277void ComboBox::DrawEntry(const UserDrawEvent& rEvt)
1278{
1279 SAL_WARN_IF(rEvt.GetWindow() != m_pImpl->m_pImplLB->GetMainWindow(), "vcl", "DrawEntry?!")do { if (true && (rEvt.GetWindow() != m_pImpl->m_pImplLB
->GetMainWindow())) { 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
() << "DrawEntry?!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/combobox.cxx"
":" "1279" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DrawEntry?!"), 0); } else { ::std::
ostringstream sal_detail_stream; sal_detail_stream << "DrawEntry?!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/control/combobox.cxx"
":" "1279" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "DrawEntry?!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/combobox.cxx"
":" "1279" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "DrawEntry?!"), 0); } else { ::std::
ostringstream sal_detail_stream; sal_detail_stream << "DrawEntry?!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/control/combobox.cxx"
":" "1279" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1280 m_pImpl->m_pImplLB->GetMainWindow()->DrawEntry(*rEvt.GetRenderContext(), rEvt.GetItemId(), /*bDrawImage*/false, /*bDrawText*/false);
1281}
1282
1283void ComboBox::AddSeparator( sal_Int32 n )
1284{
1285 m_pImpl->m_pImplLB->AddSeparator( n );
1286}
1287
1288void ComboBox::SetMRUEntries( const OUString& rEntries )
1289{
1290 m_pImpl->m_pImplLB->SetMRUEntries( rEntries, ';' );
1291}
1292
1293OUString ComboBox::GetMRUEntries() const
1294{
1295 return m_pImpl->m_pImplLB ? m_pImpl->m_pImplLB->GetMRUEntries( ';' ) : OUString();
1296}
1297
1298void ComboBox::SetMaxMRUCount( sal_Int32 n )
1299{
1300 m_pImpl->m_pImplLB->SetMaxMRUCount( n );
1301}
1302
1303sal_Int32 ComboBox::GetMaxMRUCount() const
1304{
1305 return m_pImpl->m_pImplLB ? m_pImpl->m_pImplLB->GetMaxMRUCount() : 0;
1306}
1307
1308sal_uInt16 ComboBox::GetDisplayLineCount() const
1309{
1310 return m_pImpl->m_pImplLB ? m_pImpl->m_pImplLB->GetDisplayLineCount() : 0;
1311}
1312
1313void ComboBox::SetEntryData( sal_Int32 nPos, void* pNewData )
1314{
1315 m_pImpl->m_pImplLB->SetEntryData( nPos + m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount(), pNewData );
1316}
1317
1318void* ComboBox::GetEntryData( sal_Int32 nPos ) const
1319{
1320 return m_pImpl->m_pImplLB->GetEntryList()->GetEntryData(
1321 nPos + m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount() );
1322}
1323
1324sal_Int32 ComboBox::GetTopEntry() const
1325{
1326 sal_Int32 nPos = GetEntryCount() ? m_pImpl->m_pImplLB->GetTopEntry() : LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
1327 if (nPos < m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount())
1328 nPos = 0;
1329 return nPos;
1330}
1331
1332tools::Rectangle ComboBox::GetDropDownPosSizePixel() const
1333{
1334 return m_pImpl->m_pFloatWin
1335 ? m_pImpl->m_pFloatWin->GetWindowExtentsRelative(this)
1336 : tools::Rectangle();
1337}
1338
1339const Wallpaper& ComboBox::GetDisplayBackground() const
1340{
1341 if (!m_pImpl->m_pSubEdit->IsBackground())
1342 return Control::GetDisplayBackground();
1343
1344 const Wallpaper& rBack = m_pImpl->m_pSubEdit->GetBackground();
1345 if( ! rBack.IsBitmap() &&
1346 ! rBack.IsGradient() &&
1347 rBack == COL_TRANSPARENT
1348 )
1349 return Control::GetDisplayBackground();
1350 return rBack;
1351}
1352
1353sal_Int32 ComboBox::GetSelectedEntryCount() const
1354{
1355 return m_pImpl->m_pImplLB->GetEntryList()->GetSelectedEntryCount();
1356}
1357
1358sal_Int32 ComboBox::GetSelectedEntryPos( sal_Int32 nIndex ) const
1359{
1360 sal_Int32 nPos = m_pImpl->m_pImplLB->GetEntryList()->GetSelectedEntryPos( nIndex );
1361 if ( nPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1362 {
1363 if (nPos < m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount())
1364 nPos = m_pImpl->m_pImplLB->GetEntryList()->FindEntry(m_pImpl->m_pImplLB->GetEntryList()->GetEntryText(nPos));
1365 nPos = sal::static_int_cast<sal_Int32>(nPos - m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount());
1366 }
1367 return nPos;
1368}
1369
1370bool ComboBox::IsEntryPosSelected( sal_Int32 nPos ) const
1371{
1372 return m_pImpl->m_pImplLB->GetEntryList()->IsEntryPosSelected(
1373 nPos + m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount() );
1374}
1375
1376void ComboBox::SelectEntryPos( sal_Int32 nPos, bool bSelect)
1377{
1378 if (nPos < m_pImpl->m_pImplLB->GetEntryList()->GetEntryCount())
1379 m_pImpl->m_pImplLB->SelectEntry(
1380 nPos + m_pImpl->m_pImplLB->GetEntryList()->GetMRUCount(), bSelect);
1381}
1382
1383void ComboBox::SetNoSelection()
1384{
1385 m_pImpl->m_pImplLB->SetNoSelection();
1386 m_pImpl->m_pSubEdit->SetText( OUString() );
1387}
1388
1389tools::Rectangle ComboBox::GetBoundingRectangle( sal_Int32 nItem ) const
1390{
1391 tools::Rectangle aRect = m_pImpl->m_pImplLB->GetMainWindow()->GetBoundingRectangle( nItem );
1392 tools::Rectangle aOffset = m_pImpl->m_pImplLB->GetMainWindow()->GetWindowExtentsRelative( static_cast<vcl::Window*>(const_cast<ComboBox *>(this)) );
1393 aRect.Move( aOffset.TopLeft().X(), aOffset.TopLeft().Y() );
1394 return aRect;
1395}
1396
1397void ComboBox::SetBorderStyle( WindowBorderStyle nBorderStyle )
1398{
1399 Window::SetBorderStyle( nBorderStyle );
1400 if ( !IsDropDownBox() )
1401 {
1402 m_pImpl->m_pSubEdit->SetBorderStyle( nBorderStyle );
1403 m_pImpl->m_pImplLB->SetBorderStyle( nBorderStyle );
1404 }
1405}
1406
1407long ComboBox::GetIndexForPoint( const Point& rPoint, sal_Int32& rPos ) const
1408{
1409 if( !HasLayoutData() )
1410 FillLayoutData();
1411
1412 // check whether rPoint fits at all
1413 long nIndex = Control::GetIndexForPoint( rPoint );
1414 if( nIndex != -1 )
1415 {
1416 // point must be either in main list window
1417 // or in impl window (dropdown case)
1418 ImplListBoxWindow* rMain = m_pImpl->m_pImplLB->GetMainWindow();
1419
1420 // convert coordinates to ImplListBoxWindow pixel coordinate space
1421 Point aConvPoint = LogicToPixel( rPoint );
1422 aConvPoint = OutputToAbsoluteScreenPixel( aConvPoint );
1423 aConvPoint = rMain->AbsoluteScreenToOutputPixel( aConvPoint );
1424 aConvPoint = rMain->PixelToLogic( aConvPoint );
1425
1426 // try to find entry
1427 sal_Int32 nEntry = rMain->GetEntryPosForPoint( aConvPoint );
1428 if( nEntry == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1429 nIndex = -1;
1430 else
1431 rPos = nEntry;
1432 }
1433
1434 // get line relative index
1435 if( nIndex != -1 )
1436 nIndex = ToRelativeLineIndex( nIndex );
1437
1438 return nIndex;
1439}
1440
1441ComboBoxBounds ComboBox::Impl::calcComboBoxDropDownComponentBounds(
1442 const Size &rOutSz, const Size &rBorderOutSz) const
1443{
1444 ComboBoxBounds aBounds;
1445
1446 long nTop = 0;
1447 long nBottom = rOutSz.Height();
1448
1449 vcl::Window *pBorder = m_rThis.GetWindow( GetWindowType::Border );
1450 ImplControlValue aControlValue;
1451 Point aPoint;
1452 tools::Rectangle aContent, aBound;
1453
1454 // use the full extent of the control
1455 tools::Rectangle aArea( aPoint, rBorderOutSz );
1456
1457 if (m_rThis.GetNativeControlRegion(ControlType::Combobox, ControlPart::ButtonDown,
1458 aArea, ControlState::NONE, aControlValue, aBound, aContent) )
1459 {
1460 // convert back from border space to local coordinates
1461 aPoint = pBorder->ScreenToOutputPixel(m_rThis.OutputToScreenPixel(aPoint));
1462 aContent.Move(-aPoint.X(), -aPoint.Y());
1463
1464 aBounds.aButtonPos = Point(aContent.Left(), nTop);
1465 aBounds.aButtonSize = Size(aContent.getWidth(), (nBottom-nTop));
1466
1467 // adjust the size of the edit field
1468 if (m_rThis.GetNativeControlRegion(ControlType::Combobox, ControlPart::SubEdit,
1469 aArea, ControlState::NONE, aControlValue, aBound, aContent) )
1470 {
1471 // convert back from border space to local coordinates
1472 aContent.Move(-aPoint.X(), -aPoint.Y());
1473
1474 // use the themes drop down size
1475 aBounds.aSubEditPos = aContent.TopLeft();
1476 aBounds.aSubEditSize = aContent.GetSize();
1477 }
1478 else
1479 {
1480 // use the themes drop down size for the button
1481 aBounds.aSubEditSize = Size(rOutSz.Width() - aContent.getWidth(), rOutSz.Height());
1482 }
1483 }
1484 else
1485 {
1486 long nSBWidth = m_rThis.GetSettings().GetStyleSettings().GetScrollBarSize();
1487 nSBWidth = m_rThis.CalcZoom( nSBWidth );
1488 aBounds.aSubEditSize = Size(rOutSz.Width() - nSBWidth, rOutSz.Height());
1489 aBounds.aButtonPos = Point(rOutSz.Width() - nSBWidth, nTop);
1490 aBounds.aButtonSize = Size(nSBWidth, (nBottom-nTop));
1491 }
1492 return aBounds;
1493}
1494
1495void ComboBox::SetWidthInChars(sal_Int32 nWidthInChars)
1496{
1497 if (nWidthInChars != m_pImpl->m_nWidthInChars)
1498 {
1499 m_pImpl->m_nWidthInChars = nWidthInChars;
1500 queue_resize();
1501 }
1502}
1503
1504void ComboBox::setMaxWidthChars(sal_Int32 nWidth)
1505{
1506 if (nWidth != m_pImpl->m_nMaxWidthChars)
1507 {
1508 m_pImpl->m_nMaxWidthChars = nWidth;
1509 queue_resize();
1510 }
1511}
1512
1513bool ComboBox::set_property(const OString &rKey, const OUString &rValue)
1514{
1515 if (rKey == "width-chars")
1516 SetWidthInChars(rValue.toInt32());
1517 else if (rKey == "max-width-chars")
1518 setMaxWidthChars(rValue.toInt32());
1519 else if (rKey == "can-focus")
1520 {
1521 // as far as I can see in Gtk, setting a ComboBox as can.focus means
1522 // the focus gets stuck in it, so try here to behave like gtk does
1523 // with the settings that work, i.e. can.focus of false doesn't
1524 // set the hard WB_NOTABSTOP
1525 WinBits nBits = GetStyle();
1526 nBits &= ~(WB_TABSTOP|WB_NOTABSTOP);
1527 if (toBool(rValue))
1528 nBits |= WB_TABSTOP;
1529 SetStyle(nBits);
1530 }
1531 else if (rKey == "placeholder-text")
1532 SetPlaceholderText(rValue);
1533 else
1534 return Control::set_property(rKey, rValue);
1535 return true;
1536}
1537
1538FactoryFunction ComboBox::GetUITestFactory() const
1539{
1540 return ComboBoxUIObject::create;
1541}
1542
1543void ComboBox::DumpAsPropertyTree(tools::JsonWriter& rJsonWriter)
1544{
1545 Control::DumpAsPropertyTree(rJsonWriter);
1546
1547 auto entriesNode = rJsonWriter.startNode("entries");
1548 for (int i = 0; i < GetEntryCount(); ++i)
1549 {
1550 auto entryNode = rJsonWriter.startNode("");
1551 rJsonWriter.put("", GetEntry(i));
1552 }
1553
1554 auto selectedNode = rJsonWriter.startNode("selectedEntries");
1555 for (int i = 0; i < GetSelectedEntryCount(); ++i)
1556 {
1557 auto entryNode = rJsonWriter.startNode("");
1558 rJsonWriter.put("", GetSelectedEntryPos(i));
1559 }
1560
1561 rJsonWriter.put("selectedCount", GetSelectedEntryCount());
1562}
1563
1564/* 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);
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);
2
Calling copy constructor for 'Reference<ImplBtn>'
5
Returning from copy constructor for 'Reference<ImplBtn>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
6
Calling 'Reference::clear'
13
Returning; memory was released
205 if (aTmp.get()) {
14
Calling 'Reference::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)
3
Assuming field 'm_pBody' is non-null
4
Taking true branch
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)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
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
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
)
7
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
8
Calling 'VclReferenceBase::release'
12
Returning; memory was released
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;
15
Use of memory after it is freed
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)
9
Assuming the condition is true
10
Taking true branch
40 delete this;
11
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