Line data Source code
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 <basegfx/matrix/b2dhommatrixtools.hxx>
19 : #include <basegfx/range/b2drectangle.hxx>
20 : #include <basegfx/polygon/b2dpolygon.hxx>
21 : #include <basegfx/vector/b2dsize.hxx>
22 : #include <basegfx/vector/b2dvector.hxx>
23 : #include <drawinglayer/attribute/fillgraphicattribute.hxx>
24 : #include <drawinglayer/attribute/fontattribute.hxx>
25 : #include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx>
26 : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
27 : #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
28 : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
29 : #include <drawinglayer/processor2d/baseprocessor2d.hxx>
30 : #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
31 : #include <rtl/ustring.hxx>
32 : #include <vcl/decoview.hxx>
33 : #include <vcl/svapp.hxx>
34 : #include <vcl/scrbar.hxx>
35 : #include <vcl/help.hxx>
36 : #include <vcl/settings.hxx>
37 :
38 : #include <com/sun/star/accessibility/AccessibleEventId.hpp>
39 : #include <com/sun/star/accessibility/AccessibleStateType.hpp>
40 :
41 : #include <boost/scoped_ptr.hpp>
42 :
43 : using namespace basegfx;
44 : using namespace basegfx::tools;
45 : using namespace drawinglayer::attribute;
46 : using namespace drawinglayer::primitive2d;
47 :
48 : enum
49 : {
50 : ITEM_OFFSET = 4,
51 : ITEM_OFFSET_DOUBLE = 6,
52 : NAME_LINE_OFF_X = 2,
53 : NAME_LINE_OFF_Y = 2,
54 : NAME_LINE_HEIGHT = 2,
55 : NAME_OFFSET = 2,
56 : SCROLL_OFFSET = 4
57 : };
58 :
59 4 : ThumbnailView::ThumbnailView (vcl::Window *pParent, WinBits nWinStyle, bool bDisableTransientChildren)
60 4 : : Control( pParent, nWinStyle )
61 : {
62 4 : mpItemAttrs = NULL;
63 4 : ImplInit();
64 4 : mbIsTransientChildrenDisabled = bDisableTransientChildren;
65 4 : }
66 :
67 8 : ThumbnailView::~ThumbnailView()
68 : {
69 : com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent>
70 : xComponent(GetAccessible(false),
71 4 : com::sun::star::uno::UNO_QUERY);
72 :
73 4 : if (xComponent.is())
74 0 : xComponent->dispose ();
75 :
76 4 : delete mpScrBar;
77 4 : delete mpItemAttrs;
78 4 : delete mpProcessor;
79 :
80 4 : ImplDeleteItems();
81 4 : }
82 :
83 0 : void ThumbnailView::MouseMove(const MouseEvent& rMEvt)
84 : {
85 0 : size_t nItemCount = mFilteredItemList.size();
86 0 : Point aPoint = rMEvt.GetPosPixel();
87 0 : OUString aHelp;
88 :
89 0 : for (size_t i = 0; i < nItemCount; i++)
90 : {
91 0 : ThumbnailViewItem *pItem = mFilteredItemList[i];
92 :
93 0 : if (pItem->mbVisible && !rMEvt.IsLeaveWindow() && pItem->getDrawArea().IsInside(aPoint))
94 : {
95 0 : aHelp = pItem->getHelpText();
96 : }
97 :
98 0 : Rectangle aToInvalidate(pItem->updateHighlight(pItem->mbVisible && !rMEvt.IsLeaveWindow(), aPoint));
99 :
100 0 : if (!aToInvalidate.IsEmpty() && IsReallyVisible() && IsUpdateMode())
101 0 : Invalidate(aToInvalidate);
102 : }
103 :
104 0 : if (mbShowTooltips)
105 0 : SetQuickHelpText(aHelp);
106 0 : }
107 :
108 0 : void ThumbnailView::AppendItem(ThumbnailViewItem *pItem)
109 : {
110 0 : if (maFilterFunc(pItem))
111 : {
112 : // Save current start,end range, iterator might get invalidated
113 0 : size_t nSelStartPos = 0;
114 0 : ThumbnailViewItem *pSelStartItem = NULL;
115 :
116 0 : if (mpStartSelRange != mFilteredItemList.end())
117 : {
118 0 : pSelStartItem = *mpStartSelRange;
119 0 : nSelStartPos = mpStartSelRange - mFilteredItemList.begin();
120 : }
121 :
122 0 : mFilteredItemList.push_back(pItem);
123 0 : mpStartSelRange = pSelStartItem != NULL ? mFilteredItemList.begin() + nSelStartPos : mFilteredItemList.end();
124 : }
125 :
126 0 : mItemList.push_back(pItem);
127 0 : }
128 :
129 4 : void ThumbnailView::ImplInit()
130 : {
131 4 : mpScrBar = NULL;
132 4 : mnHeaderHeight = 0;
133 4 : mnItemWidth = 0;
134 4 : mnItemHeight = 0;
135 4 : mnItemPadding = 0;
136 4 : mnVisLines = 0;
137 4 : mnLines = 0;
138 4 : mnFineness = 5;
139 4 : mnFirstLine = 0;
140 4 : mnCols = 0;
141 4 : mbScroll = false;
142 4 : mbHasVisibleItems = false;
143 4 : mbShowTooltips = false;
144 4 : maFilterFunc = ViewFilterAll();
145 4 : maColor = GetSettings().GetStyleSettings().GetFieldColor();
146 4 : mpStartSelRange = mFilteredItemList.end();
147 :
148 : // Create the processor and process the primitives
149 4 : const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
150 4 : mpProcessor = drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(*this, aNewViewInfos );
151 :
152 4 : ImplInitSettings( true, true, true );
153 4 : }
154 :
155 8 : void ThumbnailView::ImplDeleteItems()
156 : {
157 8 : const size_t n = mItemList.size();
158 :
159 12 : for ( size_t i = 0; i < n; ++i )
160 : {
161 4 : ThumbnailViewItem *const pItem = mItemList[i];
162 :
163 : // deselect all current selected items and fire events
164 4 : if (pItem->isSelected())
165 : {
166 0 : pItem->setSelection(false);
167 0 : maItemStateHdl.Call(pItem);
168 :
169 : // fire accessible event???
170 : }
171 :
172 4 : if ( pItem->isVisible() && ImplHasAccessibleListeners() )
173 : {
174 0 : ::com::sun::star::uno::Any aOldAny, aNewAny;
175 :
176 0 : aOldAny <<= pItem->GetAccessible( mbIsTransientChildrenDisabled );
177 0 : ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
178 : }
179 :
180 4 : delete pItem;
181 : }
182 :
183 8 : mItemList.clear();
184 8 : mFilteredItemList.clear();
185 :
186 8 : mpStartSelRange = mFilteredItemList.end();
187 8 : }
188 :
189 8 : void ThumbnailView::ImplInitSettings( bool bFont, bool bForeground, bool bBackground )
190 : {
191 8 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
192 :
193 8 : if ( bFont )
194 : {
195 4 : vcl::Font aFont;
196 4 : aFont = rStyleSettings.GetAppFont();
197 4 : if ( IsControlFont() )
198 0 : aFont.Merge( GetControlFont() );
199 4 : SetZoomedPointFont( aFont );
200 : }
201 :
202 8 : if ( bForeground || bFont )
203 : {
204 4 : Color aColor;
205 4 : if ( IsControlForeground() )
206 0 : aColor = GetControlForeground();
207 : else
208 4 : aColor = rStyleSettings.GetButtonTextColor();
209 4 : SetTextColor( aColor );
210 4 : SetTextFillColor();
211 : }
212 :
213 8 : if ( bBackground )
214 : {
215 8 : Color aColor = rStyleSettings.GetFieldColor();
216 8 : SetBackground( aColor );
217 : }
218 :
219 8 : delete mpItemAttrs;
220 8 : mpItemAttrs = new ThumbnailItemAttributes;
221 8 : mpItemAttrs->aFillColor = maColor.getBColor();
222 8 : mpItemAttrs->aHighlightColor = rStyleSettings.GetHighlightColor().getBColor();
223 8 : mpItemAttrs->aFontAttr = getFontAttributeFromVclFont(mpItemAttrs->aFontSize,GetFont(),false,true);
224 8 : mpItemAttrs->nMaxTextLength = 0;
225 8 : }
226 :
227 18 : void ThumbnailView::ImplInitScrollBar()
228 : {
229 18 : if ( GetStyle() & WB_VSCROLL )
230 : {
231 18 : if ( !mpScrBar )
232 : {
233 4 : mpScrBar = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
234 4 : mpScrBar->SetScrollHdl( LINK( this, ThumbnailView, ImplScrollHdl ) );
235 : }
236 : else
237 : {
238 : // adapt the width because of the changed settings
239 14 : long nScrBarWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
240 14 : mpScrBar->setPosSizePixel( 0, 0, nScrBarWidth, 0, WINDOW_POSSIZE_WIDTH );
241 : }
242 : }
243 18 : }
244 :
245 0 : void ThumbnailView::DrawItem (ThumbnailViewItem *pItem)
246 : {
247 0 : if (pItem->isVisible())
248 : {
249 0 : Rectangle aRect = pItem->getDrawArea();
250 :
251 0 : if ( (aRect.GetHeight() > 0) && (aRect.GetWidth() > 0) )
252 0 : pItem->Paint(mpProcessor,mpItemAttrs);
253 : }
254 0 : }
255 :
256 0 : void ThumbnailView::OnItemDblClicked (ThumbnailViewItem*)
257 : {
258 0 : }
259 :
260 0 : ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > ThumbnailView::CreateAccessible()
261 : {
262 0 : return new ThumbnailViewAcc( this, mbIsTransientChildrenDisabled );
263 : }
264 :
265 26 : void ThumbnailView::CalculateItemPositions (bool bScrollBarUsed)
266 : {
267 26 : if (!mnItemHeight || !mnItemWidth)
268 26 : return;
269 :
270 26 : Size aWinSize = GetOutputSizePixel();
271 26 : size_t nItemCount = mFilteredItemList.size();
272 26 : WinBits nStyle = GetStyle();
273 26 : ScrollBar* pDelScrBar = NULL;
274 :
275 : // consider the scrolling
276 26 : if ( nStyle & WB_VSCROLL )
277 18 : ImplInitScrollBar();
278 : else
279 : {
280 8 : if ( mpScrBar )
281 : {
282 : // delete ScrollBar not until later, to prevent recursive calls
283 0 : pDelScrBar = mpScrBar;
284 0 : mpScrBar = NULL;
285 : }
286 : }
287 :
288 : // calculate window scroll ratio
289 : float nScrollRatio;
290 26 : if( bScrollBarUsed && mpScrBar )
291 0 : nScrollRatio = static_cast<float>(mpScrBar->GetThumbPos()) /
292 0 : static_cast<float>(mpScrBar->GetRangeMax()-2);
293 : else
294 26 : nScrollRatio = 0;
295 :
296 : // calculate ScrollBar width
297 26 : long nScrBarWidth = 0;
298 26 : if ( mpScrBar )
299 18 : nScrBarWidth = mpScrBar->GetSizePixel().Width();
300 :
301 : // calculate maximum number of visible columns
302 26 : mnCols = (sal_uInt16)((aWinSize.Width()-nScrBarWidth) / (mnItemWidth));
303 :
304 26 : if (!mnCols)
305 8 : mnCols = 1;
306 :
307 : // calculate maximum number of visible rows
308 26 : mnVisLines = (sal_uInt16)((aWinSize.Height()-mnHeaderHeight) / (mnItemHeight));
309 :
310 : // calculate empty space
311 26 : long nHSpace = aWinSize.Width()-nScrBarWidth - mnCols*mnItemWidth;
312 26 : long nVSpace = aWinSize.Height()-mnHeaderHeight - mnVisLines*mnItemHeight;
313 26 : long nHItemSpace = nHSpace / (mnCols+1);
314 26 : long nVItemSpace = nVSpace / (mnVisLines+1);
315 :
316 : // calculate maximum number of rows
317 : // Floor( (M+N-1)/N )==Ceiling( M/N )
318 26 : mnLines = (static_cast<long>(nItemCount)+mnCols-1) / mnCols;
319 :
320 26 : if ( !mnLines )
321 22 : mnLines = 1;
322 :
323 26 : if ( mnLines <= mnVisLines )
324 18 : mnFirstLine = 0;
325 8 : else if ( mnFirstLine > (sal_uInt16)(mnLines-mnVisLines) )
326 0 : mnFirstLine = (sal_uInt16)(mnLines-mnVisLines);
327 :
328 26 : mbHasVisibleItems = true;
329 :
330 26 : long nItemHeightOffset = mnItemHeight + nVItemSpace;
331 : long nHiddenLines = (static_cast<long>(
332 26 : ( mnLines - 1 ) * nItemHeightOffset * nScrollRatio ) -
333 26 : nVItemSpace - mnHeaderHeight) /
334 26 : nItemHeightOffset;
335 :
336 : // calculate offsets
337 26 : long nStartX = nHItemSpace;
338 26 : long nStartY = nVItemSpace + mnHeaderHeight;
339 :
340 : // calculate and draw items
341 26 : long x = nStartX;
342 52 : long y = nStartY - ( mnLines - 1 ) * nItemHeightOffset * nScrollRatio +
343 52 : nHiddenLines * nItemHeightOffset;
344 :
345 : // draw items
346 : // Unless we are scrolling (via scrollbar) we just use the precalculated
347 : // mnFirstLine -- our nHiddenLines calculation takes into account only
348 : // what the user has done with the scrollbar but not any changes of selection
349 : // using the keyboard, meaning we could accidentally hide the selected item
350 : // if we believe the scrollbar (fdo#72287).
351 26 : size_t nFirstItem = (bScrollBarUsed ? nHiddenLines : mnFirstLine) * mnCols;
352 26 : size_t nLastItem = nFirstItem + (mnVisLines + 1) * mnCols;
353 :
354 : // If want also draw parts of items in the last line,
355 : // then we add one more line if parts of these line are
356 : // visible
357 :
358 26 : size_t nCurCount = 0;
359 34 : for ( size_t i = 0; i < nItemCount; i++ )
360 : {
361 8 : ThumbnailViewItem *const pItem = mFilteredItemList[i];
362 :
363 8 : if ((nCurCount >= nFirstItem) && (nCurCount < nLastItem))
364 : {
365 8 : if( !pItem->isVisible())
366 : {
367 0 : if ( ImplHasAccessibleListeners() )
368 : {
369 0 : ::com::sun::star::uno::Any aOldAny, aNewAny;
370 :
371 0 : aNewAny <<= pItem->GetAccessible( mbIsTransientChildrenDisabled );
372 0 : ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
373 : }
374 :
375 0 : pItem->show(true);
376 :
377 0 : maItemStateHdl.Call(pItem);
378 : }
379 :
380 8 : pItem->setDrawArea(Rectangle( Point(x,y), Size(mnItemWidth, mnItemHeight) ));
381 8 : pItem->calculateItemsPosition(mnThumbnailHeight,mnDisplayHeight,mnItemPadding,mpItemAttrs->nMaxTextLength,mpItemAttrs);
382 :
383 8 : if ( !((nCurCount+1) % mnCols) )
384 : {
385 4 : x = nStartX;
386 4 : y += mnItemHeight+nVItemSpace;
387 : }
388 : else
389 4 : x += mnItemWidth+nHItemSpace;
390 : }
391 : else
392 : {
393 0 : if( pItem->isVisible())
394 : {
395 0 : if ( ImplHasAccessibleListeners() )
396 : {
397 0 : ::com::sun::star::uno::Any aOldAny, aNewAny;
398 :
399 0 : aOldAny <<= pItem->GetAccessible( mbIsTransientChildrenDisabled );
400 0 : ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
401 : }
402 :
403 0 : pItem->show(false);
404 :
405 0 : maItemStateHdl.Call(pItem);
406 : }
407 :
408 : }
409 :
410 8 : ++nCurCount;
411 : }
412 :
413 : // arrange ScrollBar, set values and show it
414 26 : if ( mpScrBar )
415 : {
416 18 : mnLines = (nCurCount+mnCols-1)/mnCols;
417 :
418 : // check if scroll is needed
419 18 : mbScroll = mnLines > mnVisLines;
420 :
421 :
422 18 : Point aPos( aWinSize.Width() - nScrBarWidth, mnHeaderHeight );
423 18 : Size aSize( nScrBarWidth, aWinSize.Height() - mnHeaderHeight );
424 :
425 18 : mpScrBar->SetPosSizePixel( aPos, aSize );
426 18 : mpScrBar->SetRangeMax( (nCurCount+mnCols-1)*mnFineness/mnCols);
427 18 : mpScrBar->SetVisibleSize( mnVisLines );
428 18 : if (!bScrollBarUsed)
429 18 : mpScrBar->SetThumbPos( (long)mnFirstLine*mnFineness );
430 18 : long nPageSize = mnVisLines;
431 18 : if ( nPageSize < 1 )
432 4 : nPageSize = 1;
433 18 : mpScrBar->SetPageSize( nPageSize );
434 18 : mpScrBar->Show( mbScroll );
435 : }
436 :
437 : // delete ScrollBar
438 26 : delete pDelScrBar;
439 : }
440 :
441 0 : size_t ThumbnailView::ImplGetItem( const Point& rPos ) const
442 : {
443 0 : if ( !mbHasVisibleItems )
444 : {
445 0 : return THUMBNAILVIEW_ITEM_NOTFOUND;
446 : }
447 :
448 0 : for (size_t i = 0; i < mFilteredItemList.size(); ++i)
449 : {
450 0 : if (mFilteredItemList[i]->isVisible() && mFilteredItemList[i]->getDrawArea().IsInside(rPos))
451 0 : return i;
452 : }
453 :
454 0 : return THUMBNAILVIEW_ITEM_NOTFOUND;
455 : }
456 :
457 0 : ThumbnailViewItem* ThumbnailView::ImplGetItem( size_t nPos )
458 : {
459 0 : return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos] : NULL;
460 : }
461 :
462 0 : sal_uInt16 ThumbnailView::ImplGetVisibleItemCount() const
463 : {
464 0 : sal_uInt16 nRet = 0;
465 0 : const size_t nItemCount = mItemList.size();
466 :
467 0 : for ( size_t n = 0; n < nItemCount; ++n )
468 : {
469 0 : if ( mItemList[n]->isVisible() )
470 0 : ++nRet;
471 : }
472 :
473 0 : return nRet;
474 : }
475 :
476 0 : ThumbnailViewItem* ThumbnailView::ImplGetVisibleItem( sal_uInt16 nVisiblePos )
477 : {
478 0 : const size_t nItemCount = mItemList.size();
479 :
480 0 : for ( size_t n = 0; n < nItemCount; ++n )
481 : {
482 0 : ThumbnailViewItem *const pItem = mItemList[n];
483 :
484 0 : if ( pItem->isVisible() && !nVisiblePos-- )
485 0 : return pItem;
486 : }
487 :
488 0 : return NULL;
489 : }
490 :
491 0 : void ThumbnailView::ImplFireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue )
492 : {
493 0 : ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
494 :
495 0 : if( pAcc )
496 0 : pAcc->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
497 0 : }
498 :
499 4 : bool ThumbnailView::ImplHasAccessibleListeners()
500 : {
501 4 : ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
502 4 : return( pAcc && pAcc->HasAccessibleListeners() );
503 : }
504 :
505 0 : IMPL_LINK( ThumbnailView,ImplScrollHdl, ScrollBar*, pScrollBar )
506 : {
507 0 : if ( pScrollBar->GetDelta() )
508 : {
509 0 : CalculateItemPositions(true);
510 :
511 0 : if ( IsReallyVisible() && IsUpdateMode() )
512 0 : Invalidate();
513 : }
514 0 : return 0;
515 : }
516 :
517 0 : IMPL_LINK (ThumbnailView, OnItemSelected, ThumbnailViewItem*, pItem)
518 : {
519 0 : maItemStateHdl.Call(pItem);
520 0 : return 0;
521 : }
522 :
523 0 : void ThumbnailView::KeyInput( const KeyEvent& rKEvt )
524 : {
525 : // Get the last selected item in the list
526 0 : size_t nLastPos = 0;
527 0 : bool bFoundLast = false;
528 0 : for ( long i = mFilteredItemList.size() - 1; !bFoundLast && i >= 0; --i )
529 : {
530 0 : ThumbnailViewItem* pItem = mFilteredItemList[i];
531 0 : if ( pItem->isSelected() )
532 : {
533 0 : nLastPos = i;
534 0 : bFoundLast = true;
535 : }
536 : }
537 :
538 0 : bool bValidRange = false;
539 0 : bool bHasSelRange = mpStartSelRange != mFilteredItemList.end();
540 0 : size_t nNextPos = nLastPos;
541 0 : vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
542 0 : ThumbnailViewItem* pNext = NULL;
543 :
544 0 : if (aKeyCode.IsShift() && bHasSelRange)
545 : {
546 : //If the last elemented selected is the start range position
547 : //search for the first selected item
548 0 : size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
549 :
550 0 : if (nLastPos == nSelPos)
551 : {
552 0 : while (nLastPos && mFilteredItemList[nLastPos-1]->isSelected())
553 0 : --nLastPos;
554 : }
555 : }
556 :
557 0 : switch ( aKeyCode.GetCode() )
558 : {
559 : case KEY_RIGHT:
560 0 : if (!mFilteredItemList.empty())
561 : {
562 0 : if ( bFoundLast && nLastPos + 1 < mFilteredItemList.size() )
563 : {
564 0 : bValidRange = true;
565 0 : nNextPos = nLastPos + 1;
566 : }
567 :
568 0 : pNext = mFilteredItemList[nNextPos];
569 : }
570 0 : break;
571 : case KEY_LEFT:
572 0 : if (!mFilteredItemList.empty())
573 : {
574 0 : if ( nLastPos > 0 )
575 : {
576 0 : bValidRange = true;
577 0 : nNextPos = nLastPos - 1;
578 : }
579 :
580 0 : pNext = mFilteredItemList[nNextPos];
581 : }
582 0 : break;
583 : case KEY_DOWN:
584 0 : if (!mFilteredItemList.empty())
585 : {
586 0 : if ( bFoundLast )
587 : {
588 : //If we are in the second last row just go the one in
589 : //the row below, if theres not row below just go to the
590 : //last item but for the last row dont do anything.
591 0 : if ( nLastPos + mnCols < mFilteredItemList.size( ) )
592 : {
593 0 : bValidRange = true;
594 0 : nNextPos = nLastPos + mnCols;
595 : }
596 : else
597 : {
598 0 : int curRow = nLastPos/mnCols;
599 :
600 0 : if (curRow < mnLines-1)
601 0 : nNextPos = mFilteredItemList.size()-1;
602 : }
603 : }
604 :
605 0 : pNext = mFilteredItemList[nNextPos];
606 : }
607 0 : break;
608 : case KEY_UP:
609 0 : if (!mFilteredItemList.empty())
610 : {
611 0 : if ( nLastPos >= mnCols )
612 : {
613 0 : bValidRange = true;
614 0 : nNextPos = nLastPos - mnCols;
615 : }
616 :
617 0 : pNext = mFilteredItemList[nNextPos];
618 : }
619 0 : break;
620 : case KEY_RETURN:
621 : {
622 0 : if ( bFoundLast )
623 0 : OnItemDblClicked( mFilteredItemList[nLastPos] );
624 : }
625 : //fall-through
626 : default:
627 0 : Control::KeyInput( rKEvt );
628 : }
629 :
630 0 : if ( pNext )
631 : {
632 0 : if (aKeyCode.IsShift() && bValidRange)
633 : {
634 0 : std::pair<size_t,size_t> aRange;
635 0 : size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
636 :
637 0 : if (nLastPos < nSelPos)
638 : {
639 0 : if (nNextPos > nLastPos)
640 : {
641 0 : if ( nNextPos > nSelPos)
642 0 : aRange = std::make_pair(nLastPos,nNextPos);
643 : else
644 0 : aRange = std::make_pair(nLastPos,nNextPos-1);
645 : }
646 : else
647 0 : aRange = std::make_pair(nNextPos,nLastPos-1);
648 : }
649 0 : else if (nLastPos == nSelPos)
650 : {
651 0 : if (nNextPos > nLastPos)
652 0 : aRange = std::make_pair(nLastPos+1,nNextPos);
653 : else
654 0 : aRange = std::make_pair(nNextPos,nLastPos-1);
655 : }
656 : else
657 : {
658 0 : if (nNextPos > nLastPos)
659 0 : aRange = std::make_pair(nLastPos+1,nNextPos);
660 : else
661 : {
662 0 : if ( nNextPos < nSelPos)
663 0 : aRange = std::make_pair(nNextPos,nLastPos);
664 : else
665 0 : aRange = std::make_pair(nNextPos+1,nLastPos);
666 : }
667 : }
668 :
669 0 : for (size_t i = aRange.first; i <= aRange.second; ++i)
670 : {
671 0 : if (i != nSelPos)
672 : {
673 0 : ThumbnailViewItem *pCurItem = mFilteredItemList[i];
674 :
675 0 : pCurItem->setSelection(!pCurItem->isSelected());
676 :
677 0 : if (pCurItem->isVisible())
678 0 : DrawItem(pCurItem);
679 :
680 0 : maItemStateHdl.Call(pCurItem);
681 : }
682 : }
683 : }
684 0 : else if (!aKeyCode.IsShift())
685 : {
686 0 : deselectItems();
687 0 : SelectItem(pNext->mnId);
688 :
689 : //Mark it as the selection range start position
690 0 : mpStartSelRange = mFilteredItemList.begin() + nNextPos;
691 : }
692 :
693 0 : MakeItemVisible(pNext->mnId);
694 : }
695 0 : }
696 :
697 0 : void ThumbnailView::MakeItemVisible( sal_uInt16 nItemId )
698 : {
699 : // Get the item row
700 0 : size_t nPos = 0;
701 0 : bool bFound = false;
702 0 : for ( size_t i = 0; !bFound && i < mFilteredItemList.size(); ++i )
703 : {
704 0 : ThumbnailViewItem* pItem = mFilteredItemList[i];
705 0 : if ( pItem->mnId == nItemId )
706 : {
707 0 : nPos = i;
708 0 : bFound = true;
709 : }
710 : }
711 0 : sal_uInt16 nRow = mnCols ? nPos / mnCols : 0;
712 :
713 : // Move the visible rows as little as possible to include that one
714 0 : if ( nRow < mnFirstLine )
715 0 : mnFirstLine = nRow;
716 0 : else if ( nRow > mnFirstLine + mnVisLines )
717 0 : mnFirstLine = nRow - mnVisLines;
718 :
719 0 : CalculateItemPositions();
720 0 : Invalidate();
721 0 : }
722 :
723 0 : void ThumbnailView::MouseButtonDown( const MouseEvent& rMEvt )
724 : {
725 0 : if ( !rMEvt.IsLeft() )
726 : {
727 0 : Control::MouseButtonDown( rMEvt );
728 0 : return;
729 : }
730 :
731 0 : size_t nPos = ImplGetItem(rMEvt.GetPosPixel());
732 0 : ThumbnailViewItem* pItem = ImplGetItem(nPos);
733 :
734 0 : if ( !pItem )
735 : {
736 0 : deselectItems();
737 0 : Control::MouseButtonDown( rMEvt );
738 0 : return;
739 : }
740 :
741 0 : if ( rMEvt.GetClicks() == 2 )
742 : {
743 0 : OnItemDblClicked(pItem);
744 0 : return;
745 : }
746 :
747 0 : if ( rMEvt.GetClicks() == 1 )
748 : {
749 0 : if (rMEvt.IsMod1())
750 : {
751 : //Keep selected item group state and just invert current desired one state
752 0 : pItem->setSelection(!pItem->isSelected());
753 :
754 : //This one becomes the selection range start position if it changes its state to selected otherwise resets it
755 0 : mpStartSelRange = pItem->isSelected() ? mFilteredItemList.begin() + nPos : mFilteredItemList.end();
756 : }
757 0 : else if (rMEvt.IsShift() && mpStartSelRange != mFilteredItemList.end())
758 : {
759 0 : std::pair<size_t,size_t> aNewRange;
760 0 : aNewRange.first = mpStartSelRange - mFilteredItemList.begin();
761 0 : aNewRange.second = nPos;
762 :
763 0 : if (aNewRange.first > aNewRange.second)
764 0 : std::swap(aNewRange.first,aNewRange.second);
765 :
766 : //Deselect the ones outside of it
767 0 : for (size_t i = 0, n = mFilteredItemList.size(); i < n; ++i)
768 : {
769 0 : ThumbnailViewItem *pCurItem = mFilteredItemList[i];
770 :
771 0 : if (pCurItem->isSelected() && (i < aNewRange.first || i > aNewRange.second))
772 : {
773 0 : pCurItem->setSelection(false);
774 :
775 0 : if (pCurItem->isVisible())
776 0 : DrawItem(pCurItem);
777 :
778 0 : maItemStateHdl.Call(pCurItem);
779 : }
780 : }
781 :
782 0 : size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
783 :
784 : //Select the items between start range and the selected item
785 0 : if (nSelPos != nPos)
786 : {
787 0 : int dir = nSelPos < nPos ? 1 : -1;
788 0 : size_t nCurPos = nSelPos + dir;
789 :
790 0 : while (nCurPos != nPos)
791 : {
792 0 : ThumbnailViewItem *pCurItem = mFilteredItemList[nCurPos];
793 :
794 0 : if (!pCurItem->isSelected())
795 : {
796 0 : pCurItem->setSelection(true);
797 :
798 0 : if (pCurItem->isVisible())
799 0 : DrawItem(pCurItem);
800 :
801 0 : maItemStateHdl.Call(pCurItem);
802 : }
803 :
804 0 : nCurPos += dir;
805 : }
806 : }
807 :
808 0 : pItem->setSelection(true);
809 : }
810 : else
811 : {
812 : //If we got a group of selected items deselect the rest and only keep the desired one
813 : //mark items as not selected to not fire unnecessary change state events.
814 0 : pItem->setSelection(false);
815 0 : deselectItems();
816 0 : pItem->setSelection(true);
817 :
818 : //Mark as initial selection range position and reset end one
819 0 : mpStartSelRange = mFilteredItemList.begin() + nPos;
820 : }
821 :
822 0 : if (pItem->isSelected())
823 : {
824 0 : bool bClickOnTitle = pItem->getTextArea().IsInside(rMEvt.GetPosPixel());
825 0 : pItem->setEditTitle(bClickOnTitle);
826 : }
827 :
828 0 : if (!pItem->isHighlighted())
829 0 : DrawItem(pItem);
830 :
831 0 : maItemStateHdl.Call(pItem);
832 :
833 : //fire accessible event??
834 : }
835 : }
836 :
837 0 : void ThumbnailView::MouseButtonUp( const MouseEvent& rMEvt )
838 : {
839 0 : Control::MouseButtonUp( rMEvt );
840 0 : }
841 :
842 0 : void ThumbnailView::Command( const CommandEvent& rCEvt )
843 : {
844 0 : if ( (rCEvt.GetCommand() == COMMAND_WHEEL) ||
845 0 : (rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) ||
846 0 : (rCEvt.GetCommand() == COMMAND_AUTOSCROLL) )
847 : {
848 0 : if ( HandleScrollCommand( rCEvt, NULL, mpScrBar ) )
849 0 : return;
850 : }
851 :
852 0 : Control::Command( rCEvt );
853 : }
854 :
855 0 : void ThumbnailView::Paint(const Rectangle &aRect)
856 : {
857 0 : size_t nItemCount = mItemList.size();
858 :
859 : // Draw background
860 0 : drawinglayer::primitive2d::Primitive2DSequence aSeq(1);
861 0 : aSeq[0] = drawinglayer::primitive2d::Primitive2DReference(new PolyPolygonColorPrimitive2D(
862 : B2DPolyPolygon(Polygon(aRect, 5, 5).getB2DPolygon()),
863 0 : maColor.getBColor()));
864 :
865 0 : mpProcessor->process(aSeq);
866 :
867 : // draw items
868 0 : for (size_t i = 0; i < nItemCount; i++)
869 : {
870 0 : ThumbnailViewItem *const pItem = mItemList[i];
871 :
872 0 : if (pItem->isVisible())
873 0 : DrawItem(pItem);
874 : }
875 :
876 0 : if (mpScrBar && mpScrBar->IsVisible())
877 0 : mpScrBar->Paint(aRect);
878 0 : }
879 :
880 0 : void ThumbnailView::GetFocus()
881 : {
882 : // Select the first item if nothing selected
883 0 : int nSelected = -1;
884 0 : for (size_t i = 0, n = mItemList.size(); i < n && nSelected == -1; ++i)
885 : {
886 0 : if (mItemList[i]->isSelected())
887 0 : nSelected = i;
888 : }
889 :
890 0 : if (nSelected == -1 && mItemList.size() > 0)
891 : {
892 0 : SelectItem(1);
893 : }
894 :
895 : // Tell the accessible object that we got the focus.
896 0 : ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
897 0 : if( pAcc )
898 0 : pAcc->GetFocus();
899 :
900 0 : Control::GetFocus();
901 0 : }
902 :
903 0 : void ThumbnailView::LoseFocus()
904 : {
905 0 : Control::LoseFocus();
906 :
907 : // Tell the accessible object that we lost the focus.
908 0 : ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
909 0 : if( pAcc )
910 0 : pAcc->LoseFocus();
911 0 : }
912 :
913 18 : void ThumbnailView::Resize()
914 : {
915 18 : Control::Resize();
916 18 : CalculateItemPositions();
917 :
918 18 : if ( IsReallyVisible() && IsUpdateMode() )
919 10 : Invalidate();
920 18 : }
921 :
922 14 : void ThumbnailView::StateChanged( StateChangedType nType )
923 : {
924 14 : Control::StateChanged( nType );
925 :
926 14 : if ( nType == StateChangedType::INITSHOW )
927 : {
928 4 : if ( IsReallyVisible() && IsUpdateMode() )
929 0 : Invalidate();
930 : }
931 10 : else if ( nType == StateChangedType::UPDATEMODE )
932 : {
933 0 : if ( IsReallyVisible() && IsUpdateMode() )
934 0 : Invalidate();
935 : }
936 10 : else if ( nType == StateChangedType::TEXT )
937 : {
938 : }
939 10 : else if ( (nType == StateChangedType::ZOOM) ||
940 : (nType == StateChangedType::CONTROLFONT) )
941 : {
942 0 : ImplInitSettings( true, false, false );
943 0 : Invalidate();
944 : }
945 10 : else if ( nType == StateChangedType::CONTROLFOREGROUND )
946 : {
947 0 : ImplInitSettings( false, true, false );
948 0 : Invalidate();
949 : }
950 10 : else if ( nType == StateChangedType::CONTROLBACKGROUND )
951 : {
952 0 : ImplInitSettings( false, false, true );
953 0 : Invalidate();
954 : }
955 10 : else if ( (nType == StateChangedType::STYLE) || (nType == StateChangedType::ENABLE) )
956 : {
957 4 : ImplInitSettings( false, false, true );
958 4 : Invalidate();
959 : }
960 14 : }
961 :
962 0 : void ThumbnailView::DataChanged( const DataChangedEvent& rDCEvt )
963 : {
964 0 : Control::DataChanged( rDCEvt );
965 :
966 0 : if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
967 0 : (rDCEvt.GetType() == DATACHANGED_DISPLAY) ||
968 0 : (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
969 0 : ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
970 0 : (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
971 : {
972 0 : ImplInitSettings( true, true, true );
973 0 : Invalidate();
974 : }
975 0 : }
976 :
977 0 : void ThumbnailView::RemoveItem( sal_uInt16 nItemId )
978 : {
979 0 : size_t nPos = GetItemPos( nItemId );
980 :
981 0 : if ( nPos == THUMBNAILVIEW_ITEM_NOTFOUND )
982 0 : return;
983 :
984 0 : if ( nPos < mFilteredItemList.size() ) {
985 :
986 : // delete item from the thumbnail list
987 0 : for (size_t i = 0, n = mItemList.size(); i < n; ++i)
988 : {
989 0 : if (mItemList[i]->mnId == nItemId)
990 : {
991 0 : mItemList.erase(mItemList.begin()+i);
992 0 : break;
993 : }
994 : }
995 :
996 : // delete item from the filter item list
997 0 : ThumbnailValueItemList::iterator it = mFilteredItemList.begin();
998 0 : ::std::advance( it, nPos );
999 :
1000 0 : if ((*it)->isSelected())
1001 : {
1002 0 : (*it)->setSelection(false);
1003 0 : maItemStateHdl.Call(*it);
1004 : }
1005 :
1006 0 : delete *it;
1007 0 : mFilteredItemList.erase( it );
1008 0 : mpStartSelRange = mFilteredItemList.end();
1009 : }
1010 :
1011 0 : CalculateItemPositions();
1012 :
1013 0 : if ( IsReallyVisible() && IsUpdateMode() )
1014 0 : Invalidate();
1015 : }
1016 :
1017 2 : void ThumbnailView::Clear()
1018 : {
1019 2 : ImplDeleteItems();
1020 :
1021 : // reset variables
1022 2 : mnFirstLine = 0;
1023 :
1024 2 : CalculateItemPositions();
1025 :
1026 2 : if ( IsReallyVisible() && IsUpdateMode() )
1027 2 : Invalidate();
1028 2 : }
1029 :
1030 2 : void ThumbnailView::updateItems (const std::vector<ThumbnailViewItem*> &items)
1031 : {
1032 2 : ImplDeleteItems();
1033 :
1034 : // reset variables
1035 2 : mnFirstLine = 0;
1036 :
1037 2 : mItemList = items;
1038 :
1039 2 : filterItems(maFilterFunc);
1040 2 : }
1041 :
1042 0 : size_t ThumbnailView::GetItemPos( sal_uInt16 nItemId ) const
1043 : {
1044 0 : for ( size_t i = 0, n = mFilteredItemList.size(); i < n; ++i ) {
1045 0 : if ( mFilteredItemList[i]->mnId == nItemId ) {
1046 0 : return i;
1047 : }
1048 : }
1049 0 : return THUMBNAILVIEW_ITEM_NOTFOUND;
1050 : }
1051 :
1052 0 : sal_uInt16 ThumbnailView::GetItemId( size_t nPos ) const
1053 : {
1054 0 : return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos]->mnId : 0 ;
1055 : }
1056 :
1057 0 : sal_uInt16 ThumbnailView::GetItemId( const Point& rPos ) const
1058 : {
1059 0 : size_t nItemPos = ImplGetItem( rPos );
1060 0 : if ( nItemPos != THUMBNAILVIEW_ITEM_NOTFOUND )
1061 0 : return GetItemId( nItemPos );
1062 :
1063 0 : return 0;
1064 : }
1065 :
1066 0 : sal_uInt16 ThumbnailView::getNextItemId() const
1067 : {
1068 0 : return mItemList.empty() ? 1 : mItemList.back()->mnId + 1;
1069 : }
1070 :
1071 2 : void ThumbnailView::setItemMaxTextLength(sal_uInt32 nLength)
1072 : {
1073 2 : mpItemAttrs->nMaxTextLength = nLength;
1074 2 : }
1075 :
1076 4 : void ThumbnailView::setItemDimensions(long itemWidth, long thumbnailHeight, long displayHeight, int itemPadding)
1077 : {
1078 4 : mnItemWidth = itemWidth + 2*itemPadding;
1079 4 : mnThumbnailHeight = thumbnailHeight;
1080 4 : mnDisplayHeight = displayHeight;
1081 4 : mnItemPadding = itemPadding;
1082 4 : mnItemHeight = mnDisplayHeight + mnThumbnailHeight + 2*itemPadding;
1083 4 : }
1084 :
1085 0 : void ThumbnailView::SelectItem( sal_uInt16 nItemId )
1086 : {
1087 0 : size_t nItemPos = GetItemPos( nItemId );
1088 0 : if ( nItemPos == THUMBNAILVIEW_ITEM_NOTFOUND )
1089 0 : return;
1090 :
1091 0 : ThumbnailViewItem* pItem = mFilteredItemList[nItemPos];
1092 0 : if (!pItem->isSelected())
1093 : {
1094 0 : pItem->setSelection(true);
1095 0 : maItemStateHdl.Call(pItem);
1096 :
1097 0 : if (IsReallyVisible() && IsUpdateMode())
1098 0 : Invalidate();
1099 :
1100 0 : bool bNewOut = IsReallyVisible() && IsUpdateMode();
1101 :
1102 : // if necessary scroll to the visible area
1103 0 : if ( mbScroll && nItemId )
1104 : {
1105 0 : sal_uInt16 nNewLine = (sal_uInt16)(nItemPos / mnCols);
1106 0 : if ( nNewLine < mnFirstLine )
1107 : {
1108 0 : mnFirstLine = nNewLine;
1109 : }
1110 0 : else if ( nNewLine > (sal_uInt16)(mnFirstLine+mnVisLines-1) )
1111 : {
1112 0 : mnFirstLine = (sal_uInt16)(nNewLine-mnVisLines+1);
1113 : }
1114 : }
1115 :
1116 0 : if ( bNewOut )
1117 : {
1118 0 : if ( IsReallyVisible() && IsUpdateMode() )
1119 0 : Invalidate();
1120 : }
1121 :
1122 0 : if( ImplHasAccessibleListeners() )
1123 : {
1124 : // focus event (select)
1125 0 : ThumbnailViewItemAcc* pItemAcc = ThumbnailViewItemAcc::getImplementation( pItem->GetAccessible( mbIsTransientChildrenDisabled ) );
1126 :
1127 0 : if( pItemAcc )
1128 : {
1129 0 : ::com::sun::star::uno::Any aOldAny, aNewAny;
1130 0 : if( !mbIsTransientChildrenDisabled )
1131 : {
1132 0 : aNewAny <<= ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >(
1133 0 : static_cast< ::cppu::OWeakObject* >( pItemAcc ));
1134 0 : ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny );
1135 : }
1136 : else
1137 : {
1138 0 : aNewAny <<= ::com::sun::star::accessibility::AccessibleStateType::FOCUSED;
1139 0 : pItemAcc->FireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
1140 0 : }
1141 : }
1142 :
1143 : // selection event
1144 0 : ::com::sun::star::uno::Any aOldAny, aNewAny;
1145 0 : ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny );
1146 : }
1147 : }
1148 : }
1149 :
1150 0 : bool ThumbnailView::IsItemSelected( sal_uInt16 nItemId ) const
1151 : {
1152 0 : size_t nItemPos = GetItemPos( nItemId );
1153 0 : if ( nItemPos == THUMBNAILVIEW_ITEM_NOTFOUND )
1154 0 : return false;
1155 :
1156 0 : ThumbnailViewItem* pItem = mFilteredItemList[nItemPos];
1157 0 : return pItem->isSelected();
1158 : }
1159 :
1160 0 : void ThumbnailView::deselectItems()
1161 : {
1162 0 : for (size_t i = 0, n = mItemList.size(); i < n; ++i)
1163 : {
1164 0 : if (mItemList[i]->isSelected())
1165 : {
1166 0 : mItemList[i]->setEditTitle(false);
1167 0 : mItemList[i]->setSelection(false);
1168 :
1169 0 : maItemStateHdl.Call(mItemList[i]);
1170 : }
1171 : }
1172 :
1173 0 : if (IsReallyVisible() && IsUpdateMode())
1174 0 : Invalidate();
1175 0 : }
1176 :
1177 2 : void ThumbnailView::ShowTooltips( bool bShowTooltips )
1178 : {
1179 2 : mbShowTooltips = bShowTooltips;
1180 2 : }
1181 :
1182 4 : void ThumbnailView::filterItems (const boost::function<bool (const ThumbnailViewItem*) > &func)
1183 : {
1184 4 : mnFirstLine = 0; // start at the top of the list instead of the current position
1185 4 : maFilterFunc = func;
1186 :
1187 4 : size_t nSelPos = 0;
1188 4 : bool bHasSelRange = false;
1189 4 : ThumbnailViewItem *curSel = mpStartSelRange != mFilteredItemList.end() ? *mpStartSelRange : NULL;
1190 :
1191 4 : mFilteredItemList.clear();
1192 :
1193 12 : for (size_t i = 0, n = mItemList.size(); i < n; ++i)
1194 : {
1195 8 : ThumbnailViewItem *const pItem = mItemList[i];
1196 :
1197 8 : if (maFilterFunc(pItem))
1198 : {
1199 8 : if (curSel == pItem)
1200 : {
1201 0 : nSelPos = i;
1202 0 : bHasSelRange = true;
1203 : }
1204 :
1205 8 : mFilteredItemList.push_back(pItem);
1206 : }
1207 : else
1208 : {
1209 0 : if( pItem->isVisible())
1210 : {
1211 0 : if ( ImplHasAccessibleListeners() )
1212 : {
1213 0 : ::com::sun::star::uno::Any aOldAny, aNewAny;
1214 :
1215 0 : aOldAny <<= pItem->GetAccessible( mbIsTransientChildrenDisabled );
1216 0 : ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
1217 : }
1218 :
1219 0 : pItem->show(false);
1220 0 : pItem->setSelection(false);
1221 :
1222 0 : maItemStateHdl.Call(pItem);
1223 : }
1224 : }
1225 : }
1226 :
1227 4 : mpStartSelRange = bHasSelRange ? mFilteredItemList.begin() + nSelPos : mFilteredItemList.end();
1228 4 : CalculateItemPositions();
1229 :
1230 4 : Invalidate();
1231 4 : }
1232 :
1233 0 : void ThumbnailView::sortItems (const boost::function<bool (const ThumbnailViewItem*, const ThumbnailViewItem*) > &func)
1234 : {
1235 0 : std::sort(mItemList.begin(),mItemList.end(),func);
1236 :
1237 0 : CalculateItemPositions();
1238 :
1239 0 : Invalidate();
1240 0 : }
1241 :
1242 0 : bool ThumbnailView::renameItem(ThumbnailViewItem*, const OUString&)
1243 : {
1244 : // Do nothing by default
1245 0 : return false;
1246 : }
1247 :
1248 20 : BitmapEx ThumbnailView::readThumbnail(const OUString &msURL)
1249 : {
1250 : using namespace ::com::sun::star;
1251 : using namespace ::com::sun::star::uno;
1252 :
1253 : // Load the thumbnail from a template document.
1254 20 : uno::Reference<io::XInputStream> xIStream;
1255 :
1256 40 : uno::Reference< uno::XComponentContext > xContext(::comphelper::getProcessComponentContext());
1257 : try
1258 : {
1259 20 : uno::Reference<lang::XSingleServiceFactory> xStorageFactory = embed::StorageFactory::create(xContext);
1260 :
1261 40 : uno::Sequence<uno::Any> aArgs (2);
1262 20 : aArgs[0] <<= msURL;
1263 20 : aArgs[1] <<= embed::ElementModes::READ;
1264 : uno::Reference<embed::XStorage> xDocStorage (
1265 20 : xStorageFactory->createInstanceWithArguments(aArgs),
1266 40 : uno::UNO_QUERY);
1267 :
1268 : try
1269 : {
1270 20 : if (xDocStorage.is())
1271 : {
1272 : uno::Reference<embed::XStorage> xStorage (
1273 20 : xDocStorage->openStorageElement(
1274 : "Thumbnails",
1275 20 : embed::ElementModes::READ));
1276 20 : if (xStorage.is())
1277 : {
1278 : uno::Reference<io::XStream> xThumbnailCopy (
1279 20 : xStorage->cloneStreamElement("thumbnail.png"));
1280 20 : if (xThumbnailCopy.is())
1281 20 : xIStream = xThumbnailCopy->getInputStream();
1282 20 : }
1283 : }
1284 : }
1285 0 : catch (const uno::Exception& rException)
1286 : {
1287 : OSL_TRACE (
1288 : "caught exception while trying to access Thumbnail/thumbnail.png of %s: %s",
1289 : OUStringToOString(msURL,
1290 : RTL_TEXTENCODING_UTF8).getStr(),
1291 : OUStringToOString(rException.Message,
1292 : RTL_TEXTENCODING_UTF8).getStr());
1293 : }
1294 :
1295 : try
1296 : {
1297 : // An (older) implementation had a bug - The storage
1298 : // name was "Thumbnail" instead of "Thumbnails". The
1299 : // old name is still used as fallback but this code can
1300 : // be removed soon.
1301 20 : if ( ! xIStream.is())
1302 : {
1303 : uno::Reference<embed::XStorage> xStorage (
1304 0 : xDocStorage->openStorageElement( "Thumbnail",
1305 0 : embed::ElementModes::READ));
1306 0 : if (xStorage.is())
1307 : {
1308 : uno::Reference<io::XStream> xThumbnailCopy (
1309 0 : xStorage->cloneStreamElement("thumbnail.png"));
1310 0 : if (xThumbnailCopy.is())
1311 0 : xIStream = xThumbnailCopy->getInputStream();
1312 0 : }
1313 : }
1314 : }
1315 0 : catch (const uno::Exception& rException)
1316 : {
1317 : OSL_TRACE (
1318 : "caught exception while trying to access Thumbnails/thumbnail.png of %s: %s",
1319 : OUStringToOString(msURL,
1320 : RTL_TEXTENCODING_UTF8).getStr(),
1321 : OUStringToOString(rException.Message,
1322 : RTL_TEXTENCODING_UTF8).getStr());
1323 20 : }
1324 : }
1325 0 : catch (const uno::Exception& rException)
1326 : {
1327 : OSL_TRACE (
1328 : "caught exception while trying to access tuhmbnail of %s: %s",
1329 : OUStringToOString(msURL,
1330 : RTL_TEXTENCODING_UTF8).getStr(),
1331 : OUStringToOString(rException.Message,
1332 : RTL_TEXTENCODING_UTF8).getStr());
1333 : }
1334 :
1335 : // Extract the image from the stream.
1336 20 : BitmapEx aThumbnail;
1337 20 : if (xIStream.is())
1338 : {
1339 : boost::scoped_ptr<SvStream> pStream (
1340 20 : ::utl::UcbStreamHelper::CreateStream (xIStream));
1341 40 : ::vcl::PNGReader aReader (*pStream);
1342 40 : aThumbnail = aReader.Read ();
1343 : }
1344 :
1345 : // Note that the preview is returned without scaling it to the desired
1346 : // width. This gives the caller the chance to take advantage of a
1347 : // possibly larger resolution then was asked for.
1348 40 : return aThumbnail;
1349 951 : }
1350 :
1351 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1352 :
1353 :
|