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:
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 	//------------------------------------------------------------------------------------------------------------------
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 
127         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     {
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         }
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 
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 	//------------------------------------------------------------------------------------------------------------------
193     GridTableRenderer::GridTableRenderer( ITableModel& _rModel )
194         :m_pImpl( new GridTableRenderer_Impl( _rModel ) )
195     {
196     }
197 
198     //------------------------------------------------------------------------------------------------------------------
199     GridTableRenderer::~GridTableRenderer()
200     {
201     }
202 
203     //------------------------------------------------------------------------------------------------------------------
204     RowPos GridTableRenderer::getCurrentRow() const
205     {
206         return m_pImpl->nCurrentRow;
207     }
208 
209     //------------------------------------------------------------------------------------------------------------------
210     bool GridTableRenderer::useGridLines() const
211     {
212         return m_pImpl->bUseGridLines;
213     }
214 
215     //------------------------------------------------------------------------------------------------------------------
216     void GridTableRenderer::useGridLines( bool const i_use )
217     {
218         m_pImpl->bUseGridLines = i_use;
219     }
220 
221     //------------------------------------------------------------------------------------------------------------------
222     namespace
223     {
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     //------------------------------------------------------------------------------------------------------------------
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     //------------------------------------------------------------------------------------------------------------------
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 const nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, _nCol ) | TEXT_DRAW_CLIP;
281         _rDevice.DrawText( aTextRect, sHeaderText, nDrawTextFlags );
282 
283         ::boost::optional< ::Color > const aLineColor( m_pImpl->rModel.getLineColor() );
284         ::Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
285 		_rDevice.SetLineColor( lineColor );
286 		_rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight());
287 		_rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
288 
289         // draw sort indicator if the model data is sorted by the given column
290         ITableDataSort const * pSortAdapter = m_pImpl->rModel.getSortAdapter();
291         ColumnSort aCurrentSortOrder;
292         if ( pSortAdapter != NULL )
293             aCurrentSortOrder = pSortAdapter->getCurrentSortOrder();
294         if ( aCurrentSortOrder.nColumnPos == _nCol )
295         {
296             long const nHeaderHeight( _rArea.GetHeight() );
297             BitmapEx const aIndicatorBitmap = m_pImpl->aSortIndicator.getBitmapFor( _rDevice, nHeaderHeight, _rStyle,
298                 aCurrentSortOrder.eSortDirection == ColumnSortAscending );
299             Size const aBitmapSize( aIndicatorBitmap.GetSizePixel() );
300             long const nSortIndicatorPaddingX = 2;
301             long const nSortIndicatorPaddingY = ( nHeaderHeight - aBitmapSize.Height() ) / 2;
302 
303             if ( ( nDrawTextFlags & TEXT_DRAW_RIGHT ) != 0 )
304             {
305                 // text is right aligned => draw the sort indicator at the left hand side
306                 _rDevice.DrawBitmapEx(
307                     Point( _rArea.Left() + nSortIndicatorPaddingX, _rArea.Top() + nSortIndicatorPaddingY ),
308                     aIndicatorBitmap
309                 );
310             }
311             else
312             {
313                 // text is left-aligned or centered => draw the sort indicator at the right hand side
314                 _rDevice.DrawBitmapEx(
315                     Point( _rArea.Right() - nSortIndicatorPaddingX - aBitmapSize.Width(), nSortIndicatorPaddingY ),
316                     aIndicatorBitmap
317                 );
318             }
319         }
320 
321         _rDevice.Pop();
322 
323         (void)_bActive;
324         // no special painting for the active column at the moment
325 
326         (void)_bSelected;
327         // selection for column header not yet implemented
328     }
329 
330     //------------------------------------------------------------------------------------------------------------------
331     void GridTableRenderer::PrepareRow( RowPos _nRow, bool i_hasControlFocus, bool _bSelected,
332         OutputDevice& _rDevice, const Rectangle& _rRowArea, const StyleSettings& _rStyle )
333     {
334         // remember the row for subsequent calls to the other ->ITableRenderer methods
335         m_pImpl->nCurrentRow = _nRow;
336 
337         _rDevice.Push( PUSH_FILLCOLOR | PUSH_LINECOLOR);
338 
339         ::Color backgroundColor = _rStyle.GetFieldColor();
340 
341         ::boost::optional< ::Color > const aLineColor( m_pImpl->rModel.getLineColor() );
342         ::Color lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
343 
344         ::Color const activeSelectionBackColor =
345             lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionBackColor(), _rStyle, &StyleSettings::GetHighlightColor );
346 		if ( _bSelected )
347 		{
348             // selected rows use the background color from the style
349             backgroundColor = i_hasControlFocus
350                 ?   activeSelectionBackColor
351                 :   lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionBackColor(), _rStyle, &StyleSettings::GetDeactiveColor );
352             if ( !aLineColor )
353                 lineColor = backgroundColor;
354 		}
355         else
356         {
357             ::boost::optional< ::std::vector< ::Color > > aRowColors = m_pImpl->rModel.getRowBackgroundColors();
358             if ( !aRowColors )
359             {
360                 // use alternating default colors
361                 Color const fieldColor = _rStyle.GetFieldColor();
362                 if ( _rStyle.GetHighContrastMode() || ( ( m_pImpl->nCurrentRow % 2 ) == 0 ) )
363                 {
364                     backgroundColor = fieldColor;
365                 }
366                 else
367                 {
368                     Color hilightColor = activeSelectionBackColor;
369                     hilightColor.SetRed( 9 * ( fieldColor.GetRed() - hilightColor.GetRed() ) / 10 + hilightColor.GetRed() );
370                     hilightColor.SetGreen( 9 * ( fieldColor.GetGreen() - hilightColor.GetGreen() ) / 10 + hilightColor.GetGreen() );
371                     hilightColor.SetBlue( 9 * ( fieldColor.GetBlue() - hilightColor.GetBlue() ) / 10 + hilightColor.GetBlue() );
372                     backgroundColor = hilightColor;
373                 }
374             }
375             else
376             {
377                 if ( aRowColors->empty() )
378                 {
379                     // all colors have the same background color
380                     backgroundColor = _rStyle.GetFieldColor();
381                 }
382                 else
383                 {
384                     backgroundColor = aRowColors->at( m_pImpl->nCurrentRow % aRowColors->size() );
385                 }
386             }
387         }
388 
389         //m_pImpl->bUseGridLines ? _rDevice.SetLineColor( lineColor ) : _rDevice.SetLineColor();
390         _rDevice.SetLineColor();
391         _rDevice.SetFillColor( backgroundColor );
392         _rDevice.DrawRect( _rRowArea );
393 
394         _rDevice.Pop();
395     }
396 
397     //------------------------------------------------------------------------------------------------------------------
398     void GridTableRenderer::PaintRowHeader( bool i_hasControlFocus, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rArea,
399 		const StyleSettings& _rStyle )
400     {
401         _rDevice.Push( PUSH_LINECOLOR | PUSH_TEXTCOLOR );
402 
403         ::boost::optional< ::Color > const aLineColor( m_pImpl->rModel.getLineColor() );
404         ::Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
405         _rDevice.SetLineColor( lineColor );
406         _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
407 
408         Any const rowHeading( m_pImpl->rModel.getRowHeading( m_pImpl->nCurrentRow ) );
409         ::rtl::OUString const rowTitle( m_pImpl->aStringConverter.convertToString( rowHeading ) );
410         if ( rowTitle.getLength() )
411         {
412             ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getHeaderTextColor(), _rStyle, &StyleSettings::GetFieldTextColor );
413             _rDevice.SetTextColor( textColor );
414 
415 		    Rectangle const aTextRect( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, _rArea ) ) );
416             sal_uLong const nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, 0 ) | TEXT_DRAW_CLIP;
417                 // TODO: is using the horizontal alignment of the 0'th column a good idea here? This is pretty ... arbitray ..
418             _rDevice.DrawText( aTextRect, rowTitle, nDrawTextFlags );
419         }
420 
421         (void)i_hasControlFocus;
422         (void)_bSelected;
423         _rDevice.Pop();
424     }
425 
426     //------------------------------------------------------------------------------------------------------------------
427     struct GridTableRenderer::CellRenderContext
428     {
429         OutputDevice&           rDevice;
430         Rectangle const         aContentArea;
431         StyleSettings const &   rStyle;
432         ColPos const            nColumn;
433         bool const              bSelected;
434         bool const              bHasControlFocus;
435 
436         CellRenderContext( OutputDevice& i_device, Rectangle const & i_contentArea,
437             StyleSettings const & i_style, ColPos const i_column, bool const i_selected, bool const i_hasControlFocus )
438             :rDevice( i_device )
439             ,aContentArea( i_contentArea )
440             ,rStyle( i_style )
441             ,nColumn( i_column )
442             ,bSelected( i_selected )
443             ,bHasControlFocus( i_hasControlFocus )
444         {
445         }
446     };
447 
448 	//------------------------------------------------------------------------------------------------------------------
449     void GridTableRenderer::PaintCell( ColPos const i_column, bool _bSelected, bool i_hasControlFocus,
450 		OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle )
451     {
452         _rDevice.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
453 
454         Rectangle const aContentArea( lcl_getContentArea( *m_pImpl, _rArea ) );
455         CellRenderContext const aRenderContext( _rDevice, aContentArea, _rStyle, i_column, _bSelected, i_hasControlFocus );
456         impl_paintCellContent( aRenderContext );
457 
458         if ( m_pImpl->bUseGridLines )
459         {
460             ::boost::optional< ::Color > aLineColor( m_pImpl->rModel.getLineColor() );
461             ::Color lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
462 
463 		    if ( _bSelected && !aLineColor )
464 		    {
465                 // if no line color is specified by the model, use the usual selection color for lines in selected cells
466                 lineColor = i_hasControlFocus
467                     ?   lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionBackColor(), _rStyle, &StyleSettings::GetHighlightColor )
468                     :   lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionBackColor(), _rStyle, &StyleSettings::GetDeactiveColor );
469 		    }
470 
471             _rDevice.SetLineColor( lineColor );
472 		    _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
473 		    _rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight() );
474         }
475 
476 		_rDevice.Pop();
477     }
478 
479     //------------------------------------------------------------------------------------------------------------------
480     void GridTableRenderer::impl_paintCellImage( CellRenderContext const & i_context, Image const & i_image )
481     {
482         Point imagePos( Point( i_context.aContentArea.Left(), i_context.aContentArea.Top() ) );
483         Size imageSize = i_image.GetSizePixel();
484         if ( i_context.aContentArea.GetWidth() > imageSize.Width() )
485         {
486             const HorizontalAlignment eHorzAlign = m_pImpl->rModel.getColumnModel( i_context.nColumn )->getHorizontalAlign();
487             switch ( eHorzAlign )
488             {
489             case HorizontalAlignment_CENTER:
490                 imagePos.X() += ( i_context.aContentArea.GetWidth() - imageSize.Width() ) / 2;
491                 break;
492             case HorizontalAlignment_RIGHT:
493                 imagePos.X() = i_context.aContentArea.Right() - imageSize.Width();
494                 break;
495             default:
496                 break;
497             }
498 
499         }
500         else
501 	        imageSize.Width() = i_context.aContentArea.GetWidth();
502 
503         if ( i_context.aContentArea.GetHeight() > imageSize.Height() )
504         {
505             const VerticalAlignment eVertAlign = m_pImpl->rModel.getVerticalAlign();
506             switch ( eVertAlign )
507             {
508             case VerticalAlignment_MIDDLE:
509 		        imagePos.Y() += ( i_context.aContentArea.GetHeight() - imageSize.Height() ) / 2;
510                 break;
511             case VerticalAlignment_BOTTOM:
512 		        imagePos.Y() = i_context.aContentArea.Bottom() - imageSize.Height();
513                 break;
514             default:
515                 break;
516             }
517         }
518         else
519 	        imageSize.Height() = i_context.aContentArea.GetHeight() - 1;
520 
521         i_context.rDevice.DrawImage( imagePos, imageSize, i_image, 0 );
522     }
523 
524     //------------------------------------------------------------------------------------------------------------------
525     void GridTableRenderer::impl_paintCellContent( CellRenderContext const & i_context )
526     {
527         Any aCellContent;
528         m_pImpl->rModel.getCellContent( i_context.nColumn, m_pImpl->nCurrentRow, aCellContent );
529 
530         if ( aCellContent.getValueTypeClass() == TypeClass_INTERFACE )
531         {
532             Reference< XInterface > const xContentInterface( aCellContent, UNO_QUERY );
533             if ( !xContentInterface.is() )
534                 // allowed. kind of.
535                 return;
536 
537             Reference< XGraphic > const xGraphic( aCellContent, UNO_QUERY );
538             ENSURE_OR_RETURN_VOID( xGraphic.is(), "GridTableRenderer::impl_paintCellContent: only XGraphic interfaces (or NULL) are supported for painting." );
539 
540             const Image aImage( xGraphic );
541             impl_paintCellImage( i_context, aImage );
542             return;
543         }
544 
545         const ::rtl::OUString sText( m_pImpl->aStringConverter.convertToString( aCellContent ) );
546         impl_paintCellText( i_context, sText );
547     }
548 
549     //------------------------------------------------------------------------------------------------------------------
550     void GridTableRenderer::impl_paintCellText( CellRenderContext const & i_context, ::rtl::OUString const & i_text )
551     {
552         if ( i_context.bSelected )
553         {
554             ::Color const textColor = i_context.bHasControlFocus
555                 ?   lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionTextColor(), i_context.rStyle, &StyleSettings::GetHighlightTextColor )
556                 :   lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionTextColor(), i_context.rStyle, &StyleSettings::GetDeactiveTextColor );
557             i_context.rDevice.SetTextColor( textColor );
558         }
559         else
560         {
561             ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getTextColor(), i_context.rStyle, &StyleSettings::GetFieldTextColor );
562             i_context.rDevice.SetTextColor( textColor );
563         }
564 
565         Rectangle const textRect( lcl_getTextRenderingArea( i_context.aContentArea ) );
566         sal_uLong const nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, i_context.nColumn ) | TEXT_DRAW_CLIP;
567         i_context.rDevice.DrawText( textRect, i_text, nDrawTextFlags );
568     }
569 
570 	//------------------------------------------------------------------------------------------------------------------
571     void GridTableRenderer::ShowCellCursor( Window& _rView, const Rectangle& _rCursorRect)
572     {
573         _rView.ShowFocus( _rCursorRect );
574     }
575 
576 	//------------------------------------------------------------------------------------------------------------------
577     void GridTableRenderer::HideCellCursor( Window& _rView, const Rectangle& _rCursorRect)
578     {
579 	    (void)_rCursorRect;
580         _rView.HideFocus();
581     }
582 
583 	//------------------------------------------------------------------------------------------------------------------
584     bool GridTableRenderer::FitsIntoCell( Any const & i_cellContent, ColPos const i_colPos, RowPos const i_rowPos,
585         bool const i_active, bool const i_selected, OutputDevice& i_targetDevice, Rectangle const & i_targetArea ) const
586     {
587         if ( !i_cellContent.hasValue() )
588             return true;
589 
590         if ( i_cellContent.getValueTypeClass() == TypeClass_INTERFACE )
591         {
592             Reference< XInterface > const xContentInterface( i_cellContent, UNO_QUERY );
593             if ( !xContentInterface.is() )
594                 return true;
595 
596             Reference< XGraphic > const xGraphic( i_cellContent, UNO_QUERY );
597             if ( xGraphic.is() )
598                 // for the moment, assume it fits. We can always scale it down during painting ...
599                 return true;
600 
601             OSL_ENSURE( false, "GridTableRenderer::FitsIntoCell: only XGraphic interfaces (or NULL) are supported for painting." );
602             return true;
603         }
604 
605         ::rtl::OUString const sText( m_pImpl->aStringConverter.convertToString( i_cellContent ) );
606         if ( sText.getLength() == 0 )
607             return true;
608 
609         Rectangle const aTargetArea( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, i_targetArea ) ) );
610 
611         long const nTextHeight = i_targetDevice.GetTextHeight();
612         if ( nTextHeight > aTargetArea.GetHeight() )
613             return false;
614 
615         long const nTextWidth = i_targetDevice.GetTextWidth( sText );
616         if ( nTextWidth > aTargetArea.GetWidth() )
617             return false;
618 
619         OSL_UNUSED( i_active );
620         OSL_UNUSED( i_selected );
621         OSL_UNUSED( i_rowPos );
622         OSL_UNUSED( i_colPos );
623         return true;
624     }
625 
626 	//------------------------------------------------------------------------------------------------------------------
627     bool GridTableRenderer::GetFormattedCellString( Any const & i_cellValue, ColPos const i_colPos, RowPos const i_rowPos, ::rtl::OUString & o_cellString ) const
628     {
629         o_cellString = m_pImpl->aStringConverter.convertToString( i_cellValue );
630 
631         OSL_UNUSED( i_colPos );
632         OSL_UNUSED( i_rowPos );
633         return true;
634     }
635 
636 //......................................................................................................................
637 } } // namespace svt::table
638 //......................................................................................................................
639 
640