1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "unocontroltablemodel.hxx"
21 #include "unogridcolumnfacade.hxx"
23 #include <controls/table/defaultinputhandler.hxx>
24 #include <controls/table/gridtablerenderer.hxx>
26 #include <com/sun/star/awt/grid/XSortableGridData.hpp>
27 #include <com/sun/star/util/Color.hpp>
28 #include <o3tl/safeint.hxx>
29 #include <sal/log.hxx>
30 #include <cppuhelper/weakref.hxx>
31 #include <tools/debug.hxx>
32 #include <comphelper/diagnose_ex.hxx>
39 using css::uno::Reference
;
40 using css::uno::Sequence
;
41 using css::uno::UNO_QUERY_THROW
;
42 using css::uno::UNO_QUERY
;
43 using css::awt::grid::XGridColumn
;
44 using css::uno::Exception
;
45 using css::awt::grid::XGridDataModel
;
46 using css::awt::grid::XGridColumnModel
;
48 using css::style::VerticalAlignment_TOP
;
49 using css::style::VerticalAlignment
;
50 using css::awt::grid::GridDataEvent
;
51 using css::awt::grid::XSortableGridData
;
52 using css::beans::Pair
;
55 //= UnoControlTableModel
56 #define DBG_CHECK_ME() \
57 DBG_TESTSOLARMUTEX(); \
59 UnoControlTableModel::UnoControlTableModel()
61 ,bHasColumnHeaders ( true )
62 ,bHasRowHeaders ( false )
63 ,eVScrollMode ( ScrollbarShowNever
)
64 ,eHScrollMode ( ScrollbarShowNever
)
68 ,nColumnHeaderHeight ( 10 )
69 ,nRowHeaderWidth ( 10 )
71 ,m_aHeaderBackgroundColor ( )
72 ,m_aHeaderTextColor ( )
73 ,m_aActiveSelectionBackColor ( )
74 ,m_aInactiveSelectionBackColor ( )
75 ,m_aActiveSelectionTextColor ( )
76 ,m_aInactiveSelectionTextColor ( )
80 ,m_eVerticalAlign ( VerticalAlignment_TOP
)
83 pRenderer
= std::make_shared
<GridTableRenderer
>( *this );
84 pInputHandler
= std::make_shared
<DefaultInputHandler
>();
88 UnoControlTableModel::~UnoControlTableModel()
93 TableSize
UnoControlTableModel::getColumnCount() const
96 return static_cast<TableSize
>(aColumns
.size());
100 TableSize
UnoControlTableModel::getRowCount() const
104 TableSize nRowCount
= 0;
107 Reference
< XGridDataModel
> const xDataModel( m_aDataModel
);
108 ENSURE_OR_THROW( xDataModel
.is(), "no data model anymore!" );
109 nRowCount
= xDataModel
->getRowCount();
111 catch( const Exception
& )
113 DBG_UNHANDLED_EXCEPTION("svtools.uno");
119 bool UnoControlTableModel::hasColumnHeaders() const
122 return bHasColumnHeaders
;
126 bool UnoControlTableModel::hasRowHeaders() const
129 return bHasRowHeaders
;
133 void UnoControlTableModel::setRowHeaders(bool _bRowHeaders
)
136 if ( bHasRowHeaders
== _bRowHeaders
)
139 bHasRowHeaders
= _bRowHeaders
;
140 impl_notifyTableMetricsChanged();
144 void UnoControlTableModel::setColumnHeaders(bool _bColumnHeaders
)
147 if ( bHasColumnHeaders
== _bColumnHeaders
)
150 bHasColumnHeaders
= _bColumnHeaders
;
151 impl_notifyTableMetricsChanged();
155 PColumnModel
UnoControlTableModel::getColumnModel( ColPos column
)
158 ENSURE_OR_RETURN( ( column
>= 0 ) && ( column
< getColumnCount() ),
159 "DefaultTableModel::getColumnModel: invalid index!", PColumnModel() );
160 return aColumns
[ column
];
164 void UnoControlTableModel::appendColumn( Reference
< XGridColumn
> const & i_column
)
167 insertColumn( aColumns
.size(), i_column
);
171 void UnoControlTableModel::insertColumn( ColPos
const i_position
, Reference
< XGridColumn
> const & i_column
)
174 ENSURE_OR_RETURN_VOID( ( i_position
>= 0 ) && ( o3tl::make_unsigned( i_position
) <= aColumns
.size() ),
175 "UnoControlTableModel::insertColumn: illegal position!" );
177 const PColumnModel pColumn
= std::make_shared
<UnoGridColumnFacade
>( *this, i_column
);
178 aColumns
.insert( aColumns
.begin() + i_position
, pColumn
);
181 ModellListeners
aListeners( m_aListeners
);
182 for (auto const& listener
: aListeners
)
184 listener
->columnInserted();
189 void UnoControlTableModel::removeColumn( ColPos
const i_position
)
192 ENSURE_OR_RETURN_VOID( ( i_position
>= 0 ) && ( o3tl::make_unsigned( i_position
) <= aColumns
.size() ),
193 "UnoControlTableModel::removeColumn: illegal position!" );
196 ColumnModels::iterator pos
= aColumns
.begin() + i_position
;
197 const PColumnModel pColumn
= *pos
;
198 aColumns
.erase( pos
);
201 ModellListeners
aListeners( m_aListeners
);
202 for (auto const& listener
: aListeners
)
204 listener
->columnRemoved();
207 // dispose the column
208 UnoGridColumnFacade
* pColumnImpl
= dynamic_cast< UnoGridColumnFacade
* >( pColumn
.get() );
209 OSL_ENSURE( pColumnImpl
!= nullptr, "UnoControlTableModel::removeColumn: illegal column implementation!" );
211 pColumnImpl
->dispose();
215 void UnoControlTableModel::removeAllColumns()
218 if ( aColumns
.empty() )
221 // dispose the column instances
222 for (auto const& col
: aColumns
)
224 UnoGridColumnFacade
* pColumn
= dynamic_cast< UnoGridColumnFacade
* >( col
.get() );
227 SAL_WARN( "svtools.uno", "UnoControlTableModel::removeAllColumns: illegal column implementation!" );
236 ModellListeners
aListeners( m_aListeners
);
237 for (auto const& listener
: aListeners
)
239 listener
->allColumnsRemoved();
244 void UnoControlTableModel::impl_notifyTableMetricsChanged() const
246 ModellListeners
aListeners( m_aListeners
);
247 for (auto const& listener
: aListeners
)
249 listener
->tableMetricsChanged();
254 PTableRenderer
UnoControlTableModel::getRenderer() const
261 PTableInputHandler
UnoControlTableModel::getInputHandler() const
264 return pInputHandler
;
268 TableMetrics
UnoControlTableModel::getRowHeight() const
275 void UnoControlTableModel::setRowHeight(TableMetrics _nRowHeight
)
278 if ( nRowHeight
== _nRowHeight
)
281 nRowHeight
= _nRowHeight
;
282 impl_notifyTableMetricsChanged();
286 TableMetrics
UnoControlTableModel::getColumnHeaderHeight() const
289 DBG_ASSERT( hasColumnHeaders(), "DefaultTableModel::getColumnHeaderHeight: invalid call!" );
290 return nColumnHeaderHeight
;
294 TableMetrics
UnoControlTableModel::getRowHeaderWidth() const
297 DBG_ASSERT( hasRowHeaders(), "DefaultTableModel::getRowHeaderWidth: invalid call!" );
298 return nRowHeaderWidth
;
301 void UnoControlTableModel::setColumnHeaderHeight(TableMetrics _nHeight
)
304 if ( nColumnHeaderHeight
== _nHeight
)
307 nColumnHeaderHeight
= _nHeight
;
308 impl_notifyTableMetricsChanged();
312 void UnoControlTableModel::setRowHeaderWidth(TableMetrics _nWidth
)
315 if ( nRowHeaderWidth
== _nWidth
)
318 nRowHeaderWidth
= _nWidth
;
319 impl_notifyTableMetricsChanged();
323 ScrollbarVisibility
UnoControlTableModel::getVerticalScrollbarVisibility() const
330 ScrollbarVisibility
UnoControlTableModel::getHorizontalScrollbarVisibility() const
337 void UnoControlTableModel::addTableModelListener( const PTableModelListener
& i_listener
)
340 ENSURE_OR_RETURN_VOID( !!i_listener
, "illegal NULL listener" );
341 m_aListeners
.push_back( i_listener
);
345 void UnoControlTableModel::removeTableModelListener( const PTableModelListener
& i_listener
)
348 auto lookup
= std::find(m_aListeners
.begin(), m_aListeners
.end(), i_listener
);
349 if (lookup
!= m_aListeners
.end())
351 m_aListeners
.erase( lookup
);
354 OSL_ENSURE( false, "UnoControlTableModel::removeTableModelListener: listener is not registered - sure you're doing the right thing here?" );
358 void UnoControlTableModel::setVerticalScrollbarVisibility( ScrollbarVisibility
const i_visibility
)
361 eVScrollMode
= i_visibility
;
365 void UnoControlTableModel::setHorizontalScrollbarVisibility( ScrollbarVisibility
const i_visibility
)
368 eHScrollMode
= i_visibility
;
372 void UnoControlTableModel::setDataModel( Reference
< XGridDataModel
> const & i_gridDataModel
)
375 m_aDataModel
= i_gridDataModel
;
376 // TODO: register as listener, so we're notified of row/data changes, and can multiplex them to our
381 Reference
< XGridDataModel
> UnoControlTableModel::getDataModel() const
383 Reference
< XGridDataModel
> const xDataModel( m_aDataModel
);
388 bool UnoControlTableModel::hasDataModel() const
390 return getDataModel().is();
394 void UnoControlTableModel::setColumnModel( Reference
< XGridColumnModel
> const & i_gridColumnModel
)
397 m_aColumnModel
= i_gridColumnModel
;
401 Reference
< XGridColumnModel
> UnoControlTableModel::getColumnModel() const
403 Reference
< XGridColumnModel
> const xColumnModel( m_aColumnModel
);
408 bool UnoControlTableModel::hasColumnModel() const
410 return getColumnModel().is();
414 void UnoControlTableModel::getCellContent( ColPos
const i_col
, RowPos
const i_row
, Any
& o_cellContent
)
418 o_cellContent
.clear();
421 Reference
< XGridDataModel
> const xDataModel( m_aDataModel
);
422 ENSURE_OR_RETURN_VOID( xDataModel
.is(), "UnoControlTableModel::getCellContent: no data model anymore!" );
424 PColumnModel
const pColumn
= getColumnModel( i_col
);
425 UnoGridColumnFacade
* pColumnImpl
= dynamic_cast< UnoGridColumnFacade
* >( pColumn
.get() );
426 ENSURE_OR_RETURN_VOID( pColumnImpl
!= nullptr, "UnoControlTableModel::getCellContent: no (valid) column at this position!" );
427 sal_Int32
const nDataColumnIndex
= pColumnImpl
->getDataColumnIndex() >= 0 ? pColumnImpl
->getDataColumnIndex() : i_col
;
429 if ( nDataColumnIndex
>= xDataModel
->getColumnCount() )
431 // this is allowed, in case the column model has been dynamically extended, but the data model does
432 // not (yet?) know about it.
433 // So, handle it gracefully.
434 #if OSL_DEBUG_LEVEL > 0
435 Reference
< XGridColumnModel
> const xColumnModel( m_aColumnModel
);
436 OSL_ENSURE( xColumnModel
.is() && i_col
< xColumnModel
->getColumnCount(),
437 "UnoControlTableModel::getCellContent: request a column's value which the ColumnModel doesn't know about!" );
442 o_cellContent
= xDataModel
->getCellData( nDataColumnIndex
, i_row
);
445 catch( const Exception
& )
447 DBG_UNHANDLED_EXCEPTION("svtools.uno");
452 void UnoControlTableModel::getCellToolTip( ColPos
const i_col
, RowPos
const i_row
, Any
& o_cellToolTip
)
457 Reference
< XGridDataModel
> const xDataModel( m_aDataModel
);
458 ENSURE_OR_THROW( xDataModel
.is(), "no data model anymore!" );
460 o_cellToolTip
= xDataModel
->getCellToolTip( i_col
, i_row
);
462 catch( const Exception
& )
464 DBG_UNHANDLED_EXCEPTION("svtools.uno");
469 Any
UnoControlTableModel::getRowHeading( RowPos
const i_rowPos
) const
475 Reference
< XGridDataModel
> const xDataModel( m_aDataModel
);
476 ENSURE_OR_RETURN( xDataModel
.is(), "UnoControlTableModel::getRowHeading: no data model anymore!", aRowHeading
);
480 aRowHeading
= xDataModel
->getRowHeading( i_rowPos
);
482 catch( const Exception
& )
484 DBG_UNHANDLED_EXCEPTION("svtools.uno");
492 void lcl_setColor( Any
const & i_color
, ::std::optional
< ::Color
> & o_convertedColor
)
494 if ( !i_color
.hasValue() )
495 o_convertedColor
.reset();
498 Color nColor
= COL_TRANSPARENT
;
499 if ( i_color
>>= nColor
)
501 o_convertedColor
= nColor
;
505 OSL_ENSURE( false, "lcl_setColor: could not extract color value!" );
512 ::std::optional
< ::Color
> UnoControlTableModel::getLineColor() const
515 return m_aGridLineColor
;
519 void UnoControlTableModel::setLineColor( Any
const & i_color
)
522 lcl_setColor( i_color
, m_aGridLineColor
);
526 ::std::optional
< ::Color
> UnoControlTableModel::getHeaderBackgroundColor() const
529 return m_aHeaderBackgroundColor
;
533 void UnoControlTableModel::setHeaderBackgroundColor( Any
const & i_color
)
536 lcl_setColor( i_color
, m_aHeaderBackgroundColor
);
540 ::std::optional
< ::Color
> UnoControlTableModel::getHeaderTextColor() const
543 return m_aHeaderTextColor
;
547 ::std::optional
< ::Color
> UnoControlTableModel::getActiveSelectionBackColor() const
550 return m_aActiveSelectionBackColor
;
554 ::std::optional
< ::Color
> UnoControlTableModel::getInactiveSelectionBackColor() const
557 return m_aInactiveSelectionBackColor
;
561 ::std::optional
< ::Color
> UnoControlTableModel::getActiveSelectionTextColor() const
564 return m_aActiveSelectionTextColor
;
568 ::std::optional
< ::Color
> UnoControlTableModel::getInactiveSelectionTextColor() const
571 return m_aInactiveSelectionTextColor
;
575 void UnoControlTableModel::setHeaderTextColor( Any
const & i_color
)
578 lcl_setColor( i_color
, m_aHeaderTextColor
);
582 void UnoControlTableModel::setActiveSelectionBackColor( Any
const & i_color
)
585 lcl_setColor( i_color
, m_aActiveSelectionBackColor
);
589 void UnoControlTableModel::setInactiveSelectionBackColor( Any
const & i_color
)
592 lcl_setColor( i_color
, m_aInactiveSelectionBackColor
);
596 void UnoControlTableModel::setActiveSelectionTextColor( Any
const & i_color
)
599 lcl_setColor( i_color
, m_aActiveSelectionTextColor
);
603 void UnoControlTableModel::setInactiveSelectionTextColor( Any
const & i_color
)
606 lcl_setColor( i_color
, m_aInactiveSelectionTextColor
);
610 ::std::optional
< ::Color
> UnoControlTableModel::getTextColor() const
617 void UnoControlTableModel::setTextColor( Any
const & i_color
)
620 lcl_setColor( i_color
, m_aTextColor
);
624 ::std::optional
< ::Color
> UnoControlTableModel::getTextLineColor() const
631 void UnoControlTableModel::setTextLineColor( Any
const & i_color
)
634 lcl_setColor( i_color
, m_aTextLineColor
);
638 ::std::optional
< ::std::vector
< ::Color
> > UnoControlTableModel::getRowBackgroundColors() const
645 void UnoControlTableModel::setRowBackgroundColors( css::uno::Any
const & i_APIValue
)
648 Sequence
< css::util::Color
> aAPIColors
;
649 if ( !( i_APIValue
>>= aAPIColors
) )
650 m_aRowColors
.reset();
653 ::std::vector
< ::Color
> aColors( aAPIColors
.getLength() );
654 std::transform(std::cbegin(aAPIColors
), std::cend(aAPIColors
), aColors
.begin(),
655 [](const css::util::Color
& rAPIColor
) -> ::Color
{ return Color(ColorTransparency
, rAPIColor
); });
656 m_aRowColors
= aColors
;
661 VerticalAlignment
UnoControlTableModel::getVerticalAlign() const
664 return m_eVerticalAlign
;
668 void UnoControlTableModel::setVerticalAlign( VerticalAlignment _xAlign
)
671 m_eVerticalAlign
= _xAlign
;
675 ColPos
UnoControlTableModel::getColumnPos( UnoGridColumnFacade
const & i_column
) const
679 for (auto const& col
: aColumns
)
681 if ( &i_column
== col
.get() )
685 OSL_ENSURE( false, "UnoControlTableModel::getColumnPos: column not found!" );
690 ITableDataSort
* UnoControlTableModel::getSortAdapter()
694 Reference
< XSortableGridData
> const xSortAccess( getDataModel(), UNO_QUERY
);
695 if ( xSortAccess
.is() )
701 bool UnoControlTableModel::isEnabled() const
708 void UnoControlTableModel::setEnabled( bool _bEnabled
)
711 bEnabled
= _bEnabled
;
715 void UnoControlTableModel::sortByColumn( ColPos
const i_column
, ColumnSortDirection
const i_sortDirection
)
721 Reference
< XSortableGridData
> const xSortAccess( getDataModel(), UNO_QUERY_THROW
);
722 xSortAccess
->sortByColumn( i_column
, i_sortDirection
== ColumnSortAscending
);
724 catch( const Exception
& )
726 DBG_UNHANDLED_EXCEPTION("svtools.uno");
731 ColumnSort
UnoControlTableModel::getCurrentSortOrder() const
735 ColumnSort currentSort
;
738 Reference
< XSortableGridData
> const xSortAccess( getDataModel(), UNO_QUERY_THROW
);
739 Pair
< ::sal_Int32
, sal_Bool
> const aCurrentSortOrder( xSortAccess
->getCurrentSortOrder() );
740 currentSort
.nColumnPos
= aCurrentSortOrder
.First
;
741 currentSort
.eSortDirection
= aCurrentSortOrder
.Second
? ColumnSortAscending
: ColumnSortDescending
;
743 catch( const Exception
& )
745 DBG_UNHANDLED_EXCEPTION("svtools.uno");
751 void UnoControlTableModel::notifyColumnChange( ColPos
const i_columnPos
, ColumnAttributeGroup
const i_attributeGroup
) const
754 ENSURE_OR_RETURN_VOID( ( i_columnPos
>= 0 ) && ( i_columnPos
< getColumnCount() ),
755 "UnoControlTableModel::notifyColumnChange: invalid column index!" );
757 ModellListeners
aListeners( m_aListeners
);
758 for (auto const& listener
: aListeners
)
760 listener
->columnChanged( i_columnPos
, i_attributeGroup
);
765 void UnoControlTableModel::notifyRowsInserted( GridDataEvent
const & i_event
) const
767 // check sanity of the event
768 ENSURE_OR_RETURN_VOID( i_event
.FirstRow
>= 0, "UnoControlTableModel::notifyRowsInserted: invalid first row!" );
769 ENSURE_OR_RETURN_VOID( i_event
.LastRow
>= i_event
.FirstRow
, "UnoControlTableModel::notifyRowsInserted: invalid row indexes!" );
772 Reference
< XGridColumnModel
> const xColumnModel( m_aColumnModel
);
773 ENSURE_OR_RETURN_VOID( xColumnModel
.is(), "UnoControlTableModel::notifyRowsInserted: no column model anymore!" );
775 Reference
< XGridDataModel
> const xDataModel( m_aDataModel
);
776 ENSURE_OR_RETURN_VOID( xDataModel
.is(), "UnoControlTableModel::notifyRowsInserted: no data model anymore!" );
778 // implicitly add columns to the column model
779 // TODO: is this really a good idea?
780 sal_Int32
const dataColumnCount
= xDataModel
->getColumnCount();
781 OSL_ENSURE( dataColumnCount
> 0, "UnoControlTableModel::notifyRowsInserted: no columns at all?" );
783 sal_Int32
const modelColumnCount
= xColumnModel
->getColumnCount();
784 if ( ( modelColumnCount
== 0 ) && ( dataColumnCount
> 0 ) )
786 // TODO: shouldn't we clear the mutexes guard for this call?
787 xColumnModel
->setDefaultColumns( dataColumnCount
);
790 // multiplex the event to our own listeners
791 ModellListeners
aListeners( m_aListeners
);
792 for (auto const& listener
: aListeners
)
794 listener
->rowsInserted( i_event
.FirstRow
, i_event
.LastRow
);
799 void UnoControlTableModel::notifyRowsRemoved( GridDataEvent
const & i_event
) const
801 ModellListeners
aListeners( m_aListeners
);
802 for (auto const& listener
: aListeners
)
804 listener
->rowsRemoved( i_event
.FirstRow
, i_event
.LastRow
);
809 void UnoControlTableModel::notifyDataChanged( css::awt::grid::GridDataEvent
const & i_event
) const
811 RowPos
const firstRow
= i_event
.FirstRow
== -1 ? 0 : i_event
.FirstRow
;
812 RowPos
const lastRow
= i_event
.FirstRow
== -1 ? getRowCount() - 1 : i_event
.LastRow
;
814 ModellListeners
aListeners( m_aListeners
);
815 for (auto const& listener
: aListeners
)
817 listener
->cellsUpdated( firstRow
, lastRow
);
822 void UnoControlTableModel::notifyAllDataChanged() const
824 ModellListeners
aListeners( m_aListeners
);
825 for (auto const& listener
: aListeners
)
827 listener
->cellsUpdated( 0, getRowCount() - 1 );
834 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */