bump product version to 5.0.4.1
[LibreOffice.git] / sfx2 / source / control / thumbnailviewitem.cxx
blob68586ba42f37f482173f8a5da08b5c72c597da0c
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sfx2/thumbnailviewitem.hxx>
22 #include <sfx2/thumbnailview.hxx>
23 #include "thumbnailviewacc.hxx"
25 #include <basegfx/matrix/b2dhommatrixtools.hxx>
26 #include <basegfx/range/b2drectangle.hxx>
27 #include <basegfx/vector/b2dsize.hxx>
28 #include <basegfx/polygon/b2dpolygon.hxx>
29 #include <drawinglayer/attribute/fillgraphicattribute.hxx>
30 #include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx>
31 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
32 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
33 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
34 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
35 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
36 #include <vcl/button.hxx>
37 #include <vcl/graph.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/texteng.hxx>
41 using namespace basegfx;
42 using namespace basegfx::tools;
43 using namespace ::com::sun::star;
44 using namespace drawinglayer::attribute;
45 using namespace drawinglayer::primitive2d;
47 class ResizableMultiLineEdit : public VclMultiLineEdit
49 private:
50 ThumbnailViewItem* mpItem;
51 bool mbIsInGrabFocus;
53 public:
54 ResizableMultiLineEdit (vcl::Window* pParent, ThumbnailViewItem* pItem);
56 void SetInGrabFocus(bool bInGrabFocus) { mbIsInGrabFocus = bInGrabFocus; }
58 virtual bool PreNotify(NotifyEvent& rNEvt) SAL_OVERRIDE;
59 virtual void Modify() SAL_OVERRIDE;
62 ResizableMultiLineEdit::ResizableMultiLineEdit (vcl::Window* pParent, ThumbnailViewItem* pItem) :
63 VclMultiLineEdit (pParent, WB_CENTER | WB_BORDER),
64 mpItem(pItem),
65 mbIsInGrabFocus(false)
69 bool ResizableMultiLineEdit::PreNotify(NotifyEvent& rNEvt)
71 bool nDone = false;
72 if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
74 const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
75 vcl::KeyCode aCode = rKEvt.GetKeyCode();
76 switch (aCode.GetCode())
78 case KEY_RETURN:
79 mpItem->setTitle( GetText() );
80 //fall-through
81 case KEY_ESCAPE:
82 mpItem->setEditTitle(false);
83 nDone = true;
84 break;
85 default:
86 break;
89 else if ( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS && !mbIsInGrabFocus )
91 mpItem->setTitle( GetText() );
92 mpItem->setEditTitle(false, false);
94 return nDone || VclMultiLineEdit::PreNotify(rNEvt);
97 void ResizableMultiLineEdit::Modify()
99 VclMultiLineEdit::Modify();
100 mpItem->updateTitleEditSize();
103 ThumbnailViewItem::ThumbnailViewItem(ThumbnailView &rView, sal_uInt16 nId)
104 : mrParent(rView)
105 , mnId(nId)
106 , mbVisible(true)
107 , mbSelected(false)
108 , mbHover(false)
109 , mpxAcc(NULL)
110 , mbEditTitle(false)
111 , mpTitleED(NULL)
112 , maTextEditMaxArea()
114 mpTitleED = VclPtr<ResizableMultiLineEdit>::Create(&rView, this);
117 ThumbnailViewItem::~ThumbnailViewItem()
119 mpTitleED.disposeAndClear();
120 if( mpxAcc )
122 static_cast< ThumbnailViewItemAcc* >( mpxAcc->get() )->ParentDestroyed();
123 delete mpxAcc;
127 void ThumbnailViewItem::show (bool bVisible)
129 mbVisible = bVisible;
130 if (!mbVisible)
131 mpTitleED->Show(false);
134 void ThumbnailViewItem::setSelection (bool state)
136 mbSelected = state;
139 void ThumbnailViewItem::setHighlight (bool state)
141 mbHover = state;
144 Rectangle ThumbnailViewItem::updateHighlight(bool bVisible, const Point& rPoint)
146 bool bNeedsPaint = false;
148 if (bVisible && getDrawArea().IsInside(rPoint))
150 if (!isHighlighted())
151 bNeedsPaint = true;
152 setHighlight(true);
154 else
156 if (isHighlighted() || mpTitleED->SupportsDoubleBuffering())
157 bNeedsPaint = true;
158 setHighlight(false);
161 if (bNeedsPaint)
162 return getDrawArea();
164 return Rectangle();
167 OUString ThumbnailViewItem::getHelpText() const
169 return maTitle;
172 void ThumbnailViewItem::setEditTitle (bool edit, bool bChangeFocus)
174 mbEditTitle = edit;
175 mpTitleED->Show(edit);
176 if (edit)
178 mpTitleED->SetText(maTitle);
179 updateTitleEditSize();
180 static_cast<ResizableMultiLineEdit*>(mpTitleED.get())->SetInGrabFocus(true);
181 mpTitleED->GrabFocus();
182 static_cast<ResizableMultiLineEdit*>(mpTitleED.get())->SetInGrabFocus(false);
184 else if (bChangeFocus)
186 mrParent.GrabFocus();
190 Rectangle ThumbnailViewItem::getTextArea() const
192 Rectangle aTextArea(maTextEditMaxArea);
194 TextEngine aTextEngine;
195 aTextEngine.SetMaxTextWidth(maDrawArea.getWidth());
196 aTextEngine.SetText(maTitle);
198 long nTxtHeight = aTextEngine.GetTextHeight() + 6;
199 if (nTxtHeight < aTextArea.GetHeight())
200 aTextArea.SetSize(Size(aTextArea.GetWidth(), nTxtHeight));
202 return aTextArea;
205 void ThumbnailViewItem::updateTitleEditSize()
207 Rectangle aTextArea = getTextArea();
208 Point aPos = aTextArea.TopLeft();
209 Size aSize = aTextArea.GetSize();
210 mpTitleED->SetPosSizePixel(aPos, aSize);
213 void ThumbnailViewItem::setTitle (const OUString& rTitle)
215 if (mrParent.renameItem(this, rTitle))
216 maTitle = rTitle;
219 uno::Reference< accessibility::XAccessible > ThumbnailViewItem::GetAccessible( bool bIsTransientChildrenDisabled )
221 if( !mpxAcc )
222 mpxAcc = new uno::Reference< accessibility::XAccessible >( new ThumbnailViewItemAcc( this, bIsTransientChildrenDisabled ) );
224 return *mpxAcc;
227 void ThumbnailViewItem::setDrawArea (const Rectangle &area)
229 maDrawArea = area;
232 void ThumbnailViewItem::calculateItemsPosition (const long nThumbnailHeight, const long,
233 const long nPadding, sal_uInt32 nMaxTextLength,
234 const ThumbnailItemAttributes *pAttrs)
236 drawinglayer::primitive2d::TextLayouterDevice aTextDev;
237 aTextDev.setFontAttribute(pAttrs->aFontAttr,
238 pAttrs->aFontSize.getX(), pAttrs->aFontSize.getY(),
239 com::sun::star::lang::Locale() );
241 Size aRectSize = maDrawArea.GetSize();
242 Size aImageSize = maPreview1.GetSizePixel();
244 // Calculate thumbnail position
245 Point aPos = maDrawArea.TopLeft();
246 aPos.X() = maDrawArea.getX() + (aRectSize.Width()-aImageSize.Width())/2;
247 aPos.Y() = maDrawArea.getY() + nPadding + (nThumbnailHeight-aImageSize.Height())/2;
248 maPrev1Pos = aPos;
250 // Calculate text position
251 aPos.Y() = maDrawArea.getY() + nThumbnailHeight + nPadding * 2;
252 aPos.X() = maDrawArea.Left() + (aRectSize.Width() - aTextDev.getTextWidth(maTitle,0,nMaxTextLength))/2;
253 maTextPos = aPos;
255 // Calculate the text edit max area
256 aPos = Point(maDrawArea.getX() + nPadding, maTextPos.getY());
257 Size aEditSize(maDrawArea.GetWidth() - nPadding * 2,
258 maDrawArea.Bottom() - maTextPos.Y());
259 maTextEditMaxArea = Rectangle( aPos, aEditSize );
262 void ThumbnailViewItem::setSelectClickHdl (const Link<> &link)
264 maClickHdl = link;
267 void ThumbnailViewItem::Paint (drawinglayer::processor2d::BaseProcessor2D *pProcessor,
268 const ThumbnailItemAttributes *pAttrs)
270 BColor aFillColor = pAttrs->aFillColor;
271 drawinglayer::primitive2d::Primitive2DSequence aSeq(4);
272 double fTransparence = 0.0;
274 // Draw background
275 if (mbSelected || mbHover)
276 aFillColor = pAttrs->aHighlightColor;
278 if (mbHover)
279 fTransparence = pAttrs->fHighlightTransparence;
281 sal_uInt32 nPrimitive = 0;
282 aSeq[nPrimitive++] = drawinglayer::primitive2d::Primitive2DReference( new PolyPolygonSelectionPrimitive2D(
283 B2DPolyPolygon(Polygon(maDrawArea, THUMBNAILVIEW_ITEM_CORNER, THUMBNAILVIEW_ITEM_CORNER).getB2DPolygon()),
284 aFillColor,
285 fTransparence,
286 0.0,
287 true));
289 // Draw thumbnail
290 Point aPos = maPrev1Pos;
291 Size aImageSize = maPreview1.GetSizePixel();
293 aSeq[nPrimitive++] = drawinglayer::primitive2d::Primitive2DReference( new FillGraphicPrimitive2D(
294 createTranslateB2DHomMatrix(aPos.X(),aPos.Y()),
295 FillGraphicAttribute(Graphic(maPreview1),
296 B2DRange(
297 B2DPoint(0,0),
298 B2DPoint(aImageSize.Width(),aImageSize.Height())),
299 false)
302 // draw thumbnail borders
303 float fWidth = aImageSize.Width() - 1;
304 float fHeight = aImageSize.Height() - 1;
305 float fPosX = maPrev1Pos.getX();
306 float fPosY = maPrev1Pos.getY();
308 B2DPolygon aBounds;
309 aBounds.append(B2DPoint(fPosX,fPosY));
310 aBounds.append(B2DPoint(fPosX+fWidth,fPosY));
311 aBounds.append(B2DPoint(fPosX+fWidth,fPosY+fHeight));
312 aBounds.append(B2DPoint(fPosX,fPosY+fHeight));
313 aBounds.setClosed(true);
315 aSeq[nPrimitive++] = drawinglayer::primitive2d::Primitive2DReference(createBorderLine(aBounds));
317 // Draw text below thumbnail
318 addTextPrimitives(maTitle, pAttrs, maTextPos, aSeq);
320 pProcessor->process(aSeq);
323 void ThumbnailViewItem::addTextPrimitives (const OUString& rText, const ThumbnailItemAttributes *pAttrs, Point aPos, drawinglayer::primitive2d::Primitive2DSequence& rSeq)
325 drawinglayer::primitive2d::TextLayouterDevice aTextDev;
327 aPos.setY(aPos.getY() + aTextDev.getTextHeight());
329 OUString aText (rText);
331 TextEngine aTextEngine;
332 aTextEngine.SetMaxTextWidth(maDrawArea.getWidth());
333 aTextEngine.SetText(rText);
335 sal_Int32 nPrimitives = rSeq.getLength();
336 rSeq.realloc(nPrimitives + aTextEngine.GetLineCount(0));
338 // Create the text primitives
339 sal_uInt16 nLineStart = 0;
340 for (sal_uInt16 i=0; i < aTextEngine.GetLineCount(0); ++i)
342 sal_uInt16 nLineLength = aTextEngine.GetLineLen(0, i);
343 double nLineWidth = aTextDev.getTextWidth (aText, nLineStart, nLineLength);
345 bool bTooLong = (aPos.getY() + aTextEngine.GetCharHeight()) > maDrawArea.Bottom();
346 if (bTooLong && (nLineLength + nLineStart) < rText.getLength())
348 // Add the '...' to the last line to show, even though it may require to shorten the line
349 double nDotsWidth = aTextDev.getTextWidth(OUString("..."),0,3);
351 sal_uInt16 nLength = nLineLength - 1;
352 while ( nDotsWidth + aTextDev.getTextWidth(aText, nLineStart, nLength) > maDrawArea.getWidth() && nLength > 0)
354 --nLength;
357 aText = aText.copy(0, nLineStart+nLength);
358 aText += "...";
359 nLineLength = nLength + 3;
362 double nLineX = maDrawArea.Left() + (maDrawArea.getWidth() - nLineWidth) / 2.0;
364 basegfx::B2DHomMatrix aTextMatrix( createScaleTranslateB2DHomMatrix(
365 pAttrs->aFontSize.getX(), pAttrs->aFontSize.getY(),
366 nLineX, double( aPos.Y() ) ) );
368 // setup color
369 BColor aTextColor = pAttrs->aTextColor;
370 if (mbSelected || mbHover)
371 aTextColor = pAttrs->aHighlightTextColor;
373 rSeq[nPrimitives++] = drawinglayer::primitive2d::Primitive2DReference(
374 new TextSimplePortionPrimitive2D(aTextMatrix,
375 aText, nLineStart, nLineLength,
376 std::vector<double>(),
377 pAttrs->aFontAttr,
378 com::sun::star::lang::Locale(),
379 aTextColor));
380 nLineStart += nLineLength;
381 aPos.setY(aPos.getY() + aTextEngine.GetCharHeight());
383 if (bTooLong)
384 break;
388 drawinglayer::primitive2d::PolygonHairlinePrimitive2D*
389 ThumbnailViewItem::createBorderLine (const basegfx::B2DPolygon& rPolygon)
391 return new PolygonHairlinePrimitive2D(rPolygon, Color(128, 128, 128).getBColor());
394 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */