1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #include <sfx2/thumbnailview.hxx>
11 #include <sfx2/thumbnailviewitem.hxx>
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/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 <svtools/optionsdrawinglayer.hxx>
33 #include <vcl/decoview.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/scrbar.hxx>
36 #include <vcl/help.hxx>
37 #include <vcl/settings.hxx>
39 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
40 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
42 #include <boost/scoped_ptr.hpp>
44 using namespace basegfx
;
45 using namespace basegfx::tools
;
46 using namespace drawinglayer::attribute
;
47 using namespace drawinglayer::primitive2d
;
52 ITEM_OFFSET_DOUBLE
= 6,
60 ThumbnailView::ThumbnailView (vcl::Window
*pParent
, WinBits nWinStyle
, bool bDisableTransientChildren
)
61 : Control( pParent
, nWinStyle
)
62 , mpItemAttrs(new ThumbnailItemAttributes
)
65 mbIsTransientChildrenDisabled
= bDisableTransientChildren
;
68 ThumbnailView::~ThumbnailView()
73 void ThumbnailView::dispose()
75 com::sun::star::uno::Reference
< ::com::sun::star::lang::XComponent
>
76 xComponent(GetAccessible(false),
77 com::sun::star::uno::UNO_QUERY
);
80 xComponent
->dispose ();
82 mpScrBar
.disposeAndClear();
89 void ThumbnailView::MouseMove(const MouseEvent
& rMEvt
)
91 size_t nItemCount
= mFilteredItemList
.size();
92 Point aPoint
= rMEvt
.GetPosPixel();
95 for (size_t i
= 0; i
< nItemCount
; i
++)
97 ThumbnailViewItem
*pItem
= mFilteredItemList
[i
];
99 if (pItem
->mbVisible
&& !rMEvt
.IsLeaveWindow() && pItem
->getDrawArea().IsInside(aPoint
))
101 aHelp
= pItem
->getHelpText();
104 Rectangle
aToInvalidate(pItem
->updateHighlight(pItem
->mbVisible
&& !rMEvt
.IsLeaveWindow(), aPoint
));
106 if (!aToInvalidate
.IsEmpty() && IsReallyVisible() && IsUpdateMode())
107 Invalidate(aToInvalidate
);
111 SetQuickHelpText(aHelp
);
114 void ThumbnailView::AppendItem(ThumbnailViewItem
*pItem
)
116 if (maFilterFunc(pItem
))
118 // Save current start,end range, iterator might get invalidated
119 size_t nSelStartPos
= 0;
120 ThumbnailViewItem
*pSelStartItem
= NULL
;
122 if (mpStartSelRange
!= mFilteredItemList
.end())
124 pSelStartItem
= *mpStartSelRange
;
125 nSelStartPos
= mpStartSelRange
- mFilteredItemList
.begin();
128 mFilteredItemList
.push_back(pItem
);
129 mpStartSelRange
= pSelStartItem
!= NULL
? mFilteredItemList
.begin() + nSelStartPos
: mFilteredItemList
.end();
132 mItemList
.push_back(pItem
);
135 void ThumbnailView::ImplInit()
148 mbHasVisibleItems
= false;
149 mbShowTooltips
= false;
150 maFilterFunc
= ViewFilterAll();
151 maFillColor
= GetSettings().GetStyleSettings().GetFieldColor();
152 maTextColor
= GetSettings().GetStyleSettings().GetWindowTextColor();
153 maHighlightColor
= GetSettings().GetStyleSettings().GetHighlightColor();
154 maHighlightTextColor
= GetSettings().GetStyleSettings().GetWindowTextColor();
156 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer
;
157 mfHighlightTransparence
= aSvtOptionsDrawinglayer
.GetTransparentSelectionPercent() * 0.01;
159 mpStartSelRange
= mFilteredItemList
.end();
161 ApplySettings(*this);
164 void ThumbnailView::ImplDeleteItems()
166 const size_t n
= mItemList
.size();
168 for ( size_t i
= 0; i
< n
; ++i
)
170 ThumbnailViewItem
*const pItem
= mItemList
[i
];
172 // deselect all current selected items and fire events
173 if (pItem
->isSelected())
175 pItem
->setSelection(false);
176 maItemStateHdl
.Call(pItem
);
178 // fire accessible event???
181 if ( pItem
->isVisible() && ImplHasAccessibleListeners() )
183 ::com::sun::star::uno::Any aOldAny
, aNewAny
;
185 aOldAny
<<= pItem
->GetAccessible( mbIsTransientChildrenDisabled
);
186 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD
, aOldAny
, aNewAny
);
193 mFilteredItemList
.clear();
195 mpStartSelRange
= mFilteredItemList
.end();
198 void ThumbnailView::ApplySettings(vcl::RenderContext
& rRenderContext
)
200 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
202 ApplyControlFont(*this, rStyleSettings
.GetAppFont());
203 ApplyControlForeground(*this, rStyleSettings
.GetButtonTextColor());
204 rRenderContext
.SetTextFillColor();
205 rRenderContext
.SetBackground(maFillColor
);
207 mpItemAttrs
->aFillColor
= maFillColor
.getBColor();
208 mpItemAttrs
->aTextColor
= maTextColor
.getBColor();
209 mpItemAttrs
->aHighlightColor
= maHighlightColor
.getBColor();
210 mpItemAttrs
->aHighlightTextColor
= maHighlightTextColor
.getBColor();
211 mpItemAttrs
->fHighlightTransparence
= mfHighlightTransparence
;
212 mpItemAttrs
->aFontAttr
= getFontAttributeFromVclFont(mpItemAttrs
->aFontSize
,GetFont(),false,true);
213 mpItemAttrs
->nMaxTextLength
= 0;
216 void ThumbnailView::ImplInitScrollBar()
218 if ( GetStyle() & WB_VSCROLL
)
222 mpScrBar
= VclPtr
<ScrollBar
>::Create( this, WB_VSCROLL
| WB_DRAG
);
223 mpScrBar
->SetScrollHdl( LINK( this, ThumbnailView
, ImplScrollHdl
) );
227 // adapt the width because of the changed settings
228 long nScrBarWidth
= GetSettings().GetStyleSettings().GetScrollBarSize();
229 mpScrBar
->setPosSizePixel( 0, 0, nScrBarWidth
, 0, PosSizeFlags::Width
);
234 void ThumbnailView::DrawItem(ThumbnailViewItem
*pItem
)
236 if (pItem
->isVisible())
238 Rectangle aRect
= pItem
->getDrawArea();
240 if ((aRect
.GetHeight() > 0) && (aRect
.GetWidth() > 0))
245 void ThumbnailView::OnItemDblClicked (ThumbnailViewItem
*)
249 ::com::sun::star::uno::Reference
< ::com::sun::star::accessibility::XAccessible
> ThumbnailView::CreateAccessible()
251 return new ThumbnailViewAcc( this, mbIsTransientChildrenDisabled
);
254 void ThumbnailView::CalculateItemPositions (bool bScrollBarUsed
)
256 if (!mnItemHeight
|| !mnItemWidth
)
259 Size aWinSize
= GetOutputSizePixel();
260 size_t nItemCount
= mFilteredItemList
.size();
261 WinBits nStyle
= GetStyle();
262 VclPtr
<ScrollBar
> pDelScrBar
;
264 // consider the scrolling
265 if ( nStyle
& WB_VSCROLL
)
271 // delete ScrollBar not until later, to prevent recursive calls
272 pDelScrBar
= mpScrBar
;
277 // calculate window scroll ratio
279 if( bScrollBarUsed
&& mpScrBar
)
280 nScrollRatio
= static_cast<float>(mpScrBar
->GetThumbPos()) /
281 static_cast<float>(mpScrBar
->GetRangeMax()-2);
285 // calculate ScrollBar width
286 long nScrBarWidth
= 0;
288 nScrBarWidth
= mpScrBar
->GetSizePixel().Width();
290 // calculate maximum number of visible columns
291 mnCols
= (sal_uInt16
)((aWinSize
.Width()-nScrBarWidth
) / (mnItemWidth
));
296 // calculate maximum number of visible rows
297 mnVisLines
= (sal_uInt16
)((aWinSize
.Height()-mnHeaderHeight
) / (mnItemHeight
));
299 // calculate empty space
300 long nHSpace
= aWinSize
.Width()-nScrBarWidth
- mnCols
*mnItemWidth
;
301 long nVSpace
= aWinSize
.Height()-mnHeaderHeight
- mnVisLines
*mnItemHeight
;
302 long nHItemSpace
= nHSpace
/ (mnCols
+1);
303 long nVItemSpace
= nVSpace
/ (mnVisLines
+1);
305 // calculate maximum number of rows
306 // Floor( (M+N-1)/N )==Ceiling( M/N )
307 mnLines
= (static_cast<long>(nItemCount
)+mnCols
-1) / mnCols
;
312 if ( mnLines
<= mnVisLines
)
314 else if ( mnFirstLine
> (sal_uInt16
)(mnLines
-mnVisLines
) )
315 mnFirstLine
= (sal_uInt16
)(mnLines
-mnVisLines
);
317 mbHasVisibleItems
= true;
319 long nItemHeightOffset
= mnItemHeight
+ nVItemSpace
;
320 long nHiddenLines
= (static_cast<long>(
321 ( mnLines
- 1 ) * nItemHeightOffset
* nScrollRatio
) -
322 nVItemSpace
- mnHeaderHeight
) /
326 long nStartX
= nHItemSpace
;
327 long nStartY
= nVItemSpace
+ mnHeaderHeight
;
329 // calculate and draw items
331 long y
= nStartY
- ( mnLines
- 1 ) * nItemHeightOffset
* nScrollRatio
+
332 nHiddenLines
* nItemHeightOffset
;
335 // Unless we are scrolling (via scrollbar) we just use the precalculated
336 // mnFirstLine -- our nHiddenLines calculation takes into account only
337 // what the user has done with the scrollbar but not any changes of selection
338 // using the keyboard, meaning we could accidentally hide the selected item
339 // if we believe the scrollbar (fdo#72287).
340 size_t nFirstItem
= (bScrollBarUsed
? nHiddenLines
: mnFirstLine
) * mnCols
;
341 size_t nLastItem
= nFirstItem
+ (mnVisLines
+ 1) * mnCols
;
343 // If want also draw parts of items in the last line,
344 // then we add one more line if parts of these line are
347 size_t nCurCount
= 0;
348 for ( size_t i
= 0; i
< nItemCount
; i
++ )
350 ThumbnailViewItem
*const pItem
= mFilteredItemList
[i
];
352 if ((nCurCount
>= nFirstItem
) && (nCurCount
< nLastItem
))
354 if( !pItem
->isVisible())
356 if ( ImplHasAccessibleListeners() )
358 ::com::sun::star::uno::Any aOldAny
, aNewAny
;
360 aNewAny
<<= pItem
->GetAccessible( mbIsTransientChildrenDisabled
);
361 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD
, aOldAny
, aNewAny
);
366 maItemStateHdl
.Call(pItem
);
369 pItem
->setDrawArea(Rectangle( Point(x
,y
), Size(mnItemWidth
, mnItemHeight
) ));
370 pItem
->calculateItemsPosition(mnThumbnailHeight
,mnDisplayHeight
,mnItemPadding
,mpItemAttrs
->nMaxTextLength
,mpItemAttrs
);
372 if ( !((nCurCount
+1) % mnCols
) )
375 y
+= mnItemHeight
+nVItemSpace
;
378 x
+= mnItemWidth
+nHItemSpace
;
382 if( pItem
->isVisible())
384 if ( ImplHasAccessibleListeners() )
386 ::com::sun::star::uno::Any aOldAny
, aNewAny
;
388 aOldAny
<<= pItem
->GetAccessible( mbIsTransientChildrenDisabled
);
389 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD
, aOldAny
, aNewAny
);
394 maItemStateHdl
.Call(pItem
);
402 // arrange ScrollBar, set values and show it
405 mnLines
= (nCurCount
+mnCols
-1)/mnCols
;
407 // check if scroll is needed
408 mbScroll
= mnLines
> mnVisLines
;
411 Point
aPos( aWinSize
.Width() - nScrBarWidth
, mnHeaderHeight
);
412 Size
aSize( nScrBarWidth
, aWinSize
.Height() - mnHeaderHeight
);
414 mpScrBar
->SetPosSizePixel( aPos
, aSize
);
415 mpScrBar
->SetRangeMax( (nCurCount
+mnCols
-1)*mnFineness
/mnCols
);
416 mpScrBar
->SetVisibleSize( mnVisLines
);
418 mpScrBar
->SetThumbPos( (long)mnFirstLine
*mnFineness
);
419 long nPageSize
= mnVisLines
;
422 mpScrBar
->SetPageSize( nPageSize
);
423 mpScrBar
->Show( mbScroll
);
427 pDelScrBar
.disposeAndClear();
430 size_t ThumbnailView::ImplGetItem( const Point
& rPos
) const
432 if ( !mbHasVisibleItems
)
434 return THUMBNAILVIEW_ITEM_NOTFOUND
;
437 for (size_t i
= 0; i
< mFilteredItemList
.size(); ++i
)
439 if (mFilteredItemList
[i
]->isVisible() && mFilteredItemList
[i
]->getDrawArea().IsInside(rPos
))
443 return THUMBNAILVIEW_ITEM_NOTFOUND
;
446 ThumbnailViewItem
* ThumbnailView::ImplGetItem( size_t nPos
)
448 return ( nPos
< mFilteredItemList
.size() ) ? mFilteredItemList
[nPos
] : NULL
;
451 sal_uInt16
ThumbnailView::ImplGetVisibleItemCount() const
454 const size_t nItemCount
= mItemList
.size();
456 for ( size_t n
= 0; n
< nItemCount
; ++n
)
458 if ( mItemList
[n
]->isVisible() )
465 ThumbnailViewItem
* ThumbnailView::ImplGetVisibleItem( sal_uInt16 nVisiblePos
)
467 const size_t nItemCount
= mItemList
.size();
469 for ( size_t n
= 0; n
< nItemCount
; ++n
)
471 ThumbnailViewItem
*const pItem
= mItemList
[n
];
473 if ( pItem
->isVisible() && !nVisiblePos
-- )
480 void ThumbnailView::ImplFireAccessibleEvent( short nEventId
, const ::com::sun::star::uno::Any
& rOldValue
, const ::com::sun::star::uno::Any
& rNewValue
)
482 ThumbnailViewAcc
* pAcc
= ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
485 pAcc
->FireAccessibleEvent( nEventId
, rOldValue
, rNewValue
);
488 bool ThumbnailView::ImplHasAccessibleListeners()
490 ThumbnailViewAcc
* pAcc
= ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
491 return( pAcc
&& pAcc
->HasAccessibleListeners() );
494 IMPL_LINK( ThumbnailView
,ImplScrollHdl
, ScrollBar
*, pScrollBar
)
496 if ( pScrollBar
->GetDelta() )
498 CalculateItemPositions(true);
500 if ( IsReallyVisible() && IsUpdateMode() )
506 IMPL_LINK (ThumbnailView
, OnItemSelected
, ThumbnailViewItem
*, pItem
)
508 maItemStateHdl
.Call(pItem
);
512 void ThumbnailView::KeyInput( const KeyEvent
& rKEvt
)
514 // Get the last selected item in the list
516 bool bFoundLast
= false;
517 for ( long i
= mFilteredItemList
.size() - 1; !bFoundLast
&& i
>= 0; --i
)
519 ThumbnailViewItem
* pItem
= mFilteredItemList
[i
];
520 if ( pItem
->isSelected() )
527 bool bValidRange
= false;
528 bool bHasSelRange
= mpStartSelRange
!= mFilteredItemList
.end();
529 size_t nNextPos
= nLastPos
;
530 vcl::KeyCode aKeyCode
= rKEvt
.GetKeyCode();
531 ThumbnailViewItem
* pNext
= NULL
;
533 if (aKeyCode
.IsShift() && bHasSelRange
)
535 //If the last elemented selected is the start range position
536 //search for the first selected item
537 size_t nSelPos
= mpStartSelRange
- mFilteredItemList
.begin();
539 if (nLastPos
== nSelPos
)
541 while (nLastPos
&& mFilteredItemList
[nLastPos
-1]->isSelected())
546 switch ( aKeyCode
.GetCode() )
549 if (!mFilteredItemList
.empty())
551 if ( bFoundLast
&& nLastPos
+ 1 < mFilteredItemList
.size() )
554 nNextPos
= nLastPos
+ 1;
557 pNext
= mFilteredItemList
[nNextPos
];
561 if (!mFilteredItemList
.empty())
566 nNextPos
= nLastPos
- 1;
569 pNext
= mFilteredItemList
[nNextPos
];
573 if (!mFilteredItemList
.empty())
577 //If we are in the second last row just go the one in
578 //the row below, if theres not row below just go to the
579 //last item but for the last row dont do anything.
580 if ( nLastPos
+ mnCols
< mFilteredItemList
.size( ) )
583 nNextPos
= nLastPos
+ mnCols
;
587 int curRow
= nLastPos
/mnCols
;
589 if (curRow
< mnLines
-1)
590 nNextPos
= mFilteredItemList
.size()-1;
594 pNext
= mFilteredItemList
[nNextPos
];
598 if (!mFilteredItemList
.empty())
600 if ( nLastPos
>= mnCols
)
603 nNextPos
= nLastPos
- mnCols
;
606 pNext
= mFilteredItemList
[nNextPos
];
612 OnItemDblClicked( mFilteredItemList
[nLastPos
] );
616 Control::KeyInput( rKEvt
);
621 if (aKeyCode
.IsShift() && bValidRange
)
623 std::pair
<size_t,size_t> aRange
;
624 size_t nSelPos
= mpStartSelRange
- mFilteredItemList
.begin();
626 if (nLastPos
< nSelPos
)
628 if (nNextPos
> nLastPos
)
630 if ( nNextPos
> nSelPos
)
631 aRange
= std::make_pair(nLastPos
,nNextPos
);
633 aRange
= std::make_pair(nLastPos
,nNextPos
-1);
636 aRange
= std::make_pair(nNextPos
,nLastPos
-1);
638 else if (nLastPos
== nSelPos
)
640 if (nNextPos
> nLastPos
)
641 aRange
= std::make_pair(nLastPos
+1,nNextPos
);
643 aRange
= std::make_pair(nNextPos
,nLastPos
-1);
647 if (nNextPos
> nLastPos
)
648 aRange
= std::make_pair(nLastPos
+1,nNextPos
);
651 if ( nNextPos
< nSelPos
)
652 aRange
= std::make_pair(nNextPos
,nLastPos
);
654 aRange
= std::make_pair(nNextPos
+1,nLastPos
);
658 for (size_t i
= aRange
.first
; i
<= aRange
.second
; ++i
)
662 ThumbnailViewItem
*pCurItem
= mFilteredItemList
[i
];
664 pCurItem
->setSelection(!pCurItem
->isSelected());
666 if (pCurItem
->isVisible())
669 maItemStateHdl
.Call(pCurItem
);
673 else if (!aKeyCode
.IsShift())
676 SelectItem(pNext
->mnId
);
678 //Mark it as the selection range start position
679 mpStartSelRange
= mFilteredItemList
.begin() + nNextPos
;
682 MakeItemVisible(pNext
->mnId
);
686 void ThumbnailView::MakeItemVisible( sal_uInt16 nItemId
)
691 for ( size_t i
= 0; !bFound
&& i
< mFilteredItemList
.size(); ++i
)
693 ThumbnailViewItem
* pItem
= mFilteredItemList
[i
];
694 if ( pItem
->mnId
== nItemId
)
700 sal_uInt16 nRow
= mnCols
? nPos
/ mnCols
: 0;
702 // Move the visible rows as little as possible to include that one
703 if ( nRow
< mnFirstLine
)
705 else if ( nRow
> mnFirstLine
+ mnVisLines
)
706 mnFirstLine
= nRow
- mnVisLines
;
708 CalculateItemPositions();
712 void ThumbnailView::MouseButtonDown( const MouseEvent
& rMEvt
)
714 if ( !rMEvt
.IsLeft() )
716 Control::MouseButtonDown( rMEvt
);
720 size_t nPos
= ImplGetItem(rMEvt
.GetPosPixel());
721 ThumbnailViewItem
* pItem
= ImplGetItem(nPos
);
726 Control::MouseButtonDown( rMEvt
);
730 if ( rMEvt
.GetClicks() == 2 )
732 OnItemDblClicked(pItem
);
736 if ( rMEvt
.GetClicks() == 1 )
740 //Keep selected item group state and just invert current desired one state
741 pItem
->setSelection(!pItem
->isSelected());
743 //This one becomes the selection range start position if it changes its state to selected otherwise resets it
744 mpStartSelRange
= pItem
->isSelected() ? mFilteredItemList
.begin() + nPos
: mFilteredItemList
.end();
746 else if (rMEvt
.IsShift() && mpStartSelRange
!= mFilteredItemList
.end())
748 std::pair
<size_t,size_t> aNewRange
;
749 aNewRange
.first
= mpStartSelRange
- mFilteredItemList
.begin();
750 aNewRange
.second
= nPos
;
752 if (aNewRange
.first
> aNewRange
.second
)
753 std::swap(aNewRange
.first
,aNewRange
.second
);
755 //Deselect the ones outside of it
756 for (size_t i
= 0, n
= mFilteredItemList
.size(); i
< n
; ++i
)
758 ThumbnailViewItem
*pCurItem
= mFilteredItemList
[i
];
760 if (pCurItem
->isSelected() && (i
< aNewRange
.first
|| i
> aNewRange
.second
))
762 pCurItem
->setSelection(false);
764 if (pCurItem
->isVisible())
767 maItemStateHdl
.Call(pCurItem
);
771 size_t nSelPos
= mpStartSelRange
- mFilteredItemList
.begin();
773 //Select the items between start range and the selected item
776 int dir
= nSelPos
< nPos
? 1 : -1;
777 size_t nCurPos
= nSelPos
+ dir
;
779 while (nCurPos
!= nPos
)
781 ThumbnailViewItem
*pCurItem
= mFilteredItemList
[nCurPos
];
783 if (!pCurItem
->isSelected())
785 pCurItem
->setSelection(true);
787 if (pCurItem
->isVisible())
790 maItemStateHdl
.Call(pCurItem
);
797 pItem
->setSelection(true);
801 //If we got a group of selected items deselect the rest and only keep the desired one
802 //mark items as not selected to not fire unnecessary change state events.
803 pItem
->setSelection(false);
805 pItem
->setSelection(true);
807 //Mark as initial selection range position and reset end one
808 mpStartSelRange
= mFilteredItemList
.begin() + nPos
;
811 if (pItem
->isSelected())
813 bool bClickOnTitle
= pItem
->getTextArea().IsInside(rMEvt
.GetPosPixel());
814 pItem
->setEditTitle(bClickOnTitle
);
817 if (!pItem
->isHighlighted())
820 maItemStateHdl
.Call(pItem
);
822 //fire accessible event??
826 void ThumbnailView::MouseButtonUp( const MouseEvent
& rMEvt
)
828 Control::MouseButtonUp( rMEvt
);
831 void ThumbnailView::Command( const CommandEvent
& rCEvt
)
833 if ( (rCEvt
.GetCommand() == CommandEventId::Wheel
) ||
834 (rCEvt
.GetCommand() == CommandEventId::StartAutoScroll
) ||
835 (rCEvt
.GetCommand() == CommandEventId::AutoScroll
) )
837 if ( HandleScrollCommand( rCEvt
, NULL
, mpScrBar
) )
841 Control::Command( rCEvt
);
844 void ThumbnailView::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
846 size_t nItemCount
= mItemList
.size();
849 drawinglayer::primitive2d::Primitive2DSequence
aSeq(1);
850 aSeq
[0] = drawinglayer::primitive2d::Primitive2DReference(new PolyPolygonColorPrimitive2D(
851 B2DPolyPolygon(Polygon(Rectangle(Point(), GetOutputSizePixel()), 0, 0).getB2DPolygon()),
852 maFillColor
.getBColor()));
854 // Create the processor and process the primitives
855 const drawinglayer::geometry::ViewInformation2D aNewViewInfos
;
857 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> pProcessor(
858 drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(rRenderContext
, aNewViewInfos
));
859 pProcessor
->process(aSeq
);
862 for (size_t i
= 0; i
< nItemCount
; i
++)
864 ThumbnailViewItem
*const pItem
= mItemList
[i
];
866 if (pItem
->isVisible())
868 pItem
->Paint(pProcessor
.get(), mpItemAttrs
);
872 if (mpScrBar
&& mpScrBar
->IsVisible())
873 mpScrBar
->Invalidate(rRect
);
876 void ThumbnailView::GetFocus()
878 // Select the first item if nothing selected
880 for (size_t i
= 0, n
= mItemList
.size(); i
< n
&& nSelected
== -1; ++i
)
882 if (mItemList
[i
]->isSelected())
886 if (nSelected
== -1 && mItemList
.size() > 0)
891 // Tell the accessible object that we got the focus.
892 ThumbnailViewAcc
* pAcc
= ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
899 void ThumbnailView::LoseFocus()
901 Control::LoseFocus();
903 // Tell the accessible object that we lost the focus.
904 ThumbnailViewAcc
* pAcc
= ThumbnailViewAcc::getImplementation( GetAccessible( false ) );
909 void ThumbnailView::Resize()
912 CalculateItemPositions();
914 if ( IsReallyVisible() && IsUpdateMode() )
918 void ThumbnailView::StateChanged( StateChangedType nType
)
920 Control::StateChanged( nType
);
922 if ( nType
== StateChangedType::InitShow
)
924 if ( IsReallyVisible() && IsUpdateMode() )
927 else if ( nType
== StateChangedType::UpdateMode
)
929 if ( IsReallyVisible() && IsUpdateMode() )
932 else if ( nType
== StateChangedType::Text
)
935 else if ( (nType
== StateChangedType::Zoom
) ||
936 (nType
== StateChangedType::ControlFont
) )
940 else if ( nType
== StateChangedType::ControlForeground
)
944 else if ( nType
== StateChangedType::ControlBackground
)
948 else if ( (nType
== StateChangedType::Style
) || (nType
== StateChangedType::Enable
) )
954 void ThumbnailView::DataChanged( const DataChangedEvent
& rDCEvt
)
956 Control::DataChanged( rDCEvt
);
958 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
959 (rDCEvt
.GetType() == DataChangedEventType::DISPLAY
) ||
960 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
961 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
962 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
968 void ThumbnailView::RemoveItem( sal_uInt16 nItemId
)
970 size_t nPos
= GetItemPos( nItemId
);
972 if ( nPos
== THUMBNAILVIEW_ITEM_NOTFOUND
)
975 if ( nPos
< mFilteredItemList
.size() ) {
977 // delete item from the thumbnail list
978 for (size_t i
= 0, n
= mItemList
.size(); i
< n
; ++i
)
980 if (mItemList
[i
]->mnId
== nItemId
)
982 mItemList
.erase(mItemList
.begin()+i
);
987 // delete item from the filter item list
988 ThumbnailValueItemList::iterator it
= mFilteredItemList
.begin();
989 ::std::advance( it
, nPos
);
991 if ((*it
)->isSelected())
993 (*it
)->setSelection(false);
994 maItemStateHdl
.Call(*it
);
998 mFilteredItemList
.erase( it
);
999 mpStartSelRange
= mFilteredItemList
.end();
1002 CalculateItemPositions();
1004 if ( IsReallyVisible() && IsUpdateMode() )
1008 void ThumbnailView::Clear()
1015 CalculateItemPositions();
1017 if ( IsReallyVisible() && IsUpdateMode() )
1021 void ThumbnailView::updateItems (const std::vector
<ThumbnailViewItem
*> &items
)
1030 filterItems(maFilterFunc
);
1033 size_t ThumbnailView::GetItemPos( sal_uInt16 nItemId
) const
1035 for ( size_t i
= 0, n
= mFilteredItemList
.size(); i
< n
; ++i
) {
1036 if ( mFilteredItemList
[i
]->mnId
== nItemId
) {
1040 return THUMBNAILVIEW_ITEM_NOTFOUND
;
1043 sal_uInt16
ThumbnailView::GetItemId( size_t nPos
) const
1045 return ( nPos
< mFilteredItemList
.size() ) ? mFilteredItemList
[nPos
]->mnId
: 0 ;
1048 sal_uInt16
ThumbnailView::GetItemId( const Point
& rPos
) const
1050 size_t nItemPos
= ImplGetItem( rPos
);
1051 if ( nItemPos
!= THUMBNAILVIEW_ITEM_NOTFOUND
)
1052 return GetItemId( nItemPos
);
1057 sal_uInt16
ThumbnailView::getNextItemId() const
1059 return mItemList
.empty() ? 1 : mItemList
.back()->mnId
+ 1;
1062 void ThumbnailView::setItemMaxTextLength(sal_uInt32 nLength
)
1064 mpItemAttrs
->nMaxTextLength
= nLength
;
1067 void ThumbnailView::setItemDimensions(long itemWidth
, long thumbnailHeight
, long displayHeight
, int itemPadding
)
1069 mnItemWidth
= itemWidth
+ 2*itemPadding
;
1070 mnThumbnailHeight
= thumbnailHeight
;
1071 mnDisplayHeight
= displayHeight
;
1072 mnItemPadding
= itemPadding
;
1073 mnItemHeight
= mnDisplayHeight
+ mnThumbnailHeight
+ 2*itemPadding
;
1076 void ThumbnailView::SelectItem( sal_uInt16 nItemId
)
1078 size_t nItemPos
= GetItemPos( nItemId
);
1079 if ( nItemPos
== THUMBNAILVIEW_ITEM_NOTFOUND
)
1082 ThumbnailViewItem
* pItem
= mFilteredItemList
[nItemPos
];
1083 if (!pItem
->isSelected())
1085 pItem
->setSelection(true);
1086 maItemStateHdl
.Call(pItem
);
1088 if (IsReallyVisible() && IsUpdateMode())
1091 bool bNewOut
= IsReallyVisible() && IsUpdateMode();
1093 // if necessary scroll to the visible area
1094 if ( mbScroll
&& nItemId
)
1096 sal_uInt16 nNewLine
= (sal_uInt16
)(nItemPos
/ mnCols
);
1097 if ( nNewLine
< mnFirstLine
)
1099 mnFirstLine
= nNewLine
;
1101 else if ( nNewLine
> (sal_uInt16
)(mnFirstLine
+mnVisLines
-1) )
1103 mnFirstLine
= (sal_uInt16
)(nNewLine
-mnVisLines
+1);
1109 if ( IsReallyVisible() && IsUpdateMode() )
1113 if( ImplHasAccessibleListeners() )
1115 // focus event (select)
1116 ThumbnailViewItemAcc
* pItemAcc
= ThumbnailViewItemAcc::getImplementation( pItem
->GetAccessible( mbIsTransientChildrenDisabled
) );
1120 ::com::sun::star::uno::Any aOldAny
, aNewAny
;
1121 if( !mbIsTransientChildrenDisabled
)
1123 aNewAny
<<= ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>(
1124 static_cast< ::cppu::OWeakObject
* >( pItemAcc
));
1125 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, aOldAny
, aNewAny
);
1129 aNewAny
<<= ::com::sun::star::accessibility::AccessibleStateType::FOCUSED
;
1130 pItemAcc
->FireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::STATE_CHANGED
, aOldAny
, aNewAny
);
1135 ::com::sun::star::uno::Any aOldAny
, aNewAny
;
1136 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::SELECTION_CHANGED
, aOldAny
, aNewAny
);
1141 bool ThumbnailView::IsItemSelected( sal_uInt16 nItemId
) const
1143 size_t nItemPos
= GetItemPos( nItemId
);
1144 if ( nItemPos
== THUMBNAILVIEW_ITEM_NOTFOUND
)
1147 ThumbnailViewItem
* pItem
= mFilteredItemList
[nItemPos
];
1148 return pItem
->isSelected();
1151 void ThumbnailView::deselectItems()
1153 for (size_t i
= 0, n
= mItemList
.size(); i
< n
; ++i
)
1155 if (mItemList
[i
]->isSelected())
1157 mItemList
[i
]->setEditTitle(false);
1158 mItemList
[i
]->setSelection(false);
1160 maItemStateHdl
.Call(mItemList
[i
]);
1164 if (IsReallyVisible() && IsUpdateMode())
1168 void ThumbnailView::ShowTooltips( bool bShowTooltips
)
1170 mbShowTooltips
= bShowTooltips
;
1173 void ThumbnailView::filterItems (const boost::function
<bool (const ThumbnailViewItem
*) > &func
)
1175 mnFirstLine
= 0; // start at the top of the list instead of the current position
1176 maFilterFunc
= func
;
1179 bool bHasSelRange
= false;
1180 ThumbnailViewItem
*curSel
= mpStartSelRange
!= mFilteredItemList
.end() ? *mpStartSelRange
: NULL
;
1182 mFilteredItemList
.clear();
1184 for (size_t i
= 0, n
= mItemList
.size(); i
< n
; ++i
)
1186 ThumbnailViewItem
*const pItem
= mItemList
[i
];
1188 if (maFilterFunc(pItem
))
1190 if (curSel
== pItem
)
1193 bHasSelRange
= true;
1196 mFilteredItemList
.push_back(pItem
);
1200 if( pItem
->isVisible())
1202 if ( ImplHasAccessibleListeners() )
1204 ::com::sun::star::uno::Any aOldAny
, aNewAny
;
1206 aOldAny
<<= pItem
->GetAccessible( mbIsTransientChildrenDisabled
);
1207 ImplFireAccessibleEvent( ::com::sun::star::accessibility::AccessibleEventId::CHILD
, aOldAny
, aNewAny
);
1211 pItem
->setSelection(false);
1213 maItemStateHdl
.Call(pItem
);
1218 mpStartSelRange
= bHasSelRange
? mFilteredItemList
.begin() + nSelPos
: mFilteredItemList
.end();
1219 CalculateItemPositions();
1224 void ThumbnailView::sortItems (const boost::function
<bool (const ThumbnailViewItem
*, const ThumbnailViewItem
*) > &func
)
1226 std::sort(mItemList
.begin(),mItemList
.end(),func
);
1228 CalculateItemPositions();
1233 bool ThumbnailView::renameItem(ThumbnailViewItem
*, const OUString
&)
1235 // Do nothing by default
1239 BitmapEx
ThumbnailView::readThumbnail(const OUString
&msURL
)
1241 using namespace ::com::sun::star
;
1242 using namespace ::com::sun::star::uno
;
1244 // Load the thumbnail from a template document.
1245 uno::Reference
<io::XInputStream
> xIStream
;
1247 uno::Reference
< uno::XComponentContext
> xContext(::comphelper::getProcessComponentContext());
1250 uno::Reference
<lang::XSingleServiceFactory
> xStorageFactory
= embed::StorageFactory::create(xContext
);
1252 uno::Sequence
<uno::Any
> aArgs (2);
1254 aArgs
[1] <<= embed::ElementModes::READ
;
1255 uno::Reference
<embed::XStorage
> xDocStorage (
1256 xStorageFactory
->createInstanceWithArguments(aArgs
),
1261 if (xDocStorage
.is())
1263 uno::Reference
<embed::XStorage
> xStorage (
1264 xDocStorage
->openStorageElement(
1266 embed::ElementModes::READ
));
1269 uno::Reference
<io::XStream
> xThumbnailCopy (
1270 xStorage
->cloneStreamElement("thumbnail.png"));
1271 if (xThumbnailCopy
.is())
1272 xIStream
= xThumbnailCopy
->getInputStream();
1276 catch (const uno::Exception
& rException
)
1279 "caught exception while trying to access Thumbnail/thumbnail.png of %s: %s",
1280 OUStringToOString(msURL
,
1281 RTL_TEXTENCODING_UTF8
).getStr(),
1282 OUStringToOString(rException
.Message
,
1283 RTL_TEXTENCODING_UTF8
).getStr());
1288 // An (older) implementation had a bug - The storage
1289 // name was "Thumbnail" instead of "Thumbnails". The
1290 // old name is still used as fallback but this code can
1292 if ( ! xIStream
.is())
1294 uno::Reference
<embed::XStorage
> xStorage (
1295 xDocStorage
->openStorageElement( "Thumbnail",
1296 embed::ElementModes::READ
));
1299 uno::Reference
<io::XStream
> xThumbnailCopy (
1300 xStorage
->cloneStreamElement("thumbnail.png"));
1301 if (xThumbnailCopy
.is())
1302 xIStream
= xThumbnailCopy
->getInputStream();
1306 catch (const uno::Exception
& rException
)
1309 "caught exception while trying to access Thumbnails/thumbnail.png of %s: %s",
1310 OUStringToOString(msURL
,
1311 RTL_TEXTENCODING_UTF8
).getStr(),
1312 OUStringToOString(rException
.Message
,
1313 RTL_TEXTENCODING_UTF8
).getStr());
1316 catch (const uno::Exception
& rException
)
1319 "caught exception while trying to access tuhmbnail of %s: %s",
1320 OUStringToOString(msURL
,
1321 RTL_TEXTENCODING_UTF8
).getStr(),
1322 OUStringToOString(rException
.Message
,
1323 RTL_TEXTENCODING_UTF8
).getStr());
1326 // Extract the image from the stream.
1327 BitmapEx aThumbnail
;
1330 boost::scoped_ptr
<SvStream
> pStream (
1331 ::utl::UcbStreamHelper::CreateStream (xIStream
));
1332 vcl::PNGReader
aReader (*pStream
);
1333 aThumbnail
= aReader
.Read ();
1336 // Note that the preview is returned without scaling it to the desired
1337 // width. This gives the caller the chance to take advantage of a
1338 // possibly larger resolution then was asked for.
1342 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */