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 imp_listbox.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/imp_listbox.cxx

/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.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 <memory>
21
22#include <vcl/svapp.hxx>
23#include <vcl/settings.hxx>
24#include <vcl/event.hxx>
25#include <vcl/scrbar.hxx>
26#include <vcl/toolkit/lstbox.hxx>
27#include <vcl/i18nhelp.hxx>
28#include <vcl/naturalsort.hxx>
29
30#include <listbox.hxx>
31#include <controldata.hxx>
32#include <svdata.hxx>
33#include <window.h>
34
35#include <com/sun/star/accessibility/AccessibleRole.hpp>
36
37#include <rtl/instance.hxx>
38#include <sal/log.hxx>
39#include <o3tl/safeint.hxx>
40#include <osl/diagnose.h>
41#include <comphelper/string.hxx>
42#include <comphelper/processfactory.hxx>
43
44#include <limits>
45
46#define MULTILINE_ENTRY_DRAW_FLAGS( DrawTextFlags::WordBreak | DrawTextFlags::MultiLine | DrawTextFlags
::VCenter )
( DrawTextFlags::WordBreak | DrawTextFlags::MultiLine | DrawTextFlags::VCenter )
47
48using namespace ::com::sun::star;
49
50constexpr long gnBorder = 1;
51
52void ImplInitDropDownButton( PushButton* pButton )
53{
54 pButton->SetSymbol( SymbolType::SPIN_DOWN );
55
56 if ( pButton->IsNativeControlSupported(ControlType::Listbox, ControlPart::Entire)
57 && ! pButton->IsNativeControlSupported(ControlType::Listbox, ControlPart::ButtonDown) )
58 pButton->SetBackground();
59}
60
61ImplEntryList::ImplEntryList( vcl::Window* pWindow )
62{
63 mpWindow = pWindow;
64 mnLastSelected = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
65 mnSelectionAnchor = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
66 mnImages = 0;
67 mbCallSelectionChangedHdl = true;
68
69 mnMRUCount = 0;
70 mnMaxMRUCount = 0;
71}
72
73ImplEntryList::~ImplEntryList()
74{
75 Clear();
76}
77
78void ImplEntryList::Clear()
79{
80 mnImages = 0;
81 maEntries.clear();
82}
83
84void ImplEntryList::SelectEntry( sal_Int32 nPos, bool bSelect )
85{
86 if (0 <= nPos && o3tl::make_unsigned(nPos) < maEntries.size())
87 {
88 std::vector<std::unique_ptr<ImplEntryType> >::iterator iter = maEntries.begin()+nPos;
89
90 if ( ( (*iter)->mbIsSelected != bSelect ) &&
91 ( ( (*iter)->mnFlags & ListBoxEntryFlags::DisableSelection) == ListBoxEntryFlags::NONE ) )
92 {
93 (*iter)->mbIsSelected = bSelect;
94 if ( mbCallSelectionChangedHdl )
95 maSelectionChangedHdl.Call( nPos );
96 }
97 }
98}
99
100namespace
101{
102 struct theSorter
103 : public rtl::StaticWithInit< comphelper::string::NaturalStringSorter, theSorter >
104 {
105 comphelper::string::NaturalStringSorter operator () ()
106 {
107 return comphelper::string::NaturalStringSorter(
108 ::comphelper::getProcessComponentContext(),
109 Application::GetSettings().GetLanguageTag().getLocale());
110 }
111 };
112}
113
114namespace vcl
115{
116 sal_Int32 NaturalSortCompare(const OUString &rA, const OUString &rB)
117 {
118 const comphelper::string::NaturalStringSorter &rSorter = theSorter::get();
119 return rSorter.compare(rA, rB);
120 }
121}
122
123sal_Int32 ImplEntryList::InsertEntry( sal_Int32 nPos, ImplEntryType* pNewEntry, bool bSort )
124{
125 assert(nPos >= 0)(static_cast <bool> (nPos >= 0) ? void (0) : __assert_fail
("nPos >= 0", "/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
, 125, __extension__ __PRETTY_FUNCTION__))
;
126 assert(maEntries.size() < LISTBOX_MAX_ENTRIES)(static_cast <bool> (maEntries.size() < (((sal_Int32
) 0x7FFFFFFF) - 1)) ? void (0) : __assert_fail ("maEntries.size() < LISTBOX_MAX_ENTRIES"
, "/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
, 126, __extension__ __PRETTY_FUNCTION__))
;
127
128 if ( !!pNewEntry->maImage )
129 mnImages++;
130
131 sal_Int32 insPos = 0;
132 const sal_Int32 nEntriesSize = static_cast<sal_Int32>(maEntries.size());
133
134 if ( !bSort || maEntries.empty())
135 {
136 if (0 <= nPos && nPos < nEntriesSize)
137 {
138 insPos = nPos;
139 maEntries.insert( maEntries.begin() + nPos, std::unique_ptr<ImplEntryType>(pNewEntry) );
140 }
141 else
142 {
143 insPos = nEntriesSize;
144 maEntries.push_back(std::unique_ptr<ImplEntryType>(pNewEntry));
145 }
146 }
147 else
148 {
149 const comphelper::string::NaturalStringSorter &rSorter = theSorter::get();
150
151 const OUString& rStr = pNewEntry->maStr;
152
153 ImplEntryType* pTemp = GetEntry( nEntriesSize-1 );
154
155 try
156 {
157 sal_Int32 nComp = rSorter.compare(rStr, pTemp->maStr);
158
159 // fast insert for sorted data
160 if ( nComp >= 0 )
161 {
162 insPos = nEntriesSize;
163 maEntries.push_back(std::unique_ptr<ImplEntryType>(pNewEntry));
164 }
165 else
166 {
167 pTemp = GetEntry( mnMRUCount );
168
169 nComp = rSorter.compare(rStr, pTemp->maStr);
170 if ( nComp <= 0 )
171 {
172 insPos = 0;
173 maEntries.insert(maEntries.begin(), std::unique_ptr<ImplEntryType>(pNewEntry));
174 }
175 else
176 {
177 sal_uLong nLow = mnMRUCount;
178 sal_uLong nHigh = maEntries.size()-1;
179 sal_Int32 nMid;
180
181 // binary search
182 do
183 {
184 nMid = static_cast<sal_Int32>((nLow + nHigh) / 2);
185 pTemp = GetEntry( nMid );
186
187 nComp = rSorter.compare(rStr, pTemp->maStr);
188
189 if ( nComp < 0 )
190 nHigh = nMid-1;
191 else
192 {
193 if ( nComp > 0 )
194 nLow = nMid + 1;
195 else
196 break;
197 }
198 }
199 while ( nLow <= nHigh );
200
201 if ( nComp >= 0 )
202 nMid++;
203
204 insPos = nMid;
205 maEntries.insert(maEntries.begin()+nMid, std::unique_ptr<ImplEntryType>(pNewEntry));
206 }
207 }
208 }
209 catch (uno::RuntimeException& )
210 {
211 // XXX this is arguable, if the exception occurred because pNewEntry is
212 // garbage you wouldn't insert it. If the exception occurred because the
213 // Collator implementation is garbage then give the user a chance to see
214 // his stuff
215 insPos = 0;
216 maEntries.insert(maEntries.begin(), std::unique_ptr<ImplEntryType>(pNewEntry));
217 }
218
219 }
220
221 return insPos;
222}
223
224void ImplEntryList::RemoveEntry( sal_Int32 nPos )
225{
226 if (0 <= nPos && o3tl::make_unsigned(nPos) < maEntries.size())
227 {
228 std::vector<std::unique_ptr<ImplEntryType> >::iterator iter = maEntries.begin()+ nPos;
229
230 if ( !!(*iter)->maImage )
231 mnImages--;
232
233 maEntries.erase(iter);
234 }
235}
236
237sal_Int32 ImplEntryList::FindEntry( const OUString& rString, bool bSearchMRUArea ) const
238{
239 const sal_Int32 nEntries = static_cast<sal_Int32>(maEntries.size());
240 for ( sal_Int32 n = bSearchMRUArea ? 0 : GetMRUCount(); n < nEntries; n++ )
241 {
242 OUString aComp( vcl::I18nHelper::filterFormattingChars( maEntries[n]->maStr ) );
243 if ( aComp == rString )
244 return n;
245 }
246 return LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
247}
248
249sal_Int32 ImplEntryList::FindMatchingEntry( const OUString& rStr, sal_Int32 nStart, bool bLazy ) const
250{
251 sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
252 sal_Int32 nEntryCount = GetEntryCount();
253
254 const vcl::I18nHelper& rI18nHelper = mpWindow->GetSettings().GetLocaleI18nHelper();
255 for ( sal_Int32 n = nStart; n < nEntryCount; )
256 {
257 ImplEntryType* pImplEntry = GetEntry( n );
258 bool bMatch;
259 if ( bLazy )
260 {
261 bMatch = rI18nHelper.MatchString( rStr, pImplEntry->maStr );
262 }
263 else
264 {
265 bMatch = pImplEntry->maStr.startsWith(rStr);
266 }
267 if ( bMatch )
268 {
269 nPos = n;
270 break;
271 }
272
273 n++;
274 }
275
276 return nPos;
277}
278
279long ImplEntryList::GetAddedHeight( sal_Int32 i_nEndIndex, sal_Int32 i_nBeginIndex ) const
280{
281 long nHeight = 0;
282 sal_Int32 nStart = std::min(i_nEndIndex, i_nBeginIndex);
283 sal_Int32 nStop = std::max(i_nEndIndex, i_nBeginIndex);
284 sal_Int32 nEntryCount = GetEntryCount();
285 if( 0 <= nStop && nStop != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) && nEntryCount != 0 )
286 {
287 // sanity check
288 if( nStop > nEntryCount-1 )
289 nStop = nEntryCount-1;
290 if (nStart < 0)
291 nStart = 0;
292 else if( nStart > nEntryCount-1 )
293 nStart = nEntryCount-1;
294
295 sal_Int32 nIndex = nStart;
296 while( nIndex != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) && nIndex < nStop )
297 {
298 long nPosHeight = GetEntryPtr( nIndex )->getHeightWithMargin();
299 if (nHeight > ::std::numeric_limits<long>::max() - nPosHeight)
300 {
301 SAL_WARN( "vcl", "ImplEntryList::GetAddedHeight: truncated")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
() << "ImplEntryList::GetAddedHeight: truncated") == 1)
{ ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), (
"/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "301" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImplEntryList::GetAddedHeight: truncated"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImplEntryList::GetAddedHeight: truncated"; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "301" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImplEntryList::GetAddedHeight: truncated") == 1)
{ ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), (
"/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "301" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImplEntryList::GetAddedHeight: truncated"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImplEntryList::GetAddedHeight: truncated"; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "301" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
302 break;
303 }
304 nHeight += nPosHeight;
305 nIndex++;
306 }
307 }
308 else
309 nHeight = 0;
310 return i_nEndIndex > i_nBeginIndex ? nHeight : -nHeight;
311}
312
313long ImplEntryList::GetEntryHeight( sal_Int32 nPos ) const
314{
315 ImplEntryType* pImplEntry = GetEntry( nPos );
316 return pImplEntry ? pImplEntry->getHeightWithMargin() : 0;
317}
318
319OUString ImplEntryList::GetEntryText( sal_Int32 nPos ) const
320{
321 OUString aEntryText;
322 ImplEntryType* pImplEntry = GetEntry( nPos );
323 if ( pImplEntry )
324 aEntryText = pImplEntry->maStr;
325 return aEntryText;
326}
327
328bool ImplEntryList::HasEntryImage( sal_Int32 nPos ) const
329{
330 bool bImage = false;
331 ImplEntryType* pImplEntry = GetEntry( nPos );
332 if ( pImplEntry )
333 bImage = !!pImplEntry->maImage;
334 return bImage;
335}
336
337Image ImplEntryList::GetEntryImage( sal_Int32 nPos ) const
338{
339 Image aImage;
340 ImplEntryType* pImplEntry = GetEntry( nPos );
341 if ( pImplEntry )
342 aImage = pImplEntry->maImage;
343 return aImage;
344}
345
346void ImplEntryList::SetEntryData( sal_Int32 nPos, void* pNewData )
347{
348 ImplEntryType* pImplEntry = GetEntry( nPos );
349 if ( pImplEntry )
350 pImplEntry->mpUserData = pNewData;
351}
352
353void* ImplEntryList::GetEntryData( sal_Int32 nPos ) const
354{
355 ImplEntryType* pImplEntry = GetEntry( nPos );
356 return pImplEntry ? pImplEntry->mpUserData : nullptr;
357}
358
359void ImplEntryList::SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags )
360{
361 ImplEntryType* pImplEntry = GetEntry( nPos );
362 if ( pImplEntry )
363 pImplEntry->mnFlags = nFlags;
364}
365
366sal_Int32 ImplEntryList::GetSelectedEntryCount() const
367{
368 sal_Int32 nSelCount = 0;
369 for ( sal_Int32 n = GetEntryCount(); n; )
370 {
371 ImplEntryType* pImplEntry = GetEntry( --n );
372 if ( pImplEntry->mbIsSelected )
373 nSelCount++;
374 }
375 return nSelCount;
376}
377
378OUString ImplEntryList::GetSelectedEntry( sal_Int32 nIndex ) const
379{
380 return GetEntryText( GetSelectedEntryPos( nIndex ) );
381}
382
383sal_Int32 ImplEntryList::GetSelectedEntryPos( sal_Int32 nIndex ) const
384{
385 sal_Int32 nSelEntryPos = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
386 sal_Int32 nSel = 0;
387 sal_Int32 nEntryCount = GetEntryCount();
388
389 for ( sal_Int32 n = 0; n < nEntryCount; n++ )
390 {
391 ImplEntryType* pImplEntry = GetEntry( n );
392 if ( pImplEntry->mbIsSelected )
393 {
394 if ( nSel == nIndex )
395 {
396 nSelEntryPos = n;
397 break;
398 }
399 nSel++;
400 }
401 }
402
403 return nSelEntryPos;
404}
405
406bool ImplEntryList::IsEntryPosSelected( sal_Int32 nIndex ) const
407{
408 ImplEntryType* pImplEntry = GetEntry( nIndex );
409 return pImplEntry && pImplEntry->mbIsSelected;
410}
411
412bool ImplEntryList::IsEntrySelectable( sal_Int32 nPos ) const
413{
414 ImplEntryType* pImplEntry = GetEntry( nPos );
415 return pImplEntry == nullptr || ((pImplEntry->mnFlags & ListBoxEntryFlags::DisableSelection) == ListBoxEntryFlags::NONE);
416}
417
418sal_Int32 ImplEntryList::FindFirstSelectable( sal_Int32 nPos, bool bForward /* = true */ )
419{
420 if( IsEntrySelectable( nPos ) )
421 return nPos;
422
423 if( bForward )
424 {
425 for( nPos = nPos + 1; nPos < GetEntryCount(); nPos++ )
426 {
427 if( IsEntrySelectable( nPos ) )
428 return nPos;
429 }
430 }
431 else
432 {
433 while( nPos )
434 {
435 nPos--;
436 if( IsEntrySelectable( nPos ) )
437 return nPos;
438 }
439 }
440
441 return LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
442}
443
444ImplListBoxWindow::ImplListBoxWindow( vcl::Window* pParent, WinBits nWinStyle ) :
445 Control( pParent, 0 ),
446 maQuickSelectionEngine( *this )
447{
448 mpEntryList.reset(new ImplEntryList( this ));
449
450 mnTop = 0;
451 mnLeft = 0;
452 mnSelectModifier = 0;
453 mnUserDrawEntry = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
454 mbTrack = false;
455 mbTravelSelect = false;
456 mbTrackingSelect = false;
457 mbSelectionChanged = false;
458 mbMouseMoveSelect = false;
459 mbMulti = false;
460 mbGrabFocus = false;
461 mbUserDrawEnabled = false;
462 mbInUserDraw = false;
463 mbReadOnly = false;
464 mbHasFocusRect = false;
465 mbRight = ( nWinStyle & WB_RIGHT );
466 mbCenter = ( nWinStyle & WB_CENTER );
467 mbSimpleMode = ( nWinStyle & WB_SIMPLEMODE );
468 mbSort = ( nWinStyle & WB_SORT );
469 mbIsDropdown = ( nWinStyle & WB_DROPDOWN );
470 mbEdgeBlending = false;
471
472 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
473 mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
474
475 SetLineColor();
476 SetTextFillColor();
477 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
478
479 ApplySettings(*this);
480 ImplCalcMetrics();
481}
482
483ImplListBoxWindow::~ImplListBoxWindow()
484{
485 disposeOnce();
486}
487
488void ImplListBoxWindow::dispose()
489{
490 mpEntryList.reset();
491 Control::dispose();
492}
493
494void ImplListBoxWindow::ApplySettings(vcl::RenderContext& rRenderContext)
495{
496 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
497
498 ApplyControlFont(rRenderContext, rStyleSettings.GetFieldFont());
499 ApplyControlForeground(rRenderContext, rStyleSettings.GetFieldTextColor());
500
501 if (IsControlBackground())
502 rRenderContext.SetBackground(GetControlBackground());
503 else
504 rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
505}
506
507void ImplListBoxWindow::ImplCalcMetrics()
508{
509 mnMaxWidth = 0;
510 mnMaxTxtWidth = 0;
511 mnMaxImgWidth = 0;
512 mnMaxImgTxtWidth= 0;
513 mnMaxImgHeight = 0;
514
515 mnTextHeight = static_cast<sal_uInt16>(GetTextHeight());
516 mnMaxTxtHeight = mnTextHeight + gnBorder;
517 mnMaxHeight = mnMaxTxtHeight;
518
519 if ( maUserItemSize.Height() > mnMaxHeight )
520 mnMaxHeight = static_cast<sal_uInt16>(maUserItemSize.Height());
521 if ( maUserItemSize.Width() > mnMaxWidth )
522 mnMaxWidth= static_cast<sal_uInt16>(maUserItemSize.Width());
523
524 for ( sal_Int32 n = mpEntryList->GetEntryCount(); n; )
525 {
526 ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( --n );
527 ImplUpdateEntryMetrics( *pEntry );
528 }
529
530 if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
531 {
532 Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryPtr( mnCurrentPos )->getHeightWithMargin() );
533 maFocusRect.SetSize( aSz );
534 }
535}
536
537void ImplListBoxWindow::Clear()
538{
539 mpEntryList->Clear();
540
541 mnMaxHeight = mnMaxTxtHeight;
542 mnMaxWidth = 0;
543 mnMaxTxtWidth = 0;
544 mnMaxImgTxtWidth= 0;
545 mnMaxImgWidth = 0;
546 mnMaxImgHeight = 0;
547 mnTop = 0;
548 mnLeft = 0;
549 ImplClearLayoutData();
550
551 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
552 maQuickSelectionEngine.Reset();
553
554 Invalidate();
555}
556
557void ImplListBoxWindow::SetUserItemSize( const Size& rSz )
558{
559 ImplClearLayoutData();
560 maUserItemSize = rSz;
561 ImplCalcMetrics();
562}
563
564namespace {
565
566struct ImplEntryMetrics
567{
568 bool bText;
569 bool bImage;
570 long nEntryWidth;
571 long nEntryHeight;
572 long nTextWidth;
573 long nImgWidth;
574 long nImgHeight;
575};
576
577}
578
579long ImplEntryType::getHeightWithMargin() const
580{
581 return mnHeight + ImplGetSVData()->maNWFData.mnListBoxEntryMargin;
582}
583
584SalLayoutGlyphs* ImplEntryType::GetTextGlyphs(const OutputDevice* pOutputDevice)
585{
586 if (maStrGlyphs.IsValid())
587 // Use pre-calculated result.
588 return &maStrGlyphs;
589
590 std::unique_ptr<SalLayout> pLayout = pOutputDevice->ImplLayout(
591 maStr, 0, maStr.getLength(), Point(0, 0), 0, nullptr, SalLayoutFlags::GlyphItemsOnly);
592 if (!pLayout)
593 return nullptr;
594
595 const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs();
596 if (!pGlyphs)
597 return nullptr;
598
599 // Remember the calculation result.
600 maStrGlyphs = *pGlyphs;
601
602 return &maStrGlyphs;
603}
604
605void ImplListBoxWindow::ImplUpdateEntryMetrics( ImplEntryType& rEntry )
606{
607 ImplEntryMetrics aMetrics;
608 aMetrics.bText = !rEntry.maStr.isEmpty();
609 aMetrics.bImage = !!rEntry.maImage;
610 aMetrics.nEntryWidth = 0;
611 aMetrics.nEntryHeight = 0;
612 aMetrics.nTextWidth = 0;
613 aMetrics.nImgWidth = 0;
614 aMetrics.nImgHeight = 0;
615
616 if ( aMetrics.bText )
617 {
618 if( rEntry.mnFlags & ListBoxEntryFlags::MultiLine )
619 {
620 // multiline case
621 Size aCurSize( PixelToLogic( GetSizePixel() ) );
622 // set the current size to a large number
623 // GetTextRect should shrink it to the actual size
624 aCurSize.setHeight( 0x7fffff );
625 tools::Rectangle aTextRect( Point( 0, 0 ), aCurSize );
626 aTextRect = GetTextRect( aTextRect, rEntry.maStr, DrawTextFlags::WordBreak | DrawTextFlags::MultiLine );
627 aMetrics.nTextWidth = aTextRect.GetWidth();
628 if( aMetrics.nTextWidth > mnMaxTxtWidth )
629 mnMaxTxtWidth = aMetrics.nTextWidth;
630 aMetrics.nEntryWidth = mnMaxTxtWidth;
631 aMetrics.nEntryHeight = aTextRect.GetHeight() + gnBorder;
632 }
633 else
634 {
635 // normal single line case
636 const SalLayoutGlyphs* pGlyphs = rEntry.GetTextGlyphs(this);
637 aMetrics.nTextWidth
638 = static_cast<sal_uInt16>(GetTextWidth(rEntry.maStr, 0, -1, nullptr, pGlyphs));
639 if( aMetrics.nTextWidth > mnMaxTxtWidth )
640 mnMaxTxtWidth = aMetrics.nTextWidth;
641 aMetrics.nEntryWidth = mnMaxTxtWidth;
642 aMetrics.nEntryHeight = mnTextHeight + gnBorder;
643 }
644 }
645 if ( aMetrics.bImage )
646 {
647 Size aImgSz = rEntry.maImage.GetSizePixel();
648 aMetrics.nImgWidth = static_cast<sal_uInt16>(CalcZoom( aImgSz.Width() ));
649 aMetrics.nImgHeight = static_cast<sal_uInt16>(CalcZoom( aImgSz.Height() ));
650
651 if( aMetrics.nImgWidth > mnMaxImgWidth )
652 mnMaxImgWidth = aMetrics.nImgWidth;
653 if( aMetrics.nImgHeight > mnMaxImgHeight )
654 mnMaxImgHeight = aMetrics.nImgHeight;
655
656 mnMaxImgTxtWidth = std::max( mnMaxImgTxtWidth, aMetrics.nTextWidth );
657 aMetrics.nEntryHeight = std::max( aMetrics.nImgHeight, aMetrics.nEntryHeight );
658
659 }
660
661 bool bIsUserDrawEnabled = IsUserDrawEnabled();
662 if (bIsUserDrawEnabled || aMetrics.bImage)
663 {
664 aMetrics.nEntryWidth = std::max( aMetrics.nImgWidth, maUserItemSize.Width() );
665 if (!bIsUserDrawEnabled && aMetrics.bText)
666 aMetrics.nEntryWidth += aMetrics.nTextWidth + IMG_TXT_DISTANCE6;
667 aMetrics.nEntryHeight = std::max( std::max( mnMaxImgHeight, maUserItemSize.Height() ) + 2,
668 aMetrics.nEntryHeight );
669 }
670
671 if (!aMetrics.bText && !aMetrics.bImage && !bIsUserDrawEnabled)
672 {
673 // entries which have no (aka an empty) text, and no image,
674 // and are not user-drawn, should be shown nonetheless
675 aMetrics.nEntryHeight = mnTextHeight + gnBorder;
676 }
677
678 if ( aMetrics.nEntryWidth > mnMaxWidth )
679 mnMaxWidth = aMetrics.nEntryWidth;
680 if ( aMetrics.nEntryHeight > mnMaxHeight )
681 mnMaxHeight = aMetrics.nEntryHeight;
682
683 rEntry.mnHeight = aMetrics.nEntryHeight;
684}
685
686void ImplListBoxWindow::ImplCallSelect()
687{
688 if ( !IsTravelSelect() && GetEntryList()->GetMaxMRUCount() )
689 {
690 // Insert the selected entry as MRU, if not already first MRU
691 sal_Int32 nSelected = GetEntryList()->GetSelectedEntryPos( 0 );
692 sal_Int32 nMRUCount = GetEntryList()->GetMRUCount();
693 OUString aSelected = GetEntryList()->GetEntryText( nSelected );
694 sal_Int32 nFirstMatchingEntryPos = GetEntryList()->FindEntry( aSelected, true );
695 if ( nFirstMatchingEntryPos || !nMRUCount )
696 {
697 bool bSelectNewEntry = false;
698 if ( nFirstMatchingEntryPos < nMRUCount )
699 {
700 RemoveEntry( nFirstMatchingEntryPos );
701 nMRUCount--;
702 if ( nFirstMatchingEntryPos == nSelected )
703 bSelectNewEntry = true;
704 }
705 else if ( nMRUCount == GetEntryList()->GetMaxMRUCount() )
706 {
707 RemoveEntry( nMRUCount - 1 );
708 nMRUCount--;
709 }
710
711 ImplClearLayoutData();
712
713 ImplEntryType* pNewEntry = new ImplEntryType( aSelected );
714 pNewEntry->mbIsSelected = bSelectNewEntry;
715 GetEntryList()->InsertEntry( 0, pNewEntry, false );
716 ImplUpdateEntryMetrics( *pNewEntry );
717 GetEntryList()->SetMRUCount( ++nMRUCount );
718 SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
719 maMRUChangedHdl.Call( nullptr );
720 }
721 }
722
723 maSelectHdl.Call( nullptr );
724 mbSelectionChanged = false;
725}
726
727sal_Int32 ImplListBoxWindow::InsertEntry(sal_Int32 nPos, ImplEntryType* pNewEntry, bool bSort)
728{
729 assert(nPos >= 0)(static_cast <bool> (nPos >= 0) ? void (0) : __assert_fail
("nPos >= 0", "/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
, 729, __extension__ __PRETTY_FUNCTION__))
;
730 assert(mpEntryList->GetEntryCount() < LISTBOX_MAX_ENTRIES)(static_cast <bool> (mpEntryList->GetEntryCount() <
(((sal_Int32) 0x7FFFFFFF) - 1)) ? void (0) : __assert_fail (
"mpEntryList->GetEntryCount() < LISTBOX_MAX_ENTRIES", "/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
, 730, __extension__ __PRETTY_FUNCTION__))
;
731
732 ImplClearLayoutData();
733 sal_Int32 nNewPos = mpEntryList->InsertEntry( nPos, pNewEntry, bSort );
734
735 if( GetStyle() & WB_WORDBREAK )
736 pNewEntry->mnFlags |= ListBoxEntryFlags::MultiLine;
737
738 ImplUpdateEntryMetrics( *pNewEntry );
739 return nNewPos;
740}
741
742sal_Int32 ImplListBoxWindow::InsertEntry( sal_Int32 nPos, ImplEntryType* pNewEntry )
743{
744 return InsertEntry(nPos, pNewEntry, mbSort);
745}
746
747void ImplListBoxWindow::RemoveEntry( sal_Int32 nPos )
748{
749 ImplClearLayoutData();
750 mpEntryList->RemoveEntry( nPos );
751 if( mnCurrentPos >= mpEntryList->GetEntryCount() )
752 mnCurrentPos = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
753 ImplCalcMetrics();
754}
755
756void ImplListBoxWindow::SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags )
757{
758 mpEntryList->SetEntryFlags( nPos, nFlags );
759 ImplEntryType* pEntry = mpEntryList->GetMutableEntryPtr( nPos );
760 if( pEntry )
761 ImplUpdateEntryMetrics( *pEntry );
762}
763
764void ImplListBoxWindow::ImplShowFocusRect()
765{
766 if ( mbHasFocusRect )
767 HideFocus();
768 ShowFocus( maFocusRect );
769 mbHasFocusRect = true;
770}
771
772void ImplListBoxWindow::ImplHideFocusRect()
773{
774 if ( mbHasFocusRect )
775 {
776 HideFocus();
777 mbHasFocusRect = false;
778 }
779}
780
781sal_Int32 ImplListBoxWindow::GetEntryPosForPoint( const Point& rPoint ) const
782{
783 long nY = gnBorder;
784
785 sal_Int32 nSelect = mnTop;
786 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nSelect );
787 while (pEntry)
788 {
789 long nEntryHeight = pEntry->getHeightWithMargin();
790 if (rPoint.Y() <= nEntryHeight + nY)
791 break;
792 nY += nEntryHeight;
793 pEntry = mpEntryList->GetEntryPtr( ++nSelect );
794 }
795 if( pEntry == nullptr )
796 nSelect = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
797
798 return nSelect;
799}
800
801bool ImplListBoxWindow::IsVisible( sal_Int32 i_nEntry ) const
802{
803 bool bRet = false;
804
805 if( i_nEntry >= mnTop )
806 {
807 if( mpEntryList->GetAddedHeight( i_nEntry, mnTop ) <
808 PixelToLogic( GetSizePixel() ).Height() )
809 {
810 bRet = true;
811 }
812 }
813
814 return bRet;
815}
816
817long ImplListBoxWindow::GetEntryHeightWithMargin() const
818{
819 long nMargin = ImplGetSVData()->maNWFData.mnListBoxEntryMargin;
820 return mnMaxHeight + nMargin;
821}
822
823sal_Int32 ImplListBoxWindow::GetLastVisibleEntry() const
824{
825 sal_Int32 nPos = mnTop;
826 long nWindowHeight = GetSizePixel().Height();
827 sal_Int32 nCount = mpEntryList->GetEntryCount();
828 long nDiff;
829 for( nDiff = 0; nDiff < nWindowHeight && nPos < nCount; nDiff = mpEntryList->GetAddedHeight( nPos, mnTop ) )
830 nPos++;
831
832 if( nDiff > nWindowHeight && nPos > mnTop )
833 nPos--;
834
835 if( nPos >= nCount )
836 nPos = nCount-1;
837
838 return nPos;
839}
840
841void ImplListBoxWindow::MouseButtonDown( const MouseEvent& rMEvt )
842{
843 mbMouseMoveSelect = false; // only till the first MouseButtonDown
844 maQuickSelectionEngine.Reset();
845
846 if ( !IsReadOnly() )
847 {
848 if( rMEvt.GetClicks() == 1 )
849 {
850 sal_Int32 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
851 if( nSelect != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
852 {
853 if ( !mbMulti && GetEntryList()->GetSelectedEntryCount() )
854 mnTrackingSaveSelection = GetEntryList()->GetSelectedEntryPos( 0 );
855 else
856 mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
857
858 mnCurrentPos = nSelect;
859 mbTrackingSelect = true;
860 bool bCurPosChange = (mnCurrentPos != nSelect);
861 (void)SelectEntries( nSelect, LET_MBDOWN, rMEvt.IsShift(), rMEvt.IsMod1() ,bCurPosChange);
862 mbTrackingSelect = false;
863 if ( mbGrabFocus )
864 GrabFocus();
865
866 StartTracking( StartTrackingFlags::ScrollRepeat );
867 }
868 }
869 if( rMEvt.GetClicks() == 2 )
870 {
871 maDoubleClickHdl.Call( this );
872 }
873 }
874 else // if ( mbGrabFocus )
875 {
876 GrabFocus();
877 }
878}
879
880void ImplListBoxWindow::MouseMove( const MouseEvent& rMEvt )
881{
882 if (rMEvt.IsLeaveWindow() || mbMulti || !IsMouseMoveSelect() || !mpEntryList->GetEntryCount())
883 return;
884
885 tools::Rectangle aRect( Point(), GetOutputSizePixel() );
886 if( !aRect.IsInside( rMEvt.GetPosPixel() ) )
887 return;
888
889 if ( IsMouseMoveSelect() )
890 {
891 sal_Int32 nSelect = GetEntryPosForPoint( rMEvt.GetPosPixel() );
892 if( nSelect == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
893 nSelect = mpEntryList->GetEntryCount() - 1;
894 nSelect = std::min( nSelect, GetLastVisibleEntry() );
895 nSelect = std::min( nSelect, static_cast<sal_Int32>( mpEntryList->GetEntryCount() - 1 ) );
896 // Select only visible Entries with MouseMove, otherwise Tracking...
897 if ( IsVisible( nSelect ) &&
898 mpEntryList->IsEntrySelectable( nSelect ) &&
899 ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectedEntryCount() || ( nSelect != GetEntryList()->GetSelectedEntryPos( 0 ) ) ) )
900 {
901 mbTrackingSelect = true;
902 if ( SelectEntries( nSelect, LET_TRACKING ) )
903 {
904 // When list box selection change by mouse move, notify
905 // VclEventId::ListboxSelect vcl event.
906 maListItemSelectHdl.Call(nullptr);
907 }
908 mbTrackingSelect = false;
909 }
910 }
911
912 // if the DD button was pressed and someone moved into the ListBox
913 // with the mouse button pressed...
914 if ( rMEvt.IsLeft() && !rMEvt.IsSynthetic() )
915 {
916 if ( !mbMulti && GetEntryList()->GetSelectedEntryCount() )
917 mnTrackingSaveSelection = GetEntryList()->GetSelectedEntryPos( 0 );
918 else
919 mnTrackingSaveSelection = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
920
921 StartTracking( StartTrackingFlags::ScrollRepeat );
922 }
923}
924
925void ImplListBoxWindow::DeselectAll()
926{
927 while ( GetEntryList()->GetSelectedEntryCount() )
928 {
929 sal_Int32 nS = GetEntryList()->GetSelectedEntryPos( 0 );
930 SelectEntry( nS, false );
931 }
932}
933
934void ImplListBoxWindow::SelectEntry( sal_Int32 nPos, bool bSelect )
935{
936 if( (mpEntryList->IsEntryPosSelected( nPos ) == bSelect) || !mpEntryList->IsEntrySelectable( nPos ) )
937 return;
938
939 ImplHideFocusRect();
940 if( bSelect )
941 {
942 if( !mbMulti )
943 {
944 // deselect the selected entry
945 sal_Int32 nDeselect = GetEntryList()->GetSelectedEntryPos( 0 );
946 if( nDeselect != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
947 {
948 //SelectEntryPos( nDeselect, false );
949 GetEntryList()->SelectEntry( nDeselect, false );
950 if (IsUpdateMode() && IsReallyVisible())
951 Invalidate();
952 }
953 }
954 mpEntryList->SelectEntry( nPos, true );
955 mnCurrentPos = nPos;
956 if ( ( nPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) ) && IsUpdateMode() )
957 {
958 Invalidate();
959 if ( !IsVisible( nPos ) )
960 {
961 ImplClearLayoutData();
962 sal_Int32 nVisibleEntries = GetLastVisibleEntry()-mnTop;
963 if ( !nVisibleEntries || !IsReallyVisible() || ( nPos < GetTopEntry() ) )
964 {
965 Resize();
966 ShowProminentEntry( nPos );
967 }
968 else
969 {
970 ShowProminentEntry( nPos );
971 }
972 }
973 }
974 }
975 else
976 {
977 mpEntryList->SelectEntry( nPos, false );
978 Invalidate();
979 }
980 mbSelectionChanged = true;
981}
982
983bool ImplListBoxWindow::SelectEntries( sal_Int32 nSelect, LB_EVENT_TYPE eLET, bool bShift, bool bCtrl, bool bSelectPosChange /*=FALSE*/ )
984{
985 bool bSelectionChanged = false;
986
987 if( IsEnabled() && mpEntryList->IsEntrySelectable( nSelect ) )
988 {
989 bool bFocusChanged = false;
990
991 // here (Single-ListBox) only one entry can be deselected
992 if( !mbMulti )
993 {
994 sal_Int32 nDeselect = mpEntryList->GetSelectedEntryPos( 0 );
995 if( nSelect != nDeselect )
996 {
997 SelectEntry( nSelect, true );
998 mpEntryList->SetLastSelected( nSelect );
999 bFocusChanged = true;
1000 bSelectionChanged = true;
1001 }
1002 }
1003 // MultiListBox without Modifier
1004 else if( mbSimpleMode && !bCtrl && !bShift )
1005 {
1006 sal_Int32 nEntryCount = mpEntryList->GetEntryCount();
1007 for ( sal_Int32 nPos = 0; nPos < nEntryCount; nPos++ )
1008 {
1009 bool bSelect = nPos == nSelect;
1010 if ( mpEntryList->IsEntryPosSelected( nPos ) != bSelect )
1011 {
1012 SelectEntry( nPos, bSelect );
1013 bFocusChanged = true;
1014 bSelectionChanged = true;
1015 }
1016 }
1017 mpEntryList->SetLastSelected( nSelect );
1018 mpEntryList->SetSelectionAnchor( nSelect );
1019 }
1020 // MultiListBox only with CTRL/SHIFT or not in SimpleMode
1021 else if( ( !mbSimpleMode /* && !bShift */ ) || ( mbSimpleMode && ( bCtrl || bShift ) ) )
1022 {
1023 // Space for selection change
1024 if( !bShift && ( ( eLET == LET_KEYSPACE ) || ( eLET == LET_MBDOWN ) ) )
1025 {
1026 bool bSelect = !mpEntryList->IsEntryPosSelected( nSelect );
1027 SelectEntry( nSelect, bSelect );
1028 mpEntryList->SetLastSelected( nSelect );
1029 mpEntryList->SetSelectionAnchor( nSelect );
1030 if ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1031 mpEntryList->SetSelectionAnchor( LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) );
1032 bFocusChanged = true;
1033 bSelectionChanged = true;
1034 }
1035 else if( ( ( eLET == LET_TRACKING ) && ( nSelect != mnCurrentPos ) ) ||
1036 ( bShift && ( ( eLET == LET_KEYMOVE ) || ( eLET == LET_MBDOWN ) ) ) )
1037 {
1038 mnCurrentPos = nSelect;
1039 bFocusChanged = true;
1040
1041 sal_Int32 nAnchor = mpEntryList->GetSelectionAnchor();
1042 if( ( nAnchor == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) ) && mpEntryList->GetSelectedEntryCount() )
1043 {
1044 nAnchor = mpEntryList->GetSelectedEntryPos( mpEntryList->GetSelectedEntryCount() - 1 );
1045 }
1046 if( nAnchor != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1047 {
1048 // All entries from Anchor to nSelect have to be selected
1049 sal_Int32 nStart = std::min( nSelect, nAnchor );
1050 sal_Int32 nEnd = std::max( nSelect, nAnchor );
1051 for ( sal_Int32 n = nStart; n <= nEnd; n++ )
1052 {
1053 if ( !mpEntryList->IsEntryPosSelected( n ) )
1054 {
1055 SelectEntry( n, true );
1056 bSelectionChanged = true;
1057 }
1058 }
1059
1060 // if appropriate some more has to be deselected...
1061 sal_Int32 nLast = mpEntryList->GetLastSelected();
1062 if ( nLast != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1063 {
1064 if ( ( nLast > nSelect ) && ( nLast > nAnchor ) )
1065 {
1066 for ( sal_Int32 n = nSelect+1; n <= nLast; n++ )
1067 {
1068 if ( mpEntryList->IsEntryPosSelected( n ) )
1069 {
1070 SelectEntry( n, false );
1071 bSelectionChanged = true;
1072 }
1073 }
1074 }
1075 else if ( ( nLast < nSelect ) && ( nLast < nAnchor ) )
1076 {
1077 for ( sal_Int32 n = nLast; n < nSelect; n++ )
1078 {
1079 if ( mpEntryList->IsEntryPosSelected( n ) )
1080 {
1081 SelectEntry( n, false );
1082 bSelectionChanged = true;
1083 }
1084 }
1085 }
1086 }
1087 mpEntryList->SetLastSelected( nSelect );
1088 }
1089 }
1090 else if( eLET != LET_TRACKING )
1091 {
1092 ImplHideFocusRect();
1093 Invalidate();
1094 bFocusChanged = true;
1095 }
1096 }
1097 else if( bShift )
1098 {
1099 bFocusChanged = true;
1100 }
1101
1102 if( bSelectionChanged )
1103 mbSelectionChanged = true;
1104
1105 if( bFocusChanged )
1106 {
1107 long nHeightDiff = mpEntryList->GetAddedHeight( nSelect, mnTop );
1108 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1109 Size aSz( maFocusRect.GetWidth(),
1110 mpEntryList->GetEntryHeight( nSelect ) );
1111 maFocusRect.SetSize( aSz );
1112 if( HasFocus() )
1113 ImplShowFocusRect();
1114 if (bSelectPosChange)
1115 {
1116 maFocusHdl.Call(nSelect);
1117 }
1118 }
1119 ImplClearLayoutData();
1120 }
1121 return bSelectionChanged;
1122}
1123
1124void ImplListBoxWindow::Tracking( const TrackingEvent& rTEvt )
1125{
1126 tools::Rectangle aRect( Point(), GetOutputSizePixel() );
1127 bool bInside = aRect.IsInside( rTEvt.GetMouseEvent().GetPosPixel() );
1128
1129 if( rTEvt.IsTrackingCanceled() || rTEvt.IsTrackingEnded() ) // MouseButtonUp
1130 {
1131 if ( bInside && !rTEvt.IsTrackingCanceled() )
1132 {
1133 mnSelectModifier = rTEvt.GetMouseEvent().GetModifier();
1134 ImplCallSelect();
1135 }
1136 else
1137 {
1138 maCancelHdl.Call( nullptr );
1139 if ( !mbMulti )
1140 {
1141 mbTrackingSelect = true;
1142 SelectEntry( mnTrackingSaveSelection, true );
1143 mbTrackingSelect = false;
1144 if ( mnTrackingSaveSelection != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1145 {
1146 long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop );
1147 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1148 Size aSz( maFocusRect.GetWidth(),
1149 mpEntryList->GetEntryHeight( mnCurrentPos ) );
1150 maFocusRect.SetSize( aSz );
1151 ImplShowFocusRect();
1152 }
1153 }
1154 }
1155
1156 mbTrack = false;
1157 }
1158 else
1159 {
1160 bool bTrackOrQuickClick = mbTrack;
1161 if( !mbTrack )
1162 {
1163 if ( bInside )
1164 {
1165 mbTrack = true;
1166 }
1167
1168 // this case only happens, if the mouse button is pressed very briefly
1169 if( rTEvt.IsTrackingEnded() && mbTrack )
1170 {
1171 bTrackOrQuickClick = true;
1172 mbTrack = false;
1173 }
1174 }
1175
1176 if( bTrackOrQuickClick )
1177 {
1178 MouseEvent aMEvt = rTEvt.GetMouseEvent();
1179 Point aPt( aMEvt.GetPosPixel() );
1180 bool bShift = aMEvt.IsShift();
1181 bool bCtrl = aMEvt.IsMod1();
1182
1183 sal_Int32 nSelect = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
1184 if( aPt.Y() < 0 )
1185 {
1186 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1187 {
1188 nSelect = mnCurrentPos ? ( mnCurrentPos - 1 ) : 0;
1189 if( nSelect < mnTop )
1190 SetTopEntry( mnTop-1 );
1191 }
1192 }
1193 else if( aPt.Y() > GetOutputSizePixel().Height() )
1194 {
1195 if ( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1196 {
1197 nSelect = std::min( static_cast<sal_Int32>(mnCurrentPos+1), static_cast<sal_Int32>(mpEntryList->GetEntryCount()-1) );
1198 if( nSelect >= GetLastVisibleEntry() )
1199 SetTopEntry( mnTop+1 );
1200 }
1201 }
1202 else
1203 {
1204 nSelect = static_cast<sal_Int32>( ( aPt.Y() + gnBorder ) / mnMaxHeight ) + mnTop;
1205 nSelect = std::min( nSelect, GetLastVisibleEntry() );
1206 nSelect = std::min( nSelect, static_cast<sal_Int32>( mpEntryList->GetEntryCount() - 1 ) );
1207 }
1208
1209 if ( bInside )
1210 {
1211 if ( ( nSelect != mnCurrentPos ) || !GetEntryList()->GetSelectedEntryCount() )
1212 {
1213 mbTrackingSelect = true;
1214 SelectEntries(nSelect, LET_TRACKING, bShift, bCtrl);
1215 mbTrackingSelect = false;
1216 }
1217 }
1218 else
1219 {
1220 if ( !mbMulti && GetEntryList()->GetSelectedEntryCount() )
1221 {
1222 mbTrackingSelect = true;
1223 SelectEntry( GetEntryList()->GetSelectedEntryPos( 0 ), false );
1224 mbTrackingSelect = false;
1225 }
1226 }
1227 mnCurrentPos = nSelect;
1228 if ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1229 {
1230 ImplHideFocusRect();
1231 }
1232 else
1233 {
1234 long nHeightDiff = mpEntryList->GetAddedHeight( mnCurrentPos, mnTop );
1235 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1236 Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1237 maFocusRect.SetSize( aSz );
1238 ImplShowFocusRect();
1239 }
1240 }
1241 }
1242}
1243
1244void ImplListBoxWindow::KeyInput( const KeyEvent& rKEvt )
1245{
1246 if( !ProcessKeyInput( rKEvt ) )
1247 Control::KeyInput( rKEvt );
1248}
1249
1250bool ImplListBoxWindow::ProcessKeyInput( const KeyEvent& rKEvt )
1251{
1252 // entry to be selected
1253 sal_Int32 nSelect = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
1254 LB_EVENT_TYPE eLET = LET_KEYMOVE;
1255
1256 vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1257
1258 bool bShift = aKeyCode.IsShift();
1259 bool bCtrl = aKeyCode.IsMod1() || aKeyCode.IsMod3();
1260 bool bMod2 = aKeyCode.IsMod2();
1261 bool bDone = false;
1262 bool bHandleKey = false;
1263
1264 switch( aKeyCode.GetCode() )
1265 {
1266 case KEY_UP:
1267 {
1268 if ( IsReadOnly() )
1269 {
1270 if ( GetTopEntry() )
1271 SetTopEntry( GetTopEntry()-1 );
1272 }
1273 else if ( !bMod2 )
1274 {
1275 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1276 {
1277 nSelect = mpEntryList->FindFirstSelectable( 0 );
1278 }
1279 else if ( mnCurrentPos )
1280 {
1281 // search first selectable above the current position
1282 nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos - 1, false );
1283 }
1284
1285 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) ) && ( nSelect < mnTop ) )
1286 SetTopEntry( mnTop-1 );
1287
1288 bDone = true;
1289 }
1290 maQuickSelectionEngine.Reset();
1291 }
1292 break;
1293
1294 case KEY_DOWN:
1295 {
1296 if ( IsReadOnly() )
1297 {
1298 SetTopEntry( GetTopEntry()+1 );
1299 }
1300 else if ( !bMod2 )
1301 {
1302 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1303 {
1304 nSelect = mpEntryList->FindFirstSelectable( 0 );
1305 }
1306 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1307 {
1308 // search first selectable below the current position
1309 nSelect = mpEntryList->FindFirstSelectable( mnCurrentPos + 1 );
1310 }
1311
1312 if( ( nSelect != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) ) && ( nSelect >= GetLastVisibleEntry() ) )
1313 SetTopEntry( mnTop+1 );
1314
1315 bDone = true;
1316 }
1317 maQuickSelectionEngine.Reset();
1318 }
1319 break;
1320
1321 case KEY_PAGEUP:
1322 {
1323 if ( IsReadOnly() )
1324 {
1325 sal_Int32 nCurVis = GetLastVisibleEntry() - mnTop +1;
1326 SetTopEntry( ( mnTop > nCurVis ) ?
1327 (mnTop-nCurVis) : 0 );
1328 }
1329 else if ( !bCtrl && !bMod2 )
1330 {
1331 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1332 {
1333 nSelect = mpEntryList->FindFirstSelectable( 0 );
1334 }
1335 else if ( mnCurrentPos )
1336 {
1337 if( mnCurrentPos == mnTop )
1338 {
1339 sal_Int32 nCurVis = GetLastVisibleEntry() - mnTop +1;
1340 SetTopEntry( ( mnTop > nCurVis ) ? ( mnTop-nCurVis+1 ) : 0 );
1341 }
1342
1343 // find first selectable starting from mnTop looking forward
1344 nSelect = mpEntryList->FindFirstSelectable( mnTop );
1345 }
1346 bDone = true;
1347 }
1348 maQuickSelectionEngine.Reset();
1349 }
1350 break;
1351
1352 case KEY_PAGEDOWN:
1353 {
1354 if ( IsReadOnly() )
1355 {
1356 SetTopEntry( GetLastVisibleEntry() );
1357 }
1358 else if ( !bCtrl && !bMod2 )
1359 {
1360 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1361 {
1362 nSelect = mpEntryList->FindFirstSelectable( 0 );
1363 }
1364 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1365 {
1366 sal_Int32 nCount = mpEntryList->GetEntryCount();
1367 sal_Int32 nCurVis = GetLastVisibleEntry() - mnTop;
1368 sal_Int32 nTmp = std::min( nCurVis, nCount );
1369 nTmp += mnTop - 1;
1370 if( mnCurrentPos == nTmp && mnCurrentPos != nCount - 1 )
1371 {
1372 long nTmp2 = std::min( static_cast<long>(nCount-nCurVis), static_cast<long>(static_cast<long>(mnTop)+static_cast<long>(nCurVis)-1) );
1373 nTmp2 = std::max( long(0) , nTmp2 );
1374 nTmp = static_cast<sal_Int32>(nTmp2+(nCurVis-1) );
1375 SetTopEntry( static_cast<sal_Int32>(nTmp2) );
1376 }
1377 // find first selectable starting from nTmp looking backwards
1378 nSelect = mpEntryList->FindFirstSelectable( nTmp, false );
1379 }
1380 bDone = true;
1381 }
1382 maQuickSelectionEngine.Reset();
1383 }
1384 break;
1385
1386 case KEY_HOME:
1387 {
1388 if ( IsReadOnly() )
1389 {
1390 SetTopEntry( 0 );
1391 }
1392 else if ( !bCtrl && !bMod2 && mnCurrentPos )
1393 {
1394 nSelect = mpEntryList->FindFirstSelectable( mpEntryList->GetEntryCount() ? 0 : LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) );
1395 if( mnTop != 0 )
1396 SetTopEntry( 0 );
1397
1398 bDone = true;
1399 }
1400 maQuickSelectionEngine.Reset();
1401 }
1402 break;
1403
1404 case KEY_END:
1405 {
1406 if ( IsReadOnly() )
1407 {
1408 SetTopEntry( 0xFFFF );
1409 }
1410 else if ( !bCtrl && !bMod2 )
1411 {
1412 if( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1413 {
1414 nSelect = mpEntryList->FindFirstSelectable( 0 );
1415 }
1416 else if ( (mnCurrentPos+1) < mpEntryList->GetEntryCount() )
1417 {
1418 sal_Int32 nCount = mpEntryList->GetEntryCount();
1419 nSelect = mpEntryList->FindFirstSelectable( nCount - 1, false );
1420 sal_Int32 nCurVis = GetLastVisibleEntry() - mnTop + 1;
1421 if( nCount > nCurVis )
1422 SetTopEntry( nCount - nCurVis );
1423 }
1424 bDone = true;
1425 }
1426 maQuickSelectionEngine.Reset();
1427 }
1428 break;
1429
1430 case KEY_LEFT:
1431 {
1432 if ( !bCtrl && !bMod2 )
1433 {
1434 ScrollHorz( -HORZ_SCROLL4 );
1435 bDone = true;
1436 }
1437 maQuickSelectionEngine.Reset();
1438 }
1439 break;
1440
1441 case KEY_RIGHT:
1442 {
1443 if ( !bCtrl && !bMod2 )
1444 {
1445 ScrollHorz( HORZ_SCROLL4 );
1446 bDone = true;
1447 }
1448 maQuickSelectionEngine.Reset();
1449 }
1450 break;
1451
1452 case KEY_RETURN:
1453 {
1454 if ( !bMod2 && !IsReadOnly() )
1455 {
1456 mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1457 ImplCallSelect();
1458 bDone = false; // do not catch RETURN
1459 }
1460 maQuickSelectionEngine.Reset();
1461 }
1462 break;
1463
1464 case KEY_SPACE:
1465 {
1466 if ( !bMod2 && !IsReadOnly() )
1467 {
1468 if( mbMulti && ( !mbSimpleMode || ( mbSimpleMode && bCtrl && !bShift ) ) )
1469 {
1470 nSelect = mnCurrentPos;
1471 eLET = LET_KEYSPACE;
1472 }
1473 bDone = true;
1474 }
1475 bHandleKey = true;
1476 }
1477 break;
1478
1479 case KEY_A:
1480 {
1481 if( bCtrl && mbMulti )
1482 {
1483 // paint only once
1484 bool bUpdates = IsUpdateMode();
1485 SetUpdateMode( false );
1486
1487 sal_Int32 nEntryCount = mpEntryList->GetEntryCount();
1488 for( sal_Int32 i = 0; i < nEntryCount; i++ )
1489 SelectEntry( i, true );
1490
1491 // restore update mode
1492 SetUpdateMode( bUpdates );
1493 Invalidate();
1494
1495 maQuickSelectionEngine.Reset();
1496
1497 bDone = true;
1498 }
1499 else
1500 {
1501 bHandleKey = true;
1502 }
1503 }
1504 break;
1505
1506 default:
1507 bHandleKey = true;
1508 break;
1509 }
1510 if (bHandleKey && !IsReadOnly())
1511 {
1512 bDone = maQuickSelectionEngine.HandleKeyEvent( rKEvt );
1513 }
1514
1515 if ( ( nSelect != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1516 && ( ( !mpEntryList->IsEntryPosSelected( nSelect ) )
1517 || ( eLET == LET_KEYSPACE )
1518 )
1519 )
1520 {
1521 SAL_WARN_IF( mpEntryList->IsEntryPosSelected( nSelect ) && !mbMulti, "vcl", "ImplListBox: Selecting same Entry" )do { if (true && (mpEntryList->IsEntryPosSelected(
nSelect ) && !mbMulti)) { 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() << "ImplListBox: Selecting same Entry"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "1521" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImplListBox: Selecting same Entry")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImplListBox: Selecting same Entry"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "1521" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImplListBox: Selecting same Entry") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "1521" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImplListBox: Selecting same Entry")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImplListBox: Selecting same Entry"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "1521" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1522 sal_Int32 nCount = mpEntryList->GetEntryCount();
1523 if (nSelect >= nCount)
1524 nSelect = nCount ? nCount-1 : LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
1525 bool bCurPosChange = (mnCurrentPos != nSelect);
1526 mnCurrentPos = nSelect;
1527 if(SelectEntries( nSelect, eLET, bShift, bCtrl, bCurPosChange))
1528 {
1529 // tdf#129043 Correctly deliver events when changing values with arrow keys in combobox
1530 if (mbIsDropdown && IsReallyVisible())
1531 mbTravelSelect = true;
1532 mnSelectModifier = rKEvt.GetKeyCode().GetModifier();
1533 ImplCallSelect();
1534 mbTravelSelect = false;
1535 }
1536 }
1537
1538 return bDone;
1539}
1540
1541namespace
1542{
1543 vcl::StringEntryIdentifier lcl_getEntry( const ImplEntryList& _rList, sal_Int32 _nPos, OUString& _out_entryText )
1544 {
1545 OSL_PRECOND( ( _nPos != LISTBOX_ENTRY_NOTFOUND ), "lcl_getEntry: invalid position!" )do { if (true && (!(( _nPos != (((sal_Int32) 0x7FFFFFFF
)) )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), (
"legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "1545" ": "), "%s", "lcl_getEntry: invalid position!"); }
} while (false)
;
1546 sal_Int32 nEntryCount( _rList.GetEntryCount() );
1547 if ( _nPos >= nEntryCount )
1548 _nPos = 0;
1549 _out_entryText = _rList.GetEntryText( _nPos );
1550
1551 // vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
1552 // => normalize
1553 return reinterpret_cast< vcl::StringEntryIdentifier >( _nPos + 1 );
1554 }
1555
1556 sal_Int32 lcl_getEntryPos( vcl::StringEntryIdentifier _entry )
1557 {
1558 // our pos is 0-based, but StringEntryIdentifier does not allow for a NULL
1559 return static_cast< sal_Int32 >( reinterpret_cast< sal_Int64 >( _entry ) ) - 1;
1560 }
1561}
1562
1563vcl::StringEntryIdentifier ImplListBoxWindow::CurrentEntry( OUString& _out_entryText ) const
1564{
1565 return lcl_getEntry( *GetEntryList(), ( mnCurrentPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) ) ? 0 : mnCurrentPos, _out_entryText );
1566}
1567
1568vcl::StringEntryIdentifier ImplListBoxWindow::NextEntry( vcl::StringEntryIdentifier _currentEntry, OUString& _out_entryText ) const
1569{
1570 sal_Int32 nNextPos = lcl_getEntryPos( _currentEntry ) + 1;
1571 return lcl_getEntry( *GetEntryList(), nNextPos, _out_entryText );
1572}
1573
1574void ImplListBoxWindow::SelectEntry( vcl::StringEntryIdentifier _entry )
1575{
1576 sal_Int32 nSelect = lcl_getEntryPos( _entry );
1577 if ( mpEntryList->IsEntryPosSelected( nSelect ) )
1578 {
1579 // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
1580 // to select the given entry by typing its starting letters. No need to act.
1581 return;
1582 }
1583
1584 // normalize
1585 OSL_ENSURE( nSelect < mpEntryList->GetEntryCount(), "ImplListBoxWindow::SelectEntry: how that?" )do { if (true && (!(nSelect < mpEntryList->GetEntryCount
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/vcl/source/control/imp_listbox.cxx"
":" "1585" ": "), "%s", "ImplListBoxWindow::SelectEntry: how that?"
); } } while (false)
;
1586 sal_Int32 nCount = mpEntryList->GetEntryCount();
1587 if (nSelect >= nCount)
1588 nSelect = nCount ? nCount-1 : LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
1589
1590 // make visible
1591 ShowProminentEntry( nSelect );
1592
1593 // actually select
1594 mnCurrentPos = nSelect;
1595 if ( SelectEntries( nSelect, LET_KEYMOVE ) )
1596 {
1597 mbTravelSelect = true;
1598 mnSelectModifier = 0;
1599 ImplCallSelect();
1600 mbTravelSelect = false;
1601 }
1602}
1603
1604void ImplListBoxWindow::ImplPaint(vcl::RenderContext& rRenderContext, sal_Int32 nPos)
1605{
1606 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1607
1608 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nPos );
1609 if (!pEntry)
1610 return;
1611
1612 long nWidth = GetOutputSizePixel().Width();
1613 long nY = mpEntryList->GetAddedHeight(nPos, mnTop);
1614 tools::Rectangle aRect(Point(0, nY), Size(nWidth, pEntry->getHeightWithMargin()));
1615
1616 bool bSelected = mpEntryList->IsEntryPosSelected(nPos);
1617 if (bSelected)
1618 {
1619 rRenderContext.SetTextColor(!IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor());
1620 rRenderContext.SetFillColor(rStyleSettings.GetHighlightColor());
1621 rRenderContext.SetLineColor();
1622 rRenderContext.DrawRect(aRect);
1623 }
1624 else
1625 {
1626 ApplySettings(rRenderContext);
1627 if (!IsEnabled())
1628 rRenderContext.SetTextColor(rStyleSettings.GetDisableColor());
1629 }
1630 rRenderContext.SetTextFillColor();
1631
1632 if (IsUserDrawEnabled())
1633 {
1634 mbInUserDraw = true;
1635 mnUserDrawEntry = nPos;
1636 aRect.AdjustLeft( -mnLeft );
1637 if (nPos < GetEntryList()->GetMRUCount())
1638 nPos = GetEntryList()->FindEntry(GetEntryList()->GetEntryText(nPos));
1639 nPos = nPos - GetEntryList()->GetMRUCount();
1640
1641 UserDrawEvent aUDEvt(this, &rRenderContext, aRect, nPos, bSelected);
1642 maUserDrawHdl.Call( &aUDEvt );
1643 mbInUserDraw = false;
1644 }
1645 else
1646 {
1647 DrawEntry(rRenderContext, nPos, true, true);
1648 }
1649}
1650
1651void ImplListBoxWindow::DrawEntry(vcl::RenderContext& rRenderContext, sal_Int32 nPos, bool bDrawImage, bool bDrawText)
1652{
1653 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr(nPos);
1654 if (!pEntry)
1655 return;
1656
1657 long nEntryHeight = pEntry->getHeightWithMargin();
1658
1659 // when changing this function don't forget to adjust ImplWin::DrawEntry()
1660
1661 if (mbInUserDraw)
1662 nPos = mnUserDrawEntry; // real entry, not the matching entry from MRU
1663
1664 long nY = mpEntryList->GetAddedHeight(nPos, mnTop);
1665
1666 if (bDrawImage && mpEntryList->HasImages())
1667 {
1668 Image aImage = mpEntryList->GetEntryImage(nPos);
1669 if (!!aImage)
1670 {
1671 Size aImgSz = aImage.GetSizePixel();
1672 Point aPtImg(gnBorder - mnLeft, nY + ((nEntryHeight - aImgSz.Height()) / 2));
1673
1674 if (!IsZoom())
1675 {
1676 rRenderContext.DrawImage(aPtImg, aImage);
1677 }
1678 else
1679 {
1680 aImgSz.setWidth( CalcZoom(aImgSz.Width()) );
1681 aImgSz.setHeight( CalcZoom(aImgSz.Height()) );
1682 rRenderContext.DrawImage(aPtImg, aImgSz, aImage);
1683 }
1684
1685 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1686 const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
1687
1688 if (nEdgeBlendingPercent && aImgSz.Width() && aImgSz.Height())
1689 {
1690 const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
1691 const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
1692 const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
1693 const BitmapEx aBlendFrame(createBlendFrame(aImgSz, nAlpha, rTopLeft, rBottomRight));
1694
1695 if (!aBlendFrame.IsEmpty())
1696 {
1697 rRenderContext.DrawBitmapEx(aPtImg, aBlendFrame);
1698 }
1699 }
1700 }
1701 }
1702
1703 if (bDrawText)
1704 {
1705 OUString aStr(mpEntryList->GetEntryText(nPos));
1706 if (!aStr.isEmpty())
1707 {
1708 long nMaxWidth = std::max(mnMaxWidth, GetOutputSizePixel().Width() - 2 * gnBorder);
1709 // a multiline entry should only be as wide as the window
1710 if (pEntry->mnFlags & ListBoxEntryFlags::MultiLine)
1711 nMaxWidth = GetOutputSizePixel().Width() - 2 * gnBorder;
1712
1713 tools::Rectangle aTextRect(Point(gnBorder - mnLeft, nY),
1714 Size(nMaxWidth, nEntryHeight));
1715
1716 if (mpEntryList->HasEntryImage(nPos) || IsUserDrawEnabled())
1717 {
1718 long nImageWidth = std::max(mnMaxImgWidth, maUserItemSize.Width());
1719 aTextRect.AdjustLeft(nImageWidth + IMG_TXT_DISTANCE6 );
1720 }
1721
1722 DrawTextFlags nDrawStyle = ImplGetTextStyle();
1723 if (pEntry->mnFlags & ListBoxEntryFlags::MultiLine)
1724 nDrawStyle |= MULTILINE_ENTRY_DRAW_FLAGS( DrawTextFlags::WordBreak | DrawTextFlags::MultiLine | DrawTextFlags
::VCenter )
;
1725 if (pEntry->mnFlags & ListBoxEntryFlags::DrawDisabled)
1726 nDrawStyle |= DrawTextFlags::Disable;
1727
1728 rRenderContext.DrawText(aTextRect, aStr, nDrawStyle);
1729 }
1730 }
1731
1732 if ( !maSeparators.empty() && ( isSeparator(nPos) || isSeparator(nPos-1) ) )
1733 {
1734 Color aOldLineColor(rRenderContext.GetLineColor());
1735 rRenderContext.SetLineColor((GetBackground() != COL_LIGHTGRAY) ? COL_LIGHTGRAY : COL_GRAY);
1736 Point aStartPos(0, nY);
1737 if (isSeparator(nPos))
1738 aStartPos.AdjustY(pEntry->getHeightWithMargin() - 1 );
1739 Point aEndPos(aStartPos);
1740 aEndPos.setX( GetOutputSizePixel().Width() );
1741 rRenderContext.DrawLine(aStartPos, aEndPos);
1742 rRenderContext.SetLineColor(aOldLineColor);
1743 }
1744}
1745
1746void ImplListBoxWindow::FillLayoutData() const
1747{
1748 mpControlData->mpLayoutData.reset( new vcl::ControlLayoutData );
1749 const_cast<ImplListBoxWindow*>(this)->Invalidate(tools::Rectangle(Point(0, 0), GetOutputSize()));
1750}
1751
1752void ImplListBoxWindow::ImplDoPaint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
1753{
1754 sal_Int32 nCount = mpEntryList->GetEntryCount();
1755
1756 bool bShowFocusRect = mbHasFocusRect;
1757 if (mbHasFocusRect)
1758 ImplHideFocusRect();
1759
1760 long nY = 0; // + gnBorder;
1761 long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1762
1763 for (sal_Int32 i = mnTop; i < nCount && nY < nHeight + mnMaxHeight; i++)
1764 {
1765 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr(i);
1766 long nEntryHeight = pEntry->getHeightWithMargin();
1767 if (nY + nEntryHeight >= rRect.Top() &&
1768 nY <= rRect.Bottom() + mnMaxHeight)
1769 {
1770 ImplPaint(rRenderContext, i);
1771 }
1772 nY += nEntryHeight;
1773 }
1774
1775 long nHeightDiff = mpEntryList->GetAddedHeight(mnCurrentPos, mnTop);
1776 maFocusRect.SetPos(Point(0, nHeightDiff));
1777 Size aSz(maFocusRect.GetWidth(), mpEntryList->GetEntryHeight(mnCurrentPos));
1778 maFocusRect.SetSize(aSz);
1779 if (HasFocus() && bShowFocusRect)
1780 ImplShowFocusRect();
1781}
1782
1783void ImplListBoxWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
1784{
1785 if (SupportsDoubleBuffering())
1786 {
1787 // This widget is explicitly double-buffered, so avoid partial paints.
1788 tools::Rectangle aRect(Point(0, 0), GetOutputSizePixel());
1789 ImplDoPaint(rRenderContext, aRect);
1790 }
1791 else
1792 ImplDoPaint(rRenderContext, rRect);
1793}
1794
1795sal_uInt16 ImplListBoxWindow::GetDisplayLineCount() const
1796{
1797 // FIXME: ListBoxEntryFlags::MultiLine
1798
1799 const sal_Int32 nCount = mpEntryList->GetEntryCount()-mnTop;
1800 long nHeight = GetOutputSizePixel().Height();// - mnMaxHeight + gnBorder;
1801 sal_uInt16 nEntries = static_cast< sal_uInt16 >( ( nHeight + mnMaxHeight - 1 ) / mnMaxHeight );
1802 if( nEntries > nCount )
1803 nEntries = static_cast<sal_uInt16>(nCount);
1804
1805 return nEntries;
1806}
1807
1808void ImplListBoxWindow::Resize()
1809{
1810 Control::Resize();
1811
1812 bool bShowFocusRect = mbHasFocusRect;
1813 if ( bShowFocusRect )
1814 ImplHideFocusRect();
1815
1816 if( mnCurrentPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1817 {
1818 Size aSz( GetOutputSizePixel().Width(), mpEntryList->GetEntryHeight( mnCurrentPos ) );
1819 maFocusRect.SetSize( aSz );
1820 }
1821
1822 if ( bShowFocusRect )
1823 ImplShowFocusRect();
1824
1825 ImplClearLayoutData();
1826}
1827
1828void ImplListBoxWindow::GetFocus()
1829{
1830 sal_Int32 nPos = mnCurrentPos;
1831 if ( nPos == LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1832 nPos = 0;
1833 long nHeightDiff = mpEntryList->GetAddedHeight( nPos, mnTop );
1834 maFocusRect.SetPos( Point( 0, nHeightDiff ) );
1835 Size aSz( maFocusRect.GetWidth(), mpEntryList->GetEntryHeight( nPos ) );
1836 maFocusRect.SetSize( aSz );
1837 ImplShowFocusRect();
1838 Control::GetFocus();
1839}
1840
1841void ImplListBoxWindow::LoseFocus()
1842{
1843 ImplHideFocusRect();
1844 Control::LoseFocus();
1845}
1846
1847void ImplListBoxWindow::SetTopEntry( sal_Int32 nTop )
1848{
1849 if( mpEntryList->GetEntryCount() == 0 )
1850 return;
1851
1852 long nWHeight = PixelToLogic( GetSizePixel() ).Height();
1853
1854 sal_Int32 nLastEntry = mpEntryList->GetEntryCount()-1;
1855 if( nTop > nLastEntry )
1856 nTop = nLastEntry;
1857 const ImplEntryType* pLast = mpEntryList->GetEntryPtr( nLastEntry );
1858 while( nTop > 0 && mpEntryList->GetAddedHeight( nLastEntry, nTop-1 ) + pLast->getHeightWithMargin() <= nWHeight )
1859 nTop--;
1860
1861 if ( nTop == mnTop )
1862 return;
1863
1864 ImplClearLayoutData();
1865 long nDiff = mpEntryList->GetAddedHeight( mnTop, nTop );
1866 PaintImmediately();
1867 ImplHideFocusRect();
1868 mnTop = nTop;
1869 Scroll( 0, nDiff );
1870 PaintImmediately();
1871 if( HasFocus() )
1872 ImplShowFocusRect();
1873 maScrollHdl.Call( this );
1874}
1875
1876void ImplListBoxWindow::ShowProminentEntry( sal_Int32 nEntryPos )
1877{
1878 SetTopEntry( nEntryPos );
1879}
1880
1881void ImplListBoxWindow::SetLeftIndent( long n )
1882{
1883 ScrollHorz( n - mnLeft );
1884}
1885
1886void ImplListBoxWindow::ScrollHorz( long n )
1887{
1888 long nDiff = 0;
1889 if ( n > 0 )
1890 {
1891 long nWidth = GetOutputSizePixel().Width();
1892 if( ( mnMaxWidth - mnLeft + n ) > nWidth )
1893 nDiff = n;
1894 }
1895 else if ( n < 0 )
1896 {
1897 if( mnLeft )
1898 {
1899 long nAbs = -n;
1900 nDiff = - std::min( mnLeft, nAbs );
1901 }
1902 }
1903
1904 if ( nDiff )
1905 {
1906 ImplClearLayoutData();
1907 mnLeft = sal::static_int_cast<sal_uInt16>(mnLeft + nDiff);
1908 PaintImmediately();
1909 ImplHideFocusRect();
1910 Scroll( -nDiff, 0 );
1911 PaintImmediately();
1912 if( HasFocus() )
1913 ImplShowFocusRect();
1914 maScrollHdl.Call( this );
1915 }
1916}
1917
1918void ImplListBoxWindow::SetSeparatorPos( sal_Int32 n )
1919{
1920 maSeparators.clear();
1921
1922 if ( n != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
1923 {
1924 maSeparators.insert( n );
1925 }
1926}
1927
1928sal_Int32 ImplListBoxWindow::GetSeparatorPos() const
1929{
1930 if (!maSeparators.empty())
1931 return *(maSeparators.begin());
1932 else
1933 return LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
1934}
1935
1936bool ImplListBoxWindow::isSeparator( const sal_Int32 &n) const
1937{
1938 return maSeparators.find(n) != maSeparators.end();
1939}
1940
1941Size ImplListBoxWindow::CalcSize(sal_Int32 nMaxLines) const
1942{
1943 // FIXME: ListBoxEntryFlags::MultiLine
1944
1945 Size aSz;
1946 aSz.setHeight(nMaxLines * GetEntryHeightWithMargin());
1947 aSz.setWidth( mnMaxWidth + 2*gnBorder );
1948 return aSz;
1949}
1950
1951tools::Rectangle ImplListBoxWindow::GetBoundingRectangle( sal_Int32 nItem ) const
1952{
1953 const ImplEntryType* pEntry = mpEntryList->GetEntryPtr( nItem );
1954 Size aSz( GetSizePixel().Width(), pEntry ? pEntry->getHeightWithMargin() : GetEntryHeightWithMargin() );
1955 long nY = mpEntryList->GetAddedHeight( nItem, GetTopEntry() ) + GetEntryList()->GetMRUCount()*GetEntryHeightWithMargin();
1956 tools::Rectangle aRect( Point( 0, nY ), aSz );
1957 return aRect;
1958}
1959
1960void ImplListBoxWindow::StateChanged( StateChangedType nType )
1961{
1962 Control::StateChanged( nType );
1963
1964 if ( nType == StateChangedType::Zoom )
1965 {
1966 ApplySettings(*this);
1967 ImplCalcMetrics();
1968 Invalidate();
1969 }
1970 else if ( nType == StateChangedType::UpdateMode )
1971 {
1972 if ( IsUpdateMode() && IsReallyVisible() )
1973 Invalidate();
1974 }
1975 else if ( nType == StateChangedType::ControlFont )
1976 {
1977 ApplySettings(*this);
1978 ImplCalcMetrics();
1979 Invalidate();
1980 }
1981 else if ( nType == StateChangedType::ControlForeground )
1982 {
1983 ApplySettings(*this);
1984 Invalidate();
1985 }
1986 else if ( nType == StateChangedType::ControlBackground )
1987 {
1988 ApplySettings(*this);
1989 Invalidate();
1990 }
1991 else if( nType == StateChangedType::Enable )
1992 {
1993 Invalidate();
1994 }
1995
1996 ImplClearLayoutData();
1997}
1998
1999void ImplListBoxWindow::DataChanged( const DataChangedEvent& rDCEvt )
2000{
2001 Control::DataChanged( rDCEvt );
2002
2003 if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
2004 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
2005 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2006 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
2007 {
2008 ImplClearLayoutData();
2009 ApplySettings(*this);
2010 ImplCalcMetrics();
2011 Invalidate();
2012 }
2013}
2014
2015DrawTextFlags ImplListBoxWindow::ImplGetTextStyle() const
2016{
2017 DrawTextFlags nTextStyle = DrawTextFlags::VCenter;
2018
2019 if (mpEntryList->HasImages())
2020 nTextStyle |= DrawTextFlags::Left;
2021 else if (mbCenter)
2022 nTextStyle |= DrawTextFlags::Center;
2023 else if (mbRight)
2024 nTextStyle |= DrawTextFlags::Right;
2025 else
2026 nTextStyle |= DrawTextFlags::Left;
2027
2028 return nTextStyle;
2029}
2030
2031ImplListBox::ImplListBox( vcl::Window* pParent, WinBits nWinStyle ) :
2032 Control( pParent, nWinStyle ),
2033 maLBWindow(VclPtr<ImplListBoxWindow>::Create( this, nWinStyle&(~WB_BORDER) ))
2034{
2035 // for native widget rendering we must be able to detect this window type
2036 SetType( WindowType::LISTBOXWINDOW );
2037
2038 mpVScrollBar = VclPtr<ScrollBar>::Create( this, WB_VSCROLL | WB_DRAG );
2039 mpHScrollBar = VclPtr<ScrollBar>::Create( this, WB_HSCROLL | WB_DRAG );
2040 mpScrollBarBox = VclPtr<ScrollBarBox>::Create( this );
2041
2042 Link<ScrollBar*,void> aLink( LINK( this, ImplListBox, ScrollBarHdl )::tools::detail::makeLink( ::tools::detail::castTo<ImplListBox
*>(this), &ImplListBox::LinkStubScrollBarHdl)
);
2043 mpVScrollBar->SetScrollHdl( aLink );
2044 mpHScrollBar->SetScrollHdl( aLink );
2045
2046 mbVScroll = false;
2047 mbHScroll = false;
2048 mbAutoHScroll = ( nWinStyle & WB_AUTOHSCROLL );
2049 mbEdgeBlending = false;
2050
2051 maLBWindow->SetScrollHdl( LINK( this, ImplListBox, LBWindowScrolled )::tools::detail::makeLink( ::tools::detail::castTo<ImplListBox
*>(this), &ImplListBox::LinkStubLBWindowScrolled)
);
2052 maLBWindow->SetMRUChangedHdl( LINK( this, ImplListBox, MRUChanged )::tools::detail::makeLink( ::tools::detail::castTo<ImplListBox
*>(this), &ImplListBox::LinkStubMRUChanged)
);
2053 maLBWindow->SetEdgeBlending(GetEdgeBlending());
2054 maLBWindow->Show();
2055}
2056
2057ImplListBox::~ImplListBox()
2058{
2059 disposeOnce();
2060}
2061
2062void ImplListBox::dispose()
2063{
2064 mpHScrollBar.disposeAndClear();
2065 mpVScrollBar.disposeAndClear();
2066 mpScrollBarBox.disposeAndClear();
2067 maLBWindow.disposeAndClear();
1
Calling 'VclPtr::disposeAndClear'
2068 Control::dispose();
2069}
2070
2071void ImplListBox::Clear()
2072{
2073 maLBWindow->Clear();
2074 if ( GetEntryList()->GetMRUCount() )
2075 {
2076 maLBWindow->GetEntryList()->SetMRUCount( 0 );
2077 maLBWindow->SetSeparatorPos( LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) );
2078 }
2079 mpVScrollBar->SetThumbPos( 0 );
2080 mpHScrollBar->SetThumbPos( 0 );
2081 CompatStateChanged( StateChangedType::Data );
2082}
2083
2084sal_Int32 ImplListBox::InsertEntry( sal_Int32 nPos, const OUString& rStr )
2085{
2086 ImplEntryType* pNewEntry = new ImplEntryType( rStr );
2087 sal_Int32 nNewPos = maLBWindow->InsertEntry( nPos, pNewEntry );
2088 CompatStateChanged( StateChangedType::Data );
2089 return nNewPos;
2090}
2091
2092sal_Int32 ImplListBox::InsertEntry( sal_Int32 nPos, const OUString& rStr, const Image& rImage )
2093{
2094 ImplEntryType* pNewEntry = new ImplEntryType( rStr, rImage );
2095 sal_Int32 nNewPos = maLBWindow->InsertEntry( nPos, pNewEntry );
2096 CompatStateChanged( StateChangedType::Data );
2097 return nNewPos;
2098}
2099
2100void ImplListBox::RemoveEntry( sal_Int32 nPos )
2101{
2102 maLBWindow->RemoveEntry( nPos );
2103 CompatStateChanged( StateChangedType::Data );
2104}
2105
2106void ImplListBox::SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags )
2107{
2108 maLBWindow->SetEntryFlags( nPos, nFlags );
2109}
2110
2111void ImplListBox::SelectEntry( sal_Int32 nPos, bool bSelect )
2112{
2113 maLBWindow->SelectEntry( nPos, bSelect );
2114}
2115
2116void ImplListBox::SetNoSelection()
2117{
2118 maLBWindow->DeselectAll();
2119}
2120
2121void ImplListBox::GetFocus()
2122{
2123 if (maLBWindow)
2124 maLBWindow->GrabFocus();
2125 else
2126 Control::GetFocus();
2127}
2128
2129void ImplListBox::Resize()
2130{
2131 Control::Resize();
2132 ImplResizeControls();
2133 ImplCheckScrollBars();
2134}
2135
2136IMPL_LINK_NOARG(ImplListBox, MRUChanged, LinkParamNone*, void)void ImplListBox::LinkStubMRUChanged(void * instance, LinkParamNone
* data) { return static_cast<ImplListBox *>(instance)->
MRUChanged(data); } void ImplListBox::MRUChanged(__attribute__
((unused)) LinkParamNone*)
2137{
2138 CompatStateChanged( StateChangedType::Data );
2139}
2140
2141IMPL_LINK_NOARG(ImplListBox, LBWindowScrolled, ImplListBoxWindow*, void)void ImplListBox::LinkStubLBWindowScrolled(void * instance, ImplListBoxWindow
* data) { return static_cast<ImplListBox *>(instance)->
LBWindowScrolled(data); } void ImplListBox::LBWindowScrolled(
__attribute__ ((unused)) ImplListBoxWindow*)
2142{
2143 long nSet = GetTopEntry();
2144 if( nSet > mpVScrollBar->GetRangeMax() )
2145 mpVScrollBar->SetRangeMax( GetEntryList()->GetEntryCount() );
2146 mpVScrollBar->SetThumbPos( GetTopEntry() );
2147
2148 mpHScrollBar->SetThumbPos( GetLeftIndent() );
2149
2150 maScrollHdl.Call( this );
2151}
2152
2153IMPL_LINK( ImplListBox, ScrollBarHdl, ScrollBar*, pSB, void )void ImplListBox::LinkStubScrollBarHdl(void * instance, ScrollBar
* data) { return static_cast<ImplListBox *>(instance)->
ScrollBarHdl(data); } void ImplListBox::ScrollBarHdl(ScrollBar
* pSB)
2154{
2155 sal_uInt16 nPos = static_cast<sal_uInt16>(pSB->GetThumbPos());
2156 if( pSB == mpVScrollBar )
2157 SetTopEntry( nPos );
2158 else if( pSB == mpHScrollBar )
2159 SetLeftIndent( nPos );
2160 if( GetParent() )
2161 GetParent()->Invalidate( InvalidateFlags::Update );
2162}
2163
2164void ImplListBox::ImplCheckScrollBars()
2165{
2166 bool bArrange = false;
2167
2168 Size aOutSz = GetOutputSizePixel();
2169 sal_Int32 nEntries = GetEntryList()->GetEntryCount();
2170 sal_uInt16 nMaxVisEntries = static_cast<sal_uInt16>(aOutSz.Height() / GetEntryHeightWithMargin());
2171
2172 // vertical ScrollBar
2173 if( nEntries > nMaxVisEntries )
2174 {
2175 if( !mbVScroll )
2176 bArrange = true;
2177 mbVScroll = true;
2178
2179 // check of the scrolled-out region
2180 if( GetEntryList()->GetSelectedEntryCount() == 1 &&
2181 GetEntryList()->GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
2182 ShowProminentEntry( GetEntryList()->GetSelectedEntryPos( 0 ) );
2183 else
2184 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2185 }
2186 else
2187 {
2188 if( mbVScroll )
2189 bArrange = true;
2190 mbVScroll = false;
2191 SetTopEntry( 0 );
2192 }
2193
2194 // horizontal ScrollBar
2195 if( mbAutoHScroll )
2196 {
2197 long nWidth = static_cast<sal_uInt16>(aOutSz.Width());
2198 if ( mbVScroll )
2199 nWidth -= mpVScrollBar->GetSizePixel().Width();
2200
2201 long nMaxWidth = GetMaxEntryWidth();
2202 if( nWidth < nMaxWidth )
2203 {
2204 if( !mbHScroll )
2205 bArrange = true;
2206 mbHScroll = true;
2207
2208 if ( !mbVScroll ) // maybe we do need one now
2209 {
2210 nMaxVisEntries = static_cast<sal_uInt16>( ( aOutSz.Height() - mpHScrollBar->GetSizePixel().Height() ) / GetEntryHeightWithMargin() );
2211 if( nEntries > nMaxVisEntries )
2212 {
2213 bArrange = true;
2214 mbVScroll = true;
2215
2216 // check of the scrolled-out region
2217 if( GetEntryList()->GetSelectedEntryCount() == 1 &&
2218 GetEntryList()->GetSelectedEntryPos( 0 ) != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
2219 ShowProminentEntry( GetEntryList()->GetSelectedEntryPos( 0 ) );
2220 else
2221 SetTopEntry( GetTopEntry() ); // MaxTop is being checked...
2222 }
2223 }
2224
2225 // check of the scrolled-out region
2226 sal_uInt16 nMaxLI = static_cast<sal_uInt16>(nMaxWidth - nWidth);
2227 if ( nMaxLI < GetLeftIndent() )
2228 SetLeftIndent( nMaxLI );
2229 }
2230 else
2231 {
2232 if( mbHScroll )
2233 bArrange = true;
2234 mbHScroll = false;
2235 SetLeftIndent( 0 );
2236 }
2237 }
2238
2239 if( bArrange )
2240 ImplResizeControls();
2241
2242 ImplInitScrollBars();
2243}
2244
2245void ImplListBox::ImplInitScrollBars()
2246{
2247 Size aOutSz = maLBWindow->GetOutputSizePixel();
2248
2249 if ( mbVScroll )
2250 {
2251 sal_Int32 nEntries = GetEntryList()->GetEntryCount();
2252 sal_uInt16 nVisEntries = static_cast<sal_uInt16>(aOutSz.Height() / GetEntryHeightWithMargin());
2253 mpVScrollBar->SetRangeMax( nEntries );
2254 mpVScrollBar->SetVisibleSize( nVisEntries );
2255 mpVScrollBar->SetPageSize( nVisEntries - 1 );
2256 }
2257
2258 if ( mbHScroll )
2259 {
2260 mpHScrollBar->SetRangeMax( GetMaxEntryWidth() + HORZ_SCROLL4 );
2261 mpHScrollBar->SetVisibleSize( static_cast<sal_uInt16>(aOutSz.Width()) );
2262 mpHScrollBar->SetLineSize( HORZ_SCROLL4 );
2263 mpHScrollBar->SetPageSize( aOutSz.Width() - HORZ_SCROLL4 );
2264 }
2265}
2266
2267void ImplListBox::ImplResizeControls()
2268{
2269 // Here we only position the Controls; if the Scrollbars are to be
2270 // visible is already determined in ImplCheckScrollBars
2271
2272 Size aOutSz = GetOutputSizePixel();
2273 long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2274 nSBWidth = CalcZoom( nSBWidth );
2275
2276 Size aInnerSz( aOutSz );
2277 if ( mbVScroll )
2278 aInnerSz.AdjustWidth( -nSBWidth );
2279 if ( mbHScroll )
2280 aInnerSz.AdjustHeight( -nSBWidth );
2281
2282 Point aWinPos( 0, 0 );
2283 maLBWindow->SetPosSizePixel( aWinPos, aInnerSz );
2284
2285 // ScrollBarBox
2286 if( mbVScroll && mbHScroll )
2287 {
2288 Point aBoxPos( aInnerSz.Width(), aInnerSz.Height() );
2289 mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
2290 mpScrollBarBox->Show();
2291 }
2292 else
2293 {
2294 mpScrollBarBox->Hide();
2295 }
2296
2297 // vertical ScrollBar
2298 if( mbVScroll )
2299 {
2300 // Scrollbar on left or right side?
2301 Point aVPos( aOutSz.Width() - nSBWidth, 0 );
2302 mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, aInnerSz.Height() ) );
2303 mpVScrollBar->Show();
2304 }
2305 else
2306 {
2307 mpVScrollBar->Hide();
2308 // #107254# Don't reset top entry after resize, but check for max top entry
2309 SetTopEntry( GetTopEntry() );
2310 }
2311
2312 // horizontal ScrollBar
2313 if( mbHScroll )
2314 {
2315 Point aHPos( 0, aOutSz.Height() - nSBWidth );
2316 mpHScrollBar->SetPosSizePixel( aHPos, Size( aInnerSz.Width(), nSBWidth ) );
2317 mpHScrollBar->Show();
2318 }
2319 else
2320 {
2321 mpHScrollBar->Hide();
2322 SetLeftIndent( 0 );
2323 }
2324}
2325
2326void ImplListBox::StateChanged( StateChangedType nType )
2327{
2328 if ( nType == StateChangedType::InitShow )
2329 {
2330 ImplCheckScrollBars();
2331 }
2332 else if ( ( nType == StateChangedType::UpdateMode ) || ( nType == StateChangedType::Data ) )
2333 {
2334 bool bUpdate = IsUpdateMode();
2335 maLBWindow->SetUpdateMode( bUpdate );
2336 if ( bUpdate && IsReallyVisible() )
2337 ImplCheckScrollBars();
2338 }
2339 else if( nType == StateChangedType::Enable )
2340 {
2341 mpHScrollBar->Enable( IsEnabled() );
2342 mpVScrollBar->Enable( IsEnabled() );
2343 mpScrollBarBox->Enable( IsEnabled() );
2344 maLBWindow->Enable( IsEnabled() );
2345
2346 Invalidate();
2347 }
2348 else if ( nType == StateChangedType::Zoom )
2349 {
2350 maLBWindow->SetZoom( GetZoom() );
2351 Resize();
2352 }
2353 else if ( nType == StateChangedType::ControlFont )
2354 {
2355 maLBWindow->SetControlFont( GetControlFont() );
2356 }
2357 else if ( nType == StateChangedType::ControlForeground )
2358 {
2359 maLBWindow->SetControlForeground( GetControlForeground() );
2360 }
2361 else if ( nType == StateChangedType::ControlBackground )
2362 {
2363 maLBWindow->SetControlBackground( GetControlBackground() );
2364 }
2365 else if( nType == StateChangedType::Mirroring )
2366 {
2367 maLBWindow->EnableRTL( IsRTLEnabled() );
2368 mpHScrollBar->EnableRTL( IsRTLEnabled() );
2369 mpVScrollBar->EnableRTL( IsRTLEnabled() );
2370 ImplResizeControls();
2371 }
2372
2373 Control::StateChanged( nType );
2374}
2375
2376bool ImplListBox::EventNotify( NotifyEvent& rNEvt )
2377{
2378 bool bDone = false;
2379 if ( rNEvt.GetType() == MouseNotifyEvent::COMMAND )
2380 {
2381 const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
2382 if ( rCEvt.GetCommand() == CommandEventId::Wheel )
2383 {
2384 const CommandWheelData* pData = rCEvt.GetWheelData();
2385 if( !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) )
2386 {
2387 bDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
2388 }
2389 }
2390 else if (rCEvt.GetCommand() == CommandEventId::Gesture)
2391 {
2392 bDone = HandleScrollCommand(rCEvt, mpHScrollBar, mpVScrollBar);
2393 }
2394 }
2395
2396 return bDone || Window::EventNotify( rNEvt );
2397}
2398
2399const Wallpaper& ImplListBox::GetDisplayBackground() const
2400{
2401 return maLBWindow->GetDisplayBackground();
2402}
2403
2404bool ImplListBox::HandleWheelAsCursorTravel(const CommandEvent& rCEvt, Control& rControl)
2405{
2406 bool bDone = false;
2407 if ( rCEvt.GetCommand() == CommandEventId::Wheel )
2408 {
2409 const CommandWheelData* pData = rCEvt.GetWheelData();
2410 if( !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) )
2411 {
2412 if (!rControl.HasChildPathFocus())
2413 rControl.GrabFocus();
2414 sal_uInt16 nKey = ( pData->GetDelta() < 0 ) ? KEY_DOWN : KEY_UP;
2415 KeyEvent aKeyEvent( 0, vcl::KeyCode( nKey ) );
2416 bDone = ProcessKeyInput( aKeyEvent );
2417 }
2418 }
2419 return bDone;
2420}
2421
2422void ImplListBox::SetMRUEntries( const OUString& rEntries, sal_Unicode cSep )
2423{
2424 bool bChanges = GetEntryList()->GetMRUCount() != 0;
2425
2426 // Remove old MRU entries
2427 for ( sal_Int32 n = GetEntryList()->GetMRUCount();n; )
2428 maLBWindow->RemoveEntry( --n );
2429
2430 sal_Int32 nMRUCount = 0;
2431 sal_Int32 nIndex = 0;
2432 do
2433 {
2434 OUString aEntry = rEntries.getToken( 0, cSep, nIndex );
2435 // Accept only existing entries
2436 if ( GetEntryList()->FindEntry( aEntry ) != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
2437 {
2438 ImplEntryType* pNewEntry = new ImplEntryType( aEntry );
2439 maLBWindow->InsertEntry(nMRUCount++, pNewEntry, false);
2440 bChanges = true;
2441 }
2442 }
2443 while ( nIndex >= 0 );
2444
2445 if ( bChanges )
2446 {
2447 maLBWindow->GetEntryList()->SetMRUCount( nMRUCount );
2448 SetSeparatorPos( nMRUCount ? nMRUCount-1 : 0 );
2449 CompatStateChanged( StateChangedType::Data );
2450 }
2451}
2452
2453OUString ImplListBox::GetMRUEntries( sal_Unicode cSep ) const
2454{
2455 OUStringBuffer aEntries;
2456 for ( sal_Int32 n = 0; n < GetEntryList()->GetMRUCount(); n++ )
2457 {
2458 aEntries.append(GetEntryList()->GetEntryText( n ));
2459 if( n < ( GetEntryList()->GetMRUCount() - 1 ) )
2460 aEntries.append(cSep);
2461 }
2462 return aEntries.makeStringAndClear();
2463}
2464
2465void ImplListBox::SetEdgeBlending(bool bNew)
2466{
2467 if(mbEdgeBlending != bNew)
2468 {
2469 mbEdgeBlending = bNew;
2470 maLBWindow->SetEdgeBlending(GetEdgeBlending());
2471 }
2472}
2473
2474ImplWin::ImplWin( vcl::Window* pParent, WinBits nWinStyle ) :
2475 Control ( pParent, nWinStyle )
2476{
2477 if ( IsNativeControlSupported(ControlType::Listbox, ControlPart::Entire)
2478 && ! IsNativeControlSupported(ControlType::Listbox, ControlPart::ButtonDown) )
2479 SetBackground();
2480 else
2481 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) );
2482
2483 ImplGetWindowImpl()->mbUseNativeFocus = ImplGetSVData()->maNWFData.mbNoFocusRects;
2484
2485 mbEdgeBlending = false;
2486 mnItemPos = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
2487}
2488
2489void ImplWin::MouseButtonDown( const MouseEvent& )
2490{
2491 if( IsEnabled() )
2492 {
2493 maMBDownHdl.Call(this);
2494 }
2495}
2496
2497void ImplWin::FillLayoutData() const
2498{
2499 mpControlData->mpLayoutData.reset( new vcl::ControlLayoutData );
2500 ImplWin* pThis = const_cast<ImplWin*>(this);
2501 pThis->ImplDraw(*pThis, true);
2502}
2503
2504bool ImplWin::PreNotify( NotifyEvent& rNEvt )
2505{
2506 if( rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE )
2507 {
2508 const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
2509 if( pMouseEvt && (pMouseEvt->IsEnterWindow() || pMouseEvt->IsLeaveWindow()) )
2510 {
2511 // trigger redraw as mouse over state has changed
2512 if ( IsNativeControlSupported(ControlType::Listbox, ControlPart::Entire)
2513 && ! IsNativeControlSupported(ControlType::Listbox, ControlPart::ButtonDown) )
2514 {
2515 GetParent()->GetWindow( GetWindowType::Border )->Invalidate( InvalidateFlags::NoErase );
2516 }
2517 }
2518 }
2519
2520 return Control::PreNotify(rNEvt);
2521}
2522
2523void ImplWin::ImplDraw(vcl::RenderContext& rRenderContext, bool bLayout)
2524{
2525 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2526
2527 if (!bLayout)
2528 {
2529 bool bNativeOK = false;
2530 bool bHasFocus = HasFocus();
2531 bool bIsEnabled = IsEnabled();
2532
2533 ControlState nState = ControlState::ENABLED;
2534 if (rRenderContext.IsNativeControlSupported(ControlType::Listbox, ControlPart::Entire)
2535 && rRenderContext.IsNativeControlSupported(ControlType::Listbox, ControlPart::HasBackgroundTexture) )
2536 {
2537 // Repaint the (focused) area similarly to
2538 // ImplSmallBorderWindowView::DrawWindow() in
2539 // vcl/source/window/brdwin.cxx
2540 vcl::Window *pWin = GetParent();
2541
2542 ImplControlValue aControlValue;
2543 bIsEnabled &= pWin->IsEnabled();
2544 if ( !bIsEnabled )
2545 nState &= ~ControlState::ENABLED;
2546 bHasFocus |= pWin->HasFocus();
2547 if ( bHasFocus )
2548 nState |= ControlState::FOCUSED;
2549
2550 // The listbox is painted over the entire control including the
2551 // border, but ImplWin does not contain the border => correction
2552 // needed.
2553 sal_Int32 nLeft, nTop, nRight, nBottom;
2554 pWin->GetBorder( nLeft, nTop, nRight, nBottom );
2555 Point aPoint( -nLeft, -nTop );
2556 tools::Rectangle aCtrlRegion( aPoint - GetPosPixel(), pWin->GetSizePixel() );
2557
2558 bool bMouseOver = false;
2559 vcl::Window *pChild = pWin->GetWindow( GetWindowType::FirstChild );
2560 while( pChild )
2561 {
2562 bMouseOver = pChild->IsMouseOver();
2563 if (bMouseOver)
2564 break;
2565 pChild = pChild->GetWindow( GetWindowType::Next );
2566 }
2567 if( bMouseOver )
2568 nState |= ControlState::ROLLOVER;
2569
2570 // if parent has no border, then nobody has drawn the background
2571 // since no border window exists. so draw it here.
2572 WinBits nParentStyle = pWin->GetStyle();
2573 if( ! (nParentStyle & WB_BORDER) || (nParentStyle & WB_NOBORDER) )
2574 {
2575 tools::Rectangle aParentRect( Point( 0, 0 ), pWin->GetSizePixel() );
2576 pWin->DrawNativeControl( ControlType::Listbox, ControlPart::Entire, aParentRect,
2577 nState, aControlValue, OUString() );
2578 }
2579
2580 bNativeOK = rRenderContext.DrawNativeControl(ControlType::Listbox, ControlPart::Entire, aCtrlRegion,
2581 nState, aControlValue, OUString());
2582 }
2583
2584 if (bIsEnabled)
2585 {
2586 if (bHasFocus && !ImplGetSVData()->maNWFData.mbDDListBoxNoTextArea)
2587 {
2588 if ( !ImplGetSVData()->maNWFData.mbNoFocusRects )
2589 {
2590 rRenderContext.SetFillColor( rStyleSettings.GetHighlightColor() );
2591 rRenderContext.SetTextColor( rStyleSettings.GetHighlightTextColor() );
2592 }
2593 else
2594 {
2595 rRenderContext.SetLineColor();
2596 rRenderContext.SetFillColor();
2597 rRenderContext.SetTextColor( rStyleSettings.GetFieldTextColor() );
2598 }
2599 rRenderContext.DrawRect( maFocusRect );
2600 }
2601 else
2602 {
2603 Color aColor;
2604 if (IsControlForeground())
2605 aColor = GetControlForeground();
2606 else if (ImplGetSVData()->maNWFData.mbDDListBoxNoTextArea)
2607 {
2608 if( bNativeOK && (nState & ControlState::ROLLOVER) )
2609 aColor = rStyleSettings.GetButtonRolloverTextColor();
2610 else
2611 aColor = rStyleSettings.GetButtonTextColor();
2612 }
2613 else
2614 {
2615 if( bNativeOK && (nState & ControlState::ROLLOVER) )
2616 aColor = rStyleSettings.GetFieldRolloverTextColor();
2617 else
2618 aColor = rStyleSettings.GetFieldTextColor();
2619 }
2620 rRenderContext.SetTextColor(aColor);
2621 if (!bNativeOK)
2622 rRenderContext.Erase(maFocusRect);
2623 }
2624 }
2625 else // Disabled
2626 {
2627 rRenderContext.SetTextColor(rStyleSettings.GetDisableColor());
2628 if (!bNativeOK)
2629 rRenderContext.Erase(maFocusRect);
2630 }
2631 }
2632
2633 DrawEntry(rRenderContext, bLayout);
2634}
2635
2636void ImplWin::ApplySettings(vcl::RenderContext& rRenderContext)
2637{
2638 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
2639
2640 ApplyControlFont(rRenderContext, rStyleSettings.GetFieldFont());
2641 ApplyControlForeground(rRenderContext, rStyleSettings.GetFieldTextColor());
2642
2643 if (IsControlBackground())
2644 rRenderContext.SetBackground(GetControlBackground());
2645 else
2646 rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
2647}
2648
2649void ImplWin::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
2650{
2651 ImplDraw(rRenderContext);
2652}
2653
2654void ImplWin::DrawEntry(vcl::RenderContext& rRenderContext, bool bLayout)
2655{
2656 long nBorder = 1;
2657 Size aOutSz(GetOutputSizePixel());
2658
2659 bool bImage = !!maImage;
2660 if (bImage && !bLayout)
2661 {
2662 DrawImageFlags nStyle = DrawImageFlags::NONE;
2663 Size aImgSz = maImage.GetSizePixel();
2664 Point aPtImg( nBorder, ( ( aOutSz.Height() - aImgSz.Height() ) / 2 ) );
2665 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2666
2667 // check for HC mode
2668 Image *pImage = &maImage;
2669
2670 if ( !IsZoom() )
2671 {
2672 rRenderContext.DrawImage( aPtImg, *pImage, nStyle );
2673 }
2674 else
2675 {
2676 aImgSz.setWidth( CalcZoom( aImgSz.Width() ) );
2677 aImgSz.setHeight( CalcZoom( aImgSz.Height() ) );
2678 rRenderContext.DrawImage( aPtImg, aImgSz, *pImage, nStyle );
2679 }
2680
2681 const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
2682
2683 if(nEdgeBlendingPercent)
2684 {
2685 const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
2686 const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
2687 const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
2688 const BitmapEx aBlendFrame(createBlendFrame(aImgSz, nAlpha, rTopLeft, rBottomRight));
2689
2690 if(!aBlendFrame.IsEmpty())
2691 {
2692 rRenderContext.DrawBitmapEx(aPtImg, aBlendFrame);
2693 }
2694 }
2695 }
2696
2697 if( !maString.isEmpty() )
2698 {
2699 DrawTextFlags nTextStyle = DrawTextFlags::VCenter;
2700
2701 if ( bImage && !bLayout )
2702 nTextStyle |= DrawTextFlags::Left;
2703 else if ( GetStyle() & WB_CENTER )
2704 nTextStyle |= DrawTextFlags::Center;
2705 else if ( GetStyle() & WB_RIGHT )
2706 nTextStyle |= DrawTextFlags::Right;
2707 else
2708 nTextStyle |= DrawTextFlags::Left;
2709
2710 tools::Rectangle aTextRect( Point( nBorder, 0 ), Size( aOutSz.Width()-2*nBorder, aOutSz.Height() ) );
2711
2712 if ( bImage )
2713 {
2714 aTextRect.AdjustLeft(maImage.GetSizePixel().Width() + IMG_TXT_DISTANCE6 );
2715 }
2716
2717 MetricVector* pVector = bLayout ? &mpControlData->mpLayoutData->m_aUnicodeBoundRects : nullptr;
2718 OUString* pDisplayText = bLayout ? &mpControlData->mpLayoutData->m_aDisplayText : nullptr;
2719 rRenderContext.DrawText( aTextRect, maString, nTextStyle, pVector, pDisplayText );
2720 }
2721
2722 if( HasFocus() && !bLayout )
2723 ShowFocus( maFocusRect );
2724}
2725
2726void ImplWin::Resize()
2727{
2728 Control::Resize();
2729 maFocusRect.SetSize( GetOutputSizePixel() );
2730 Invalidate();
2731}
2732
2733void ImplWin::GetFocus()
2734{
2735 ShowFocus( maFocusRect );
2736 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2737 IsNativeWidgetEnabled() &&
2738 IsNativeControlSupported( ControlType::Listbox, ControlPart::Entire ) )
2739 {
2740 vcl::Window* pWin = GetParent()->GetWindow( GetWindowType::Border );
2741 if( ! pWin )
2742 pWin = GetParent();
2743 pWin->Invalidate();
2744 }
2745 else
2746 Invalidate();
2747 Control::GetFocus();
2748}
2749
2750void ImplWin::LoseFocus()
2751{
2752 HideFocus();
2753 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2754 IsNativeWidgetEnabled() &&
2755 IsNativeControlSupported( ControlType::Listbox, ControlPart::Entire ) )
2756 {
2757 vcl::Window* pWin = GetParent()->GetWindow( GetWindowType::Border );
2758 if( ! pWin )
2759 pWin = GetParent();
2760 pWin->Invalidate();
2761 }
2762 else
2763 Invalidate();
2764 Control::LoseFocus();
2765}
2766
2767void ImplWin::ShowFocus(const tools::Rectangle& rRect)
2768{
2769 if (IsNativeControlSupported(ControlType::Listbox, ControlPart::Focus))
2770 {
2771 ImplControlValue aControlValue;
2772
2773 vcl::Window *pWin = GetParent();
2774 tools::Rectangle aParentRect(Point(0, 0), pWin->GetSizePixel());
2775 pWin->DrawNativeControl(ControlType::Listbox, ControlPart::Focus, aParentRect,
2776 ControlState::FOCUSED, aControlValue, OUString());
2777 }
2778 Control::ShowFocus(rRect);
2779}
2780
2781ImplBtn::ImplBtn( vcl::Window* pParent, WinBits nWinStyle ) :
2782 PushButton( pParent, nWinStyle )
2783{
2784}
2785
2786void ImplBtn::MouseButtonDown( const MouseEvent& )
2787{
2788 if( IsEnabled() )
2789 maMBDownHdl.Call(this);
2790}
2791
2792ImplListBoxFloatingWindow::ImplListBoxFloatingWindow( vcl::Window* pParent ) :
2793 FloatingWindow( pParent, WB_BORDER | WB_SYSTEMWINDOW | WB_NOSHADOW ) // no drop shadow for list boxes
2794{
2795 mpImplLB = nullptr;
2796 mnDDLineCount = 0;
2797 mbAutoWidth = false;
2798
2799 mnPopupModeStartSaveSelection = LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF));
2800
2801 vcl::Window * pBorderWindow = ImplGetBorderWindow();
2802 if( pBorderWindow )
2803 {
2804 SetAccessibleRole(accessibility::AccessibleRole::PANEL);
2805 pBorderWindow->SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
2806 }
2807 else
2808 {
2809 SetAccessibleRole(accessibility::AccessibleRole::WINDOW);
2810 }
2811
2812}
2813
2814ImplListBoxFloatingWindow::~ImplListBoxFloatingWindow()
2815{
2816 disposeOnce();
2817}
2818
2819void ImplListBoxFloatingWindow::dispose()
2820{
2821 mpImplLB.clear();
2822 FloatingWindow::dispose();
2823}
2824
2825
2826bool ImplListBoxFloatingWindow::PreNotify( NotifyEvent& rNEvt )
2827{
2828 if( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
2829 {
2830 if( !GetParent()->HasChildPathFocus( true ) )
2831 EndPopupMode();
2832 }
2833
2834 return FloatingWindow::PreNotify( rNEvt );
2835}
2836
2837void ImplListBoxFloatingWindow::setPosSizePixel( long nX, long nY, long nWidth, long nHeight, PosSizeFlags nFlags )
2838{
2839 FloatingWindow::setPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
2840
2841 // Fix #60890# ( MBA ): to be able to resize the Listbox even in its open state
2842 // after a call to Resize(), we adjust its position if necessary
2843 if ( IsReallyVisible() && ( nFlags & PosSizeFlags::Height ) )
2844 {
2845 Point aPos = GetParent()->GetPosPixel();
2846 aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
2847
2848 if ( nFlags & PosSizeFlags::X )
2849 aPos.setX( nX );
2850
2851 if ( nFlags & PosSizeFlags::Y )
2852 aPos.setY( nY );
2853
2854 sal_uInt16 nIndex;
2855 SetPosPixel( ImplCalcPos( this, tools::Rectangle( aPos, GetParent()->GetSizePixel() ), FloatWinPopupFlags::Down, nIndex ) );
2856 }
2857
2858// if( !IsReallyVisible() )
2859 {
2860 // The ImplListBox does not get a Resize() as not visible.
2861 // But the windows must get a Resize(), so that the number of
2862 // visible entries is correct for PgUp/PgDown.
2863 // The number also cannot be calculated by List/Combobox, as for
2864 // this the presence of the vertical Scrollbar has to be known.
2865 mpImplLB->SetSizePixel( GetOutputSizePixel() );
2866 static_cast<vcl::Window*>(mpImplLB)->Resize();
2867 static_cast<vcl::Window*>(mpImplLB->GetMainWindow())->Resize();
2868 }
2869}
2870
2871void ImplListBoxFloatingWindow::Resize()
2872{
2873 mpImplLB->GetMainWindow()->ImplClearLayoutData();
2874 FloatingWindow::Resize();
2875}
2876
2877Size ImplListBoxFloatingWindow::CalcFloatSize()
2878{
2879 Size aFloatSz( maPrefSz );
2880
2881 sal_Int32 nLeft, nTop, nRight, nBottom;
2882 GetBorder( nLeft, nTop, nRight, nBottom );
2883
2884 sal_Int32 nLines = mpImplLB->GetEntryList()->GetEntryCount();
2885 if ( mnDDLineCount && ( nLines > mnDDLineCount ) )
2886 nLines = mnDDLineCount;
2887
2888 Size aSz = mpImplLB->CalcSize( nLines );
2889 long nMaxHeight = aSz.Height() + nTop + nBottom;
2890
2891 if ( mnDDLineCount )
2892 aFloatSz.setHeight( nMaxHeight );
2893
2894 if( mbAutoWidth )
2895 {
2896 // AutoSize first only for width...
2897
2898 aFloatSz.setWidth( aSz.Width() + nLeft + nRight );
2899 aFloatSz.AdjustWidth(nRight ); // adding some space looks better...
2900
2901 if ( ( aFloatSz.Height() < nMaxHeight ) || ( mnDDLineCount && ( mnDDLineCount < mpImplLB->GetEntryList()->GetEntryCount() ) ) )
2902 {
2903 // then we also need the vertical Scrollbar
2904 long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2905 aFloatSz.AdjustWidth(nSBWidth );
2906 }
2907
2908 long nDesktopWidth = GetDesktopRectPixel().getWidth();
2909 if (aFloatSz.Width() > nDesktopWidth)
2910 // Don't exceed the desktop width.
2911 aFloatSz.setWidth( nDesktopWidth );
2912 }
2913
2914 if ( aFloatSz.Height() > nMaxHeight )
2915 aFloatSz.setHeight( nMaxHeight );
2916
2917 // Minimal height, in case height is not set to Float height.
2918 // The parent of FloatWin must be DropDown-Combo/Listbox.
2919 Size aParentSz = GetParent()->GetSizePixel();
2920 if( (!mnDDLineCount || !nLines) && ( aFloatSz.Height() < aParentSz.Height() ) )
2921 aFloatSz.setHeight( aParentSz.Height() );
2922
2923 // do not get narrower than the parent...
2924 if( aFloatSz.Width() < aParentSz.Width() )
2925 aFloatSz.setWidth( aParentSz.Width() );
2926
2927 // align height to entries...
2928 long nInnerHeight = aFloatSz.Height() - nTop - nBottom;
2929 long nEntryHeight = mpImplLB->GetEntryHeightWithMargin();
2930 if ( nInnerHeight % nEntryHeight )
2931 {
2932 nInnerHeight /= nEntryHeight;
2933 nInnerHeight++;
2934 nInnerHeight *= nEntryHeight;
2935 aFloatSz.setHeight( nInnerHeight + nTop + nBottom );
2936 }
2937
2938 if (aFloatSz.Width() < aSz.Width())
2939 {
2940 // The max width of list box entries exceeds the window width.
2941 // Account for the scroll bar height.
2942 long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
2943 aFloatSz.AdjustHeight(nSBWidth );
2944 }
2945
2946 return aFloatSz;
2947}
2948
2949void ImplListBoxFloatingWindow::StartFloat( bool bStartTracking )
2950{
2951 if( IsInPopupMode() )
2952 return;
2953
2954 Size aFloatSz = CalcFloatSize();
2955
2956 SetSizePixel( aFloatSz );
2957 mpImplLB->SetSizePixel( GetOutputSizePixel() );
2958
2959 sal_Int32 nPos = mpImplLB->GetEntryList()->GetSelectedEntryPos( 0 );
2960 mnPopupModeStartSaveSelection = nPos;
2961
2962 Size aSz = GetParent()->GetSizePixel();
2963 Point aPos = GetParent()->GetPosPixel();
2964 aPos = GetParent()->GetParent()->OutputToScreenPixel( aPos );
2965 // FIXME: this ugly hack is for Mac/Aqua
2966 // should be replaced by a real mechanism to place the float rectangle
2967 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2968 GetParent()->IsNativeWidgetEnabled() )
2969 {
2970 const sal_Int32 nLeft = 4, nTop = 4, nRight = 4, nBottom = 4;
2971 aPos.AdjustX(nLeft );
2972 aPos.AdjustY(nTop );
2973 aSz.AdjustWidth( -(nLeft + nRight) );
2974 aSz.AdjustHeight( -(nTop + nBottom) );
2975 }
2976 tools::Rectangle aRect( aPos, aSz );
2977
2978 // check if the control's parent is un-mirrored which is the case for form controls in a mirrored UI
2979 // where the document is unmirrored
2980 // because StartPopupMode() expects a rectangle in mirrored coordinates we have to re-mirror
2981 vcl::Window *pGrandparent = GetParent()->GetParent();
2982 const OutputDevice *pGrandparentOutDev = pGrandparent->GetOutDev();
2983
2984 if( pGrandparent->ImplIsAntiparallel() )
2985 pGrandparentOutDev->ReMirror( aRect );
2986
2987 // mouse-button right: close the List-Box-Float-win and don't stop the handling fdo#84795
2988 StartPopupMode( aRect, FloatWinPopupFlags::Down | FloatWinPopupFlags::NoHorzPlacement | FloatWinPopupFlags::AllMouseButtonClose );
2989
2990 if( nPos != LISTBOX_ENTRY_NOTFOUND(((sal_Int32) 0x7FFFFFFF)) )
2991 mpImplLB->ShowProminentEntry( nPos );
2992
2993 if( bStartTracking )
2994 mpImplLB->GetMainWindow()->EnableMouseMoveSelect( true );
2995
2996 if ( mpImplLB->GetMainWindow()->IsGrabFocusAllowed() )
2997 mpImplLB->GetMainWindow()->GrabFocus();
2998
2999 mpImplLB->GetMainWindow()->ImplClearLayoutData();
3000
3001}
3002
3003/* 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<ImplListBoxWindow>'
5
Returning from copy constructor for 'Reference<ImplListBoxWindow>'
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