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 // MARKER(update_precomp.py): autogen include statement, do not remove
24 #include "precompiled_svtools.hxx"
25 
26 #include "unocontroltablemodel.hxx"
27 #include "unogridcolumnfacade.hxx"
28 
29 #include "svtools/table/defaultinputhandler.hxx"
30 #include "svtools/table/gridtablerenderer.hxx"
31 #include "svtools/table/tablecontrol.hxx"
32 
33 /** === begin UNO includes === **/
34 #include <com/sun/star/awt/grid/XGridColumn.hpp>
35 #include <com/sun/star/view/SelectionType.hpp>
36 #include <com/sun/star/awt/grid/XGridColumnListener.hpp>
37 #include <com/sun/star/awt/grid/XSortableGridData.hpp>
38 /** === end UNO includes === **/
39 
40 #include <comphelper/stlunosequence.hxx>
41 #include <cppuhelper/weakref.hxx>
42 #include <tools/debug.hxx>
43 #include <tools/diagnose_ex.h>
44 #include <vcl/svapp.hxx>
45 #include <vos/mutex.hxx>
46 
47 // .....................................................................................................................
48 namespace svt { namespace table
49 {
50 // .....................................................................................................................
51 
52     /** === begin UNO using === **/
53     using ::com::sun::star::uno::Reference;
54     using ::com::sun::star::uno::RuntimeException;
55     using ::com::sun::star::uno::Sequence;
56     using ::com::sun::star::uno::UNO_QUERY_THROW;
57     using ::com::sun::star::uno::UNO_QUERY;
58     using ::com::sun::star::awt::grid::XGridColumn;
59     using ::com::sun::star::uno::XInterface;
60     using ::com::sun::star::uno::Exception;
61     using ::com::sun::star::awt::grid::XGridColumnListener;
62     using ::com::sun::star::lang::EventObject;
63     using ::com::sun::star::awt::grid::GridColumnEvent;
64     using ::com::sun::star::awt::grid::XGridDataModel;
65     using ::com::sun::star::awt::grid::XGridColumnModel;
66     using ::com::sun::star::uno::Any;
67     using ::com::sun::star::style::HorizontalAlignment_LEFT;
68     using ::com::sun::star::style::HorizontalAlignment;
69     using ::com::sun::star::style::VerticalAlignment_TOP;
70     using ::com::sun::star::style::VerticalAlignment;
71     using ::com::sun::star::uno::WeakReference;
72     using ::com::sun::star::awt::grid::GridDataEvent;
73     using ::com::sun::star::awt::grid::XSortableGridData;
74     using ::com::sun::star::beans::Pair;
75     /** === end UNO using === **/
76 
77 	//==================================================================================================================
78 	//= UnoControlTableModel_Impl
79 	//==================================================================================================================
80     typedef ::std::vector< PTableModelListener >    ModellListeners;
81     typedef ::std::vector< PColumnModel >           ColumnModels;
82     struct UnoControlTableModel_Impl
83     {
84         ColumnModels                                    aColumns;
85         bool                                            bHasColumnHeaders;
86         bool                                            bHasRowHeaders;
87         ScrollbarVisibility                             eVScrollMode;
88         ScrollbarVisibility                             eHScrollMode;
89         PTableRenderer                                  pRenderer;
90         PTableInputHandler                              pInputHandler;
91         TableMetrics                                    nRowHeight;
92         TableMetrics                                    nColumnHeaderHeight;
93         TableMetrics                                    nRowHeaderWidth;
94         ::boost::optional< ::Color >                    m_aGridLineColor;
95         ::boost::optional< ::Color >                    m_aHeaderBackgroundColor;
96         ::boost::optional< ::Color >                    m_aHeaderTextColor;
97         ::boost::optional< ::Color >                    m_aActiveSelectionBackColor;
98         ::boost::optional< ::Color >                    m_aInactiveSelectionBackColor;
99         ::boost::optional< ::Color >                    m_aActiveSelectionTextColor;
100         ::boost::optional< ::Color >                    m_aInactiveSelectionTextColor;
101         ::boost::optional< ::Color >                    m_aTextColor;
102         ::boost::optional< ::Color >                    m_aTextLineColor;
103         ::boost::optional< ::std::vector< ::Color > >   m_aRowColors;
104         VerticalAlignment                               m_eVerticalAlign;
105         ModellListeners                                 m_aListeners;
106         WeakReference< XGridDataModel >                 m_aDataModel;
107         WeakReference< XGridColumnModel >               m_aColumnModel;
108 
109         UnoControlTableModel_Impl()
110             :aColumns                       ( )
111             ,bHasColumnHeaders              ( true      )
112             ,bHasRowHeaders                 ( false     )
113             ,eVScrollMode                   ( ScrollbarShowNever )
114             ,eHScrollMode                   ( ScrollbarShowNever )
115             ,pRenderer                      ( )
116             ,pInputHandler                  ( )
117             ,nRowHeight                     ( 10 )
118             ,nColumnHeaderHeight            ( 10 )
119             ,nRowHeaderWidth                ( 10 )
120             ,m_aGridLineColor               ( )
121             ,m_aHeaderBackgroundColor       ( )
122             ,m_aHeaderTextColor             ( )
123             ,m_aActiveSelectionBackColor    ( )
124             ,m_aInactiveSelectionBackColor  ( )
125             ,m_aActiveSelectionTextColor    ( )
126             ,m_aInactiveSelectionTextColor  ( )
127             ,m_aTextColor                   ( )
128             ,m_aTextLineColor               ( )
129             ,m_aRowColors                   ( )
130             ,m_eVerticalAlign               ( VerticalAlignment_TOP )
131         {
132         }
133     };
134 
135 	//==================================================================================================================
136 	//= UnoControlTableModel
137 	//==================================================================================================================
138 #ifdef DBG_UTIL
139     const char* UnoControlTableModel_checkInvariants( const void* _pInstance )
140     {
141         return static_cast< const UnoControlTableModel* >( _pInstance )->checkInvariants();
142     }
143 
144 	//------------------------------------------------------------------------------------------------------------------
145     const char* UnoControlTableModel::checkInvariants() const
146     {
147         Reference< XGridDataModel > const xDataModel( m_pImpl->m_aDataModel );
148         if ( !xDataModel.is() )
149             return "data model anymore";
150 
151         // TODO: more?
152 
153         return NULL;
154     }
155 #endif
156 
157 #define DBG_CHECK_ME() \
158     DBG_TESTSOLARMUTEX(); \
159     DBG_CHKTHIS( UnoControlTableModel, UnoControlTableModel_checkInvariants )
160 
161 	//------------------------------------------------------------------------------------------------------------------
162     DBG_NAME( UnoControlTableModel )
163     UnoControlTableModel::UnoControlTableModel()
164         :m_pImpl( new UnoControlTableModel_Impl )
165 	{
166         DBG_CTOR( UnoControlTableModel, UnoControlTableModel_checkInvariants );
167         m_pImpl->bHasColumnHeaders = true;
168         m_pImpl->bHasRowHeaders = false;
169         m_pImpl->pRenderer.reset( new GridTableRenderer( *this ) );
170         m_pImpl->pInputHandler.reset( new DefaultInputHandler );
171     }
172 
173 	//------------------------------------------------------------------------------------------------------------------
174     UnoControlTableModel::~UnoControlTableModel()
175     {
176         DBG_DTOR( UnoControlTableModel, UnoControlTableModel_checkInvariants );
177         DELETEZ( m_pImpl );
178     }
179 
180 	//------------------------------------------------------------------------------------------------------------------
181     TableSize UnoControlTableModel::getColumnCount() const
182     {
183         DBG_CHECK_ME();
184 		return (TableSize)m_pImpl->aColumns.size();
185     }
186 
187 	//------------------------------------------------------------------------------------------------------------------
188     TableSize UnoControlTableModel::getRowCount() const
189     {
190         DBG_CHECK_ME();
191 
192         TableSize nRowCount = 0;
193         try
194         {
195             Reference< XGridDataModel > const xDataModel( m_pImpl->m_aDataModel );
196             ENSURE_OR_THROW( xDataModel.is(), "no data model anymore!" );
197             nRowCount = xDataModel->getRowCount();
198         }
199         catch( const Exception& )
200         {
201         	DBG_UNHANDLED_EXCEPTION();
202         }
203         return nRowCount;
204     }
205 
206 	//------------------------------------------------------------------------------------------------------------------
207     bool UnoControlTableModel::hasColumnHeaders() const
208     {
209         DBG_CHECK_ME();
210         return m_pImpl->bHasColumnHeaders;
211     }
212 
213 	//------------------------------------------------------------------------------------------------------------------
214     bool UnoControlTableModel::hasRowHeaders() const
215     {
216         DBG_CHECK_ME();
217         return m_pImpl->bHasRowHeaders;
218     }
219 
220 	//------------------------------------------------------------------------------------------------------------------
221     void UnoControlTableModel::setRowHeaders(bool _bRowHeaders)
222     {
223         DBG_CHECK_ME();
224         if ( m_pImpl->bHasRowHeaders == _bRowHeaders )
225             return;
226 
227         m_pImpl->bHasRowHeaders = _bRowHeaders;
228         impl_notifyTableMetricsChanged();
229     }
230 
231     //------------------------------------------------------------------------------------------------------------------
232     void UnoControlTableModel::setColumnHeaders(bool _bColumnHeaders)
233     {
234         DBG_CHECK_ME();
235         if ( m_pImpl->bHasColumnHeaders == _bColumnHeaders )
236             return;
237 
238         m_pImpl->bHasColumnHeaders = _bColumnHeaders;
239         impl_notifyTableMetricsChanged();
240     }
241 
242 	//------------------------------------------------------------------------------------------------------------------
243     bool UnoControlTableModel::isCellEditable( ColPos col, RowPos row ) const
244     {
245         DBG_CHECK_ME();
246         (void)col;
247         (void)row;
248         return false;
249     }
250 
251 	//------------------------------------------------------------------------------------------------------------------
252     PColumnModel UnoControlTableModel::getColumnModel( ColPos column )
253     {
254         DBG_CHECK_ME();
255         ENSURE_OR_RETURN( ( column >= 0 ) && ( column < getColumnCount() ),
256             "DefaultTableModel::getColumnModel: invalid index!", PColumnModel() );
257         return m_pImpl->aColumns[ column ];
258     }
259 
260 	//------------------------------------------------------------------------------------------------------------------
261     void UnoControlTableModel::appendColumn( Reference< XGridColumn > const & i_column )
262     {
263         DBG_CHECK_ME();
264         insertColumn( m_pImpl->aColumns.size(), i_column );
265     }
266 
267 	//------------------------------------------------------------------------------------------------------------------
268     void UnoControlTableModel::insertColumn( ColPos const i_position, Reference< XGridColumn > const & i_column )
269     {
270         DBG_CHECK_ME();
271         ENSURE_OR_RETURN_VOID( ( i_position >= 0 ) && ( size_t( i_position ) <= m_pImpl->aColumns.size() ),
272             "UnoControlTableModel::insertColumn: illegal position!" );
273 
274         const PColumnModel pColumn( new UnoGridColumnFacade( *this, i_column ) );
275         m_pImpl->aColumns.insert( m_pImpl->aColumns.begin() + i_position, pColumn );
276 
277         // notify listeners
278         ModellListeners aListeners( m_pImpl->m_aListeners );
279         for (   ModellListeners::const_iterator loop = aListeners.begin();
280                 loop != aListeners.end();
281                 ++loop
282             )
283         {
284             (*loop)->columnInserted( i_position );
285         }
286     }
287 
288 	//------------------------------------------------------------------------------------------------------------------
289     void UnoControlTableModel::removeColumn( ColPos const i_position )
290     {
291         DBG_CHECK_ME();
292         ENSURE_OR_RETURN_VOID( ( i_position >= 0 ) && ( size_t( i_position ) <= m_pImpl->aColumns.size() ),
293             "UnoControlTableModel::removeColumn: illegal position!" );
294 
295         // remove the column
296         ColumnModels::iterator pos = m_pImpl->aColumns.begin() + i_position;
297         const PColumnModel pColumn = *pos;
298         m_pImpl->aColumns.erase( pos );
299 
300         // notify listeners
301         ModellListeners aListeners( m_pImpl->m_aListeners );
302         for (   ModellListeners::const_iterator loop = aListeners.begin();
303                 loop != aListeners.end();
304                 ++loop
305             )
306         {
307             (*loop)->columnRemoved( i_position );
308         }
309 
310         // dispose the column
311         UnoGridColumnFacade* pColumnImpl = dynamic_cast< UnoGridColumnFacade* >( pColumn.get() );
312         OSL_ENSURE( pColumnImpl != NULL, "UnoControlTableModel::removeColumn: illegal column implementation!" );
313         if ( pColumnImpl )
314             pColumnImpl->dispose();
315     }
316 
317 	//------------------------------------------------------------------------------------------------------------------
318     void UnoControlTableModel::removeAllColumns()
319     {
320         DBG_CHECK_ME();
321         if ( m_pImpl->aColumns.empty() )
322             return;
323 
324         // dispose the column instances
325         for (   ColumnModels::const_iterator col = m_pImpl->aColumns.begin();
326                 col != m_pImpl->aColumns.end();
327                 ++col
328             )
329         {
330             UnoGridColumnFacade* pColumn = dynamic_cast< UnoGridColumnFacade* >( col->get() );
331             ENSURE_OR_CONTINUE( pColumn != NULL, "UnoControlTableModel::removeAllColumns: illegal column implementation!" );
332             pColumn->dispose();
333         }
334         m_pImpl->aColumns.clear();
335 
336         // notify listeners
337         ModellListeners aListeners( m_pImpl->m_aListeners );
338         for (   ModellListeners::const_iterator loop = aListeners.begin();
339                 loop != aListeners.end();
340                 ++loop
341             )
342         {
343             (*loop)->allColumnsRemoved();
344         }
345     }
346 
347     //------------------------------------------------------------------------------------------------------------------
348     void UnoControlTableModel::impl_notifyTableMetricsChanged() const
349     {
350         ModellListeners aListeners( m_pImpl->m_aListeners );
351         for (   ModellListeners::const_iterator loop = aListeners.begin();
352                 loop != aListeners.end();
353                 ++loop
354             )
355         {
356             (*loop)->tableMetricsChanged();
357         }
358     }
359 
360     //------------------------------------------------------------------------------------------------------------------
361     PTableRenderer UnoControlTableModel::getRenderer() const
362     {
363         DBG_CHECK_ME();
364         return m_pImpl->pRenderer;
365     }
366 
367     //------------------------------------------------------------------------------------------------------------------
368     PTableInputHandler UnoControlTableModel::getInputHandler() const
369     {
370         DBG_CHECK_ME();
371         return m_pImpl->pInputHandler;
372     }
373 
374     //------------------------------------------------------------------------------------------------------------------
375     TableMetrics UnoControlTableModel::getRowHeight() const
376     {
377         DBG_CHECK_ME();
378         return m_pImpl->nRowHeight;
379     }
380 
381     //------------------------------------------------------------------------------------------------------------------
382     void UnoControlTableModel::setRowHeight(TableMetrics _nRowHeight)
383     {
384         DBG_CHECK_ME();
385         if ( m_pImpl->nRowHeight == _nRowHeight )
386             return;
387 
388         m_pImpl->nRowHeight = _nRowHeight;
389         impl_notifyTableMetricsChanged();
390     }
391 
392     //------------------------------------------------------------------------------------------------------------------
393     TableMetrics UnoControlTableModel::getColumnHeaderHeight() const
394     {
395         DBG_CHECK_ME();
396         DBG_ASSERT( hasColumnHeaders(), "DefaultTableModel::getColumnHeaderHeight: invalid call!" );
397         return m_pImpl->nColumnHeaderHeight;
398     }
399 
400     //------------------------------------------------------------------------------------------------------------------
401     TableMetrics UnoControlTableModel::getRowHeaderWidth() const
402     {
403         DBG_CHECK_ME();
404         DBG_ASSERT( hasRowHeaders(), "DefaultTableModel::getRowHeaderWidth: invalid call!" );
405         return m_pImpl->nRowHeaderWidth;
406     }
407 	//------------------------------------------------------------------------------------------------------------------
408     void UnoControlTableModel::setColumnHeaderHeight(TableMetrics _nHeight)
409     {
410         DBG_CHECK_ME();
411         if ( m_pImpl->nColumnHeaderHeight == _nHeight )
412             return;
413 
414         m_pImpl->nColumnHeaderHeight = _nHeight;
415         impl_notifyTableMetricsChanged();
416     }
417 
418     //------------------------------------------------------------------------------------------------------------------
419     void UnoControlTableModel::setRowHeaderWidth(TableMetrics _nWidth)
420     {
421         DBG_CHECK_ME();
422         if ( m_pImpl->nRowHeaderWidth == _nWidth )
423             return;
424 
425         m_pImpl->nRowHeaderWidth = _nWidth;
426         impl_notifyTableMetricsChanged();
427     }
428 
429     //------------------------------------------------------------------------------------------------------------------
430     ScrollbarVisibility UnoControlTableModel::getVerticalScrollbarVisibility() const
431     {
432         DBG_CHECK_ME();
433         return m_pImpl->eVScrollMode;
434     }
435 
436     //------------------------------------------------------------------------------------------------------------------
437     ScrollbarVisibility UnoControlTableModel::getHorizontalScrollbarVisibility() const
438     {
439         DBG_CHECK_ME();
440         return m_pImpl->eHScrollMode;
441     }
442 
443     //------------------------------------------------------------------------------------------------------------------
444     void UnoControlTableModel::addTableModelListener( const PTableModelListener& i_listener )
445     {
446         DBG_CHECK_ME();
447         ENSURE_OR_RETURN_VOID( !!i_listener, "illegal NULL listener" );
448         m_pImpl->m_aListeners.push_back( i_listener );
449     }
450 
451     //------------------------------------------------------------------------------------------------------------------
452     void UnoControlTableModel::removeTableModelListener( const PTableModelListener& i_listener )
453     {
454         DBG_CHECK_ME();
455         for (   ModellListeners::iterator lookup = m_pImpl->m_aListeners.begin();
456                 lookup != m_pImpl->m_aListeners.end();
457                 ++lookup
458             )
459         {
460             if ( *lookup == i_listener )
461             {
462                 m_pImpl->m_aListeners.erase( lookup );
463                 return;
464             }
465         }
466         OSL_ENSURE( false, "UnoControlTableModel::removeTableModelListener: listener is not registered - sure you're doing the right thing here?" );
467     }
468 
469     //------------------------------------------------------------------------------------------------------------------
470     void UnoControlTableModel::setVerticalScrollbarVisibility( ScrollbarVisibility const i_visibility ) const
471     {
472         DBG_CHECK_ME();
473 		m_pImpl->eVScrollMode = i_visibility;
474     }
475 
476     //------------------------------------------------------------------------------------------------------------------
477     void UnoControlTableModel::setHorizontalScrollbarVisibility( ScrollbarVisibility const i_visibility ) const
478     {
479         DBG_CHECK_ME();
480 		m_pImpl->eHScrollMode = i_visibility;
481     }
482 
483     //------------------------------------------------------------------------------------------------------------------
484     void UnoControlTableModel::setDataModel( Reference< XGridDataModel > const & i_gridDataModel )
485     {
486         DBG_CHECK_ME();
487         m_pImpl->m_aDataModel = i_gridDataModel;
488         // TODO: register as listener, so we're notified of row/data changes, and can multiplex them to our
489         // own listeners
490     }
491 
492     //------------------------------------------------------------------------------------------------------------------
493     Reference< XGridDataModel > UnoControlTableModel::getDataModel() const
494     {
495         Reference< XGridDataModel > const xDataModel( m_pImpl->m_aDataModel );
496         return xDataModel;
497     }
498 
499     //------------------------------------------------------------------------------------------------------------------
500     bool UnoControlTableModel::hasDataModel() const
501     {
502         return getDataModel().is();
503     }
504 
505     //------------------------------------------------------------------------------------------------------------------
506     void UnoControlTableModel::setColumnModel( Reference< XGridColumnModel > const & i_gridColumnModel )
507     {
508         DBG_CHECK_ME();
509         m_pImpl->m_aColumnModel = i_gridColumnModel;
510     }
511 
512     //------------------------------------------------------------------------------------------------------------------
513     Reference< XGridColumnModel > UnoControlTableModel::getColumnModel() const
514     {
515         Reference< XGridColumnModel > const xColumnModel( m_pImpl->m_aColumnModel );
516         return xColumnModel;
517     }
518 
519     //------------------------------------------------------------------------------------------------------------------
520     bool UnoControlTableModel::hasColumnModel() const
521     {
522         return getColumnModel().is();
523     }
524 
525     //------------------------------------------------------------------------------------------------------------------
526     void UnoControlTableModel::getCellContent( ColPos const i_col, RowPos const i_row, Any& o_cellContent )
527     {
528         DBG_CHECK_ME();
529 
530         o_cellContent.clear();
531         try
532         {
533             Reference< XGridDataModel > const xDataModel( m_pImpl->m_aDataModel );
534             ENSURE_OR_RETURN_VOID( xDataModel.is(), "UnoControlTableModel::getCellContent: no data model anymore!" );
535 
536             PColumnModel const pColumn = getColumnModel( i_col );
537             UnoGridColumnFacade* pColumnImpl = dynamic_cast< UnoGridColumnFacade* >( pColumn.get() );
538             ENSURE_OR_RETURN_VOID( pColumnImpl != NULL, "UnoControlTableModel::getCellContent: no (valid) column at this position!" );
539             sal_Int32 const nDataColumnIndex = pColumnImpl->getDataColumnIndex() >= 0 ? pColumnImpl->getDataColumnIndex() : i_col;
540 
541             if ( nDataColumnIndex >= xDataModel->getColumnCount() )
542             {
543                 // this is allowed, in case the column model has been dynamically extended, but the data model does
544                 // not (yet?) know about it.
545                 // So, handle it gracefully.
546             #if OSL_DEBUG_LEVEL > 0
547                 {
548                     Reference< XGridColumnModel > const xColumnModel( m_pImpl->m_aColumnModel );
549                     OSL_ENSURE( xColumnModel.is() && i_col < xColumnModel->getColumnCount(),
550                         "UnoControlTableModel::getCellContent: request a column's value which the ColumnModel doesn't know about!" );
551                 }
552             #endif
553             }
554             else
555             {
556                 o_cellContent = xDataModel->getCellData( nDataColumnIndex, i_row );
557             }
558         }
559         catch( const Exception& )
560         {
561         	DBG_UNHANDLED_EXCEPTION();
562         }
563     }
564 
565     //------------------------------------------------------------------------------------------------------------------
566     void UnoControlTableModel::getCellToolTip( ColPos const i_col, RowPos const i_row, Any& o_cellToolTip )
567     {
568         DBG_CHECK_ME();
569         try
570         {
571             Reference< XGridDataModel > const xDataModel( m_pImpl->m_aDataModel );
572             ENSURE_OR_THROW( xDataModel.is(), "no data model anymore!" );
573 
574             o_cellToolTip = xDataModel->getCellToolTip( i_col, i_row );
575         }
576         catch( const Exception& )
577         {
578         	DBG_UNHANDLED_EXCEPTION();
579         }
580     }
581 
582     //------------------------------------------------------------------------------------------------------------------
583     Any UnoControlTableModel::getRowHeading( RowPos const i_rowPos ) const
584     {
585         DBG_CHECK_ME();
586 
587         Any aRowHeading;
588 
589         Reference< XGridDataModel > const xDataModel( m_pImpl->m_aDataModel );
590         ENSURE_OR_RETURN( xDataModel.is(), "UnoControlTableModel::getRowHeading: no data model anymore!", aRowHeading );
591 
592         try
593         {
594             aRowHeading = xDataModel->getRowHeading( i_rowPos );
595         }
596         catch( const Exception& )
597         {
598         	DBG_UNHANDLED_EXCEPTION();
599         }
600         return aRowHeading;
601     }
602 
603     //------------------------------------------------------------------------------------------------------------------
604     namespace
605     {
606         void lcl_setColor( Any const & i_color, ::boost::optional< ::Color > & o_convertedColor )
607         {
608             if ( !i_color.hasValue() )
609                 o_convertedColor.reset();
610             else
611             {
612                 sal_Int32 nColor = COL_TRANSPARENT;
613                 if ( i_color >>= nColor )
614                 {
615                     o_convertedColor.reset( ::Color( nColor ) );
616                 }
617                 else
618                 {
619                     OSL_ENSURE( false, "lcl_setColor: could not extract color value!" );
620                 }
621             }
622         }
623     }
624 
625     //------------------------------------------------------------------------------------------------------------------
626     ::boost::optional< ::Color > UnoControlTableModel::getLineColor() const
627     {
628         DBG_CHECK_ME();
629         return m_pImpl->m_aGridLineColor;
630     }
631 
632     //------------------------------------------------------------------------------------------------------------------
633     void UnoControlTableModel::setLineColor( Any const & i_color )
634     {
635         DBG_CHECK_ME();
636         lcl_setColor( i_color, m_pImpl->m_aGridLineColor );
637     }
638 
639     //------------------------------------------------------------------------------------------------------------------
640     ::boost::optional< ::Color > UnoControlTableModel::getHeaderBackgroundColor() const
641     {
642         DBG_CHECK_ME();
643         return m_pImpl->m_aHeaderBackgroundColor;
644     }
645 
646     //------------------------------------------------------------------------------------------------------------------
647     void UnoControlTableModel::setHeaderBackgroundColor( Any const & i_color )
648     {
649         DBG_CHECK_ME();
650         lcl_setColor( i_color, m_pImpl->m_aHeaderBackgroundColor );
651     }
652 
653     //------------------------------------------------------------------------------------------------------------------
654     ::boost::optional< ::Color > UnoControlTableModel::getHeaderTextColor() const
655     {
656         DBG_CHECK_ME();
657         return m_pImpl->m_aHeaderTextColor;
658     }
659 
660     //------------------------------------------------------------------------------------------------------------------
661     ::boost::optional< ::Color > UnoControlTableModel::getActiveSelectionBackColor() const
662     {
663         DBG_CHECK_ME();
664         return m_pImpl->m_aActiveSelectionBackColor;
665     }
666 
667     //------------------------------------------------------------------------------------------------------------------
668     ::boost::optional< ::Color > UnoControlTableModel::getInactiveSelectionBackColor() const
669     {
670         DBG_CHECK_ME();
671         return m_pImpl->m_aInactiveSelectionBackColor;
672     }
673 
674     //------------------------------------------------------------------------------------------------------------------
675     ::boost::optional< ::Color > UnoControlTableModel::getActiveSelectionTextColor() const
676     {
677         DBG_CHECK_ME();
678         return m_pImpl->m_aActiveSelectionTextColor;
679     }
680 
681     //------------------------------------------------------------------------------------------------------------------
682     ::boost::optional< ::Color > UnoControlTableModel::getInactiveSelectionTextColor() const
683     {
684         DBG_CHECK_ME();
685         return m_pImpl->m_aInactiveSelectionTextColor;
686     }
687 
688     //------------------------------------------------------------------------------------------------------------------
689     void UnoControlTableModel::setHeaderTextColor( Any const & i_color )
690     {
691         DBG_CHECK_ME();
692         lcl_setColor( i_color, m_pImpl->m_aHeaderTextColor );
693     }
694 
695     //------------------------------------------------------------------------------------------------------------------
696     void UnoControlTableModel::setActiveSelectionBackColor( Any const & i_color )
697     {
698         DBG_CHECK_ME();
699         lcl_setColor( i_color, m_pImpl->m_aActiveSelectionBackColor );
700     }
701 
702     //------------------------------------------------------------------------------------------------------------------
703     void UnoControlTableModel::setInactiveSelectionBackColor( Any const & i_color )
704     {
705         DBG_CHECK_ME();
706         lcl_setColor( i_color, m_pImpl->m_aInactiveSelectionBackColor );
707     }
708 
709     //------------------------------------------------------------------------------------------------------------------
710     void UnoControlTableModel::setActiveSelectionTextColor( Any const & i_color )
711     {
712         DBG_CHECK_ME();
713         lcl_setColor( i_color, m_pImpl->m_aActiveSelectionTextColor );
714     }
715 
716     //------------------------------------------------------------------------------------------------------------------
717     void UnoControlTableModel::setInactiveSelectionTextColor( Any const & i_color )
718     {
719         DBG_CHECK_ME();
720         lcl_setColor( i_color, m_pImpl->m_aInactiveSelectionTextColor );
721     }
722 
723     //------------------------------------------------------------------------------------------------------------------
724     ::boost::optional< ::Color > UnoControlTableModel::getTextColor() const
725     {
726         DBG_CHECK_ME();
727         return m_pImpl->m_aTextColor;
728     }
729 
730     //------------------------------------------------------------------------------------------------------------------
731     void UnoControlTableModel::setTextColor( Any const & i_color )
732     {
733         DBG_CHECK_ME();
734         lcl_setColor( i_color, m_pImpl->m_aTextColor );
735     }
736 
737     //------------------------------------------------------------------------------------------------------------------
738     ::boost::optional< ::Color > UnoControlTableModel::getTextLineColor() const
739     {
740         DBG_CHECK_ME();
741         return m_pImpl->m_aTextColor;
742     }
743 
744     //------------------------------------------------------------------------------------------------------------------
745     void UnoControlTableModel::setTextLineColor( Any const & i_color )
746     {
747         DBG_CHECK_ME();
748         lcl_setColor( i_color, m_pImpl->m_aTextLineColor );
749     }
750 
751     //------------------------------------------------------------------------------------------------------------------
752     ::boost::optional< ::std::vector< ::Color > > UnoControlTableModel::getRowBackgroundColors() const
753     {
754         DBG_CHECK_ME();
755         return m_pImpl->m_aRowColors;
756     }
757 
758     //------------------------------------------------------------------------------------------------------------------
759     void UnoControlTableModel::setRowBackgroundColors( ::com::sun::star::uno::Any const & i_APIValue )
760     {
761         DBG_CHECK_ME();
762         Sequence< ::com::sun::star::util::Color > aAPIColors;
763         if ( !( i_APIValue >>= aAPIColors ) )
764             m_pImpl->m_aRowColors.reset();
765         else
766         {
767             ::std::vector< ::Color > aColors( aAPIColors.getLength() );
768             for ( sal_Int32 i=0; i<aAPIColors.getLength(); ++i )
769             {
770                 aColors[i] = ::Color( aAPIColors[i] );
771             }
772             m_pImpl->m_aRowColors.reset( aColors );
773         }
774     }
775 
776     //------------------------------------------------------------------------------------------------------------------
777     VerticalAlignment UnoControlTableModel::getVerticalAlign() const
778     {
779         DBG_CHECK_ME();
780         return  m_pImpl->m_eVerticalAlign;
781     }
782 
783     //------------------------------------------------------------------------------------------------------------------
784     void UnoControlTableModel::setVerticalAlign( VerticalAlignment _xAlign )
785     {
786         DBG_CHECK_ME();
787         m_pImpl->m_eVerticalAlign = _xAlign;
788     }
789 
790     //------------------------------------------------------------------------------------------------------------------
791     ColPos UnoControlTableModel::getColumnPos( UnoGridColumnFacade const & i_column ) const
792     {
793         DBG_CHECK_ME();
794         for (   ColumnModels::const_iterator col = m_pImpl->aColumns.begin();
795                 col != m_pImpl->aColumns.end();
796                 ++col
797             )
798         {
799             if ( &i_column == col->get() )
800                 return col - m_pImpl->aColumns.begin();
801         }
802         OSL_ENSURE( false, "UnoControlTableModel::getColumnPos: column not found!" );
803         return COL_INVALID;
804     }
805 
806     //------------------------------------------------------------------------------------------------------------------
807     ITableDataSort* UnoControlTableModel::getSortAdapter()
808     {
809         DBG_CHECK_ME();
810 
811         Reference< XSortableGridData > const xSortAccess( getDataModel(), UNO_QUERY );
812         if ( xSortAccess.is() )
813             return this;
814         return NULL;
815     }
816 
817     //------------------------------------------------------------------------------------------------------------------
818     void UnoControlTableModel::sortByColumn( ColPos const i_column, ColumnSortDirection const i_sortDirection )
819     {
820         DBG_CHECK_ME();
821 
822         try
823         {
824             Reference< XSortableGridData > const xSortAccess( getDataModel(), UNO_QUERY_THROW );
825             xSortAccess->sortByColumn( i_column, i_sortDirection == ColumnSortAscending );
826         }
827         catch( const Exception& )
828         {
829         	DBG_UNHANDLED_EXCEPTION();
830         }
831     }
832 
833     //------------------------------------------------------------------------------------------------------------------
834     ColumnSort UnoControlTableModel::getCurrentSortOrder() const
835     {
836         DBG_CHECK_ME();
837 
838         ColumnSort currentSort;
839         try
840         {
841             Reference< XSortableGridData > const xSortAccess( getDataModel(), UNO_QUERY_THROW );
842             Pair< ::sal_Int32, ::sal_Bool > const aCurrentSortOrder( xSortAccess->getCurrentSortOrder() );
843             currentSort.nColumnPos = aCurrentSortOrder.First;
844             currentSort.eSortDirection = aCurrentSortOrder.Second ? ColumnSortAscending : ColumnSortDescending;
845         }
846         catch( const Exception& )
847         {
848         	DBG_UNHANDLED_EXCEPTION();
849         }
850         return currentSort;
851     }
852 
853     //--------------------------------------------------------------------
854     void UnoControlTableModel::notifyColumnChange( ColPos const i_columnPos, ColumnAttributeGroup const i_attributeGroup ) const
855     {
856         DBG_CHECK_ME();
857         ENSURE_OR_RETURN_VOID( ( i_columnPos >= 0 ) && ( i_columnPos < getColumnCount() ),
858             "UnoControlTableModel::notifyColumnChange: invalid column index!" );
859 
860         ModellListeners aListeners( m_pImpl->m_aListeners );
861         for (   ModellListeners::const_iterator loop = aListeners.begin();
862                 loop != aListeners.end();
863                 ++loop
864             )
865         {
866             (*loop)->columnChanged( i_columnPos, i_attributeGroup );
867         }
868     }
869 
870     //------------------------------------------------------------------------------------------------------------------
871     void UnoControlTableModel::notifyRowsInserted( GridDataEvent const & i_event ) const
872     {
873         // check sanity of the event
874         ENSURE_OR_RETURN_VOID( i_event.FirstRow >= 0, "UnoControlTableModel::notifyRowsInserted: invalid first row!" );
875         ENSURE_OR_RETURN_VOID( i_event.LastRow >= i_event.FirstRow, "UnoControlTableModel::notifyRowsInserted: invalid row indexes!" );
876 
877         // check own sanity
878         Reference< XGridColumnModel > const xColumnModel( m_pImpl->m_aColumnModel );
879         ENSURE_OR_RETURN_VOID( xColumnModel.is(), "UnoControlTableModel::notifyRowsInserted: no column model anymore!" );
880 
881         Reference< XGridDataModel > const xDataModel( m_pImpl->m_aDataModel );
882         ENSURE_OR_RETURN_VOID( xDataModel.is(), "UnoControlTableModel::notifyRowsInserted: no data model anymore!" );
883 
884         // implicitly add columns to the column model
885         // TODO: is this really a good idea?
886         sal_Int32 const dataColumnCount = xDataModel->getColumnCount();
887         OSL_ENSURE( dataColumnCount > 0, "UnoControlTableModel::notifyRowsInserted: no columns at all?" );
888 
889         sal_Int32 const modelColumnCount = xColumnModel->getColumnCount();
890         if ( ( modelColumnCount == 0 ) && ( dataColumnCount > 0 ) )
891         {
892             // TODO: shouldn't we clear the mutexes guard for this call?
893 		    xColumnModel->setDefaultColumns( dataColumnCount );
894         }
895 
896         // multiplex the event to our own listeners
897         ModellListeners aListeners( m_pImpl->m_aListeners );
898         for (   ModellListeners::const_iterator loop = aListeners.begin();
899                 loop != aListeners.end();
900                 ++loop
901             )
902         {
903             (*loop)->rowsInserted( i_event.FirstRow, i_event.LastRow );
904         }
905     }
906 
907     //------------------------------------------------------------------------------------------------------------------
908     void UnoControlTableModel::notifyRowsRemoved( GridDataEvent const & i_event ) const
909     {
910         ModellListeners aListeners( m_pImpl->m_aListeners );
911         for (   ModellListeners::const_iterator loop = aListeners.begin();
912                 loop != aListeners.end();
913                 ++loop
914             )
915         {
916             (*loop)->rowsRemoved( i_event.FirstRow, i_event.LastRow );
917         }
918     }
919 
920     //------------------------------------------------------------------------------------------------------------------
921     void UnoControlTableModel::notifyDataChanged( ::com::sun::star::awt::grid::GridDataEvent const & i_event ) const
922     {
923         ColPos const firstCol = i_event.FirstColumn == -1 ? 0 : i_event.FirstColumn;
924         ColPos const lastCol = i_event.FirstColumn == -1 ? getColumnCount() - 1 : i_event.LastColumn;
925         RowPos const firstRow = i_event.FirstRow == -1 ? 0 : i_event.FirstRow;
926         RowPos const lastRow = i_event.FirstRow == -1 ? getRowCount() - 1 : i_event.LastRow;
927 
928         ModellListeners aListeners( m_pImpl->m_aListeners );
929         for (   ModellListeners::const_iterator loop = aListeners.begin();
930                 loop != aListeners.end();
931                 ++loop
932             )
933         {
934             (*loop)->cellsUpdated( firstCol, lastCol, firstRow, lastRow );
935         }
936     }
937 
938     //------------------------------------------------------------------------------------------------------------------
939     void UnoControlTableModel::notifyAllDataChanged() const
940     {
941         ModellListeners aListeners( m_pImpl->m_aListeners );
942         for (   ModellListeners::const_iterator loop = aListeners.begin();
943                 loop != aListeners.end();
944                 ++loop
945             )
946         {
947             (*loop)->cellsUpdated( 0, getColumnCount() - 1, 0, getRowCount() - 1 );
948         }
949     }
950 
951 // .....................................................................................................................
952 } } // svt::table
953 // .....................................................................................................................
954