Bump version to 4.1-6
[LibreOffice.git] / sfx2 / source / control / thumbnailview.cxx
blobea91ee276f15c3206b78d97719dd377a89b4db88
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include <sfx2/thumbnailview.hxx>
11 #include <sfx2/thumbnailviewitem.hxx>
13 #include <utility>
15 #include "thumbnailviewacc.hxx"
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/fillbitmapattribute.hxx>
24 #include <drawinglayer/attribute/fontattribute.hxx>
25 #include <drawinglayer/primitive2d/fillbitmapprimitive2d.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>
37 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
38 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
40 using namespace basegfx;
41 using namespace basegfx::tools;
42 using namespace drawinglayer::attribute;
43 using namespace drawinglayer::primitive2d;
45 enum
47 ITEM_OFFSET = 4,
48 ITEM_OFFSET_DOUBLE = 6,
49 NAME_LINE_OFF_X = 2,
50 NAME_LINE_OFF_Y = 2,
51 NAME_LINE_HEIGHT = 2,
52 NAME_OFFSET = 2,
53 SCROLL_OFFSET = 4
56 ThumbnailView::ThumbnailView (Window *pParent, WinBits nWinStyle, bool bDisableTransientChildren)
57 : Control( pParent, nWinStyle )
59 ImplInit();
60 mbIsTransientChildrenDisabled = bDisableTransientChildren;
63 ThumbnailView::ThumbnailView (Window *pParent, const ResId &rResId, bool bDisableTransientChildren)
64 : Control( pParent, rResId )
66 ImplInit();
67 mbIsTransientChildrenDisabled = bDisableTransientChildren;
70 ThumbnailView::~ThumbnailView()
72 com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent>
73 xComponent(GetAccessible(sal_False),
74 com::sun::star::uno::UNO_QUERY);
76 if (xComponent.is())
77 xComponent->dispose ();
79 delete mpScrBar;
80 delete mpItemAttrs;
81 delete mpProcessor;
83 ImplDeleteItems();
86 void ThumbnailView::AppendItem(ThumbnailViewItem *pItem)
88 if (maFilterFunc(pItem))
90 // Save current start,end range, iterator might get invalidated
91 size_t nSelStartPos = 0;
92 ThumbnailViewItem *pSelStartItem = NULL;
94 if (mpStartSelRange != mFilteredItemList.end())
96 pSelStartItem = *mpStartSelRange;
97 nSelStartPos = mpStartSelRange - mFilteredItemList.begin();
100 mFilteredItemList.push_back(pItem);
101 mpStartSelRange = pSelStartItem != NULL ? mFilteredItemList.begin() + nSelStartPos : mFilteredItemList.end();
104 mItemList.push_back(pItem);
107 void ThumbnailView::ImplInit()
109 mpScrBar = NULL;
110 mnHeaderHeight = 0;
111 mnItemWidth = 0;
112 mnItemHeight = 0;
113 mnItemPadding = 0;
114 mnVisLines = 0;
115 mnLines = 0;
116 mnFirstLine = 0;
117 mnHighItemId = 0;
118 mnCols = 0;
119 mnSpacing = 0;
120 mbScroll = false;
121 mbHasVisibleItems = false;
122 maFilterFunc = ViewFilterAll();
123 maColor = GetSettings().GetStyleSettings().GetFieldColor();
124 mpStartSelRange = mFilteredItemList.end();
126 // Create the processor and process the primitives
127 const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
128 mpProcessor = drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(*this, aNewViewInfos );
130 ImplInitSettings( true, true, true );
133 void ThumbnailView::ImplDeleteItems()
135 const size_t n = mItemList.size();
137 for ( size_t i = 0; i < n; ++i )
139 ThumbnailViewItem *const pItem = mItemList[i];
141 // deselect all current selected items and fire events
142 if (pItem->isSelected())
144 pItem->setSelection(false);
145 maItemStateHdl.Call(pItem);
147 // fire accessible event???
150 if ( pItem->isVisible() && ImplHasAccessibleListeners() )
152 ::com::sun::star::uno::Any aOldAny, aNewAny;
154 aOldAny <<= pItem->GetAccessible( mbIsTransientChildrenDisabled );
155 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
158 delete pItem;
161 mItemList.clear();
162 mFilteredItemList.clear();
164 mpStartSelRange = mFilteredItemList.end();
167 void ThumbnailView::ImplInitSettings( bool bFont, bool bForeground, bool bBackground )
169 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
171 if ( bFont )
173 Font aFont;
174 aFont = rStyleSettings.GetAppFont();
175 if ( IsControlFont() )
176 aFont.Merge( GetControlFont() );
177 SetZoomedPointFont( aFont );
180 if ( bForeground || bFont )
182 Color aColor;
183 if ( IsControlForeground() )
184 aColor = GetControlForeground();
185 else
186 aColor = rStyleSettings.GetButtonTextColor();
187 SetTextColor( aColor );
188 SetTextFillColor();
191 if ( bBackground )
193 Color aColor = rStyleSettings.GetFieldColor();
194 SetBackground( aColor );
198 mpItemAttrs = new ThumbnailItemAttributes;
199 mpItemAttrs->aFillColor = maColor.getBColor();
200 mpItemAttrs->aHighlightColor = rStyleSettings.GetHighlightColor().getBColor();
201 mpItemAttrs->aFontAttr = getFontAttributeFromVclFont(mpItemAttrs->aFontSize,GetFont(),false,true);
202 mpItemAttrs->nMaxTextLenght = -1;
205 void ThumbnailView::ImplInitScrollBar()
207 if ( GetStyle() & WB_VSCROLL )
209 if ( !mpScrBar )
211 mpScrBar = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
212 mpScrBar->SetScrollHdl( LINK( this, ThumbnailView, ImplScrollHdl ) );
214 else
216 // adapt the width because of the changed settings
217 long nScrBarWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
218 mpScrBar->setPosSizePixel( 0, 0, nScrBarWidth, 0, WINDOW_POSSIZE_WIDTH );
223 void ThumbnailView::DrawItem (ThumbnailViewItem *pItem)
225 if (pItem->isVisible())
227 Rectangle aRect = pItem->getDrawArea();
229 if ( (aRect.GetHeight() > 0) && (aRect.GetWidth() > 0) )
230 pItem->Paint(mpProcessor,mpItemAttrs);
234 void ThumbnailView::OnItemDblClicked (ThumbnailViewItem*)
238 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > ThumbnailView::CreateAccessible()
240 return new ThumbnailViewAcc( this, mbIsTransientChildrenDisabled );
243 void ThumbnailView::CalculateItemPositions ()
245 if (!mnItemHeight || !mnItemWidth)
246 return;
248 Size aWinSize = GetOutputSizePixel();
249 size_t nItemCount = mFilteredItemList.size();
250 WinBits nStyle = GetStyle();
251 ScrollBar* pDelScrBar = NULL;
253 // consider the scrolling
254 if ( nStyle & WB_VSCROLL )
255 ImplInitScrollBar();
256 else
258 if ( mpScrBar )
260 // delete ScrollBar not until later, to prevent recursive calls
261 pDelScrBar = mpScrBar;
262 mpScrBar = NULL;
266 // calculate ScrollBar width
267 long nScrBarWidth = 0;
268 if ( mpScrBar )
269 nScrBarWidth = mpScrBar->GetSizePixel().Width();
271 // calculate maximum number of visible columns
272 mnCols = (sal_uInt16)((aWinSize.Width()-nScrBarWidth) / (mnItemWidth));
274 if (!mnCols)
275 mnCols = 1;
277 // calculate maximum number of visible rows
278 mnVisLines = (sal_uInt16)((aWinSize.Height()-mnHeaderHeight) / (mnItemHeight));
280 // calculate empty space
281 long nHSpace = aWinSize.Width()-nScrBarWidth - mnCols*mnItemWidth;
282 long nVSpace = aWinSize.Height()-mnHeaderHeight - mnVisLines*mnItemHeight;
283 long nHItemSpace = nHSpace / (mnCols+1);
284 long nVItemSpace = nVSpace / (mnVisLines+1);
286 // calculate maximum number of rows
287 // Floor( (M+N-1)/N )==Ceiling( M/N )
288 mnLines = (static_cast<long>(nItemCount)+mnCols-1) / mnCols;
290 if ( !mnLines )
291 mnLines = 1;
293 if ( mnLines <= mnVisLines )
294 mnFirstLine = 0;
295 else
297 if ( mnFirstLine > (sal_uInt16)(mnLines-mnVisLines) )
298 mnFirstLine = (sal_uInt16)(mnLines-mnVisLines);
301 mbHasVisibleItems = true;
303 // calculate offsets
304 long nStartX = nHItemSpace;
305 long nStartY = nVItemSpace + mnHeaderHeight;
307 // calculate and draw items
308 long x = nStartX;
309 long y = nStartY;
311 // draw items
312 size_t nFirstItem = mnFirstLine * mnCols;
313 size_t nLastItem = nFirstItem + (mnVisLines * mnCols);
315 maItemListRect.Left() = x;
316 maItemListRect.Top() = y;
317 maItemListRect.Right() = x + mnCols*(mnItemWidth+nHItemSpace) - nHItemSpace - 1;
318 maItemListRect.Bottom() = y + mnVisLines*(mnItemHeight+nVItemSpace) - nVItemSpace - 1;
320 // If want also draw parts of items in the last line,
321 // then we add one more line if parts of these line are
322 // visible
324 size_t nCurCount = 0;
325 for ( size_t i = 0; i < nItemCount; i++ )
327 ThumbnailViewItem *const pItem = mFilteredItemList[i];
329 if ((nCurCount >= nFirstItem) && (nCurCount < nLastItem))
331 if( !pItem->isVisible())
333 if ( ImplHasAccessibleListeners() )
335 ::com::sun::star::uno::Any aOldAny, aNewAny;
337 aNewAny <<= pItem->GetAccessible( mbIsTransientChildrenDisabled );
338 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
341 pItem->show(true);
343 maItemStateHdl.Call(pItem);
346 pItem->setDrawArea(Rectangle( Point(x,y), Size(mnItemWidth, mnItemHeight) ));
347 pItem->calculateItemsPosition(mnThumbnailHeight,mnDisplayHeight,mnItemPadding,mpItemAttrs->nMaxTextLenght,mpItemAttrs);
349 if ( !((nCurCount+1) % mnCols) )
351 x = nStartX;
352 y += mnItemHeight+nVItemSpace;
354 else
355 x += mnItemWidth+nHItemSpace;
357 else
359 if( pItem->isVisible())
361 if ( ImplHasAccessibleListeners() )
363 ::com::sun::star::uno::Any aOldAny, aNewAny;
365 aOldAny <<= pItem->GetAccessible( mbIsTransientChildrenDisabled );
366 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
369 pItem->show(false);
371 maItemStateHdl.Call(pItem);
376 ++nCurCount;
379 // arrange ScrollBar, set values and show it
380 if ( mpScrBar )
382 mnLines = (nCurCount+mnCols-1)/mnCols;
384 // check if scroll is needed
385 mbScroll = mnLines > mnVisLines;
388 Point aPos( aWinSize.Width() - nScrBarWidth, mnHeaderHeight );
389 Size aSize( nScrBarWidth, aWinSize.Height() - mnHeaderHeight );
391 mpScrBar->SetPosSizePixel( aPos, aSize );
392 mpScrBar->SetRangeMax( (nCurCount+mnCols-1)/mnCols);
393 mpScrBar->SetVisibleSize( mnVisLines );
394 mpScrBar->SetThumbPos( (long)mnFirstLine );
395 long nPageSize = mnVisLines;
396 if ( nPageSize < 1 )
397 nPageSize = 1;
398 mpScrBar->SetPageSize( nPageSize );
399 mpScrBar->Show( mbScroll );
402 // delete ScrollBar
403 delete pDelScrBar;
406 size_t ThumbnailView::ImplGetItem( const Point& rPos, bool bMove ) const
408 if ( !mbHasVisibleItems )
410 return THUMBNAILVIEW_ITEM_NOTFOUND;
413 if ( maItemListRect.IsInside( rPos ) )
415 for (size_t i = 0; i < mFilteredItemList.size(); ++i)
417 if (mFilteredItemList[i]->isVisible() && mFilteredItemList[i]->getDrawArea().IsInside(rPos))
418 return i;
421 // return the previously selected item if spacing is set and
422 // the mouse hasn't left the window yet
423 if ( bMove && mnSpacing && mnHighItemId )
425 return GetItemPos( mnHighItemId );
429 return THUMBNAILVIEW_ITEM_NOTFOUND;
432 ThumbnailViewItem* ThumbnailView::ImplGetItem( size_t nPos )
434 return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos] : NULL;
437 sal_uInt16 ThumbnailView::ImplGetVisibleItemCount() const
439 sal_uInt16 nRet = 0;
440 const size_t nItemCount = mItemList.size();
442 for ( size_t n = 0; n < nItemCount; ++n )
444 if ( mItemList[n]->isVisible() )
445 ++nRet;
448 return nRet;
451 ThumbnailViewItem* ThumbnailView::ImplGetVisibleItem( sal_uInt16 nVisiblePos )
453 const size_t nItemCount = mItemList.size();
455 for ( size_t n = 0; n < nItemCount; ++n )
457 ThumbnailViewItem *const pItem = mItemList[n];
459 if ( pItem->isVisible() && !nVisiblePos-- )
460 return pItem;
463 return NULL;
466 void ThumbnailView::ImplFireAccessibleEvent( short nEventId, const ::com::sun::star::uno::Any& rOldValue, const ::com::sun::star::uno::Any& rNewValue )
468 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( sal_False ) );
470 if( pAcc )
471 pAcc->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
474 bool ThumbnailView::ImplHasAccessibleListeners()
476 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( sal_False ) );
477 return( pAcc && pAcc->HasAccessibleListeners() );
480 IMPL_LINK( ThumbnailView,ImplScrollHdl, ScrollBar*, pScrollBar )
482 sal_uInt16 nNewFirstLine = mnFirstLine;
484 if (pScrollBar->GetDelta() > 0)
485 nNewFirstLine += 1;
486 else
487 nNewFirstLine -= 1;
489 if ( nNewFirstLine != mnFirstLine )
491 mnFirstLine = nNewFirstLine;
493 CalculateItemPositions();
495 if ( IsReallyVisible() && IsUpdateMode() )
496 Invalidate();
498 return 0;
501 IMPL_LINK (ThumbnailView, OnItemSelected, ThumbnailViewItem*, pItem)
503 maItemStateHdl.Call(pItem);
504 return 0;
507 void ThumbnailView::KeyInput( const KeyEvent& rKEvt )
509 // Get the last selected item in the list
510 size_t nLastPos = 0;
511 bool bFoundLast = false;
512 for ( long i = mFilteredItemList.size() - 1; !bFoundLast && i >= 0; --i )
514 ThumbnailViewItem* pItem = mFilteredItemList[i];
515 if ( pItem->isSelected() )
517 nLastPos = i;
518 bFoundLast = true;
522 bool bValidRange = false;
523 bool bHasSelRange = mpStartSelRange != mFilteredItemList.end();
524 size_t nNextPos = nLastPos;
525 KeyCode aKeyCode = rKEvt.GetKeyCode();
526 ThumbnailViewItem* pNext = NULL;
528 if (aKeyCode.IsShift() && bHasSelRange)
530 //If the last elemented selected is the start range position
531 //search for the first selected item
532 size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
534 if (nLastPos == nSelPos)
536 while (nLastPos && mFilteredItemList[nLastPos-1]->isSelected())
537 --nLastPos;
541 switch ( aKeyCode.GetCode() )
543 case KEY_RIGHT:
545 if ( bFoundLast && nLastPos < mFilteredItemList.size( ) - 1 )
547 bValidRange = true;
548 nNextPos = nLastPos + 1;
551 pNext = mFilteredItemList[nNextPos];
553 break;
554 case KEY_LEFT:
556 if ( nLastPos > 0 )
558 bValidRange = true;
559 nNextPos = nLastPos - 1;
562 pNext = mFilteredItemList[nNextPos];
564 break;
565 case KEY_DOWN:
567 if ( bFoundLast )
569 //If we are in the second last row just go the one in
570 //the row below, if theres not row below just go to the
571 //last item but for the last row dont do anything.
572 if ( nLastPos < mFilteredItemList.size( ) - mnCols )
574 bValidRange = true;
575 nNextPos = nLastPos + mnCols;
577 else
579 int curRow = nLastPos/mnCols;
581 if (curRow < mnLines-1)
582 nNextPos = mFilteredItemList.size()-1;
586 pNext = mFilteredItemList[nNextPos];
588 break;
589 case KEY_UP:
591 if ( nLastPos >= mnCols )
593 bValidRange = true;
594 nNextPos = nLastPos - mnCols;
597 pNext = mFilteredItemList[nNextPos];
599 break;
600 case KEY_RETURN:
602 if ( bFoundLast )
603 OnItemDblClicked( mFilteredItemList[nLastPos] );
605 default:
606 Control::KeyInput( rKEvt );
609 if ( pNext )
611 if (aKeyCode.IsShift() && bValidRange)
613 std::pair<size_t,size_t> aRange;
614 size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
616 if (nLastPos < nSelPos)
618 if (nNextPos > nLastPos)
620 if ( nNextPos > nSelPos)
621 aRange = std::make_pair(nLastPos,nNextPos);
622 else
623 aRange = std::make_pair(nLastPos,nNextPos-1);
625 else
626 aRange = std::make_pair(nNextPos,nLastPos-1);
628 else if (nLastPos == nSelPos)
630 if (nNextPos > nLastPos)
631 aRange = std::make_pair(nLastPos+1,nNextPos);
632 else
633 aRange = std::make_pair(nNextPos,nLastPos-1);
635 else
637 if (nNextPos > nLastPos)
638 aRange = std::make_pair(nLastPos+1,nNextPos);
639 else
641 if ( nNextPos < nSelPos)
642 aRange = std::make_pair(nNextPos,nLastPos);
643 else
644 aRange = std::make_pair(nNextPos+1,nLastPos);
648 for (size_t i = aRange.first; i <= aRange.second; ++i)
650 if (i != nSelPos)
652 ThumbnailViewItem *pCurItem = mFilteredItemList[i];
654 pCurItem->setSelection(!pCurItem->isSelected());
656 if (pCurItem->isVisible())
657 DrawItem(pCurItem);
659 maItemStateHdl.Call(pCurItem);
663 else if (!aKeyCode.IsShift())
665 deselectItems();
666 SelectItem(pNext->mnId);
668 //Mark it as the selection range start position
669 mpStartSelRange = mFilteredItemList.begin() + nNextPos;
672 MakeItemVisible(pNext->mnId);
676 void ThumbnailView::MakeItemVisible( sal_uInt16 nItemId )
678 // Get the item row
679 size_t nPos = 0;
680 bool bFound = false;
681 for ( size_t i = 0; !bFound && i < mFilteredItemList.size(); ++i )
683 ThumbnailViewItem* pItem = mFilteredItemList[i];
684 if ( pItem->mnId == nItemId )
686 nPos = i;
687 bFound = true;
690 sal_uInt16 nRow = nPos / mnCols;
692 // Move the visible rows as little as possible to include that one
693 if ( nRow < mnFirstLine )
694 mnFirstLine = nRow;
695 else if ( nRow > mnFirstLine + mnVisLines )
696 mnFirstLine = nRow - mnVisLines;
698 CalculateItemPositions();
699 Invalidate();
702 void ThumbnailView::MouseButtonDown( const MouseEvent& rMEvt )
704 if ( rMEvt.IsLeft() )
706 size_t nPos = ImplGetItem(rMEvt.GetPosPixel());
707 ThumbnailViewItem* pItem = ImplGetItem(nPos);
709 if (pItem && pItem->isVisible())
711 if ( rMEvt.GetClicks() == 1 )
713 if (rMEvt.IsMod1())
715 //Keep selected item group state and just invert current desired one state
716 pItem->setSelection(!pItem->isSelected());
718 //This one becomes the selection range start position if it changes its state to selected otherwise resets it
719 mpStartSelRange = pItem->isSelected() ? mFilteredItemList.begin() + nPos : mFilteredItemList.end();
721 else if (rMEvt.IsShift() && mpStartSelRange != mFilteredItemList.end())
723 std::pair<size_t,size_t> aNewRange;
724 aNewRange.first = mpStartSelRange - mFilteredItemList.begin();
725 aNewRange.second = nPos;
727 if (aNewRange.first > aNewRange.second)
728 std::swap(aNewRange.first,aNewRange.second);
730 //Deselect the ones outside of it
731 for (size_t i = 0, n = mFilteredItemList.size(); i < n; ++i)
733 ThumbnailViewItem *pCurItem = mFilteredItemList[i];
735 if (pCurItem->isSelected() && (i < aNewRange.first || i > aNewRange.second))
737 pCurItem->setSelection(false);
739 if (pCurItem->isVisible())
740 DrawItem(pCurItem);
742 maItemStateHdl.Call(pCurItem);
746 size_t nSelPos = mpStartSelRange - mFilteredItemList.begin();
748 //Select the items between start range and the selected item
749 if (nSelPos != nPos)
751 int dir = nSelPos < nPos ? 1 : -1;
752 size_t nCurPos = nSelPos + dir;
754 while (nCurPos != nPos)
756 ThumbnailViewItem *pCurItem = mFilteredItemList[nCurPos];
758 if (!pCurItem->isSelected())
760 pCurItem->setSelection(true);
762 if (pCurItem->isVisible())
763 DrawItem(pCurItem);
765 maItemStateHdl.Call(pCurItem);
768 nCurPos += dir;
772 pItem->setSelection(true);
774 else
776 //If we got a group of selected items deselect the rest and only keep the desired one
777 //mark items as not selected to not fire unnecessary change state events.
778 pItem->setSelection(false);
779 deselectItems();
780 pItem->setSelection(true);
782 //Mark as initial selection range position and reset end one
783 mpStartSelRange = mFilteredItemList.begin() + nPos;
786 if (pItem->isSelected())
788 bool bClickOnTitle = pItem->getTextArea().IsInside(rMEvt.GetPosPixel());
789 pItem->setEditTitle(bClickOnTitle);
792 if (!pItem->isHighlighted())
793 DrawItem(pItem);
795 maItemStateHdl.Call(pItem);
797 //fire accessible event??
799 else if ( rMEvt.GetClicks() == 2 )
801 Rectangle aRect(pItem->getDrawArea());
803 if (aRect.IsInside(rMEvt.GetPosPixel()))
804 OnItemDblClicked(pItem);
807 return;
809 else if (!pItem)
810 deselectItems( );
813 Control::MouseButtonDown( rMEvt );
816 void ThumbnailView::MouseButtonUp( const MouseEvent& rMEvt )
818 Control::MouseButtonUp( rMEvt );
821 void ThumbnailView::Command( const CommandEvent& rCEvt )
823 if ( (rCEvt.GetCommand() == COMMAND_WHEEL) ||
824 (rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) ||
825 (rCEvt.GetCommand() == COMMAND_AUTOSCROLL) )
827 if ( HandleScrollCommand( rCEvt, NULL, mpScrBar ) )
828 return;
831 Control::Command( rCEvt );
834 void ThumbnailView::Paint( const Rectangle &aRect)
836 size_t nItemCount = mItemList.size();
838 // Draw background
839 Primitive2DSequence aSeq(1);
840 aSeq[0] = Primitive2DReference( new PolyPolygonColorPrimitive2D(
841 B2DPolyPolygon(Polygon(aRect,5,5).getB2DPolygon()),
842 maColor.getBColor()));
844 mpProcessor->process(aSeq);
846 // draw items
847 for ( size_t i = 0; i < nItemCount; i++ )
849 ThumbnailViewItem *const pItem = mItemList[i];
851 if ( pItem->isVisible() )
852 DrawItem(pItem);
855 if ( mpScrBar && mpScrBar->IsVisible() )
856 mpScrBar->Paint(aRect);
859 void ThumbnailView::GetFocus()
861 if(GETFOCUS_TAB & GetGetFocusFlags())
863 // Select the first item if nothing selected
864 int nSelected = -1;
865 for (size_t i = 0, n = mItemList.size(); i < n && nSelected == -1; ++i)
867 if (mItemList[i]->isSelected())
868 nSelected = i;
871 if ( nSelected == -1 && mItemList.size( ) > 0 )
873 SelectItem( 1 );
877 // Tell the accessible object that we got the focus.
878 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( sal_False ) );
879 if( pAcc )
880 pAcc->GetFocus();
882 Control::GetFocus();
885 void ThumbnailView::LoseFocus()
887 if (mnHighItemId)
889 size_t nPos = GetItemPos(mnHighItemId);
891 if (nPos != THUMBNAILVIEW_ITEM_NOTFOUND)
893 ThumbnailViewItem *pOld = mItemList[nPos];
895 pOld->setHighlight(false);
897 if (!pOld->isSelected())
898 DrawItem(pOld);
901 mnHighItemId = 0;
904 Control::LoseFocus();
906 // Tell the accessible object that we lost the focus.
907 ThumbnailViewAcc* pAcc = ThumbnailViewAcc::getImplementation( GetAccessible( sal_False ) );
908 if( pAcc )
909 pAcc->LoseFocus();
912 void ThumbnailView::Resize()
914 Control::Resize();
915 CalculateItemPositions();
917 if ( IsReallyVisible() && IsUpdateMode() )
918 Invalidate();
921 void ThumbnailView::StateChanged( StateChangedType nType )
923 Control::StateChanged( nType );
925 if ( nType == STATE_CHANGE_INITSHOW )
927 if ( IsReallyVisible() && IsUpdateMode() )
928 Invalidate();
930 else if ( nType == STATE_CHANGE_UPDATEMODE )
932 if ( IsReallyVisible() && IsUpdateMode() )
933 Invalidate();
935 else if ( nType == STATE_CHANGE_TEXT )
938 else if ( (nType == STATE_CHANGE_ZOOM) ||
939 (nType == STATE_CHANGE_CONTROLFONT) )
941 ImplInitSettings( true, false, false );
942 Invalidate();
944 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
946 ImplInitSettings( false, true, false );
947 Invalidate();
949 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
951 ImplInitSettings( false, false, true );
952 Invalidate();
954 else if ( (nType == STATE_CHANGE_STYLE) || (nType == STATE_CHANGE_ENABLE) )
956 ImplInitSettings( false, false, true );
957 Invalidate();
961 void ThumbnailView::DataChanged( const DataChangedEvent& rDCEvt )
963 Control::DataChanged( rDCEvt );
965 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
966 (rDCEvt.GetType() == DATACHANGED_DISPLAY) ||
967 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
968 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
969 (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
971 ImplInitSettings( true, true, true );
972 Invalidate();
976 void ThumbnailView::RemoveItem( sal_uInt16 nItemId )
978 size_t nPos = GetItemPos( nItemId );
980 if ( nPos == THUMBNAILVIEW_ITEM_NOTFOUND )
981 return;
983 if ( nPos < mFilteredItemList.size() ) {
985 // delete item from the thumbnail list
986 for (size_t i = 0, n = mItemList.size(); i < n; ++i)
988 if (mItemList[i]->mnId == nItemId)
990 mItemList.erase(mItemList.begin()+i);
991 break;
995 // delete item from the filter item list
996 ValueItemList::iterator it = mFilteredItemList.begin();
997 ::std::advance( it, nPos );
999 if ((*it)->isSelected())
1001 (*it)->setSelection(false);
1002 maItemStateHdl.Call(*it);
1005 delete *it;
1006 mFilteredItemList.erase( it );
1007 mpStartSelRange = mFilteredItemList.end();
1010 // reset variables
1011 if ( mnHighItemId == nItemId )
1013 mnHighItemId = 0;
1016 CalculateItemPositions();
1018 if ( IsReallyVisible() && IsUpdateMode() )
1019 Invalidate();
1022 void ThumbnailView::Clear()
1024 ImplDeleteItems();
1026 // reset variables
1027 mnFirstLine = 0;
1028 mnHighItemId = 0;
1030 CalculateItemPositions();
1032 if ( IsReallyVisible() && IsUpdateMode() )
1033 Invalidate();
1036 void ThumbnailView::updateItems (const std::vector<ThumbnailViewItem*> &items)
1038 ImplDeleteItems();
1040 // reset variables
1041 mnFirstLine = 0;
1042 mnHighItemId = 0;
1044 mItemList = items;
1046 filterItems(maFilterFunc);
1049 size_t ThumbnailView::GetItemPos( sal_uInt16 nItemId ) const
1051 for ( size_t i = 0, n = mFilteredItemList.size(); i < n; ++i ) {
1052 if ( mFilteredItemList[i]->mnId == nItemId ) {
1053 return i;
1056 return THUMBNAILVIEW_ITEM_NOTFOUND;
1059 sal_uInt16 ThumbnailView::GetItemId( size_t nPos ) const
1061 return ( nPos < mFilteredItemList.size() ) ? mFilteredItemList[nPos]->mnId : 0 ;
1064 sal_uInt16 ThumbnailView::GetItemId( const Point& rPos ) const
1066 size_t nItemPos = ImplGetItem( rPos );
1067 if ( nItemPos != THUMBNAILVIEW_ITEM_NOTFOUND )
1068 return GetItemId( nItemPos );
1070 return 0;
1073 sal_uInt16 ThumbnailView::getNextItemId() const
1075 return mItemList.empty() ? 1 : mItemList.back()->mnId + 1;
1078 void ThumbnailView::setItemMaxTextLength(sal_uInt32 nLength)
1080 mpItemAttrs->nMaxTextLenght = nLength;
1083 void ThumbnailView::setItemDimensions(long itemWidth, long thumbnailHeight, long displayHeight, int itemPadding)
1085 mnItemWidth = itemWidth + 2*itemPadding;
1086 mnThumbnailHeight = thumbnailHeight;
1087 mnDisplayHeight = displayHeight;
1088 mnItemPadding = itemPadding;
1089 mnItemHeight = mnDisplayHeight + mnThumbnailHeight + 2*itemPadding;
1092 void ThumbnailView::SelectItem( sal_uInt16 nItemId )
1094 size_t nItemPos = GetItemPos( nItemId );
1095 if ( nItemPos == THUMBNAILVIEW_ITEM_NOTFOUND )
1096 return;
1098 ThumbnailViewItem* pItem = mFilteredItemList[nItemPos];
1099 if (!pItem->isSelected())
1101 pItem->setSelection(true);
1102 maItemStateHdl.Call(pItem);
1104 if (IsReallyVisible() && IsUpdateMode())
1105 Invalidate();
1107 bool bNewOut = IsReallyVisible() && IsUpdateMode();
1109 // if necessary scroll to the visible area
1110 if ( mbScroll && nItemId )
1112 sal_uInt16 nNewLine = (sal_uInt16)(nItemPos / mnCols);
1113 if ( nNewLine < mnFirstLine )
1115 mnFirstLine = nNewLine;
1117 else if ( nNewLine > (sal_uInt16)(mnFirstLine+mnVisLines-1) )
1119 mnFirstLine = (sal_uInt16)(nNewLine-mnVisLines+1);
1123 if ( bNewOut )
1125 if ( IsReallyVisible() && IsUpdateMode() )
1126 Invalidate();
1129 if( ImplHasAccessibleListeners() )
1131 // focus event (select)
1132 ThumbnailViewAcc* pItemAcc = ThumbnailViewAcc::getImplementation( pItem->GetAccessible( mbIsTransientChildrenDisabled ) );
1134 if( pItemAcc )
1136 ::com::sun::star::uno::Any aOldAny, aNewAny;
1137 if( !mbIsTransientChildrenDisabled )
1139 aNewAny <<= ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >(
1140 static_cast< ::cppu::OWeakObject* >( pItemAcc ));
1141 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny );
1143 else
1145 aNewAny <<= ::com::sun::star::accessibility::AccessibleStateType::FOCUSED;
1146 pItemAcc->FireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
1150 // selection event
1151 ::com::sun::star::uno::Any aOldAny, aNewAny;
1152 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny );
1157 void ThumbnailView::DeselectItem( sal_uInt16 nItemId )
1159 size_t nItemPos = GetItemPos( nItemId );
1160 if ( nItemPos == THUMBNAILVIEW_ITEM_NOTFOUND )
1161 return;
1163 ThumbnailViewItem* pItem = mFilteredItemList[nItemPos];
1164 if (pItem->isSelected())
1166 pItem->setSelection(false);
1167 maItemStateHdl.Call(pItem);
1169 if (IsReallyVisible() && IsUpdateMode())
1170 Invalidate();
1172 // TODO Trigger event in accessible object?
1176 bool ThumbnailView::IsItemSelected( sal_uInt16 nItemId ) const
1178 size_t nItemPos = GetItemPos( nItemId );
1179 if ( nItemPos == THUMBNAILVIEW_ITEM_NOTFOUND )
1180 return false;
1182 ThumbnailViewItem* pItem = mFilteredItemList[nItemPos];
1183 return pItem->isSelected();
1186 void ThumbnailView::deselectItems()
1188 for (size_t i = 0, n = mItemList.size(); i < n; ++i)
1190 if (mItemList[i]->isSelected())
1192 mItemList[i]->setEditTitle(false);
1193 mItemList[i]->setSelection(false);
1195 maItemStateHdl.Call(mItemList[i]);
1199 if (IsReallyVisible() && IsUpdateMode())
1200 Invalidate();
1203 OUString ThumbnailView::GetItemText( sal_uInt16 nItemId ) const
1205 size_t nPos = GetItemPos( nItemId );
1207 if ( nPos != THUMBNAILVIEW_ITEM_NOTFOUND )
1208 return mFilteredItemList[nPos]->maTitle;
1210 return OUString();
1213 void ThumbnailView::SetColor( const Color& rColor )
1215 maColor = rColor;
1216 mpItemAttrs->aFillColor = rColor.getBColor();
1218 if ( IsReallyVisible() && IsUpdateMode() )
1219 Invalidate();
1222 void ThumbnailView::filterItems (const boost::function<bool (const ThumbnailViewItem*) > &func)
1224 mnFirstLine = 0; // start at the top of the list instead of the current position
1225 maFilterFunc = func;
1227 size_t nSelPos = 0;
1228 bool bHasSelRange = false;
1229 ThumbnailViewItem *curSel = mpStartSelRange != mFilteredItemList.end() ? *mpStartSelRange : NULL;
1231 mFilteredItemList.clear();
1233 for (size_t i = 0, n = mItemList.size(); i < n; ++i)
1235 ThumbnailViewItem *const pItem = mItemList[i];
1237 if (maFilterFunc(pItem))
1239 if (curSel == pItem)
1241 nSelPos = i;
1242 bHasSelRange = true;
1245 mFilteredItemList.push_back(pItem);
1247 else
1249 if( pItem->isVisible())
1251 if ( ImplHasAccessibleListeners() )
1253 ::com::sun::star::uno::Any aOldAny, aNewAny;
1255 aOldAny <<= pItem->GetAccessible( mbIsTransientChildrenDisabled );
1256 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD, aOldAny, aNewAny );
1259 pItem->show(false);
1260 pItem->setSelection(false);
1262 maItemStateHdl.Call(pItem);
1267 mpStartSelRange = bHasSelRange ? mFilteredItemList.begin() + nSelPos : mFilteredItemList.end();
1268 CalculateItemPositions();
1270 Invalidate();
1273 void ThumbnailView::sortItems (const boost::function<bool (const ThumbnailViewItem*, const ThumbnailViewItem*) > &func)
1275 std::sort(mItemList.begin(),mItemList.end(),func);
1277 CalculateItemPositions();
1279 Invalidate();
1282 bool ThumbnailView::renameItem(ThumbnailViewItem*, OUString)
1284 // Do nothing by default
1285 return false;
1288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */