1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26 
27 #include "cellvalueconversion.hxx"
28 #include "svtools/table/gridtablerenderer.hxx"
29 #include "svtools/colorcfg.hxx"
30 
31 /** === begin UNO includes === **/
32 #include <com/sun/star/graphic/XGraphic.hpp>
33 /** === end UNO includes === **/
34 
35 #include <comphelper/componentcontext.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <tools/debug.hxx>
38 #include <tools/diagnose_ex.h>
39 #include <vcl/window.hxx>
40 #include <vcl/image.hxx>
41 #include <vcl/virdev.hxx>
42 #include <vcl/decoview.hxx>
43 
44 //......................................................................................................................
45 namespace svt { namespace table
46 {
47 //......................................................................................................................
48 
49     /** === begin UNO using === **/
50     using ::com::sun::star::uno::Any;
51     using ::com::sun::star::uno::Reference;
52     using ::com::sun::star::uno::UNO_QUERY;
53     using ::com::sun::star::uno::XInterface;
54     using ::com::sun::star::uno::TypeClass_INTERFACE;
55     using ::com::sun::star::graphic::XGraphic;
56     using ::com::sun::star::style::HorizontalAlignment;
57     using ::com::sun::star::style::HorizontalAlignment_LEFT;
58     using ::com::sun::star::style::HorizontalAlignment_CENTER;
59     using ::com::sun::star::style::HorizontalAlignment_RIGHT;
60     using ::com::sun::star::style::VerticalAlignment;
61     using ::com::sun::star::style::VerticalAlignment_TOP;
62     using ::com::sun::star::style::VerticalAlignment_MIDDLE;
63     using ::com::sun::star::style::VerticalAlignment_BOTTOM;
64     /** === end UNO using === **/
65 
66     //==================================================================================================================
67 	//= CachedSortIndicator
68     //==================================================================================================================
69     class CachedSortIndicator
70     {
71     public:
CachedSortIndicator()72         CachedSortIndicator()
73             :m_lastHeaderHeight( 0 )
74             ,m_lastArrowColor( COL_TRANSPARENT )
75         {
76         }
77 
78         BitmapEx const & getBitmapFor( OutputDevice const & i_device, long const i_headerHeight, StyleSettings const & i_style, bool const i_sortAscending );
79 
80     private:
81         long        m_lastHeaderHeight;
82         Color       m_lastArrowColor;
83         BitmapEx    m_sortAscending;
84         BitmapEx    m_sortDescending;
85     };
86 
87 	//------------------------------------------------------------------------------------------------------------------
getBitmapFor(OutputDevice const & i_device,long const i_headerHeight,StyleSettings const & i_style,bool const i_sortAscending)88     BitmapEx const & CachedSortIndicator::getBitmapFor( OutputDevice const & i_device, long const i_headerHeight,
89         StyleSettings const & i_style, bool const i_sortAscending )
90     {
91         BitmapEx & rBitmap( i_sortAscending ? m_sortAscending : m_sortDescending );
92         if ( !rBitmap || ( i_headerHeight != m_lastHeaderHeight ) || ( i_style.GetActiveColor() != m_lastArrowColor ) )
93         {
94             long const nSortIndicatorWidth = 2 * i_headerHeight / 3;
95             long const nSortIndicatorHeight = 2 * nSortIndicatorWidth / 3;
96 
97             Point const aBitmapPos( 0, 0 );
98             Size const aBitmapSize( nSortIndicatorWidth, nSortIndicatorHeight );
99             VirtualDevice aDevice( i_device, 0, 0 );
100             aDevice.SetOutputSizePixel( aBitmapSize );
101 
102             DecorationView aDecoView( &aDevice );
103             aDecoView.DrawSymbol(
104                 Rectangle( aBitmapPos, aBitmapSize ),
105                 i_sortAscending ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN,
106                 i_style.GetActiveColor()
107             );
108 
109             rBitmap = aDevice.GetBitmapEx( aBitmapPos, aBitmapSize );
110             m_lastHeaderHeight = i_headerHeight;
111             m_lastArrowColor = i_style.GetActiveColor();
112         }
113         return rBitmap;
114     }
115 
116     //==================================================================================================================
117 	//= GridTableRenderer_Impl
118     //==================================================================================================================
119     struct GridTableRenderer_Impl
120     {
121         ITableModel&        rModel;
122         RowPos              nCurrentRow;
123         bool                bUseGridLines;
124         CachedSortIndicator aSortIndicator;
125         CellValueConversion aStringConverter;
126 
GridTableRenderer_Implsvt::table::GridTableRenderer_Impl127         GridTableRenderer_Impl( ITableModel& _rModel )
128             :rModel( _rModel )
129             ,nCurrentRow( ROW_INVALID )
130             ,bUseGridLines( true )
131             ,aSortIndicator( )
132             ,aStringConverter( ::comphelper::ComponentContext( ::comphelper::getProcessServiceFactory() ) )
133         {
134         }
135     };
136 
137     //==================================================================================================================
138 	//= helper
139     //==================================================================================================================
140     namespace
141     {
lcl_getContentArea(GridTableRenderer_Impl const & i_impl,Rectangle const & i_cellArea)142         static Rectangle lcl_getContentArea( GridTableRenderer_Impl const & i_impl, Rectangle const & i_cellArea )
143         {
144             Rectangle aContentArea( i_cellArea );
145             if ( i_impl.bUseGridLines )
146             {
147                 --aContentArea.Right();
148                 --aContentArea.Bottom();
149             }
150             return aContentArea;
151         }
lcl_getTextRenderingArea(Rectangle const & i_contentArea)152         static Rectangle lcl_getTextRenderingArea( Rectangle const & i_contentArea )
153         {
154             Rectangle aTextArea( i_contentArea );
155             aTextArea.Left() += 2; aTextArea.Right() -= 2;
156             ++aTextArea.Top(); --aTextArea.Bottom();
157             return aTextArea;
158         }
159 
lcl_getAlignmentTextDrawFlags(GridTableRenderer_Impl const & i_impl,ColPos const i_columnPos)160         static sal_uLong lcl_getAlignmentTextDrawFlags( GridTableRenderer_Impl const & i_impl, ColPos const i_columnPos )
161         {
162             sal_uLong nVertFlag = TEXT_DRAW_TOP;
163             VerticalAlignment const eVertAlign = i_impl.rModel.getVerticalAlign();
164             switch ( eVertAlign )
165             {
166             case VerticalAlignment_MIDDLE:  nVertFlag = TEXT_DRAW_VCENTER;  break;
167             case VerticalAlignment_BOTTOM:  nVertFlag = TEXT_DRAW_BOTTOM;   break;
168             default:
169                 break;
170             }
171 
172             sal_uLong nHorzFlag = TEXT_DRAW_LEFT;
173             HorizontalAlignment const eHorzAlign = i_impl.rModel.getColumnCount() > 0
174                                                 ?  i_impl.rModel.getColumnModel( i_columnPos )->getHorizontalAlign()
175                                                 :  HorizontalAlignment_CENTER;
176             switch ( eHorzAlign )
177             {
178             case HorizontalAlignment_CENTER:    nHorzFlag = TEXT_DRAW_CENTER;   break;
179             case HorizontalAlignment_RIGHT:     nHorzFlag = TEXT_DRAW_RIGHT;    break;
180             default:
181                 break;
182             }
183 
184             return nVertFlag | nHorzFlag;
185         }
186 
187     }
188 
189     //==================================================================================================================
190 	//= GridTableRenderer
191     //==================================================================================================================
192 	//------------------------------------------------------------------------------------------------------------------
GridTableRenderer(ITableModel & _rModel)193     GridTableRenderer::GridTableRenderer( ITableModel& _rModel )
194         :m_pImpl( new GridTableRenderer_Impl( _rModel ) )
195     {
196     }
197 
198     //------------------------------------------------------------------------------------------------------------------
~GridTableRenderer()199     GridTableRenderer::~GridTableRenderer()
200     {
201     }
202 
203     //------------------------------------------------------------------------------------------------------------------
getCurrentRow() const204     RowPos GridTableRenderer::getCurrentRow() const
205     {
206         return m_pImpl->nCurrentRow;
207     }
208 
209     //------------------------------------------------------------------------------------------------------------------
useGridLines() const210     bool GridTableRenderer::useGridLines() const
211     {
212         return m_pImpl->bUseGridLines;
213     }
214 
215     //------------------------------------------------------------------------------------------------------------------
useGridLines(bool const i_use)216     void GridTableRenderer::useGridLines( bool const i_use )
217     {
218         m_pImpl->bUseGridLines = i_use;
219     }
220 
221     //------------------------------------------------------------------------------------------------------------------
222     namespace
223     {
lcl_getEffectiveColor(::boost::optional<::Color> const & i_modelColor,StyleSettings const & i_styleSettings,::Color const & (StyleSettings::* i_getDefaultColor)()const)224         Color lcl_getEffectiveColor(
225             ::boost::optional< ::Color > const & i_modelColor,
226             StyleSettings const & i_styleSettings,
227             ::Color const & ( StyleSettings::*i_getDefaultColor ) () const
228         )
229         {
230             if ( !!i_modelColor )
231                 return *i_modelColor;
232             return ( i_styleSettings.*i_getDefaultColor )();
233         }
234     }
235 
236     //------------------------------------------------------------------------------------------------------------------
PaintHeaderArea(OutputDevice & _rDevice,const Rectangle & _rArea,bool _bIsColHeaderArea,bool _bIsRowHeaderArea,const StyleSettings & _rStyle)237     void GridTableRenderer::PaintHeaderArea(
238         OutputDevice& _rDevice, const Rectangle& _rArea, bool _bIsColHeaderArea, bool _bIsRowHeaderArea,
239         const StyleSettings& _rStyle )
240 	{
241 		OSL_PRECOND( _bIsColHeaderArea || _bIsRowHeaderArea,
242             "GridTableRenderer::PaintHeaderArea: invalid area flags!" );
243 
244         _rDevice.Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
245 
246         Color const background = lcl_getEffectiveColor( m_pImpl->rModel.getHeaderBackgroundColor(), _rStyle, &StyleSettings::GetDialogColor );
247 		_rDevice.SetFillColor( background );
248 
249         _rDevice.SetLineColor();
250         _rDevice.DrawRect( _rArea );
251 
252         // delimiter lines at bottom/right
253         ::boost::optional< ::Color > aLineColor( m_pImpl->rModel.getLineColor() );
254         ::Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
255         _rDevice.SetLineColor( lineColor );
256         _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
257         _rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight() );
258 
259         _rDevice.Pop();
260 		(void)_bIsColHeaderArea;
261 		(void)_bIsRowHeaderArea;
262     }
263 
264     //------------------------------------------------------------------------------------------------------------------
PaintColumnHeader(ColPos _nCol,bool _bActive,bool _bSelected,OutputDevice & _rDevice,const Rectangle & _rArea,const StyleSettings & _rStyle)265     void GridTableRenderer::PaintColumnHeader( ColPos _nCol, bool _bActive, bool _bSelected,
266         OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle )
267     {
268         _rDevice.Push( PUSH_LINECOLOR);
269 
270         String sHeaderText;
271         PColumnModel const pColumn = m_pImpl->rModel.getColumnModel( _nCol );
272         DBG_ASSERT( !!pColumn, "GridTableRenderer::PaintColumnHeader: invalid column model object!" );
273         if ( !!pColumn )
274             sHeaderText = pColumn->getName();
275 
276         ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getTextColor(), _rStyle, &StyleSettings::GetFieldTextColor );
277         _rDevice.SetTextColor( textColor );
278 
279 		Rectangle const aTextRect( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, _rArea ) ) );
280         sal_uLong nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, _nCol ) | TEXT_DRAW_CLIP;
281         if ( !m_pImpl->rModel.isEnabled() )
282             nDrawTextFlags |= TEXT_DRAW_DISABLE;
283         _rDevice.DrawText( aTextRect, sHeaderText, nDrawTextFlags );
284 
285         ::boost::optional< ::Color > const aLineColor( m_pImpl->rModel.getLineColor() );
286         ::Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
287 		_rDevice.SetLineColor( lineColor );
288 		_rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight());
289 		_rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
290 
291         // draw sort indicator if the model data is sorted by the given column
292         ITableDataSort const * pSortAdapter = m_pImpl->rModel.getSortAdapter();
293         ColumnSort aCurrentSortOrder;
294         if ( pSortAdapter != NULL )
295             aCurrentSortOrder = pSortAdapter->getCurrentSortOrder();
296         if ( aCurrentSortOrder.nColumnPos == _nCol )
297         {
298             long const nHeaderHeight( _rArea.GetHeight() );
299             BitmapEx const aIndicatorBitmap = m_pImpl->aSortIndicator.getBitmapFor( _rDevice, nHeaderHeight, _rStyle,
300                 aCurrentSortOrder.eSortDirection == ColumnSortAscending );
301             Size const aBitmapSize( aIndicatorBitmap.GetSizePixel() );
302             long const nSortIndicatorPaddingX = 2;
303             long const nSortIndicatorPaddingY = ( nHeaderHeight - aBitmapSize.Height() ) / 2;
304 
305             if ( ( nDrawTextFlags & TEXT_DRAW_RIGHT ) != 0 )
306             {
307                 // text is right aligned => draw the sort indicator at the left hand side
308                 _rDevice.DrawBitmapEx(
309                     Point( _rArea.Left() + nSortIndicatorPaddingX, _rArea.Top() + nSortIndicatorPaddingY ),
310                     aIndicatorBitmap
311                 );
312             }
313             else
314             {
315                 // text is left-aligned or centered => draw the sort indicator at the right hand side
316                 _rDevice.DrawBitmapEx(
317                     Point( _rArea.Right() - nSortIndicatorPaddingX - aBitmapSize.Width(), nSortIndicatorPaddingY ),
318                     aIndicatorBitmap
319                 );
320             }
321         }
322 
323         _rDevice.Pop();
324 
325         (void)_bActive;
326         // no special painting for the active column at the moment
327 
328         (void)_bSelected;
329         // selection for column header not yet implemented
330     }
331 
332     //------------------------------------------------------------------------------------------------------------------
PrepareRow(RowPos _nRow,bool i_hasControlFocus,bool _bSelected,OutputDevice & _rDevice,const Rectangle & _rRowArea,const StyleSettings & _rStyle)333     void GridTableRenderer::PrepareRow( RowPos _nRow, bool i_hasControlFocus, bool _bSelected,
334         OutputDevice& _rDevice, const Rectangle& _rRowArea, const StyleSettings& _rStyle )
335     {
336         // remember the row for subsequent calls to the other ->ITableRenderer methods
337         m_pImpl->nCurrentRow = _nRow;
338 
339         _rDevice.Push( PUSH_FILLCOLOR | PUSH_LINECOLOR);
340 
341         ::Color backgroundColor = _rStyle.GetFieldColor();
342 
343         ::boost::optional< ::Color > const aLineColor( m_pImpl->rModel.getLineColor() );
344         ::Color lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
345 
346         ::Color const activeSelectionBackColor =
347             lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionBackColor(), _rStyle, &StyleSettings::GetHighlightColor );
348 		if ( _bSelected )
349 		{
350             // selected rows use the background color from the style
351             backgroundColor = i_hasControlFocus
352                 ?   activeSelectionBackColor
353                 :   lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionBackColor(), _rStyle, &StyleSettings::GetDeactiveColor );
354             if ( !aLineColor )
355                 lineColor = backgroundColor;
356 		}
357         else
358         {
359             ::boost::optional< ::std::vector< ::Color > > aRowColors = m_pImpl->rModel.getRowBackgroundColors();
360             if ( !aRowColors )
361             {
362                 // use alternating default colors
363                 Color const fieldColor = _rStyle.GetFieldColor();
364                 if ( _rStyle.GetHighContrastMode() || ( ( m_pImpl->nCurrentRow % 2 ) == 0 ) )
365                 {
366                     backgroundColor = fieldColor;
367                 }
368                 else
369                 {
370                     Color hilightColor = activeSelectionBackColor;
371                     hilightColor.SetRed( 9 * ( fieldColor.GetRed() - hilightColor.GetRed() ) / 10 + hilightColor.GetRed() );
372                     hilightColor.SetGreen( 9 * ( fieldColor.GetGreen() - hilightColor.GetGreen() ) / 10 + hilightColor.GetGreen() );
373                     hilightColor.SetBlue( 9 * ( fieldColor.GetBlue() - hilightColor.GetBlue() ) / 10 + hilightColor.GetBlue() );
374                     backgroundColor = hilightColor;
375                 }
376             }
377             else
378             {
379                 if ( aRowColors->empty() )
380                 {
381                     // all colors have the same background color
382                     backgroundColor = _rStyle.GetFieldColor();
383                 }
384                 else
385                 {
386                     backgroundColor = aRowColors->at( m_pImpl->nCurrentRow % aRowColors->size() );
387                 }
388             }
389         }
390 
391         //m_pImpl->bUseGridLines ? _rDevice.SetLineColor( lineColor ) : _rDevice.SetLineColor();
392         _rDevice.SetLineColor();
393         _rDevice.SetFillColor( backgroundColor );
394         _rDevice.DrawRect( _rRowArea );
395 
396         _rDevice.Pop();
397     }
398 
399     //------------------------------------------------------------------------------------------------------------------
PaintRowHeader(bool i_hasControlFocus,bool _bSelected,OutputDevice & _rDevice,const Rectangle & _rArea,const StyleSettings & _rStyle)400     void GridTableRenderer::PaintRowHeader( bool i_hasControlFocus, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rArea,
401 		const StyleSettings& _rStyle )
402     {
403         _rDevice.Push( PUSH_LINECOLOR | PUSH_TEXTCOLOR );
404 
405         ::boost::optional< ::Color > const aLineColor( m_pImpl->rModel.getLineColor() );
406         ::Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
407         _rDevice.SetLineColor( lineColor );
408         _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
409 
410         Any const rowHeading( m_pImpl->rModel.getRowHeading( m_pImpl->nCurrentRow ) );
411         ::rtl::OUString const rowTitle( m_pImpl->aStringConverter.convertToString( rowHeading ) );
412         if ( rowTitle.getLength() )
413         {
414             ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getHeaderTextColor(), _rStyle, &StyleSettings::GetFieldTextColor );
415             _rDevice.SetTextColor( textColor );
416 
417 		    Rectangle const aTextRect( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, _rArea ) ) );
418             sal_uLong nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, 0 ) | TEXT_DRAW_CLIP;
419             if ( !m_pImpl->rModel.isEnabled() )
420                 nDrawTextFlags |= TEXT_DRAW_DISABLE;
421                 // TODO: is using the horizontal alignment of the 0'th column a good idea here? This is pretty ... arbitrary ..
422             _rDevice.DrawText( aTextRect, rowTitle, nDrawTextFlags );
423         }
424 
425         (void)i_hasControlFocus;
426         (void)_bSelected;
427         _rDevice.Pop();
428     }
429 
430     //------------------------------------------------------------------------------------------------------------------
431     struct GridTableRenderer::CellRenderContext
432     {
433         OutputDevice&           rDevice;
434         Rectangle const         aContentArea;
435         StyleSettings const &   rStyle;
436         ColPos const            nColumn;
437         bool const              bSelected;
438         bool const              bHasControlFocus;
439 
CellRenderContextsvt::table::GridTableRenderer::CellRenderContext440         CellRenderContext( OutputDevice& i_device, Rectangle const & i_contentArea,
441             StyleSettings const & i_style, ColPos const i_column, bool const i_selected, bool const i_hasControlFocus )
442             :rDevice( i_device )
443             ,aContentArea( i_contentArea )
444             ,rStyle( i_style )
445             ,nColumn( i_column )
446             ,bSelected( i_selected )
447             ,bHasControlFocus( i_hasControlFocus )
448         {
449         }
450     };
451 
452 	//------------------------------------------------------------------------------------------------------------------
PaintCell(ColPos const i_column,bool _bSelected,bool i_hasControlFocus,OutputDevice & _rDevice,const Rectangle & _rArea,const StyleSettings & _rStyle)453     void GridTableRenderer::PaintCell( ColPos const i_column, bool _bSelected, bool i_hasControlFocus,
454 		OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle )
455     {
456         _rDevice.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
457 
458         Rectangle const aContentArea( lcl_getContentArea( *m_pImpl, _rArea ) );
459         CellRenderContext const aRenderContext( _rDevice, aContentArea, _rStyle, i_column, _bSelected, i_hasControlFocus );
460         impl_paintCellContent( aRenderContext );
461 
462         if ( m_pImpl->bUseGridLines )
463         {
464             ::boost::optional< ::Color > aLineColor( m_pImpl->rModel.getLineColor() );
465             ::Color lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
466 
467 		    if ( _bSelected && !aLineColor )
468 		    {
469                 // if no line color is specified by the model, use the usual selection color for lines in selected cells
470                 lineColor = i_hasControlFocus
471                     ?   lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionBackColor(), _rStyle, &StyleSettings::GetHighlightColor )
472                     :   lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionBackColor(), _rStyle, &StyleSettings::GetDeactiveColor );
473 		    }
474 
475             _rDevice.SetLineColor( lineColor );
476 		    _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
477 		    _rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight() );
478         }
479 
480 		_rDevice.Pop();
481     }
482 
483     //------------------------------------------------------------------------------------------------------------------
impl_paintCellImage(CellRenderContext const & i_context,Image const & i_image)484     void GridTableRenderer::impl_paintCellImage( CellRenderContext const & i_context, Image const & i_image )
485     {
486         Point imagePos( Point( i_context.aContentArea.Left(), i_context.aContentArea.Top() ) );
487         Size imageSize = i_image.GetSizePixel();
488         if ( i_context.aContentArea.GetWidth() > imageSize.Width() )
489         {
490             const HorizontalAlignment eHorzAlign = m_pImpl->rModel.getColumnModel( i_context.nColumn )->getHorizontalAlign();
491             switch ( eHorzAlign )
492             {
493             case HorizontalAlignment_CENTER:
494                 imagePos.X() += ( i_context.aContentArea.GetWidth() - imageSize.Width() ) / 2;
495                 break;
496             case HorizontalAlignment_RIGHT:
497                 imagePos.X() = i_context.aContentArea.Right() - imageSize.Width();
498                 break;
499             default:
500                 break;
501             }
502 
503         }
504         else
505 	        imageSize.Width() = i_context.aContentArea.GetWidth();
506 
507         if ( i_context.aContentArea.GetHeight() > imageSize.Height() )
508         {
509             const VerticalAlignment eVertAlign = m_pImpl->rModel.getVerticalAlign();
510             switch ( eVertAlign )
511             {
512             case VerticalAlignment_MIDDLE:
513 		        imagePos.Y() += ( i_context.aContentArea.GetHeight() - imageSize.Height() ) / 2;
514                 break;
515             case VerticalAlignment_BOTTOM:
516 		        imagePos.Y() = i_context.aContentArea.Bottom() - imageSize.Height();
517                 break;
518             default:
519                 break;
520             }
521         }
522         else
523 	        imageSize.Height() = i_context.aContentArea.GetHeight() - 1;
524         sal_uInt16 const nStyle = m_pImpl->rModel.isEnabled() ? 0 : IMAGE_DRAW_DISABLE;
525         i_context.rDevice.DrawImage( imagePos, imageSize, i_image, nStyle );
526     }
527 
528     //------------------------------------------------------------------------------------------------------------------
impl_paintCellContent(CellRenderContext const & i_context)529     void GridTableRenderer::impl_paintCellContent( CellRenderContext const & i_context )
530     {
531         Any aCellContent;
532         m_pImpl->rModel.getCellContent( i_context.nColumn, m_pImpl->nCurrentRow, aCellContent );
533 
534         if ( aCellContent.getValueTypeClass() == TypeClass_INTERFACE )
535         {
536             Reference< XInterface > const xContentInterface( aCellContent, UNO_QUERY );
537             if ( !xContentInterface.is() )
538                 // allowed. kind of.
539                 return;
540 
541             Reference< XGraphic > const xGraphic( aCellContent, UNO_QUERY );
542             ENSURE_OR_RETURN_VOID( xGraphic.is(), "GridTableRenderer::impl_paintCellContent: only XGraphic interfaces (or NULL) are supported for painting." );
543 
544             const Image aImage( xGraphic );
545             impl_paintCellImage( i_context, aImage );
546             return;
547         }
548 
549         const ::rtl::OUString sText( m_pImpl->aStringConverter.convertToString( aCellContent ) );
550         impl_paintCellText( i_context, sText );
551     }
552 
553     //------------------------------------------------------------------------------------------------------------------
impl_paintCellText(CellRenderContext const & i_context,::rtl::OUString const & i_text)554     void GridTableRenderer::impl_paintCellText( CellRenderContext const & i_context, ::rtl::OUString const & i_text )
555     {
556         if ( i_context.bSelected )
557         {
558             ::Color const textColor = i_context.bHasControlFocus
559                 ?   lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionTextColor(), i_context.rStyle, &StyleSettings::GetHighlightTextColor )
560                 :   lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionTextColor(), i_context.rStyle, &StyleSettings::GetDeactiveTextColor );
561             i_context.rDevice.SetTextColor( textColor );
562         }
563         else
564         {
565             ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getTextColor(), i_context.rStyle, &StyleSettings::GetFieldTextColor );
566             i_context.rDevice.SetTextColor( textColor );
567         }
568 
569         Rectangle const textRect( lcl_getTextRenderingArea( i_context.aContentArea ) );
570         sal_uLong nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, i_context.nColumn ) | TEXT_DRAW_CLIP;
571         if ( !m_pImpl->rModel.isEnabled() )
572             nDrawTextFlags |= TEXT_DRAW_DISABLE;
573         i_context.rDevice.DrawText( textRect, i_text, nDrawTextFlags );
574     }
575 
576 	//------------------------------------------------------------------------------------------------------------------
ShowCellCursor(Window & _rView,const Rectangle & _rCursorRect)577     void GridTableRenderer::ShowCellCursor( Window& _rView, const Rectangle& _rCursorRect)
578     {
579         _rView.ShowFocus( _rCursorRect );
580     }
581 
582 	//------------------------------------------------------------------------------------------------------------------
HideCellCursor(Window & _rView,const Rectangle & _rCursorRect)583     void GridTableRenderer::HideCellCursor( Window& _rView, const Rectangle& _rCursorRect)
584     {
585 	    (void)_rCursorRect;
586         _rView.HideFocus();
587     }
588 
589 	//------------------------------------------------------------------------------------------------------------------
FitsIntoCell(Any const & i_cellContent,ColPos const i_colPos,RowPos const i_rowPos,bool const i_active,bool const i_selected,OutputDevice & i_targetDevice,Rectangle const & i_targetArea) const590     bool GridTableRenderer::FitsIntoCell( Any const & i_cellContent, ColPos const i_colPos, RowPos const i_rowPos,
591         bool const i_active, bool const i_selected, OutputDevice& i_targetDevice, Rectangle const & i_targetArea ) const
592     {
593         if ( !i_cellContent.hasValue() )
594             return true;
595 
596         if ( i_cellContent.getValueTypeClass() == TypeClass_INTERFACE )
597         {
598             Reference< XInterface > const xContentInterface( i_cellContent, UNO_QUERY );
599             if ( !xContentInterface.is() )
600                 return true;
601 
602             Reference< XGraphic > const xGraphic( i_cellContent, UNO_QUERY );
603             if ( xGraphic.is() )
604                 // for the moment, assume it fits. We can always scale it down during painting ...
605                 return true;
606 
607             OSL_ENSURE( false, "GridTableRenderer::FitsIntoCell: only XGraphic interfaces (or NULL) are supported for painting." );
608             return true;
609         }
610 
611         ::rtl::OUString const sText( m_pImpl->aStringConverter.convertToString( i_cellContent ) );
612         if ( sText.getLength() == 0 )
613             return true;
614 
615         Rectangle const aTargetArea( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, i_targetArea ) ) );
616 
617         long const nTextHeight = i_targetDevice.GetTextHeight();
618         if ( nTextHeight > aTargetArea.GetHeight() )
619             return false;
620 
621         long const nTextWidth = i_targetDevice.GetTextWidth( sText );
622         if ( nTextWidth > aTargetArea.GetWidth() )
623             return false;
624 
625         OSL_UNUSED( i_active );
626         OSL_UNUSED( i_selected );
627         OSL_UNUSED( i_rowPos );
628         OSL_UNUSED( i_colPos );
629         return true;
630     }
631 
632 	//------------------------------------------------------------------------------------------------------------------
GetFormattedCellString(Any const & i_cellValue,ColPos const i_colPos,RowPos const i_rowPos,::rtl::OUString & o_cellString) const633     bool GridTableRenderer::GetFormattedCellString( Any const & i_cellValue, ColPos const i_colPos, RowPos const i_rowPos, ::rtl::OUString & o_cellString ) const
634     {
635         o_cellString = m_pImpl->aStringConverter.convertToString( i_cellValue );
636 
637         OSL_UNUSED( i_colPos );
638         OSL_UNUSED( i_rowPos );
639         return true;
640     }
641 
642 //......................................................................................................................
643 } } // namespace svt::table
644 //......................................................................................................................
645 
646