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 thumbnailview.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 /usr/include/libxml2 -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 SFX2_DLLIMPLEMENTATION -D ENABLE_CUPS -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/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/sfx2/inc -I /home/maarten/src/libreoffice/core/sfx2/source/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sfx2/sdi -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/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -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/sfx2/source/control/thumbnailview.cxx

/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.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
10#include <sfx2/thumbnailview.hxx>
11#include <sfx2/thumbnailviewitem.hxx>
12
13#include <utility>
14
15#include "thumbnailviewacc.hxx"
16
17#include <basegfx/color/bcolortools.hxx>
18#include <comphelper/processfactory.hxx>
19#include <drawinglayer/attribute/fontattribute.hxx>
20#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
21#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
22#include <drawinglayer/processor2d/baseprocessor2d.hxx>
23#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
24#include <o3tl/safeint.hxx>
25#include <rtl/ustring.hxx>
26#include <sal/log.hxx>
27#include <svtools/optionsdrawinglayer.hxx>
28#include <tools/diagnose_ex.h>
29#include <unotools/ucbstreamhelper.hxx>
30#include <vcl/svapp.hxx>
31#include <vcl/scrbar.hxx>
32#include <vcl/settings.hxx>
33#include <vcl/commandevent.hxx>
34#include <vcl/event.hxx>
35#include <vcl/pngread.hxx>
36
37#include <com/sun/star/accessibility/AccessibleEventId.hpp>
38#include <com/sun/star/embed/ElementModes.hpp>
39#include <com/sun/star/embed/StorageFactory.hpp>
40#include <com/sun/star/embed/XStorage.hpp>
41
42#include <memory>
43
44using namespace basegfx;
45using namespace basegfx::utils;
46using namespace drawinglayer::attribute;
47using namespace drawinglayer::primitive2d;
48
49constexpr int gnFineness = 5;
50
51ThumbnailView::ThumbnailView (vcl::Window *pParent)
52 : Control( pParent, WB_TABSTOP )
53 , mpItemAttrs(new ThumbnailItemAttributes)
54{
55 ImplInit();
56}
57
58ThumbnailView::~ThumbnailView()
59{
60 disposeOnce();
61}
62
63void ThumbnailView::dispose()
64{
65 css::uno::Reference< css::lang::XComponent> xComponent(GetAccessible(false), css::uno::UNO_QUERY);
66
67 if (xComponent.is())
1
Taking false branch
68 xComponent->dispose ();
69
70 mpScrBar.disposeAndClear();
2
Calling 'VclPtr::disposeAndClear'
71 mpItemAttrs.reset();
72
73 ImplDeleteItems();
74 Control::dispose();
75}
76
77void ThumbnailView::MouseMove(const MouseEvent& rMEvt)
78{
79 size_t nItemCount = mFilteredItemList.size();
80 Point aPoint = rMEvt.GetPosPixel();
81 OUString aHelp;
82
83 for (size_t i = 0; i < nItemCount; i++)
84 {
85 ThumbnailViewItem *pItem = mFilteredItemList[i];
86
87 if (pItem->mbVisible && !rMEvt.IsLeaveWindow() && pItem->getDrawArea().IsInside(aPoint))
88 {
89 aHelp = pItem->getHelpText();
90 }
91
92 ::tools::Rectangle aToInvalidate(pItem->updateHighlight(pItem->mbVisible && !rMEvt.IsLeaveWindow(), aPoint));
93
94 if (!aToInvalidate.IsEmpty() && IsReallyVisible() && IsUpdateMode())
95 Invalidate(aToInvalidate);
96 }
97
98 if (mbShowTooltips)
99 SetQuickHelpText(aHelp);
100}
101
102void ThumbnailView::AppendItem(std::unique_ptr<ThumbnailViewItem> pItem)
103{
104 if (maFilterFunc(pItem.get()))
105 {
106 // Save current start,end range, iterator might get invalidated
107 size_t nSelStartPos = 0;
108 ThumbnailViewItem *pSelStartItem = nullptr;
109
110 if (mpStartSelRange != mFilteredItemList.end())
111 {
112 pSelStartItem = *mpStartSelRange;
113 nSelStartPos = mpStartSelRange - mFilteredItemList.begin();
114 }
115
116 mFilteredItemList.push_back(pItem.get());
117 mpStartSelRange = pSelStartItem != nullptr ? mFilteredItemList.begin() + nSelStartPos : mFilteredItemList.end();
118 }
119
120 mItemList.push_back(std::move(pItem));
121}
122
123void ThumbnailView::ImplInit()
124{
125 mpScrBar = nullptr;
126 mnItemWidth = 0;
127 mnItemHeight = 0;
128 mnItemPadding = 0;
129 mnVisLines = 0;
130 mnLines = 0;
131 mnFirstLine = 0;
132 mnCols = 0;
133 mbScroll = false;
134 mbHasVisibleItems = false;
135 mbShowTooltips = false;
136 maFilterFunc = ViewFilterAll();
137 maFillColor = GetSettings().GetStyleSettings().GetFieldColor();
138 maTextColor = GetSettings().GetStyleSettings().GetWindowTextColor();
139 maHighlightColor = GetSettings().GetStyleSettings().GetHighlightColor();
140 maHighlightTextColor = GetSettings().GetStyleSettings().GetHighlightTextColor();
141 maSelectHighlightColor = GetSettings().GetStyleSettings().GetActiveColor();
142 maSelectHighlightTextColor = GetSettings().GetStyleSettings().GetActiveTextColor();
143
144 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
145 mfHighlightTransparence = aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01;
146
147 mpStartSelRange = mFilteredItemList.end();
148
149 ApplySettings(*this);
150}
151
152void ThumbnailView::ImplDeleteItems()
153{
154 const size_t n = mItemList.size();
155
156 for ( size_t i = 0; i < n; ++i )
157 {
158 ThumbnailViewItem *const pItem = mItemList[i].get();
159
160 // deselect all current selected items and fire events
161 if (pItem->isSelected())
162 {
163 pItem->setSelection(false);
164 // fire accessible event???
165 }
166
167 if ( pItem->isVisible() && ImplHasAccessibleListeners() )
168 {
169 css::uno::Any aOldAny, aNewAny;
170
171 aOldAny <<= pItem->GetAccessible( false );
172 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
173 }
174
175 mItemList[i].reset();
176 }
177
178 mItemList.clear();
179 mFilteredItemList.clear();
180
181 mpStartSelRange = mFilteredItemList.end();
182}
183
184void ThumbnailView::ApplySettings(vcl::RenderContext& rRenderContext)
185{
186 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
187
188 ApplyControlFont(*this, rStyleSettings.GetAppFont());
189 ApplyControlForeground(*this, rStyleSettings.GetButtonTextColor());
190 rRenderContext.SetTextFillColor();
191 rRenderContext.SetBackground(maFillColor);
192
193 mpItemAttrs->aFillColor = maFillColor.getBColor();
194 mpItemAttrs->aTextColor = maTextColor.getBColor();
195 mpItemAttrs->aHighlightColor = maHighlightColor.getBColor();
196 mpItemAttrs->aHighlightTextColor = maHighlightTextColor.getBColor();
197 mpItemAttrs->aSelectHighlightColor = maSelectHighlightColor.getBColor();
198 mpItemAttrs->aSelectHighlightTextColor = maSelectHighlightTextColor.getBColor();
199 mpItemAttrs->fHighlightTransparence = mfHighlightTransparence;
200 mpItemAttrs->aFontAttr = getFontAttributeFromVclFont(mpItemAttrs->aFontSize,GetFont(),false,true);
201 mpItemAttrs->nMaxTextLength = 0;
202}
203
204void ThumbnailView::DrawItem(ThumbnailViewItem const *pItem)
205{
206 if (pItem->isVisible())
207 {
208 ::tools::Rectangle aRect = pItem->getDrawArea();
209
210 if (!aRect.IsEmpty())
211 Invalidate(aRect);
212 }
213}
214
215void ThumbnailView::OnItemDblClicked (ThumbnailViewItem*)
216{
217}
218
219css::uno::Reference< css::accessibility::XAccessible > ThumbnailView::CreateAccessible()
220{
221 return new ThumbnailViewAcc( this );
222}
223
224css::uno::Reference< css::accessibility::XAccessible > ThumbnailView::getAccessible()
225{
226 return GetAccessible();
227}
228
229void ThumbnailView::CalculateItemPositions (bool bScrollBarUsed)
230{
231 if (!mnItemHeight || !mnItemWidth)
232 return;
233
234 Size aWinSize = GetOutputSizePixel();
235 size_t nItemCount = mFilteredItemList.size();
236 WinBits nStyle = GetStyle();
237 VclPtr<ScrollBar> pDelScrBar;
238 long nScrBarWidth = 0;
239
240 // consider the scrolling
241 if ( nStyle & WB_VSCROLL )
242 {
243 if ( !mpScrBar )
244 {
245 mpScrBar = VclPtr<ScrollBar>::Create( this, WB_VSCROLL | WB_DRAG );
246 mpScrBar->SetScrollHdl( LINK( this, ThumbnailView, ImplScrollHdl )::tools::detail::makeLink( ::tools::detail::castTo<ThumbnailView
*>(this), &ThumbnailView::LinkStubImplScrollHdl)
);
247 }
248
249 // adapt the width because of the changed settings
250 nScrBarWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
251 }
252 else
253 {
254 if ( mpScrBar )
255 {
256 // delete ScrollBar not until later, to prevent recursive calls
257 pDelScrBar = mpScrBar;
258 mpScrBar = nullptr;
259 }
260 }
261
262 // calculate window scroll ratio
263 float nScrollRatio;
264 if( bScrollBarUsed && mpScrBar )
265 nScrollRatio = static_cast<float>(mpScrBar->GetThumbPos()) /
266 static_cast<float>(mpScrBar->GetRangeMax() - mpScrBar->GetVisibleSize());
267 else
268 nScrollRatio = 0;
269
270 // calculate maximum number of visible columns
271 mnCols = static_cast<sal_uInt16>((aWinSize.Width()-nScrBarWidth) / mnItemWidth);
272
273 if (!mnCols)
274 mnCols = 1;
275
276 // calculate maximum number of visible rows
277 mnVisLines = static_cast<sal_uInt16>(aWinSize.Height() / mnItemHeight);
278
279 // calculate empty space
280 long nHSpace = aWinSize.Width()-nScrBarWidth - mnCols*mnItemWidth;
281 long nVSpace = aWinSize.Height() - mnVisLines*mnItemHeight;
282 long nHItemSpace = nHSpace / (mnCols+1);
283 long nVItemSpace = nVSpace / (mnVisLines+1);
284
285 // calculate maximum number of rows
286 // Floor( (M+N-1)/N )==Ceiling( M/N )
287 mnLines = (static_cast<long>(nItemCount)+mnCols-1) / mnCols;
288
289 if ( !mnLines )
290 mnLines = 1;
291
292 if ( mnLines <= mnVisLines )
293 mnFirstLine = 0;
294 else if ( mnFirstLine > o3tl::make_unsigned(mnLines-mnVisLines) )
295 mnFirstLine = static_cast<sal_uInt16>(mnLines-mnVisLines);
296
297 mbHasVisibleItems = true;
298
299 long nFullSteps = (mnLines > mnVisLines) ? mnLines - mnVisLines + 1 : 1;
300
301 long nItemHeightOffset = mnItemHeight + nVItemSpace;
302 long nHiddenLines = static_cast<long>((nFullSteps - 1) * nScrollRatio);
303
304 // calculate offsets
305 long nStartX = nHItemSpace;
306 long nStartY = nVItemSpace;
307
308 // calculate and draw items
309 long x = nStartX;
310 long y = nStartY - ((nFullSteps - 1) * nScrollRatio - nHiddenLines) * nItemHeightOffset;
311
312 // draw items
313 // Unless we are scrolling (via scrollbar) we just use the precalculated
314 // mnFirstLine -- our nHiddenLines calculation takes into account only
315 // what the user has done with the scrollbar but not any changes of selection
316 // using the keyboard, meaning we could accidentally hide the selected item
317 // if we believe the scrollbar (fdo#72287).
318 size_t nFirstItem = (bScrollBarUsed ? nHiddenLines : mnFirstLine) * mnCols;
319 size_t nLastItem = nFirstItem + (mnVisLines + 1) * mnCols;
320
321 // If want also draw parts of items in the last line,
322 // then we add one more line if parts of this line are visible
323
324 size_t nCurCount = 0;
325 for ( size_t i = 0; i < nItemCount; i++ )
326 {
327 ThumbnailViewItem *const pItem = mFilteredItemList[i];
328
329 if ((nCurCount >= nFirstItem) && (nCurCount < nLastItem))
330 {
331 if( !pItem->isVisible())
332 {
333 if ( ImplHasAccessibleListeners() )
334 {
335 css::uno::Any aOldAny, aNewAny;
336
337 aNewAny <<= pItem->GetAccessible( false );
338 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
339 }
340
341 pItem->show(true);
342 }
343
344 pItem->setDrawArea(::tools::Rectangle( Point(x,y), Size(mnItemWidth, mnItemHeight) ));
345 pItem->calculateItemsPosition(mnThumbnailHeight,mnItemPadding,mpItemAttrs->nMaxTextLength,mpItemAttrs.get());
346
347 if ( !((nCurCount+1) % mnCols) )
348 {
349 x = nStartX;
350 y += mnItemHeight+nVItemSpace;
351 }
352 else
353 x += mnItemWidth+nHItemSpace;
354 }
355 else
356 {
357 if( pItem->isVisible())
358 {
359 if ( ImplHasAccessibleListeners() )
360 {
361 css::uno::Any aOldAny, aNewAny;
362
363 aOldAny <<= pItem->GetAccessible( false );
364 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
365 }
366
367 pItem->show(false);
368 }
369
370 }
371
372 ++nCurCount;
373 }
374
375 // arrange ScrollBar, set values and show it
376 if ( mpScrBar )
377 {
378 mnLines = (nCurCount+mnCols-1)/mnCols;
379
380 // check if scroll is needed
381 mbScroll = mnLines > mnVisLines;
382
383
384 Point aPos( aWinSize.Width() - nScrBarWidth, 0 );
385 Size aSize( nScrBarWidth, aWinSize.Height() );
386
387 mpScrBar->SetPosSizePixel( aPos, aSize );
388 mpScrBar->SetRangeMax(mnLines * gnFineness);
389 mpScrBar->SetVisibleSize(mnVisLines * gnFineness);
390 if (!bScrollBarUsed)
391 mpScrBar->SetThumbPos( static_cast<long>(mnFirstLine)*gnFineness );
392 long nPageSize = mnVisLines;
393 if ( nPageSize < 1 )
394 nPageSize = 1;
395 mpScrBar->SetPageSize( nPageSize );
396 mpScrBar->Show( mbScroll );
397 mpScrBar->Enable( mbScroll );
398 }
399
400 // delete ScrollBar
401 pDelScrBar.disposeAndClear();
402}
403
404size_t ThumbnailView::ImplGetItem( const Point& rPos ) const
405{
406 if ( !mbHasVisibleItems )
407 {
408 return THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1));
409 }
410
411 for (size_t i = 0; i < mFilteredItemList.size(); ++i)
412 {
413 if (mFilteredItemList[i]->isVisible() && mFilteredItemList[i]->getDrawArea().IsInside(rPos))
414 return i;
415 }
416
417 return THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1));
418}
419
420ThumbnailViewItem* ThumbnailView::ImplGetItem( size_t nPos )
421{
422 return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos] : nullptr;
423}
424
425sal_uInt16 ThumbnailView::ImplGetVisibleItemCount() const
426{
427 sal_uInt16 nRet = 0;
428 const size_t nItemCount = mItemList.size();
429
430 for ( size_t n = 0; n < nItemCount; ++n )
431 {
432 if ( mItemList[n]->isVisible() )
433 ++nRet;
434 }
435
436 return nRet;
437}
438
439ThumbnailViewItem* ThumbnailView::ImplGetVisibleItem( sal_uInt16 nVisiblePos )
440{
441 const size_t nItemCount = mItemList.size();
442
443 for ( size_t n = 0; n < nItemCount; ++n )
444 {
445 ThumbnailViewItem *const pItem = mItemList[n].get();
446
447 if ( pItem->isVisible() && !nVisiblePos-- )
448 return pItem;
449 }
450
451 return nullptr;
452}
453
454void ThumbnailView::ImplFireAccessibleEvent( short nEventId, const css::uno::Any& rOldValue, const css::uno::Any& rNewValue )
455{
456 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
457
458 if( pAcc )
459 pAcc->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
460}
461
462bool ThumbnailView::ImplHasAccessibleListeners()
463{
464 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
465 return( pAcc && pAcc->HasAccessibleListeners() );
466}
467
468IMPL_LINK( ThumbnailView,ImplScrollHdl, ScrollBar*, pScrollBar, void )void ThumbnailView::LinkStubImplScrollHdl(void * instance, ScrollBar
* data) { return static_cast<ThumbnailView *>(instance)
->ImplScrollHdl(data); } void ThumbnailView::ImplScrollHdl
(ScrollBar* pScrollBar)
469{
470 if ( pScrollBar->GetDelta() )
471 {
472 CalculateItemPositions(true);
473
474 if ( IsReallyVisible() && IsUpdateMode() )
475 Invalidate();
476 }
477}
478
479void ThumbnailView::KeyInput( const KeyEvent& rKEvt )
480{
481 // Get the last selected item in the list
482 size_t nLastPos = 0;
483 bool bFoundLast = false;
484 for ( long i = mFilteredItemList.size() - 1; !bFoundLast && i >= 0; --i )
485 {
486 ThumbnailViewItem* pItem = mFilteredItemList[i];
487 if ( pItem->isSelected() )
488 {
489 nLastPos = i;
490 bFoundLast = true;
491 }
492 }
493
494 bool bValidRange = false;
495 bool bHasSelRange = mpStartSelRange != mFilteredItemList.end();
496 size_t nNextPos = nLastPos;
497 vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
498 ThumbnailViewItem* pNext = nullptr;
499
500 if (aKeyCode.IsShift() && bHasSelRange)
501 {
502 //If the last element selected is the start range position
503 //search for the first selected item
504 size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
505
506 if (nLastPos == nSelPos)
507 {
508 while (nLastPos && mFilteredItemList[nLastPos-1]->isSelected())
509 --nLastPos;
510 }
511 }
512
513 switch ( aKeyCode.GetCode() )
514 {
515 case KEY_RIGHT:
516 if (!mFilteredItemList.empty())
517 {
518 if ( bFoundLast && nLastPos + 1 < mFilteredItemList.size() )
519 {
520 bValidRange = true;
521 nNextPos = nLastPos + 1;
522 }
523
524 pNext = mFilteredItemList[nNextPos];
525 }
526 break;
527 case KEY_LEFT:
528 if (!mFilteredItemList.empty())
529 {
530 if ( nLastPos > 0 )
531 {
532 bValidRange = true;
533 nNextPos = nLastPos - 1;
534 }
535
536 pNext = mFilteredItemList[nNextPos];
537 }
538 break;
539 case KEY_DOWN:
540 if (!mFilteredItemList.empty())
541 {
542 if ( bFoundLast )
543 {
544 //If we are in the second last row just go the one in
545 //the row below, if there's not row below just go to the
546 //last item but for the last row don't do anything.
547 if ( nLastPos + mnCols < mFilteredItemList.size( ) )
548 {
549 bValidRange = true;
550 nNextPos = nLastPos + mnCols;
551 }
552 else
553 {
554 int curRow = nLastPos/mnCols;
555
556 if (curRow < mnLines-1)
557 nNextPos = mFilteredItemList.size()-1;
558 }
559 }
560
561 pNext = mFilteredItemList[nNextPos];
562 }
563 break;
564 case KEY_UP:
565 if (!mFilteredItemList.empty())
566 {
567 if ( nLastPos >= mnCols )
568 {
569 bValidRange = true;
570 nNextPos = nLastPos - mnCols;
571 }
572
573 pNext = mFilteredItemList[nNextPos];
574 }
575 break;
576 case KEY_RETURN:
577 {
578 if ( bFoundLast )
579 OnItemDblClicked( mFilteredItemList[nLastPos] );
580 }
581 [[fallthrough]];
582 default:
583 Control::KeyInput( rKEvt );
584 }
585
586 if ( !pNext )
587 return;
588
589 if (aKeyCode.IsShift() && bValidRange)
590 {
591 std::pair<size_t,size_t> aRange;
592 size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
593
594 if (nLastPos < nSelPos)
595 {
596 if (nNextPos > nLastPos)
597 {
598 if ( nNextPos > nSelPos)
599 aRange = std::make_pair(nLastPos,nNextPos);
600 else
601 aRange = std::make_pair(nLastPos,nNextPos-1);
602 }
603 else
604 aRange = std::make_pair(nNextPos,nLastPos-1);
605 }
606 else if (nLastPos == nSelPos)
607 {
608 if (nNextPos > nLastPos)
609 aRange = std::make_pair(nLastPos+1,nNextPos);
610 else
611 aRange = std::make_pair(nNextPos,nLastPos-1);
612 }
613 else
614 {
615 if (nNextPos > nLastPos)
616 aRange = std::make_pair(nLastPos+1,nNextPos);
617 else
618 {
619 if ( nNextPos < nSelPos)
620 aRange = std::make_pair(nNextPos,nLastPos);
621 else
622 aRange = std::make_pair(nNextPos+1,nLastPos);
623 }
624 }
625
626 for (size_t i = aRange.first; i <= aRange.second; ++i)
627 {
628 if (i != nSelPos)
629 {
630 ThumbnailViewItem *pCurItem = mFilteredItemList[i];
631
632 pCurItem->setSelection(!pCurItem->isSelected());
633
634 if (pCurItem->isVisible())
635 DrawItem(pCurItem);
636 }
637 }
638 }
639 else if (!aKeyCode.IsShift())
640 {
641 deselectItems();
642 SelectItem(pNext->mnId);
643
644 //Mark it as the selection range start position
645 mpStartSelRange = mFilteredItemList.begin() + nNextPos;
646 }
647
648 MakeItemVisible(pNext->mnId);
649}
650
651void ThumbnailView::MakeItemVisible( sal_uInt16 nItemId )
652{
653 // Get the item row
654 size_t nPos = 0;
655 bool bFound = false;
656 for ( size_t i = 0; !bFound && i < mFilteredItemList.size(); ++i )
657 {
658 ThumbnailViewItem* pItem = mFilteredItemList[i];
659 if ( pItem->mnId == nItemId )
660 {
661 nPos = i;
662 bFound = true;
663 }
664 }
665 sal_uInt16 nRow = mnCols ? nPos / mnCols : 0;
666
667 // Move the visible rows as little as possible to include that one
668 if ( nRow < mnFirstLine )
669 mnFirstLine = nRow;
670 else if ( nRow > mnFirstLine + mnVisLines )
671 mnFirstLine = nRow - mnVisLines;
672
673 CalculateItemPositions();
674 Invalidate();
675}
676
677void ThumbnailView::MouseButtonDown( const MouseEvent& rMEvt )
678{
679 if ( !rMEvt.IsLeft() )
680 {
681 Control::MouseButtonDown( rMEvt );
682 return;
683 }
684
685 size_t nPos = ImplGetItem(rMEvt.GetPosPixel());
686 ThumbnailViewItem* pItem = ImplGetItem(nPos);
687
688 if ( !pItem )
689 {
690 deselectItems();
691 Control::MouseButtonDown( rMEvt );
692 return;
693 }
694
695 if ( rMEvt.GetClicks() == 2 )
696 {
697 OnItemDblClicked(pItem);
698 return;
699 }
700
701 if(rMEvt.GetClicks() != 1)
702 return;
703
704 if (rMEvt.IsMod1())
705 {
706 //Keep selected item group state and just invert current desired one state
707 pItem->setSelection(!pItem->isSelected());
708
709 //This one becomes the selection range start position if it changes its state to selected otherwise resets it
710 mpStartSelRange = pItem->isSelected() ? mFilteredItemList.begin() + nPos : mFilteredItemList.end();
711 }
712 else if (rMEvt.IsShift() && mpStartSelRange != mFilteredItemList.end())
713 {
714 std::pair<size_t,size_t> aNewRange;
715 aNewRange.first = mpStartSelRange - mFilteredItemList.begin();
716 aNewRange.second = nPos;
717
718 if (aNewRange.first > aNewRange.second)
719 std::swap(aNewRange.first,aNewRange.second);
720
721 //Deselect the ones outside of it
722 for (size_t i = 0, n = mFilteredItemList.size(); i < n; ++i)
723 {
724 ThumbnailViewItem *pCurItem = mFilteredItemList[i];
725
726 if (pCurItem->isSelected() && (i < aNewRange.first || i > aNewRange.second))
727 {
728 pCurItem->setSelection(false);
729
730 if (pCurItem->isVisible())
731 DrawItem(pCurItem);
732 }
733 }
734
735 size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
736
737 //Select the items between start range and the selected item
738 if (nSelPos != nPos)
739 {
740 int dir = nSelPos < nPos ? 1 : -1;
741 size_t nCurPos = nSelPos + dir;
742
743 while (nCurPos != nPos)
744 {
745 ThumbnailViewItem *pCurItem = mFilteredItemList[nCurPos];
746
747 if (!pCurItem->isSelected())
748 {
749 pCurItem->setSelection(true);
750
751 if (pCurItem->isVisible())
752 DrawItem(pCurItem);
753 }
754
755 nCurPos += dir;
756 }
757 }
758
759 pItem->setSelection(true);
760 }
761 else
762 {
763 //If we got a group of selected items deselect the rest and only keep the desired one
764 //mark items as not selected to not fire unnecessary change state events.
765 pItem->setSelection(false);
766 deselectItems();
767 pItem->setSelection(true);
768
769 //Mark as initial selection range position and reset end one
770 mpStartSelRange = mFilteredItemList.begin() + nPos;
771 }
772
773 if (!pItem->isHighlighted())
774 DrawItem(pItem);
775
776 //fire accessible event??
777}
778
779void ThumbnailView::Command( const CommandEvent& rCEvt )
780{
781 if ( (rCEvt.GetCommand() == CommandEventId::Wheel) ||
782 (rCEvt.GetCommand() == CommandEventId::StartAutoScroll) ||
783 (rCEvt.GetCommand() == CommandEventId::AutoScroll) )
784 {
785 if ( HandleScrollCommand( rCEvt, nullptr, mpScrBar ) )
786 return;
787 }
788
789 Control::Command( rCEvt );
790}
791
792void ThumbnailView::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& rRect)
793{
794 size_t nItemCount = mItemList.size();
795
796 // Draw background
797 drawinglayer::primitive2d::Primitive2DContainer aSeq(1);
798 aSeq[0] = drawinglayer::primitive2d::Primitive2DReference(
799 new PolyPolygonColorPrimitive2D(
800 B2DPolyPolygon( ::tools::Polygon(::tools::Rectangle(Point(), GetOutputSizePixel()), 0, 0).getB2DPolygon()),
801 maFillColor.getBColor()));
802
803 // Create the processor and process the primitives
804 const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
805
806 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
807 drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(rRenderContext, aNewViewInfos));
808 pProcessor->process(aSeq);
809
810 // draw items
811 for (size_t i = 0; i < nItemCount; i++)
812 {
813 ThumbnailViewItem *const pItem = mItemList[i].get();
814
815 if (pItem->isVisible())
816 {
817 pItem->Paint(pProcessor.get(), mpItemAttrs.get());
818 }
819 }
820
821 if (mpScrBar && mpScrBar->IsVisible())
822 mpScrBar->Invalidate(rRect);
823}
824
825void ThumbnailView::GetFocus()
826{
827 // Select the first item if nothing selected
828 int nSelected = -1;
829 for (size_t i = 0, n = mItemList.size(); i < n && nSelected == -1; ++i)
830 {
831 if (mItemList[i]->isSelected())
832 nSelected = i;
833 }
834
835 if (nSelected == -1 && !mItemList.empty())
836 {
837 SelectItem(1);
838 }
839
840 // Tell the accessible object that we got the focus.
841 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
842 if( pAcc )
843 pAcc->GetFocus();
844
845 Control::GetFocus();
846}
847
848void ThumbnailView::LoseFocus()
849{
850 Control::LoseFocus();
851
852 // Tell the accessible object that we lost the focus.
853 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
854 if( pAcc )
855 pAcc->LoseFocus();
856}
857
858void ThumbnailView::Resize()
859{
860 Control::Resize();
861 CalculateItemPositions();
862
863 if ( IsReallyVisible() && IsUpdateMode() )
864 Invalidate();
865}
866
867void ThumbnailView::StateChanged( StateChangedType nType )
868{
869 Control::StateChanged( nType );
870
871 if ( nType == StateChangedType::InitShow )
872 {
873 if ( IsReallyVisible() && IsUpdateMode() )
874 Invalidate();
875 }
876 else if ( nType == StateChangedType::UpdateMode )
877 {
878 if ( IsReallyVisible() && IsUpdateMode() )
879 Invalidate();
880 }
881 else if ( nType == StateChangedType::Text )
882 {
883 }
884 else if ( (nType == StateChangedType::Zoom) ||
885 (nType == StateChangedType::ControlFont) )
886 {
887 Invalidate();
888 }
889 else if ( nType == StateChangedType::ControlForeground )
890 {
891 Invalidate();
892 }
893 else if ( nType == StateChangedType::ControlBackground )
894 {
895 Invalidate();
896 }
897 else if ( (nType == StateChangedType::Style) || (nType == StateChangedType::Enable) )
898 {
899 Invalidate();
900 }
901}
902
903void ThumbnailView::DataChanged( const DataChangedEvent& rDCEvt )
904{
905 Control::DataChanged( rDCEvt );
906
907 if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
908 (rDCEvt.GetType() == DataChangedEventType::DISPLAY) ||
909 (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
910 ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
911 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
912 {
913 Invalidate();
914 }
915}
916
917void ThumbnailView::Clear()
918{
919 ImplDeleteItems();
920
921 // reset variables
922 mnFirstLine = 0;
923
924 CalculateItemPositions();
925
926 if ( IsReallyVisible() && IsUpdateMode() )
927 Invalidate();
928}
929
930void ThumbnailView::updateItems (std::vector<std::unique_ptr<ThumbnailViewItem>> items)
931{
932 ImplDeleteItems();
933
934 // reset variables
935 mnFirstLine = 0;
936
937 mItemList = std::move(items);
938
939 filterItems(maFilterFunc);
940}
941
942size_t ThumbnailView::GetItemPos( sal_uInt16 nItemId ) const
943{
944 for ( size_t i = 0, n = mFilteredItemList.size(); i < n; ++i ) {
945 if ( mFilteredItemList[i]->mnId == nItemId ) {
946 return i;
947 }
948 }
949 return THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1));
950}
951
952sal_uInt16 ThumbnailView::GetItemId( size_t nPos ) const
953{
954 return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos]->mnId : 0 ;
955}
956
957sal_uInt16 ThumbnailView::GetItemId( const Point& rPos ) const
958{
959 size_t nItemPos = ImplGetItem( rPos );
960 if ( nItemPos != THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1)) )
961 return GetItemId( nItemPos );
962
963 return 0;
964}
965
966void ThumbnailView::setItemMaxTextLength(sal_uInt32 nLength)
967{
968 mpItemAttrs->nMaxTextLength = nLength;
969}
970
971void ThumbnailView::setItemDimensions(long itemWidth, long thumbnailHeight, long displayHeight, int itemPadding)
972{
973 mnItemWidth = itemWidth + 2*itemPadding;
974 mnThumbnailHeight = thumbnailHeight;
975 mnDisplayHeight = displayHeight;
976 mnItemPadding = itemPadding;
977 mnItemHeight = mnDisplayHeight + mnThumbnailHeight + 2*itemPadding;
978}
979
980void ThumbnailView::SelectItem( sal_uInt16 nItemId )
981{
982 size_t nItemPos = GetItemPos( nItemId );
983 if ( nItemPos == THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1)) )
984 return;
985
986 ThumbnailViewItem* pItem = mFilteredItemList[nItemPos];
987 if (pItem->isSelected())
988 return;
989
990 pItem->setSelection(true);
991
992 if (IsReallyVisible() && IsUpdateMode())
993 Invalidate();
994
995 bool bNewOut = IsReallyVisible() && IsUpdateMode();
996
997 // if necessary scroll to the visible area
998 if (mbScroll && nItemId && mnCols)
999 {
1000 sal_uInt16 nNewLine = static_cast<sal_uInt16>(nItemPos / mnCols);
1001 if ( nNewLine < mnFirstLine )
1002 {
1003 mnFirstLine = nNewLine;
1004 }
1005 else if ( mnVisLines != 0 && nNewLine > o3tl::make_unsigned(mnFirstLine+mnVisLines-1) )
1006 {
1007 mnFirstLine = static_cast<sal_uInt16>(nNewLine-mnVisLines+1);
1008 }
1009 }
1010
1011 if ( bNewOut )
1012 {
1013 if ( IsReallyVisible() && IsUpdateMode() )
1014 Invalidate();
1015 }
1016
1017 if( !ImplHasAccessibleListeners() )
1018 return;
1019
1020 // focus event (select)
1021 ThumbnailViewItemAcc* pItemAcc = ThumbnailViewItemAcc::getImplementation( pItem->GetAccessible( false ) );
1022
1023 if( pItemAcc )
1024 {
1025 css::uno::Any aOldAny, aNewAny;
1026 aNewAny <<= css::uno::Reference< css::uno::XInterface >(
1027 static_cast< ::cppu::OWeakObject* >( pItemAcc ));
1028 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny );
1029 }
1030
1031 // selection event
1032 css::uno::Any aOldAny, aNewAny;
1033 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny );
1034}
1035
1036bool ThumbnailView::IsItemSelected( sal_uInt16 nItemId ) const
1037{
1038 size_t nItemPos = GetItemPos( nItemId );
1039 if ( nItemPos == THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1)) )
1040 return false;
1041
1042 ThumbnailViewItem* pItem = mFilteredItemList[nItemPos];
1043 return pItem->isSelected();
1044}
1045
1046void ThumbnailView::deselectItems()
1047{
1048 for (std::unique_ptr<ThumbnailViewItem>& p : mItemList)
1049 {
1050 if (p->isSelected())
1051 {
1052 p->setSelection(false);
1053 }
1054 }
1055
1056 if (IsReallyVisible() && IsUpdateMode())
1057 Invalidate();
1058}
1059
1060void ThumbnailView::ShowTooltips( bool bShowTooltips )
1061{
1062 mbShowTooltips = bShowTooltips;
1063}
1064
1065void ThumbnailView::filterItems(const std::function<bool (const ThumbnailViewItem*)> &func)
1066{
1067 mnFirstLine = 0; // start at the top of the list instead of the current position
1068 maFilterFunc = func;
1069
1070 size_t nSelPos = 0;
1071 bool bHasSelRange = false;
1072 ThumbnailViewItem *curSel = mpStartSelRange != mFilteredItemList.end() ? *mpStartSelRange : nullptr;
1073
1074 mFilteredItemList.clear();
1075
1076 for (size_t i = 0, n = mItemList.size(); i < n; ++i)
1077 {
1078 ThumbnailViewItem *const pItem = mItemList[i].get();
1079
1080 if (maFilterFunc(pItem))
1081 {
1082 if (curSel == pItem)
1083 {
1084 nSelPos = i;
1085 bHasSelRange = true;
1086 }
1087
1088 mFilteredItemList.push_back(pItem);
1089 }
1090 else
1091 {
1092 if( pItem->isVisible())
1093 {
1094 if ( ImplHasAccessibleListeners() )
1095 {
1096 css::uno::Any aOldAny, aNewAny;
1097
1098 aOldAny <<= pItem->GetAccessible( false );
1099 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
1100 }
1101
1102 pItem->show(false);
1103 pItem->setSelection(false);
1104 }
1105 }
1106 }
1107
1108 mpStartSelRange = bHasSelRange ? mFilteredItemList.begin() + nSelPos : mFilteredItemList.end();
1109 CalculateItemPositions();
1110
1111 Invalidate();
1112}
1113
1114bool ThumbnailViewBase::renameItem(ThumbnailViewItem*, const OUString&)
1115{
1116 // Do nothing by default
1117 return false;
1118}
1119
1120ThumbnailViewBase::~ThumbnailViewBase()
1121{
1122}
1123
1124BitmapEx ThumbnailView::readThumbnail(const OUString &msURL)
1125{
1126 using namespace ::com::sun::star;
1127 using namespace ::com::sun::star::uno;
1128
1129 // Load the thumbnail from a template document.
1130 uno::Reference<io::XInputStream> xIStream;
1131
1132 uno::Reference< uno::XComponentContext > xContext(::comphelper::getProcessComponentContext());
1133 try
1134 {
1135 uno::Reference<lang::XSingleServiceFactory> xStorageFactory = embed::StorageFactory::create(xContext);
1136
1137 uno::Sequence<uno::Any> aArgs (2);
1138 aArgs[0] <<= msURL;
1139 aArgs[1] <<= embed::ElementModes::READ;
1140 uno::Reference<embed::XStorage> xDocStorage (
1141 xStorageFactory->createInstanceWithArguments(aArgs),
1142 uno::UNO_QUERY);
1143
1144 try
1145 {
1146 if (xDocStorage.is())
1147 {
1148 uno::Reference<embed::XStorage> xStorage (
1149 xDocStorage->openStorageElement(
1150 "Thumbnails",
1151 embed::ElementModes::READ));
1152 if (xStorage.is())
1153 {
1154 uno::Reference<io::XStream> xThumbnailCopy (
1155 xStorage->cloneStreamElement("thumbnail.png"));
1156 if (xThumbnailCopy.is())
1157 xIStream = xThumbnailCopy->getInputStream();
1158 }
1159 }
1160 }
1161 catch (const uno::Exception&)
1162 {
1163 TOOLS_WARN_EXCEPTION("sfx",do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sfx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1164" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1164" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1164" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1164" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
1164 "caught exception while trying to access Thumbnail/thumbnail.png of " << msURL)do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sfx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1164" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1164" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1164" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access Thumbnail/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1164" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1165 }
1166
1167 try
1168 {
1169 // An (older) implementation had a bug - The storage
1170 // name was "Thumbnail" instead of "Thumbnails". The
1171 // old name is still used as fallback but this code can
1172 // be removed soon.
1173 if ( ! xIStream.is())
1174 {
1175 uno::Reference<embed::XStorage> xStorage (
1176 xDocStorage->openStorageElement( "Thumbnail",
1177 embed::ElementModes::READ));
1178 if (xStorage.is())
1179 {
1180 uno::Reference<io::XStream> xThumbnailCopy (
1181 xStorage->cloneStreamElement("thumbnail.png"));
1182 if (xThumbnailCopy.is())
1183 xIStream = xThumbnailCopy->getInputStream();
1184 }
1185 }
1186 }
1187 catch (const uno::Exception&)
1188 {
1189 TOOLS_WARN_EXCEPTION("sfx",do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sfx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1190" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1190" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1190" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1190" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
1190 "caught exception while trying to access Thumbnails/thumbnail.png of " << msURL)do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sfx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1190" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1190" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1190" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access Thumbnails/thumbnail.png of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1190" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1191 }
1192 }
1193 catch (const uno::Exception&)
1194 {
1195 TOOLS_WARN_EXCEPTION("sfx",do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sfx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
1196 "caught exception while trying to access thumbnail of "do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sfx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
1197 << msURL)do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sfx")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"sfx"), ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "caught exception while trying to access thumbnail of "
<< msURL << " " << exceptionToString(tools_warn_exception
); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sfx")
, ("/home/maarten/src/libreoffice/core/sfx2/source/control/thumbnailview.cxx"
":" "1197" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
1198 }
1199
1200 // Extract the image from the stream.
1201 BitmapEx aThumbnail;
1202 if (xIStream.is())
1203 {
1204 std::unique_ptr<SvStream> pStream (
1205 ::utl::UcbStreamHelper::CreateStream (xIStream));
1206 vcl::PNGReader aReader (*pStream);
1207 aThumbnail = aReader.Read ();
1208 }
1209
1210 // Note that the preview is returned without scaling it to the desired
1211 // width. This gives the caller the chance to take advantage of a
1212 // possibly larger resolution then was asked for.
1213 return aThumbnail;
1214}
1215
1216SfxThumbnailView::SfxThumbnailView(std::unique_ptr<weld::ScrolledWindow> xWindow, std::unique_ptr<weld::Menu> xMenu)
1217 : mnThumbnailHeight(0)
1218 , mnDisplayHeight(0)
1219 , mnVItemSpace(-1)
1220 , mbAllowVScrollBar(xWindow->get_vpolicy() != VclPolicyType::NEVER)
1221 , mpItemAttrs(new ThumbnailItemAttributes)
1222 , mxScrolledWindow(std::move(xWindow))
1223 , mxContextMenu(std::move(xMenu))
1224{
1225 ImplInit();
1226 mxScrolledWindow->connect_vadjustment_changed(LINK(this, SfxThumbnailView, ImplScrollHdl)::tools::detail::makeLink( ::tools::detail::castTo<SfxThumbnailView
*>(this), &SfxThumbnailView::LinkStubImplScrollHdl)
);
1227}
1228
1229SfxThumbnailView::~SfxThumbnailView()
1230{
1231 css::uno::Reference< css::lang::XComponent> xComponent(mxAccessible, css::uno::UNO_QUERY);
1232
1233 if (xComponent.is())
1234 xComponent->dispose();
1235
1236 mpItemAttrs.reset();
1237
1238 ImplDeleteItems();
1239}
1240
1241bool SfxThumbnailView::MouseMove(const MouseEvent& rMEvt)
1242{
1243 size_t nItemCount = mFilteredItemList.size();
1244 Point aPoint = rMEvt.GetPosPixel();
1245
1246 for (size_t i = 0; i < nItemCount; i++)
1247 {
1248 ThumbnailViewItem *pItem = mFilteredItemList[i];
1249 ::tools::Rectangle aToInvalidate(pItem->updateHighlight(pItem->mbVisible && !rMEvt.IsLeaveWindow(), aPoint));
1250 if (!aToInvalidate.IsEmpty() && IsReallyVisible() && IsUpdateMode())
1251 Invalidate(aToInvalidate);
1252 }
1253
1254 return true;
1255}
1256
1257OUString SfxThumbnailView::RequestHelp(tools::Rectangle& rHelpRect)
1258{
1259 if (!mbShowTooltips)
1260 return OUString();
1261
1262 Point aPos = rHelpRect.TopLeft();
1263 size_t nItemCount = mFilteredItemList.size();
1264 for (size_t i = 0; i < nItemCount; i++)
1265 {
1266 ThumbnailViewItem *pItem = mFilteredItemList[i];
1267 if (!pItem->mbVisible)
1268 continue;
1269 const tools::Rectangle& rDrawArea = pItem->getDrawArea();
1270 if (pItem->mbVisible && rDrawArea.IsInside(aPos))
1271 {
1272 rHelpRect = rDrawArea;
1273 return pItem->getHelpText();
1274 }
1275 }
1276
1277 return OUString();
1278}
1279
1280void SfxThumbnailView::AppendItem(std::unique_ptr<ThumbnailViewItem> pItem)
1281{
1282 if (maFilterFunc(pItem.get()))
1283 {
1284 // Save current start,end range, iterator might get invalidated
1285 size_t nSelStartPos = 0;
1286 ThumbnailViewItem *pSelStartItem = nullptr;
1287
1288 if (mpStartSelRange != mFilteredItemList.end())
1289 {
1290 pSelStartItem = *mpStartSelRange;
1291 nSelStartPos = mpStartSelRange - mFilteredItemList.begin();
1292 }
1293
1294 mFilteredItemList.push_back(pItem.get());
1295 mpStartSelRange = pSelStartItem != nullptr ? mFilteredItemList.begin() + nSelStartPos : mFilteredItemList.end();
1296 }
1297
1298 mItemList.push_back(std::move(pItem));
1299}
1300
1301void SfxThumbnailView::ImplInit()
1302{
1303 mnItemWidth = 0;
1304 mnItemHeight = 0;
1305 mnItemPadding = 0;
1306 mnVisLines = 0;
1307 mnLines = 0;
1308 mnFirstLine = 0;
1309 mnCols = 0;
1310 mbScroll = false;
1311 mbHasVisibleItems = false;
1312 mbShowTooltips = false;
1313 mbDrawMnemonics = false;
1314 mbIsMultiSelectionEnabled = true;
1315 maFilterFunc = ViewFilterAll();
1316
1317 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
1318 maFillColor = rSettings.GetFieldColor();
1319 maTextColor = rSettings.GetWindowTextColor();
1320 maHighlightColor = rSettings.GetHighlightColor();
1321 maHighlightTextColor = rSettings.GetHighlightTextColor();
1322 maSelectHighlightColor = rSettings.GetActiveColor();
1323 maSelectHighlightTextColor = rSettings.GetActiveTextColor();
1324
1325 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
1326 mfHighlightTransparence = aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01;
1327
1328 mpStartSelRange = mFilteredItemList.end();
1329
1330 mpItemAttrs->aFillColor = maFillColor.getBColor();
1331 mpItemAttrs->aTextColor = maTextColor.getBColor();
1332 mpItemAttrs->aHighlightColor = maHighlightColor.getBColor();
1333 mpItemAttrs->aHighlightTextColor = maHighlightTextColor.getBColor();
1334 mpItemAttrs->aSelectHighlightColor = maSelectHighlightColor.getBColor();
1335 mpItemAttrs->aSelectHighlightTextColor = maSelectHighlightTextColor.getBColor();
1336 mpItemAttrs->fHighlightTransparence = mfHighlightTransparence;
1337
1338 mpItemAttrs->nMaxTextLength = 0;
1339}
1340
1341void SfxThumbnailView::ImplDeleteItems()
1342{
1343 const size_t n = mItemList.size();
1344
1345 for ( size_t i = 0; i < n; ++i )
1346 {
1347 ThumbnailViewItem *const pItem = mItemList[i].get();
1348
1349 // deselect all current selected items and fire events
1350 if (pItem->isSelected())
1351 {
1352 pItem->setSelection(false);
1353 maItemStateHdl.Call(pItem);
1354
1355 // fire accessible event???
1356 }
1357
1358 if ( pItem->isVisible() && ImplHasAccessibleListeners() )
1359 {
1360 css::uno::Any aOldAny, aNewAny;
1361
1362 aOldAny <<= pItem->GetAccessible( false );
1363 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
1364 }
1365
1366 mItemList[i].reset();
1367 }
1368
1369 mItemList.clear();
1370 mFilteredItemList.clear();
1371
1372 mpStartSelRange = mFilteredItemList.end();
1373}
1374
1375void SfxThumbnailView::DrawItem(ThumbnailViewItem const *pItem)
1376{
1377 if (pItem->isVisible())
1378 {
1379 ::tools::Rectangle aRect = pItem->getDrawArea();
1380
1381 if (!aRect.IsEmpty())
1382 Invalidate(aRect);
1383 }
1384}
1385
1386void SfxThumbnailView::OnItemDblClicked (ThumbnailViewItem*)
1387{
1388}
1389
1390css::uno::Reference< css::accessibility::XAccessible > SfxThumbnailView::CreateAccessible()
1391{
1392 mxAccessible.set(new SfxThumbnailViewAcc(this));
1393 return mxAccessible;
1394}
1395
1396css::uno::Reference< css::accessibility::XAccessible > SfxThumbnailView::getAccessible()
1397{
1398 return mxAccessible;
1399}
1400
1401void SfxThumbnailView::CalculateItemPositions(bool bScrollBarUsed)
1402{
1403 if (!mnItemHeight || !mnItemWidth)
1404 return;
1405
1406 Size aWinSize = GetOutputSizePixel();
1407 size_t nItemCount = mFilteredItemList.size();
1408
1409 // calculate window scroll ratio
1410 float nScrollRatio;
1411 if (bScrollBarUsed)
1412 nScrollRatio = static_cast<float>(mxScrolledWindow->vadjustment_get_value()) /
1413 static_cast<float>(mxScrolledWindow->vadjustment_get_upper()-2);
1414 else
1415 nScrollRatio = 0;
1416
1417 // calculate ScrollBar width
1418 long nScrBarWidth = mbAllowVScrollBar ? mxScrolledWindow->get_vscroll_width() : 0;
1419
1420 // calculate maximum number of visible columns
1421 mnCols = static_cast<sal_uInt16>((aWinSize.Width()-nScrBarWidth) / mnItemWidth);
1422
1423 if (!mnCols)
1424 mnCols = 1;
1425
1426 // calculate maximum number of visible rows
1427 mnVisLines = static_cast<sal_uInt16>(aWinSize.Height() / mnItemHeight);
1428
1429 // calculate empty space
1430 long nHSpace = aWinSize.Width()-nScrBarWidth - mnCols*mnItemWidth;
1431 long nVSpace = aWinSize.Height() - mnVisLines*mnItemHeight;
1432 long nHItemSpace = nHSpace / (mnCols+1);
1433 long nVItemSpace = mnVItemSpace;
1434 if (nVItemSpace == -1) // auto, split up extra space to use as vertical spacing
1435 nVItemSpace = nVSpace / (mnVisLines+1);
1436
1437 // calculate maximum number of rows
1438 // Floor( (M+N-1)/N )==Ceiling( M/N )
1439 mnLines = (static_cast<long>(nItemCount)+mnCols-1) / mnCols;
1440
1441 if ( !mnLines )
1442 mnLines = 1;
1443
1444 if ( mnLines <= mnVisLines )
1445 mnFirstLine = 0;
1446 else if ( mnFirstLine > o3tl::make_unsigned(mnLines-mnVisLines) )
1447 mnFirstLine = static_cast<sal_uInt16>(mnLines-mnVisLines);
1448
1449 mbHasVisibleItems = true;
1450
1451 long nItemHeightOffset = mnItemHeight + nVItemSpace;
1452 long nHiddenLines = (static_cast<long>(
1453 ( mnLines - 1 ) * nItemHeightOffset * nScrollRatio ) -
1454 nVItemSpace ) /
1455 nItemHeightOffset;
1456
1457 // calculate offsets
1458 long nStartX = nHItemSpace;
1459 long nStartY = nVItemSpace;
1460
1461 // calculate and draw items
1462 long x = nStartX;
1463 long y = nStartY - ( mnLines - 1 ) * nItemHeightOffset * nScrollRatio +
1464 nHiddenLines * nItemHeightOffset;
1465
1466 // draw items
1467 // Unless we are scrolling (via scrollbar) we just use the precalculated
1468 // mnFirstLine -- our nHiddenLines calculation takes into account only
1469 // what the user has done with the scrollbar but not any changes of selection
1470 // using the keyboard, meaning we could accidentally hide the selected item
1471 // if we believe the scrollbar (fdo#72287).
1472 size_t nFirstItem = (bScrollBarUsed ? nHiddenLines : mnFirstLine) * mnCols;
1473 size_t nLastItem = nFirstItem + (mnVisLines + 1) * mnCols;
1474
1475 // If want also draw parts of items in the last line,
1476 // then we add one more line if parts of this line are visible
1477
1478 size_t nCurCount = 0;
1479 for ( size_t i = 0; i < nItemCount; i++ )
1480 {
1481 ThumbnailViewItem *const pItem = mFilteredItemList[i];
1482
1483 if ((nCurCount >= nFirstItem) && (nCurCount < nLastItem))
1484 {
1485 if( !pItem->isVisible())
1486 {
1487 if ( ImplHasAccessibleListeners() )
1488 {
1489 css::uno::Any aOldAny, aNewAny;
1490
1491 aNewAny <<= pItem->GetAccessible( false );
1492 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
1493 }
1494
1495 pItem->show(true);
1496
1497 maItemStateHdl.Call(pItem);
1498 }
1499
1500 pItem->setDrawArea(::tools::Rectangle( Point(x,y), Size(mnItemWidth, mnItemHeight) ));
1501 pItem->calculateItemsPosition(mnThumbnailHeight,mnItemPadding,mpItemAttrs->nMaxTextLength,mpItemAttrs.get());
1502
1503 if ( !((nCurCount+1) % mnCols) )
1504 {
1505 x = nStartX;
1506 y += mnItemHeight+nVItemSpace;
1507 }
1508 else
1509 x += mnItemWidth+nHItemSpace;
1510 }
1511 else
1512 {
1513 if( pItem->isVisible())
1514 {
1515 if ( ImplHasAccessibleListeners() )
1516 {
1517 css::uno::Any aOldAny, aNewAny;
1518
1519 aOldAny <<= pItem->GetAccessible( false );
1520 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
1521 }
1522
1523 pItem->show(false);
1524
1525 maItemStateHdl.Call(pItem);
1526 }
1527
1528 }
1529
1530 ++nCurCount;
1531 }
1532
1533 // arrange ScrollBar, set values and show it
1534 mnLines = (nCurCount+mnCols-1)/mnCols;
1535
1536 // check if scroll is needed
1537 mbScroll = mnLines > mnVisLines;
1538
1539 mxScrolledWindow->vadjustment_set_upper((nCurCount+mnCols-1)*gnFineness/mnCols);
1540 mxScrolledWindow->vadjustment_set_page_size(mnVisLines);
1541 if (!bScrollBarUsed)
1542 mxScrolledWindow->vadjustment_set_value(static_cast<long>(mnFirstLine)*gnFineness);
1543 long nPageSize = mnVisLines;
1544 if ( nPageSize < 1 )
1545 nPageSize = 1;
1546 mxScrolledWindow->vadjustment_set_page_increment(nPageSize);
1547 if (mbAllowVScrollBar)
1548 mxScrolledWindow->set_vpolicy(mbScroll ? VclPolicyType::ALWAYS : VclPolicyType::NEVER);
1549}
1550
1551size_t SfxThumbnailView::ImplGetItem( const Point& rPos ) const
1552{
1553 if ( !mbHasVisibleItems )
1554 {
1555 return THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1));
1556 }
1557
1558 for (size_t i = 0; i < mFilteredItemList.size(); ++i)
1559 {
1560 if (mFilteredItemList[i]->isVisible() && mFilteredItemList[i]->getDrawArea().IsInside(rPos))
1561 return i;
1562 }
1563
1564 return THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1));
1565}
1566
1567ThumbnailViewItem* SfxThumbnailView::ImplGetItem( size_t nPos )
1568{
1569 return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos] : nullptr;
1570}
1571
1572sal_uInt16 SfxThumbnailView::ImplGetVisibleItemCount() const
1573{
1574 sal_uInt16 nRet = 0;
1575 const size_t nItemCount = mItemList.size();
1576
1577 for ( size_t n = 0; n < nItemCount; ++n )
1578 {
1579 if ( mItemList[n]->isVisible() )
1580 ++nRet;
1581 }
1582
1583 return nRet;
1584}
1585
1586ThumbnailViewItem* SfxThumbnailView::ImplGetVisibleItem( sal_uInt16 nVisiblePos )
1587{
1588 const size_t nItemCount = mItemList.size();
1589
1590 for ( size_t n = 0; n < nItemCount; ++n )
1591 {
1592 ThumbnailViewItem *const pItem = mItemList[n].get();
1593
1594 if ( pItem->isVisible() && !nVisiblePos-- )
1595 return pItem;
1596 }
1597
1598 return nullptr;
1599}
1600
1601void SfxThumbnailView::ImplFireAccessibleEvent( short nEventId, const css::uno::Any& rOldValue, const css::uno::Any& rNewValue )
1602{
1603 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation(mxAccessible);
1604
1605 if( pAcc )
1606 pAcc->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
1607}
1608
1609bool SfxThumbnailView::ImplHasAccessibleListeners()
1610{
1611 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation(mxAccessible);
1612 return( pAcc && pAcc->HasAccessibleListeners() );
1613}
1614
1615IMPL_LINK_NOARG(SfxThumbnailView, ImplScrollHdl, weld::ScrolledWindow&, void)void SfxThumbnailView::LinkStubImplScrollHdl(void * instance,
weld::ScrolledWindow& data) { return static_cast<SfxThumbnailView
*>(instance)->ImplScrollHdl(data); } void SfxThumbnailView
::ImplScrollHdl(__attribute__ ((unused)) weld::ScrolledWindow
&)
1616{
1617 CalculateItemPositions(true);
1618 if (IsReallyVisible() && IsUpdateMode())
1619 Invalidate();
1620}
1621
1622bool SfxThumbnailView::KeyInput( const KeyEvent& rKEvt )
1623{
1624 bool bHandled = true;
1625
1626 // Get the last selected item in the list
1627 size_t nLastPos = 0;
1628 bool bFoundLast = false;
1629 for ( long i = mFilteredItemList.size() - 1; !bFoundLast && i >= 0; --i )
1630 {
1631 ThumbnailViewItem* pItem = mFilteredItemList[i];
1632 if ( pItem->isSelected() )
1633 {
1634 nLastPos = i;
1635 bFoundLast = true;
1636 }
1637 }
1638
1639 bool bValidRange = false;
1640 bool bHasSelRange = mpStartSelRange != mFilteredItemList.end();
1641 size_t nNextPos = nLastPos;
1642 vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1643 ThumbnailViewItem* pNext = nullptr;
1644
1645 if (aKeyCode.IsShift() && bHasSelRange)
1646 {
1647 //If the last element selected is the start range position
1648 //search for the first selected item
1649 size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
1650
1651 if (nLastPos == nSelPos)
1652 {
1653 while (nLastPos && mFilteredItemList[nLastPos-1]->isSelected())
1654 --nLastPos;
1655 }
1656 }
1657
1658 switch ( aKeyCode.GetCode() )
1659 {
1660 case KEY_RIGHT:
1661 if (!mFilteredItemList.empty())
1662 {
1663 if ( bFoundLast && nLastPos + 1 < mFilteredItemList.size() )
1664 {
1665 bValidRange = true;
1666 nNextPos = nLastPos + 1;
1667 }
1668
1669 pNext = mFilteredItemList[nNextPos];
1670 }
1671 break;
1672 case KEY_LEFT:
1673 if (!mFilteredItemList.empty())
1674 {
1675 if ( nLastPos > 0 )
1676 {
1677 bValidRange = true;
1678 nNextPos = nLastPos - 1;
1679 }
1680
1681 pNext = mFilteredItemList[nNextPos];
1682 }
1683 break;
1684 case KEY_DOWN:
1685 if (!mFilteredItemList.empty())
1686 {
1687 if ( bFoundLast )
1688 {
1689 //If we are in the second last row just go the one in
1690 //the row below, if there's not row below just go to the
1691 //last item but for the last row don't do anything.
1692 if ( nLastPos + mnCols < mFilteredItemList.size( ) )
1693 {
1694 bValidRange = true;
1695 nNextPos = nLastPos + mnCols;
1696 }
1697 else
1698 {
1699 int curRow = nLastPos/mnCols;
1700
1701 if (curRow < mnLines-1)
1702 nNextPos = mFilteredItemList.size()-1;
1703 }
1704 }
1705
1706 pNext = mFilteredItemList[nNextPos];
1707 }
1708 break;
1709 case KEY_UP:
1710 if (!mFilteredItemList.empty())
1711 {
1712 if ( nLastPos >= mnCols )
1713 {
1714 bValidRange = true;
1715 nNextPos = nLastPos - mnCols;
1716 }
1717
1718 pNext = mFilteredItemList[nNextPos];
1719 }
1720 break;
1721 case KEY_RETURN:
1722 {
1723 if ( bFoundLast )
1724 OnItemDblClicked( mFilteredItemList[nLastPos] );
1725 }
1726 [[fallthrough]];
1727 default:
1728 bHandled = CustomWidgetController::KeyInput(rKEvt);
1729 }
1730
1731 if ( pNext && mbIsMultiSelectionEnabled)
1732 {
1733 if (aKeyCode.IsShift() && bValidRange)
1734 {
1735 std::pair<size_t,size_t> aRange;
1736 size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
1737
1738 if (nLastPos < nSelPos)
1739 {
1740 if (nNextPos > nLastPos)
1741 {
1742 if ( nNextPos > nSelPos)
1743 aRange = std::make_pair(nLastPos,nNextPos);
1744 else
1745 aRange = std::make_pair(nLastPos,nNextPos-1);
1746 }
1747 else
1748 aRange = std::make_pair(nNextPos,nLastPos-1);
1749 }
1750 else if (nLastPos == nSelPos)
1751 {
1752 if (nNextPos > nLastPos)
1753 aRange = std::make_pair(nLastPos+1,nNextPos);
1754 else
1755 aRange = std::make_pair(nNextPos,nLastPos-1);
1756 }
1757 else
1758 {
1759 if (nNextPos > nLastPos)
1760 aRange = std::make_pair(nLastPos+1,nNextPos);
1761 else
1762 {
1763 if ( nNextPos < nSelPos)
1764 aRange = std::make_pair(nNextPos,nLastPos);
1765 else
1766 aRange = std::make_pair(nNextPos+1,nLastPos);
1767 }
1768 }
1769
1770 for (size_t i = aRange.first; i <= aRange.second; ++i)
1771 {
1772 if (i != nSelPos)
1773 {
1774 ThumbnailViewItem *pCurItem = mFilteredItemList[i];
1775
1776 pCurItem->setSelection(!pCurItem->isSelected());
1777
1778 if (pCurItem->isVisible())
1779 DrawItem(pCurItem);
1780
1781 maItemStateHdl.Call(pCurItem);
1782 }
1783 }
1784 }
1785 else if (!aKeyCode.IsShift())
1786 {
1787 deselectItems();
1788 SelectItem(pNext->mnId);
1789
1790 //Mark it as the selection range start position
1791 mpStartSelRange = mFilteredItemList.begin() + nNextPos;
1792 }
1793
1794 MakeItemVisible(pNext->mnId);
1795 }
1796 else if(pNext && !mbIsMultiSelectionEnabled)
1797 {
1798 deselectItems();
1799 SelectItem(pNext->mnId);
1800 MakeItemVisible(pNext->mnId);
1801 }
1802 return bHandled;
1803}
1804
1805void SfxThumbnailView::MakeItemVisible( sal_uInt16 nItemId )
1806{
1807 // Get the item row
1808 size_t nPos = 0;
1809 bool bFound = false;
1810 for ( size_t i = 0; !bFound && i < mFilteredItemList.size(); ++i )
1811 {
1812 ThumbnailViewItem* pItem = mFilteredItemList[i];
1813 if ( pItem->mnId == nItemId )
1814 {
1815 nPos = i;
1816 bFound = true;
1817 }
1818 }
1819 sal_uInt16 nRow = mnCols ? nPos / mnCols : 0;
1820
1821 // Move the visible rows as little as possible to include that one
1822 if ( nRow < mnFirstLine )
1823 mnFirstLine = nRow;
1824 else if ( nRow > mnFirstLine + mnVisLines )
1825 mnFirstLine = nRow - mnVisLines;
1826
1827 CalculateItemPositions();
1828 Invalidate();
1829}
1830
1831bool SfxThumbnailView::MouseButtonDown( const MouseEvent& rMEvt )
1832{
1833 GrabFocus();
1834
1835 if (!rMEvt.IsLeft())
1836 {
1837 return CustomWidgetController::MouseButtonDown( rMEvt );
1838 }
1839
1840 size_t nPos = ImplGetItem(rMEvt.GetPosPixel());
1841 ThumbnailViewItem* pItem = ImplGetItem(nPos);
1842
1843 if ( !pItem )
1844 {
1845 deselectItems();
1846 return CustomWidgetController::MouseButtonDown( rMEvt );
1847 }
1848
1849 if ( rMEvt.GetClicks() == 2 )
1850 {
1851 OnItemDblClicked(pItem);
1852 return true;
1853 }
1854
1855 if ( rMEvt.GetClicks() == 1 && !mbIsMultiSelectionEnabled )
1856 {
1857 deselectItems();
1858 pItem->setSelection(!pItem->isSelected());
1859
1860 if (!pItem->isHighlighted())
1861 DrawItem(pItem);
1862
1863 maItemStateHdl.Call(pItem);
1864 }
1865 else if(rMEvt.GetClicks() == 1)
1866 {
1867 if (rMEvt.IsMod1())
1868 {
1869 //Keep selected item group state and just invert current desired one state
1870 pItem->setSelection(!pItem->isSelected());
1871
1872 //This one becomes the selection range start position if it changes its state to selected otherwise resets it
1873 mpStartSelRange = pItem->isSelected() ? mFilteredItemList.begin() + nPos : mFilteredItemList.end();
1874 }
1875 else if (rMEvt.IsShift() && mpStartSelRange != mFilteredItemList.end())
1876 {
1877 std::pair<size_t,size_t> aNewRange;
1878 aNewRange.first = mpStartSelRange - mFilteredItemList.begin();
1879 aNewRange.second = nPos;
1880
1881 if (aNewRange.first > aNewRange.second)
1882 std::swap(aNewRange.first,aNewRange.second);
1883
1884 //Deselect the ones outside of it
1885 for (size_t i = 0, n = mFilteredItemList.size(); i < n; ++i)
1886 {
1887 ThumbnailViewItem *pCurItem = mFilteredItemList[i];
1888
1889 if (pCurItem->isSelected() && (i < aNewRange.first || i > aNewRange.second))
1890 {
1891 pCurItem->setSelection(false);
1892
1893 if (pCurItem->isVisible())
1894 DrawItem(pCurItem);
1895
1896 maItemStateHdl.Call(pCurItem);
1897 }
1898 }
1899
1900 size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
1901
1902 //Select the items between start range and the selected item
1903 if (nSelPos != nPos)
1904 {
1905 int dir = nSelPos < nPos ? 1 : -1;
1906 size_t nCurPos = nSelPos + dir;
1907
1908 while (nCurPos != nPos)
1909 {
1910 ThumbnailViewItem *pCurItem = mFilteredItemList[nCurPos];
1911
1912 if (!pCurItem->isSelected())
1913 {
1914 pCurItem->setSelection(true);
1915
1916 if (pCurItem->isVisible())
1917 DrawItem(pCurItem);
1918
1919 maItemStateHdl.Call(pCurItem);
1920 }
1921
1922 nCurPos += dir;
1923 }
1924 }
1925
1926 pItem->setSelection(true);
1927 }
1928 else
1929 {
1930 //If we got a group of selected items deselect the rest and only keep the desired one
1931 //mark items as not selected to not fire unnecessary change state events.
1932 pItem->setSelection(false);
1933 deselectItems();
1934 pItem->setSelection(true);
1935
1936 //Mark as initial selection range position and reset end one
1937 mpStartSelRange = mFilteredItemList.begin() + nPos;
1938 }
1939
1940 if (!pItem->isHighlighted())
1941 DrawItem(pItem);
1942
1943 maItemStateHdl.Call(pItem);
1944
1945 //fire accessible event??
1946 }
1947 return true;
1948}
1949
1950void SfxThumbnailView::SetDrawingArea(weld::DrawingArea* pDrawingArea)
1951{
1952 CustomWidgetController::SetDrawingArea(pDrawingArea);
1953
1954 if (vcl::Window* pDefaultDevice = dynamic_cast<vcl::Window*>(Application::GetDefaultDevice()))
1955 {
1956 OutputDevice& rDevice = pDrawingArea->get_ref_device();
1957 pDefaultDevice->SetPointFont(rDevice, pDrawingArea->get_font());
1958 mpItemAttrs->aFontAttr = getFontAttributeFromVclFont(mpItemAttrs->aFontSize, rDevice.GetFont(), false, true);
1959 }
1960
1961 SetOutputSizePixel(pDrawingArea->get_preferred_size());
1962}
1963
1964void SfxThumbnailView::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& /*rRect*/)
1965{
1966 rRenderContext.Push(PushFlags::ALL);
1967
1968 rRenderContext.SetTextFillColor();
1969 rRenderContext.SetBackground(maFillColor);
1970
1971 size_t nItemCount = mItemList.size();
1972
1973 // Draw background
1974 drawinglayer::primitive2d::Primitive2DContainer aSeq(1);
1975 aSeq[0] = drawinglayer::primitive2d::Primitive2DReference(
1976 new PolyPolygonColorPrimitive2D(
1977 B2DPolyPolygon( ::tools::Polygon(::tools::Rectangle(Point(), GetOutputSizePixel()), 0, 0).getB2DPolygon()),
1978 maFillColor.getBColor()));
1979
1980 // Create the processor and process the primitives
1981 const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
1982
1983 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
1984 drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(rRenderContext, aNewViewInfos));
1985 pProcessor->process(aSeq);
1986
1987 // draw items
1988 for (size_t i = 0; i < nItemCount; i++)
1989 {
1990 ThumbnailViewItem *const pItem = mItemList[i].get();
1991 if (!pItem->isVisible())
1992 continue;
1993 pItem->Paint(pProcessor.get(), mpItemAttrs.get());
1994 }
1995
1996 rRenderContext.Pop();
1997}
1998
1999void SfxThumbnailView::GetFocus()
2000{
2001 // Select the first item if nothing selected
2002 int nSelected = -1;
2003 for (size_t i = 0, n = mItemList.size(); i < n && nSelected == -1; ++i)
2004 {
2005 if (mItemList[i]->isSelected())
2006 nSelected = i;
2007 }
2008
2009 if (nSelected == -1 && !mItemList.empty())
2010 {
2011 SelectItem(1);
2012 }
2013
2014 // Tell the accessible object that we got the focus.
2015 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation(mxAccessible);
2016 if( pAcc )
2017 pAcc->GetFocus();
2018
2019 CustomWidgetController::GetFocus();
2020}
2021
2022void SfxThumbnailView::LoseFocus()
2023{
2024 CustomWidgetController::LoseFocus();
2025
2026 // Tell the accessible object that we lost the focus.
2027 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation(mxAccessible);
2028 if( pAcc )
2029 pAcc->LoseFocus();
2030}
2031
2032void SfxThumbnailView::Resize()
2033{
2034 CustomWidgetController::Resize();
2035 CalculateItemPositions();
2036
2037 if ( IsReallyVisible() && IsUpdateMode() )
2038 Invalidate();
2039}
2040
2041void SfxThumbnailView::RemoveItem( sal_uInt16 nItemId )
2042{
2043 size_t nPos = GetItemPos( nItemId );
2044
2045 if ( nPos == THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1)) )
2046 return;
2047
2048 if ( nPos < mFilteredItemList.size() ) {
2049
2050 // keep it alive until after we have deleted it from the filter item list
2051 std::unique_ptr<ThumbnailViewItem> xKeepAliveViewItem;
2052
2053 // delete item from the thumbnail list
2054 for (auto it = mItemList.begin(); it != mItemList.end(); ++it)
2055 {
2056 if ((*it)->mnId == nItemId)
2057 {
2058 xKeepAliveViewItem = std::move(*it);
2059 mItemList.erase(it);
2060 break;
2061 }
2062 }
2063
2064 // delete item from the filter item list
2065 ThumbnailValueItemList::iterator it = mFilteredItemList.begin();
2066 ::std::advance( it, nPos );
2067
2068 if ((*it)->isSelected())
2069 {
2070 (*it)->setSelection(false);
2071 maItemStateHdl.Call(*it);
2072 }
2073
2074 mFilteredItemList.erase( it );
2075 mpStartSelRange = mFilteredItemList.end();
2076 }
2077
2078 CalculateItemPositions();
2079
2080 if ( IsReallyVisible() && IsUpdateMode() )
2081 Invalidate();
2082}
2083
2084void SfxThumbnailView::Clear()
2085{
2086 ImplDeleteItems();
2087
2088 // reset variables
2089 mnFirstLine = 0;
2090
2091 CalculateItemPositions();
2092
2093 if ( IsReallyVisible() && IsUpdateMode() )
2094 Invalidate();
2095}
2096
2097void SfxThumbnailView::updateItems (std::vector<std::unique_ptr<ThumbnailViewItem>> items)
2098{
2099 ImplDeleteItems();
2100
2101 // reset variables
2102 mnFirstLine = 0;
2103
2104 mItemList = std::move(items);
2105
2106 filterItems(maFilterFunc);
2107}
2108
2109size_t SfxThumbnailView::GetItemPos( sal_uInt16 nItemId ) const
2110{
2111 for ( size_t i = 0, n = mFilteredItemList.size(); i < n; ++i ) {
2112 if ( mFilteredItemList[i]->mnId == nItemId ) {
2113 return i;
2114 }
2115 }
2116 return THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1));
2117}
2118
2119sal_uInt16 SfxThumbnailView::GetItemId( size_t nPos ) const
2120{
2121 return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos]->mnId : 0 ;
2122}
2123
2124sal_uInt16 SfxThumbnailView::GetItemId( const Point& rPos ) const
2125{
2126 size_t nItemPos = ImplGetItem( rPos );
2127 if ( nItemPos != THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1)) )
2128 return GetItemId( nItemPos );
2129
2130 return 0;
2131}
2132
2133sal_uInt16 SfxThumbnailView::getNextItemId() const
2134{
2135 return mItemList.empty() ? 1 : mItemList.back()->mnId + 1;
2136}
2137
2138void SfxThumbnailView::setItemMaxTextLength(sal_uInt32 nLength)
2139{
2140 mpItemAttrs->nMaxTextLength = nLength;
2141}
2142
2143void SfxThumbnailView::setItemDimensions(long itemWidth, long thumbnailHeight, long displayHeight, int itemPadding)
2144{
2145 mnItemWidth = itemWidth + 2*itemPadding;
2146 mnThumbnailHeight = thumbnailHeight;
2147 mnDisplayHeight = displayHeight;
2148 mnItemPadding = itemPadding;
2149 mnItemHeight = mnDisplayHeight + mnThumbnailHeight + 2*itemPadding;
2150}
2151
2152void SfxThumbnailView::SelectItem( sal_uInt16 nItemId )
2153{
2154 size_t nItemPos = GetItemPos( nItemId );
2155 if ( nItemPos == THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1)) )
2156 return;
2157
2158 ThumbnailViewItem* pItem = mFilteredItemList[nItemPos];
2159 if (pItem->isSelected())
2160 return;
2161
2162 pItem->setSelection(true);
2163 maItemStateHdl.Call(pItem);
2164
2165 if (IsReallyVisible() && IsUpdateMode())
2166 Invalidate();
2167
2168 bool bNewOut = IsReallyVisible() && IsUpdateMode();
2169
2170 // if necessary scroll to the visible area
2171 if (mbScroll && nItemId && mnCols)
2172 {
2173 sal_uInt16 nNewLine = static_cast<sal_uInt16>(nItemPos / mnCols);
2174 if ( nNewLine < mnFirstLine )
2175 {
2176 mnFirstLine = nNewLine;
2177 }
2178 else if ( mnVisLines != 0 && nNewLine > o3tl::make_unsigned(mnFirstLine+mnVisLines-1) )
2179 {
2180 mnFirstLine = static_cast<sal_uInt16>(nNewLine-mnVisLines+1);
2181 }
2182 }
2183
2184 if ( bNewOut )
2185 {
2186 if ( IsReallyVisible() && IsUpdateMode() )
2187 Invalidate();
2188 }
2189
2190 if( !ImplHasAccessibleListeners() )
2191 return;
2192
2193 // focus event (select)
2194 ThumbnailViewItemAcc* pItemAcc = ThumbnailViewItemAcc::getImplementation( pItem->GetAccessible( false ) );
2195
2196 if( pItemAcc )
2197 {
2198 css::uno::Any aOldAny, aNewAny;
2199 aNewAny <<= css::uno::Reference< css::uno::XInterface >(
2200 static_cast< ::cppu::OWeakObject* >( pItemAcc ));
2201 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny );
2202 }
2203
2204 // selection event
2205 css::uno::Any aOldAny, aNewAny;
2206 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny );
2207}
2208
2209bool SfxThumbnailView::IsItemSelected( sal_uInt16 nItemId ) const
2210{
2211 size_t nItemPos = GetItemPos( nItemId );
2212 if ( nItemPos == THUMBNAILVIEW_ITEM_NOTFOUND(sal_uInt16(-1)) )
2213 return false;
2214
2215 ThumbnailViewItem* pItem = mFilteredItemList[nItemPos];
2216 return pItem->isSelected();
2217}
2218
2219void SfxThumbnailView::deselectItems()
2220{
2221 for (std::unique_ptr<ThumbnailViewItem>& p : mItemList)
2222 {
2223 if (p->isSelected())
2224 {
2225 p->setSelection(false);
2226
2227 maItemStateHdl.Call(p.get());
2228 }
2229 }
2230
2231 if (IsReallyVisible() && IsUpdateMode())
2232 Invalidate();
2233}
2234
2235void SfxThumbnailView::ShowTooltips( bool bShowTooltips )
2236{
2237 mbShowTooltips = bShowTooltips;
2238}
2239
2240void SfxThumbnailView::DrawMnemonics( bool bDrawMnemonics )
2241{
2242 mbDrawMnemonics = bDrawMnemonics;
2243}
2244
2245void SfxThumbnailView::SetMultiSelectionEnabled( bool bIsMultiSelectionEnabled )
2246{
2247 mbIsMultiSelectionEnabled = bIsMultiSelectionEnabled;
2248}
2249
2250void SfxThumbnailView::filterItems(const std::function<bool (const ThumbnailViewItem*)> &func)
2251{
2252 mnFirstLine = 0; // start at the top of the list instead of the current position
2253 maFilterFunc = func;
2254
2255 size_t nSelPos = 0;
2256 bool bHasSelRange = false;
2257 ThumbnailViewItem *curSel = mpStartSelRange != mFilteredItemList.end() ? *mpStartSelRange : nullptr;
2258
2259 mFilteredItemList.clear();
2260
2261 for (size_t i = 0, n = mItemList.size(); i < n; ++i)
2262 {
2263 ThumbnailViewItem *const pItem = mItemList[i].get();
2264
2265 if (maFilterFunc(pItem))
2266 {
2267 if (curSel == pItem)
2268 {
2269 nSelPos = i;
2270 bHasSelRange = true;
2271 }
2272
2273 mFilteredItemList.push_back(pItem);
2274 }
2275 else
2276 {
2277 if( pItem->isVisible())
2278 {
2279 if ( ImplHasAccessibleListeners() )
2280 {
2281 css::uno::Any aOldAny, aNewAny;
2282
2283 aOldAny <<= pItem->GetAccessible( false );
2284 ImplFireAccessibleEvent( css::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
2285 }
2286
2287 pItem->show(false);
2288 pItem->setSelection(false);
2289
2290 maItemStateHdl.Call(pItem);
2291 }
2292 }
2293 }
2294
2295 mpStartSelRange = bHasSelRange ? mFilteredItemList.begin() + nSelPos : mFilteredItemList.end();
2296 CalculateItemPositions();
2297
2298 Invalidate();
2299}
2300
2301/* 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);
3
Calling copy constructor for 'Reference<ScrollBar>'
6
Returning from copy constructor for 'Reference<ScrollBar>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
7
Calling 'Reference::clear'
14
Returning; memory was released
205 if (aTmp.get()) {
15
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)
4
Assuming field 'm_pBody' is non-null
5
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
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
)
8
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
9
Calling 'VclReferenceBase::release'
13
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;
16
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)
10
Assuming the condition is true
11
Taking true branch
40 delete this;
12
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