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