Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 : : *
5 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
6 : : *
7 : : * OpenOffice.org - a multi-platform office productivity suite
8 : : *
9 : : * This file is part of OpenOffice.org.
10 : : *
11 : : * OpenOffice.org is free software: you can redistribute it and/or modify
12 : : * it under the terms of the GNU Lesser General Public License version 3
13 : : * only, as published by the Free Software Foundation.
14 : : *
15 : : * OpenOffice.org is distributed in the hope that it will be useful,
16 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : : * GNU Lesser General Public License version 3 for more details
19 : : * (a copy is included in the LICENSE file that accompanied this code).
20 : : *
21 : : * You should have received a copy of the GNU Lesser General Public License
22 : : * version 3 along with OpenOffice.org. If not, see
23 : : * <http://www.openoffice.org/license.html>
24 : : * for a copy of the LGPLv3 License.
25 : : *
26 : : ************************************************************************/
27 : :
28 : :
29 : : #include "svtools/table/tablecontrol.hxx"
30 : : #include "svtools/table/defaultinputhandler.hxx"
31 : : #include "svtools/table/tablemodel.hxx"
32 : :
33 : : #include "tabledatawindow.hxx"
34 : : #include "tablecontrol_impl.hxx"
35 : : #include "tablegeometry.hxx"
36 : : #include "cellvalueconversion.hxx"
37 : :
38 : : #include <com/sun/star/accessibility/XAccessible.hpp>
39 : : #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
40 : : #include <com/sun/star/accessibility/AccessibleEventId.hpp>
41 : : #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
42 : :
43 : : #include <comphelper/flagguard.hxx>
44 : : #include <vcl/scrbar.hxx>
45 : : #include <vcl/seleng.hxx>
46 : : #include <rtl/ref.hxx>
47 : : #include <vcl/image.hxx>
48 : : #include <tools/diagnose_ex.h>
49 : :
50 : : #include <functional>
51 : :
52 : : #define MIN_COLUMN_WIDTH_PIXEL 4
53 : :
54 : : //......................................................................................................................
55 : : namespace svt { namespace table
56 : : {
57 : : //......................................................................................................................
58 : :
59 : : /** === begin UNO using === **/
60 : : using ::com::sun::star::accessibility::AccessibleTableModelChange;
61 : : using ::com::sun::star::uno::makeAny;
62 : : using ::com::sun::star::uno::Any;
63 : : using ::com::sun::star::accessibility::XAccessible;
64 : : using ::com::sun::star::uno::Reference;
65 : : /** === end UNO using === **/
66 : : namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId;
67 : : namespace AccessibleTableModelChangeType = ::com::sun::star::accessibility::AccessibleTableModelChangeType;
68 : :
69 : : //==================================================================================================================
70 : : //= SuppressCursor
71 : : //==================================================================================================================
72 : : class SuppressCursor
73 : : {
74 : : private:
75 : : ITableControl& m_rTable;
76 : :
77 : : public:
78 : 0 : SuppressCursor( ITableControl& _rTable )
79 : 0 : :m_rTable( _rTable )
80 : : {
81 : 0 : m_rTable.hideCursor();
82 : 0 : }
83 : 0 : ~SuppressCursor()
84 : : {
85 : 0 : m_rTable.showCursor();
86 : 0 : }
87 : : };
88 : :
89 : : //====================================================================
90 : : //= EmptyTableModel
91 : : //====================================================================
92 : : /** default implementation of an ->ITableModel, used as fallback when no
93 : : real model is present
94 : :
95 : : Instances of this class are static in any way, and provide the least
96 : : necessary default functionality for a table model.
97 : : */
98 [ # # ]: 0 : class EmptyTableModel : public ITableModel
99 : : {
100 : : public:
101 : 0 : EmptyTableModel()
102 : 0 : {
103 : 0 : }
104 : :
105 : : // ITableModel overridables
106 : 0 : virtual TableSize getColumnCount() const
107 : : {
108 : 0 : return 0;
109 : : }
110 : 0 : virtual TableSize getRowCount() const
111 : : {
112 : 0 : return 0;
113 : : }
114 : 0 : virtual bool hasColumnHeaders() const
115 : : {
116 : 0 : return false;
117 : : }
118 : 0 : virtual bool hasRowHeaders() const
119 : : {
120 : 0 : return false;
121 : : }
122 : 0 : virtual bool isCellEditable( ColPos col, RowPos row ) const
123 : : {
124 : : (void)col;
125 : : (void)row;
126 : 0 : return false;
127 : : }
128 : 0 : virtual PColumnModel getColumnModel( ColPos column )
129 : : {
130 : : OSL_FAIL( "EmptyTableModel::getColumnModel: invalid call!" );
131 : : (void)column;
132 : 0 : return PColumnModel();
133 : : }
134 : 0 : virtual PTableRenderer getRenderer() const
135 : : {
136 : 0 : return PTableRenderer();
137 : : }
138 : 0 : virtual PTableInputHandler getInputHandler() const
139 : : {
140 : 0 : return PTableInputHandler();
141 : : }
142 : 0 : virtual TableMetrics getRowHeight() const
143 : : {
144 : 0 : return 5 * 100;
145 : : }
146 : 0 : virtual void setRowHeight(TableMetrics _nRowHeight)
147 : : {
148 : : (void)_nRowHeight;
149 : 0 : }
150 : 0 : virtual TableMetrics getColumnHeaderHeight() const
151 : : {
152 : 0 : return 0;
153 : : }
154 : 0 : virtual TableMetrics getRowHeaderWidth() const
155 : : {
156 : 0 : return 0;
157 : : }
158 : 0 : virtual ScrollbarVisibility getVerticalScrollbarVisibility() const
159 : : {
160 : 0 : return ScrollbarShowNever;
161 : : }
162 : 0 : virtual ScrollbarVisibility getHorizontalScrollbarVisibility() const
163 : : {
164 : 0 : return ScrollbarShowNever;
165 : : }
166 : 0 : virtual void addTableModelListener( const PTableModelListener& i_listener )
167 : : {
168 : : (void)i_listener;
169 : 0 : }
170 : 0 : virtual void removeTableModelListener( const PTableModelListener& i_listener )
171 : : {
172 : : (void)i_listener;
173 : 0 : }
174 : 0 : virtual ::boost::optional< ::Color > getLineColor() const
175 : : {
176 : 0 : return ::boost::optional< ::Color >();
177 : : }
178 : 0 : virtual ::boost::optional< ::Color > getHeaderBackgroundColor() const
179 : : {
180 : 0 : return ::boost::optional< ::Color >();
181 : : }
182 : 0 : virtual ::boost::optional< ::Color > getHeaderTextColor() const
183 : : {
184 : 0 : return ::boost::optional< ::Color >();
185 : : }
186 : 0 : virtual ::boost::optional< ::Color > getTextColor() const
187 : : {
188 : 0 : return ::boost::optional< ::Color >();
189 : : }
190 : 0 : virtual ::boost::optional< ::Color > getTextLineColor() const
191 : : {
192 : 0 : return ::boost::optional< ::Color >();
193 : : }
194 : 0 : virtual ::boost::optional< ::std::vector< ::Color > > getRowBackgroundColors() const
195 : : {
196 : 0 : return ::boost::optional< ::std::vector< ::Color > >();
197 : : }
198 : 0 : virtual ::com::sun::star::style::VerticalAlignment getVerticalAlign() const
199 : : {
200 : 0 : return com::sun::star::style::VerticalAlignment(0);
201 : : }
202 : 0 : virtual ITableDataSort* getSortAdapter()
203 : : {
204 : 0 : return NULL;
205 : : }
206 : 0 : virtual void getCellContent( ColPos const i_col, RowPos const i_row, ::com::sun::star::uno::Any& o_cellContent )
207 : : {
208 : : (void)i_row;
209 : : (void)i_col;
210 : 0 : o_cellContent.clear();
211 : 0 : }
212 : 0 : virtual void getCellToolTip( ColPos const, RowPos const, ::com::sun::star::uno::Any& )
213 : : {
214 : 0 : }
215 : 0 : virtual Any getRowHeading( RowPos const i_rowPos ) const
216 : : {
217 : : (void)i_rowPos;
218 : 0 : return Any();
219 : : }
220 : : };
221 : :
222 : :
223 : : //====================================================================
224 : : //= TableControl_Impl
225 : : //====================================================================
226 : : DBG_NAME( TableControl_Impl )
227 : :
228 : : #if DBG_UTIL
229 : : //====================================================================
230 : : //= SuspendInvariants
231 : : //====================================================================
232 : : class SuspendInvariants
233 : : {
234 : : private:
235 : : const TableControl_Impl& m_rTable;
236 : : sal_Int32 m_nSuspendFlags;
237 : :
238 : : public:
239 : : SuspendInvariants( const TableControl_Impl& _rTable, sal_Int32 _nSuspendFlags )
240 : : :m_rTable( _rTable )
241 : : ,m_nSuspendFlags( _nSuspendFlags )
242 : : {
243 : : //DBG_ASSERT( ( m_rTable.m_nRequiredInvariants & m_nSuspendFlags ) == m_nSuspendFlags,
244 : : // "SuspendInvariants: cannot suspend what is already suspended!" );
245 : : const_cast< TableControl_Impl& >( m_rTable ).m_nRequiredInvariants &= ~m_nSuspendFlags;
246 : : }
247 : : ~SuspendInvariants()
248 : : {
249 : : const_cast< TableControl_Impl& >( m_rTable ).m_nRequiredInvariants |= m_nSuspendFlags;
250 : : }
251 : : };
252 : : #define DBG_SUSPEND_INV( flags ) \
253 : : SuspendInvariants aSuspendInv( *this, flags );
254 : : #else
255 : : #define DBG_SUSPEND_INV( flags )
256 : : #endif
257 : :
258 : : #if DBG_UTIL
259 : : //====================================================================
260 : : const char* TableControl_Impl_checkInvariants( const void* _pInstance )
261 : : {
262 : : return static_cast< const TableControl_Impl* >( _pInstance )->impl_checkInvariants();
263 : : }
264 : :
265 : : namespace
266 : : {
267 : : template< typename SCALAR_TYPE >
268 : : bool lcl_checkLimitsExclusive( SCALAR_TYPE _nValue, SCALAR_TYPE _nMin, SCALAR_TYPE _nMax )
269 : : {
270 : : return ( _nValue > _nMin ) && ( _nValue < _nMax );
271 : : }
272 : :
273 : : template< typename SCALAR_TYPE >
274 : : bool lcl_checkLimitsExclusive_OrDefault_OrFallback( SCALAR_TYPE _nValue, SCALAR_TYPE _nMin, SCALAR_TYPE _nMax,
275 : : PTableModel _pModel, SCALAR_TYPE _nDefaultOrFallback )
276 : : {
277 : : if ( !_pModel )
278 : : return _nValue == _nDefaultOrFallback;
279 : : if ( _nMax <= _nMin )
280 : : return _nDefaultOrFallback == _nValue;
281 : : return lcl_checkLimitsExclusive( _nValue, _nMin, _nMax );
282 : : }
283 : : }
284 : :
285 : : //------------------------------------------------------------------------------------------------------------------
286 : : const sal_Char* TableControl_Impl::impl_checkInvariants() const
287 : : {
288 : : if ( !m_pModel )
289 : : return "no model, not even an EmptyTableModel";
290 : :
291 : : if ( !m_pDataWindow )
292 : : return "invalid data window!";
293 : :
294 : : if ( m_pModel->getColumnCount() != m_nColumnCount )
295 : : return "column counts are inconsistent!";
296 : :
297 : : if ( m_pModel->getRowCount() != m_nRowCount )
298 : : return "row counts are inconsistent!";
299 : :
300 : : if ( ( ( m_nCurColumn != COL_INVALID ) && !m_aColumnWidths.empty() && ( m_nCurColumn < 0 ) ) || ( m_nCurColumn >= (ColPos)m_aColumnWidths.size() ) )
301 : : return "current column is invalid!";
302 : :
303 : : if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nTopRow, (RowPos)-1, m_nRowCount, getModel(), (RowPos)0 ) )
304 : : return "invalid top row value!";
305 : :
306 : : if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurRow, (RowPos)-1, m_nRowCount, getModel(), ROW_INVALID ) )
307 : : return "invalid current row value!";
308 : :
309 : : if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nLeftColumn, (ColPos)-1, m_nColumnCount, getModel(), (ColPos)0 ) )
310 : : return "invalid current column value!";
311 : :
312 : : if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurColumn, (ColPos)-1, m_nColumnCount, getModel(), COL_INVALID ) )
313 : : return "invalid current column value!";
314 : :
315 : : if ( m_pInputHandler != m_pModel->getInputHandler() )
316 : : return "input handler is not the model-provided one!";
317 : :
318 : : // m_aSelectedRows should have reasonable content
319 : : {
320 : : if ( m_aSelectedRows.size() > size_t( m_pModel->getRowCount() ) )
321 : : return "there are more rows selected than actually exist";
322 : : for ( ::std::vector< RowPos >::const_iterator selRow = m_aSelectedRows.begin();
323 : : selRow != m_aSelectedRows.end();
324 : : ++selRow
325 : : )
326 : : {
327 : : if ( ( *selRow < 0 ) || ( *selRow >= m_pModel->getRowCount() ) )
328 : : return "a non-existent row is selected";
329 : : }
330 : : }
331 : :
332 : : // m_nColHeaderHeightPixel consistent with the model's value?
333 : : {
334 : : TableMetrics nHeaderHeight = m_pModel->hasColumnHeaders() ? m_pModel->getColumnHeaderHeight() : 0;
335 : : nHeaderHeight = m_rAntiImpl.LogicToPixel( Size( 0, nHeaderHeight ), MAP_APPFONT ).Height();
336 : : if ( nHeaderHeight != m_nColHeaderHeightPixel )
337 : : return "column header heights are inconsistent!";
338 : : }
339 : :
340 : : bool isDummyModel = dynamic_cast< const EmptyTableModel* >( m_pModel.get() ) != NULL;
341 : : if ( !isDummyModel )
342 : : {
343 : : TableMetrics nRowHeight = m_pModel->getRowHeight();
344 : : nRowHeight = m_rAntiImpl.LogicToPixel( Size( 0, nRowHeight ), MAP_APPFONT).Height();
345 : : if ( nRowHeight != m_nRowHeightPixel )
346 : : return "row heights are inconsistent!";
347 : : }
348 : :
349 : : // m_nRowHeaderWidthPixel consistent with the model's value?
350 : : {
351 : : TableMetrics nHeaderWidth = m_pModel->hasRowHeaders() ? m_pModel->getRowHeaderWidth() : 0;
352 : : nHeaderWidth = m_rAntiImpl.LogicToPixel( Size( nHeaderWidth, 0 ), MAP_APPFONT ).Width();
353 : : if ( nHeaderWidth != m_nRowHeaderWidthPixel )
354 : : return "row header widths are inconsistent!";
355 : : }
356 : :
357 : : // m_aColumnWidths consistency
358 : : if ( size_t( m_nColumnCount ) != m_aColumnWidths.size() )
359 : : return "wrong number of cached column widths";
360 : :
361 : : for ( ColumnPositions::const_iterator col = m_aColumnWidths.begin();
362 : : col != m_aColumnWidths.end();
363 : : )
364 : : {
365 : : if ( col->getEnd() < col->getStart() )
366 : : return "column widths: 'end' is expected to not be smaller than start";
367 : :
368 : : ColumnPositions::const_iterator nextCol = col + 1;
369 : : if ( nextCol != m_aColumnWidths.end() )
370 : : if ( col->getEnd() != nextCol->getStart() )
371 : : return "column widths: one column's end should be the next column's start";
372 : : col = nextCol;
373 : : }
374 : :
375 : : if ( m_nLeftColumn < m_nColumnCount )
376 : : if ( m_aColumnWidths[ m_nLeftColumn ].getStart() != m_nRowHeaderWidthPixel )
377 : : return "the left-most column should start immediately after the row header";
378 : :
379 : : if ( m_nCursorHidden < 0 )
380 : : return "invalid hidden count for the cursor!";
381 : :
382 : : if ( ( m_nRequiredInvariants & INV_SCROLL_POSITION ) && m_pVScroll )
383 : : {
384 : : DBG_SUSPEND_INV( INV_SCROLL_POSITION );
385 : : // prevent infinite recursion
386 : :
387 : : if ( m_nLeftColumn < 0 )
388 : : return "invalid left-most column index";
389 : : if ( m_pVScroll->GetThumbPos() != m_nTopRow )
390 : : return "vertical scroll bar |position| is incorrect!";
391 : : if ( m_pVScroll->GetRange().Max() != m_nRowCount )
392 : : return "vertical scroll bar |range| is incorrect!";
393 : : if ( m_pVScroll->GetVisibleSize() != impl_getVisibleRows( false ) )
394 : : return "vertical scroll bar |visible size| is incorrect!";
395 : : }
396 : :
397 : : if ( ( m_nRequiredInvariants & INV_SCROLL_POSITION ) && m_pHScroll )
398 : : {
399 : : DBG_SUSPEND_INV( INV_SCROLL_POSITION );
400 : : // prevent infinite recursion
401 : :
402 : : if ( m_pHScroll->GetThumbPos() != m_nLeftColumn )
403 : : return "horizontal scroll bar |position| is incorrect!";
404 : : if ( m_pHScroll->GetRange().Max() != m_nColumnCount )
405 : : return "horizontal scroll bar |range| is incorrect!";
406 : : if ( m_pHScroll->GetVisibleSize() != impl_getVisibleColumns( false ) )
407 : : return "horizontal scroll bar |visible size| is incorrect!";
408 : : }
409 : :
410 : : return NULL;
411 : : }
412 : : #endif
413 : :
414 : : #define DBG_CHECK_ME() \
415 : : DBG_CHKTHIS( TableControl_Impl, TableControl_Impl_checkInvariants )
416 : :
417 : : //------------------------------------------------------------------------------------------------------------------
418 : 0 : TableControl_Impl::TableControl_Impl( TableControl& _rAntiImpl )
419 : : :m_rAntiImpl ( _rAntiImpl )
420 : 0 : ,m_pModel ( new EmptyTableModel )
421 : : ,m_pInputHandler ( )
422 : : ,m_nRowHeightPixel ( 15 )
423 : : ,m_nColHeaderHeightPixel( 0 )
424 : : ,m_nRowHeaderWidthPixel ( 0 )
425 : : ,m_nColumnCount ( 0 )
426 : : ,m_nRowCount ( 0 )
427 : : ,m_bColumnsFit ( true )
428 : : ,m_nCurColumn ( COL_INVALID )
429 : : ,m_nCurRow ( ROW_INVALID )
430 : : ,m_nLeftColumn ( 0 )
431 : : ,m_nTopRow ( 0 )
432 : : ,m_nCursorHidden ( 1 )
433 [ # # ]: 0 : ,m_pDataWindow ( new TableDataWindow( *this ) )
434 : : ,m_pVScroll ( NULL )
435 : : ,m_pHScroll ( NULL )
436 : : ,m_pScrollCorner ( NULL )
437 : : ,m_pSelEngine ( )
438 : : ,m_aSelectedRows ( )
439 [ # # ]: 0 : ,m_pTableFunctionSet ( new TableFunctionSet( this ) )
440 : : ,m_nAnchor ( -1 )
441 : : ,m_bUpdatingColWidths ( false )
442 [ # # ]: 0 : ,m_pAccessibleTable ( NULL )
[ # # # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
443 : : #if DBG_UTIL
444 : : ,m_nRequiredInvariants ( INV_SCROLL_POSITION )
445 : : #endif
446 : : {
447 : : DBG_CTOR( TableControl_Impl, TableControl_Impl_checkInvariants );
448 [ # # ][ # # ]: 0 : m_pSelEngine = new SelectionEngine( m_pDataWindow.get(), m_pTableFunctionSet );
449 [ # # ]: 0 : m_pSelEngine->SetSelectionMode(SINGLE_SELECTION);
450 [ # # ]: 0 : m_pDataWindow->SetPosPixel( Point( 0, 0 ) );
451 [ # # ]: 0 : m_pDataWindow->Show();
452 : 0 : }
453 : :
454 : : //------------------------------------------------------------------------------------------------------------------
455 [ # # ][ # # ]: 0 : TableControl_Impl::~TableControl_Impl()
[ # # ][ # # ]
[ # # ]
456 : : {
457 : : DBG_DTOR( TableControl_Impl, TableControl_Impl_checkInvariants );
458 : :
459 [ # # ][ # # ]: 0 : DELETEZ( m_pVScroll );
460 [ # # ][ # # ]: 0 : DELETEZ( m_pHScroll );
461 [ # # ][ # # ]: 0 : DELETEZ( m_pScrollCorner );
462 [ # # ][ # # ]: 0 : DELETEZ( m_pTableFunctionSet );
463 [ # # ][ # # ]: 0 : DELETEZ( m_pSelEngine );
464 [ # # ]: 0 : }
465 : :
466 : : //------------------------------------------------------------------------------------------------------------------
467 : 0 : void TableControl_Impl::setModel( PTableModel _pModel )
468 : : {
469 : : DBG_CHECK_ME();
470 : :
471 [ # # ]: 0 : SuppressCursor aHideCursor( *this );
472 : :
473 [ # # ]: 0 : if ( !!m_pModel )
474 [ # # ][ # # ]: 0 : m_pModel->removeTableModelListener( shared_from_this() );
[ # # ]
475 : :
476 [ # # ]: 0 : m_pModel = _pModel;
477 [ # # ]: 0 : if ( !m_pModel)
478 [ # # ][ # # ]: 0 : m_pModel.reset( new EmptyTableModel );
479 : :
480 [ # # ][ # # ]: 0 : m_pModel->addTableModelListener( shared_from_this() );
[ # # ]
481 : :
482 : 0 : m_nCurRow = ROW_INVALID;
483 : 0 : m_nCurColumn = COL_INVALID;
484 : :
485 : : // recalc some model-dependent cached info
486 [ # # ]: 0 : impl_ni_updateCachedModelValues();
487 [ # # ]: 0 : impl_ni_updateScrollbars();
488 : :
489 : : // completely invalidate
490 [ # # ]: 0 : m_rAntiImpl.Invalidate();
491 : :
492 : : // reset cursor to (0,0)
493 [ # # ]: 0 : if ( m_nRowCount ) m_nCurRow = 0;
494 [ # # ][ # # ]: 0 : if ( m_nColumnCount ) m_nCurColumn = 0;
495 : 0 : }
496 : :
497 : : //------------------------------------------------------------------------------------------------------------------
498 : : namespace
499 : : {
500 : 0 : bool lcl_adjustSelectedRows( ::std::vector< RowPos >& io_selectionIndexes, RowPos const i_firstAffectedRowIndex, TableSize const i_offset )
501 : : {
502 : 0 : bool didChanges = false;
503 [ # # # # ]: 0 : for ( ::std::vector< RowPos >::iterator selPos = io_selectionIndexes.begin();
[ # # ]
504 : 0 : selPos != io_selectionIndexes.end();
505 : : ++selPos
506 : : )
507 : : {
508 [ # # ][ # # ]: 0 : if ( *selPos < i_firstAffectedRowIndex )
509 : 0 : continue;
510 [ # # ]: 0 : *selPos += i_offset;
511 : 0 : didChanges = true;
512 : : }
513 : 0 : return didChanges;
514 : : }
515 : : }
516 : :
517 : : //------------------------------------------------------------------------------------------------------------------
518 : 0 : void TableControl_Impl::rowsInserted( RowPos i_first, RowPos i_last )
519 : : {
520 : : DBG_CHECK_ME();
521 : : OSL_PRECOND( i_last >= i_first, "TableControl_Impl::rowsInserted: invalid row indexes!" );
522 : :
523 : 0 : TableSize const insertedRows = i_last - i_first + 1;
524 : :
525 : : // adjust selection, if necessary
526 : 0 : bool const selectionChanged = lcl_adjustSelectedRows( m_aSelectedRows, i_first, insertedRows );
527 : :
528 : : // adjust our cached row count
529 : 0 : m_nRowCount = m_pModel->getRowCount();
530 : :
531 : : // if the rows have been inserted before the current row, adjust this
532 [ # # ]: 0 : if ( i_first <= m_nCurRow )
533 : 0 : goTo( m_nCurColumn, m_nCurRow + insertedRows );
534 : :
535 : : // adjust scrollbars
536 : 0 : impl_ni_updateScrollbars();
537 : :
538 : : // notify A1YY events
539 [ # # ]: 0 : if ( impl_isAccessibleAlive() )
540 : : {
541 : : impl_commitAccessibleEvent( AccessibleEventId::TABLE_MODEL_CHANGED,
542 [ # # ]: 0 : makeAny( AccessibleTableModelChange( AccessibleTableModelChangeType::INSERT, i_first, i_last, 0, m_pModel->getColumnCount() ) ),
543 : : Any()
544 [ # # ][ # # ]: 0 : );
545 : : impl_commitAccessibleEvent( AccessibleEventId::CHILD,
546 : 0 : makeAny( m_pAccessibleTable->getTableHeader( TCTYPE_ROWHEADERBAR ) ),
547 : : Any()
548 [ # # ][ # # ]: 0 : );
[ # # ]
549 : :
550 : : // for ( sal_Int32 i = 0 ; i <= m_pModel->getColumnCount(); ++i )
551 : : // {
552 : : // impl_commitAccessibleEvent(
553 : : // CHILD,
554 : : // makeAny( m_pAccessibleTable->getTable() ),
555 : : // Any());
556 : : // }
557 : : // Huh? What's that? We're notifying |columnCount| CHILD events here, claiming the *table* itself
558 : : // has been inserted. Doesn't make much sense, does it?
559 : : }
560 : :
561 : : // schedule repaint
562 : 0 : invalidateRowRange( i_first, ROW_INVALID );
563 : :
564 : : // call selection handlers, if necessary
565 [ # # ]: 0 : if ( selectionChanged )
566 : 0 : m_rAntiImpl.Select();
567 : 0 : }
568 : :
569 : : //------------------------------------------------------------------------------------------------------------------
570 : 0 : void TableControl_Impl::rowsRemoved( RowPos i_first, RowPos i_last )
571 : : {
572 : 0 : sal_Int32 firstRemovedRow = i_first;
573 : 0 : sal_Int32 lastRemovedRow = i_last;
574 : :
575 : : // adjust selection, if necessary
576 : 0 : bool selectionChanged = false;
577 [ # # ]: 0 : if ( i_first == -1 )
578 : : {
579 : 0 : selectionChanged = markAllRowsAsDeselected();
580 : :
581 : 0 : firstRemovedRow = 0;
582 : 0 : lastRemovedRow = m_nRowCount - 1;
583 : : }
584 : : else
585 : : {
586 [ # # ]: 0 : ENSURE_OR_RETURN_VOID( i_last >= i_first, "TableControl_Impl::rowsRemoved: illegal indexes!" );
587 : :
588 [ # # ]: 0 : for ( sal_Int32 row = i_first; row <= i_last; ++row )
589 : : {
590 [ # # ][ # # ]: 0 : if ( markRowAsDeselected( row ) )
591 : 0 : selectionChanged = true;
592 : : }
593 : :
594 [ # # ][ # # ]: 0 : if ( lcl_adjustSelectedRows( m_aSelectedRows, i_last + 1, i_first - i_last - 1 ) )
595 : 0 : selectionChanged = true;
596 : : }
597 : :
598 : : // adjust cached row count
599 [ # # ]: 0 : m_nRowCount = m_pModel->getRowCount();
600 : :
601 : : // adjust the current row, if it is larger than the row count now
602 [ # # ]: 0 : if ( m_nCurRow >= m_nRowCount )
603 : : {
604 [ # # ]: 0 : if ( m_nRowCount > 0 )
605 [ # # ]: 0 : goTo( m_nCurColumn, m_nRowCount - 1 );
606 : : else
607 : 0 : m_nCurRow = ROW_INVALID;
608 : : }
609 : :
610 : : // adjust scrollbars
611 [ # # ]: 0 : impl_ni_updateScrollbars();
612 : :
613 : : // notify A11Y events
614 [ # # ][ # # ]: 0 : if ( impl_isAccessibleAlive() )
615 : : {
616 : : impl_commitAccessibleEvent(
617 : : AccessibleEventId::TABLE_MODEL_CHANGED,
618 : : makeAny( AccessibleTableModelChange(
619 : : AccessibleTableModelChangeType::DELETE,
620 : : firstRemovedRow,
621 : : lastRemovedRow,
622 : : 0,
623 [ # # ]: 0 : m_pModel->getColumnCount()
624 : : ) ),
625 : : Any()
626 [ # # ][ # # ]: 0 : );
627 : : }
628 : :
629 : : // schedule a repaint
630 [ # # ]: 0 : invalidateRowRange( firstRemovedRow, ROW_INVALID );
631 : :
632 : : // call selection handlers, if necessary
633 [ # # ]: 0 : if ( selectionChanged )
634 [ # # ]: 0 : m_rAntiImpl.Select();
635 : : }
636 : :
637 : : //------------------------------------------------------------------------------------------------------------------
638 : 0 : void TableControl_Impl::columnInserted( ColPos const i_colIndex )
639 : : {
640 : 0 : m_nColumnCount = m_pModel->getColumnCount();
641 : 0 : impl_ni_updateColumnWidths();
642 : 0 : impl_ni_updateScrollbars();
643 : :
644 : 0 : m_rAntiImpl.Invalidate();
645 : :
646 : : OSL_UNUSED( i_colIndex );
647 : 0 : }
648 : :
649 : : //------------------------------------------------------------------------------------------------------------------
650 : 0 : void TableControl_Impl::columnRemoved( ColPos const i_colIndex )
651 : : {
652 : 0 : m_nColumnCount = m_pModel->getColumnCount();
653 : 0 : impl_ni_updateColumnWidths();
654 : 0 : impl_ni_updateScrollbars();
655 : :
656 : 0 : m_rAntiImpl.Invalidate();
657 : :
658 : : OSL_UNUSED( i_colIndex );
659 : 0 : }
660 : :
661 : : //------------------------------------------------------------------------------------------------------------------
662 : 0 : void TableControl_Impl::allColumnsRemoved()
663 : : {
664 : 0 : m_nColumnCount = m_pModel->getColumnCount();
665 : 0 : impl_ni_updateColumnWidths();
666 : 0 : impl_ni_updateScrollbars();
667 : :
668 : 0 : m_rAntiImpl.Invalidate();
669 : 0 : }
670 : :
671 : : //------------------------------------------------------------------------------------------------------------------
672 : 0 : void TableControl_Impl::cellsUpdated( ColPos const i_firstCol, ColPos i_lastCol, RowPos const i_firstRow, RowPos const i_lastRow )
673 : : {
674 : 0 : invalidateRowRange( i_firstRow, i_lastRow );
675 : :
676 : : OSL_UNUSED( i_firstCol );
677 : : OSL_UNUSED( i_lastCol );
678 : 0 : }
679 : :
680 : : //------------------------------------------------------------------------------------------------------------------
681 : 0 : void TableControl_Impl::tableMetricsChanged()
682 : : {
683 : 0 : long const oldRowHeaderWidthPixel = m_nRowHeaderWidthPixel;
684 : 0 : impl_ni_updateCachedTableMetrics();
685 [ # # ]: 0 : if ( oldRowHeaderWidthPixel != m_nRowHeaderWidthPixel )
686 : 0 : impl_ni_updateColumnWidths();
687 : 0 : impl_ni_updateScrollbars();
688 : 0 : m_rAntiImpl.Invalidate();
689 : 0 : }
690 : :
691 : : //------------------------------------------------------------------------------------------------------------------
692 : 0 : void TableControl_Impl::impl_invalidateColumn( ColPos const i_column )
693 : : {
694 : : DBG_CHECK_ME();
695 : :
696 [ # # ]: 0 : Rectangle const aAllCellsArea( impl_getAllVisibleCellsArea() );
697 : :
698 [ # # ]: 0 : const TableColumnGeometry aColumn( *this, aAllCellsArea, i_column );
699 [ # # ][ # # ]: 0 : if ( aColumn.isValid() )
700 [ # # ]: 0 : m_rAntiImpl.Invalidate( aColumn.getRect() );
701 : 0 : }
702 : :
703 : : //------------------------------------------------------------------------------------------------------------------
704 : 0 : void TableControl_Impl::columnChanged( ColPos const i_column, ColumnAttributeGroup const i_attributeGroup )
705 : : {
706 : 0 : ColumnAttributeGroup nGroup( i_attributeGroup );
707 [ # # ]: 0 : if ( nGroup & COL_ATTRS_APPEARANCE )
708 : : {
709 : 0 : impl_invalidateColumn( i_column );
710 : 0 : nGroup &= ~COL_ATTRS_APPEARANCE;
711 : : }
712 : :
713 [ # # ]: 0 : if ( nGroup & COL_ATTRS_WIDTH )
714 : : {
715 [ # # ]: 0 : if ( !m_bUpdatingColWidths )
716 : : {
717 : 0 : impl_ni_updateColumnWidths( i_column );
718 : 0 : invalidate( TableAreaAll );
719 : 0 : impl_ni_updateScrollbars();
720 : : }
721 : :
722 : 0 : nGroup &= ~COL_ATTRS_WIDTH;
723 : : }
724 : :
725 : : OSL_ENSURE( ( nGroup == COL_ATTRS_NONE ) || ( i_attributeGroup == COL_ATTRS_ALL ),
726 : : "TableControl_Impl::columnChanged: don't know how to handle this change!" );
727 : 0 : }
728 : :
729 : : //------------------------------------------------------------------------------------------------------------------
730 : 0 : Rectangle TableControl_Impl::impl_getAllVisibleCellsArea() const
731 : : {
732 : : DBG_CHECK_ME();
733 : :
734 [ # # ]: 0 : Rectangle aArea( Point( 0, 0 ), Size( 0, 0 ) );
735 : :
736 : : // determine the right-most border of the last column which is
737 : : // at least partially visible
738 : 0 : aArea.Right() = m_nRowHeaderWidthPixel;
739 [ # # ]: 0 : if ( !m_aColumnWidths.empty() )
740 : : {
741 : : // the number of pixels which are scrolled out of the left hand
742 : : // side of the window
743 [ # # ]: 0 : const long nScrolledOutLeft = m_nLeftColumn == 0 ? 0 : m_aColumnWidths[ m_nLeftColumn - 1 ].getEnd();
744 : :
745 : 0 : ColumnPositions::const_reverse_iterator loop = m_aColumnWidths.rbegin();
746 [ # # # # ]: 0 : do
[ # # ]
747 : : {
748 [ # # ]: 0 : aArea.Right() = loop->getEnd() - nScrolledOutLeft + m_nRowHeaderWidthPixel;
749 [ # # ]: 0 : ++loop;
750 : : }
751 [ # # ][ # # ]: 0 : while ( ( loop != m_aColumnWidths.rend() )
[ # # ]
752 [ # # ]: 0 : && ( loop->getEnd() - nScrolledOutLeft >= aArea.Right() )
753 : : );
754 : : }
755 : : // so far, aArea.Right() denotes the first pixel *after* the cell area
756 : 0 : --aArea.Right();
757 : :
758 : : // determine the last row which is at least partially visible
759 : 0 : aArea.Bottom() =
760 : : m_nColHeaderHeightPixel
761 : 0 : + impl_getVisibleRows( true ) * m_nRowHeightPixel
762 : 0 : - 1;
763 : :
764 : 0 : return aArea;
765 : : }
766 : :
767 : : //------------------------------------------------------------------------------------------------------------------
768 : 0 : Rectangle TableControl_Impl::impl_getAllVisibleDataCellArea() const
769 : : {
770 : : DBG_CHECK_ME();
771 : :
772 : 0 : Rectangle aArea( impl_getAllVisibleCellsArea() );
773 : 0 : aArea.Left() = m_nRowHeaderWidthPixel;
774 : 0 : aArea.Top() = m_nColHeaderHeightPixel;
775 : 0 : return aArea;
776 : : }
777 : :
778 : : //------------------------------------------------------------------------------------------------------------------
779 : 0 : void TableControl_Impl::impl_ni_updateCachedTableMetrics()
780 : : {
781 [ # # ][ # # ]: 0 : m_nRowHeightPixel = m_rAntiImpl.LogicToPixel( Size( 0, m_pModel->getRowHeight() ), MAP_APPFONT ).Height();
782 : :
783 : 0 : m_nColHeaderHeightPixel = 0;
784 [ # # ]: 0 : if ( m_pModel->hasColumnHeaders() )
785 [ # # ][ # # ]: 0 : m_nColHeaderHeightPixel = m_rAntiImpl.LogicToPixel( Size( 0, m_pModel->getColumnHeaderHeight() ), MAP_APPFONT ).Height();
786 : :
787 : 0 : m_nRowHeaderWidthPixel = 0;
788 [ # # ]: 0 : if ( m_pModel->hasRowHeaders() )
789 [ # # ][ # # ]: 0 : m_nRowHeaderWidthPixel = m_rAntiImpl.LogicToPixel( Size( m_pModel->getRowHeaderWidth(), 0 ), MAP_APPFONT).Width();
790 : 0 : }
791 : :
792 : : //------------------------------------------------------------------------------------------------------------------
793 : 0 : void TableControl_Impl::impl_ni_updateCachedModelValues()
794 : : {
795 : 0 : m_pInputHandler.reset();
796 : 0 : m_nColumnCount = m_nRowCount = 0;
797 : :
798 : 0 : impl_ni_updateCachedTableMetrics();
799 : 0 : impl_ni_updateColumnWidths();
800 : :
801 [ # # ]: 0 : m_pInputHandler = m_pModel->getInputHandler();
802 [ # # ]: 0 : if ( !m_pInputHandler )
803 [ # # ]: 0 : m_pInputHandler.reset( new DefaultInputHandler );
804 : :
805 : 0 : m_nColumnCount = m_pModel->getColumnCount();
806 : 0 : m_nRowCount = m_pModel->getRowCount();
807 : 0 : }
808 : :
809 : : //------------------------------------------------------------------------------------------------------------------
810 : 0 : void TableControl_Impl::impl_ni_updateColumnWidths( ColPos const i_assumeInflexibleColumnsUpToIncluding )
811 : : {
812 [ # # ]: 0 : ENSURE_OR_RETURN_VOID( !m_bUpdatingColWidths, "TableControl_Impl::impl_ni_updateColumnWidths: recursive call detected!" );
813 : :
814 [ # # ]: 0 : m_aColumnWidths.resize( 0 );
815 [ # # ]: 0 : if ( !m_pModel )
816 : : return;
817 : :
818 [ # # ]: 0 : const TableSize colCount = m_pModel->getColumnCount();
819 [ # # ]: 0 : if ( colCount == 0 )
820 : : return;
821 : :
822 : 0 : m_bUpdatingColWidths = true;
823 [ # # ]: 0 : const ::comphelper::FlagGuard aWidthUpdateFlag( m_bUpdatingColWidths );
824 : :
825 [ # # ]: 0 : m_aColumnWidths.reserve( colCount );
826 : :
827 : : // the available horizontal space
828 : 0 : long gridWidthPixel = m_rAntiImpl.GetOutputSizePixel().Width();
829 [ # # ][ # # ]: 0 : if ( m_pModel->hasRowHeaders() && ( gridWidthPixel != 0 ) )
[ # # ][ # # ]
830 : : {
831 : 0 : gridWidthPixel -= m_nRowHeaderWidthPixel;
832 : : }
833 [ # # ][ # # ]: 0 : if ( m_pModel->getVerticalScrollbarVisibility() != ScrollbarShowNever )
834 : : {
835 : 0 : long nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize();
836 : 0 : gridWidthPixel -= nScrollbarMetrics;
837 : : }
838 : :
839 : : // TODO: shouldn't we take the visibility of the vertical scroll bar into account here, too?
840 [ # # ][ # # ]: 0 : long const gridWidthAppFont = m_rAntiImpl.PixelToLogic( Size( gridWidthPixel, 0 ), MAP_APPFONT ).Width();
[ # # ]
841 : :
842 : : // determine the accumulated current width of all columns
843 [ # # ]: 0 : for ( ColPos col = 0; col < colCount; ++col )
844 : : {
845 [ # # ]: 0 : const PColumnModel pColumn = m_pModel->getColumnModel( col );
846 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( !!pColumn, "invalid column returned by the model!" );
[ # # ][ # # ]
847 : :
848 [ # # ]: 0 : }
849 : :
850 : : // collect some meta data for our columns:
851 : : // - their current (appt-font) metrics
852 : 0 : long accumulatedCurrentWidth = 0;
853 [ # # ]: 0 : ::std::vector< long > currentColWidths;
854 [ # # ]: 0 : currentColWidths.reserve( colCount );
855 : : // - their effective minimal and maximal width (app-font!)
856 : : typedef ::std::vector< ::std::pair< long, long > > ColumnLimits;
857 [ # # ]: 0 : ColumnLimits effectiveColumnLimits;
858 [ # # ]: 0 : effectiveColumnLimits.reserve( colCount );
859 : 0 : long accumulatedMinWidth = 0;
860 : 0 : long accumulatedMaxWidth = 0;
861 : : // - their relative flexibility
862 [ # # ]: 0 : ::std::vector< ::sal_Int32 > columnFlexibilities;
863 [ # # ]: 0 : columnFlexibilities.reserve( colCount );
864 : 0 : long flexibilityDenominator = 0;
865 [ # # ]: 0 : for ( ColPos col = 0; col < colCount; ++col )
866 : : {
867 [ # # ]: 0 : PColumnModel const pColumn = m_pModel->getColumnModel( col );
868 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( !!pColumn, "invalid column returned by the model!" );
[ # # ][ # # ]
869 : :
870 : : // current width
871 [ # # ]: 0 : TableMetrics const currentWidth = pColumn->getWidth();
872 [ # # ]: 0 : currentColWidths.push_back( currentWidth );
873 : :
874 : : // accumulated width
875 : 0 : accumulatedCurrentWidth += currentWidth;
876 : :
877 : : // flexibility
878 [ # # ]: 0 : ::sal_Int32 flexibility = pColumn->getFlexibility();
879 : : OSL_ENSURE( flexibility >= 0, "TableControl_Impl::impl_ni_updateColumnWidths: a column's flexibility should be non-negative." );
880 [ # # ][ # # ]: 0 : if ( ( flexibility < 0 ) // normalization
[ # # ][ # # ]
881 [ # # ]: 0 : || ( !pColumn->isResizable() ) // column not resizeable => no auto-resize
882 : : || ( col <= i_assumeInflexibleColumnsUpToIncluding ) // column shall be treated as inflexible => respec this
883 : : )
884 : 0 : flexibility = 0;
885 : :
886 : : // min/max width
887 : 0 : long effectiveMin = currentWidth, effectiveMax = currentWidth;
888 : : // if the column is not flexible, it will not be asked for min/max, but we assume the current width as limit then
889 [ # # ]: 0 : if ( flexibility > 0 )
890 : : {
891 [ # # ]: 0 : long const minWidth = pColumn->getMinWidth();
892 [ # # ]: 0 : if ( minWidth > 0 )
893 : 0 : effectiveMin = minWidth;
894 : : else
895 : 0 : effectiveMin = MIN_COLUMN_WIDTH_PIXEL;
896 : :
897 [ # # ]: 0 : long const maxWidth = pColumn->getMaxWidth();
898 : : OSL_ENSURE( minWidth <= maxWidth, "TableControl_Impl::impl_ni_updateColumnWidths: pretty undecided 'bout its width limits, this column!" );
899 [ # # ][ # # ]: 0 : if ( ( maxWidth > 0 ) && ( maxWidth >= minWidth ) )
900 : 0 : effectiveMax = maxWidth;
901 : : else
902 : 0 : effectiveMax = gridWidthAppFont; // TODO: any better guess here?
903 : :
904 [ # # ]: 0 : if ( effectiveMin == effectiveMax )
905 : : // if the min and the max are identical, this implies no flexibility at all
906 : 0 : flexibility = 0;
907 : : }
908 : :
909 [ # # ]: 0 : columnFlexibilities.push_back( flexibility );
910 : 0 : flexibilityDenominator += flexibility;
911 : :
912 [ # # ][ # # ]: 0 : effectiveColumnLimits.push_back( ::std::pair< long, long >( effectiveMin, effectiveMax ) );
913 : 0 : accumulatedMinWidth += effectiveMin;
914 : 0 : accumulatedMaxWidth += effectiveMax;
915 [ # # ]: 0 : }
916 : :
917 [ # # ]: 0 : ::std::vector< long > newWidths( currentColWidths );
918 [ # # ]: 0 : if ( flexibilityDenominator == 0 )
919 : : {
920 : : // no column is flexible => don't adjust anything
921 : : }
922 [ # # ]: 0 : else if ( gridWidthAppFont > accumulatedCurrentWidth )
923 : : { // we have space to give away ...
924 : 0 : long distributeAppFontUnits = gridWidthAppFont - accumulatedCurrentWidth;
925 [ # # ]: 0 : if ( gridWidthAppFont > accumulatedMaxWidth )
926 : : {
927 : : // ... but the column's maximal widths are still less than we have
928 : : // => set them all to max
929 [ # # ]: 0 : for ( size_t i = 0; i < size_t( colCount ); ++i )
930 : : {
931 [ # # ][ # # ]: 0 : newWidths[i] = effectiveColumnLimits[i].second;
932 : : }
933 : : }
934 : : else
935 : : {
936 : 0 : bool startOver = false;
937 [ # # ]: 0 : do
938 : : {
939 : 0 : startOver = false;
940 : : // distribute the remaining space amongst all columns with a positive flexibility
941 [ # # ][ # # ]: 0 : for ( size_t i=0; i<newWidths.size() && !startOver; ++i )
[ # # ]
942 : : {
943 [ # # ]: 0 : long const columnFlexibility = columnFlexibilities[i];
944 [ # # ]: 0 : if ( columnFlexibility == 0 )
945 : 0 : continue;
946 : :
947 [ # # ]: 0 : long newColWidth = currentColWidths[i] + columnFlexibility * distributeAppFontUnits / flexibilityDenominator;
948 : :
949 [ # # ][ # # ]: 0 : if ( newColWidth > effectiveColumnLimits[i].second )
950 : : { // that was too much, we hit the col's maximum
951 : : // set the new width to exactly this maximum
952 [ # # ]: 0 : newColWidth = effectiveColumnLimits[i].second;
953 : : // adjust the flexibility denominator ...
954 : 0 : flexibilityDenominator -= columnFlexibility;
955 [ # # ]: 0 : columnFlexibilities[i] = 0;
956 : : // ... and the remaining width ...
957 [ # # ]: 0 : long const difference = newColWidth - currentColWidths[i];
958 : 0 : distributeAppFontUnits -= difference;
959 : : // ... this way, we ensure that the width not taken up by this column is consumed by the other
960 : : // flexible ones (if there are some)
961 : :
962 : : // and start over with the first column, since there might be earlier columns which need
963 : : // to be recalculated now
964 : 0 : startOver = true;
965 : : }
966 : :
967 [ # # ]: 0 : newWidths[i] = newColWidth;
968 : : }
969 : : }
970 : : while ( startOver );
971 : : }
972 : : }
973 [ # # ]: 0 : else if ( gridWidthAppFont < accumulatedCurrentWidth )
974 : : { // we need to take away some space from the columns which allow it ...
975 : 0 : long takeAwayAppFontUnits = accumulatedCurrentWidth - gridWidthAppFont;
976 [ # # ]: 0 : if ( gridWidthAppFont < accumulatedMinWidth )
977 : : {
978 : : // ... but the column's minimal widths are still more than we have
979 : : // => set them all to min
980 [ # # ]: 0 : for ( size_t i = 0; i < size_t( colCount ); ++i )
981 : : {
982 [ # # ][ # # ]: 0 : newWidths[i] = effectiveColumnLimits[i].first;
983 : : }
984 : : }
985 : : else
986 : : {
987 : 0 : bool startOver = false;
988 [ # # ]: 0 : do
989 : : {
990 : 0 : startOver = false;
991 : : // take away the space we need from the columns with a positive flexibility
992 [ # # ][ # # ]: 0 : for ( size_t i=0; i<newWidths.size() && !startOver; ++i )
[ # # ]
993 : : {
994 [ # # ]: 0 : long const columnFlexibility = columnFlexibilities[i];
995 [ # # ]: 0 : if ( columnFlexibility == 0 )
996 : 0 : continue;
997 : :
998 [ # # ]: 0 : long newColWidth = currentColWidths[i] - columnFlexibility * takeAwayAppFontUnits / flexibilityDenominator;
999 : :
1000 [ # # ][ # # ]: 0 : if ( newColWidth < effectiveColumnLimits[i].first )
1001 : : { // that was too much, we hit the col's minimum
1002 : : // set the new width to exactly this minimum
1003 [ # # ]: 0 : newColWidth = effectiveColumnLimits[i].first;
1004 : : // adjust the flexibility denominator ...
1005 : 0 : flexibilityDenominator -= columnFlexibility;
1006 [ # # ]: 0 : columnFlexibilities[i] = 0;
1007 : : // ... and the remaining width ...
1008 [ # # ]: 0 : long const difference = currentColWidths[i] - newColWidth;
1009 : 0 : takeAwayAppFontUnits -= difference;
1010 : :
1011 : : // and start over with the first column, since there might be earlier columns which need
1012 : : // to be recalculated now
1013 : 0 : startOver = true;
1014 : : }
1015 : :
1016 [ # # ]: 0 : newWidths[i] = newColWidth;
1017 : : }
1018 : : }
1019 : : while ( startOver );
1020 : : }
1021 : : }
1022 : :
1023 : : // now that we have calculated the app-font widths, get the actual pixels
1024 : 0 : long accumulatedWidthPixel = m_nRowHeaderWidthPixel;
1025 [ # # ]: 0 : for ( ColPos col = 0; col < colCount; ++col )
1026 : : {
1027 [ # # ][ # # ]: 0 : long const colWidth = m_rAntiImpl.LogicToPixel( Size( newWidths[col], 0 ), MAP_APPFONT ).Width();
[ # # ][ # # ]
1028 : 0 : const long columnStart = accumulatedWidthPixel;
1029 : 0 : const long columnEnd = columnStart + colWidth;
1030 [ # # ]: 0 : m_aColumnWidths.push_back( MutableColumnMetrics( columnStart, columnEnd ) );
1031 : 0 : accumulatedWidthPixel = columnEnd;
1032 : :
1033 : : // and don't forget to forward this to the column models
1034 [ # # ]: 0 : PColumnModel const pColumn = m_pModel->getColumnModel( col );
1035 [ # # ][ # # ]: 0 : ENSURE_OR_THROW( !!pColumn, "invalid column returned by the model!" );
[ # # ][ # # ]
1036 [ # # ][ # # ]: 0 : pColumn->setWidth( newWidths[col] );
1037 [ # # ]: 0 : }
1038 : :
1039 : : // if the column resizing happened to leave some space at the right, but there are columns
1040 : : // scrolled out to the left, scroll them in
1041 [ # # # # ]: 0 : while ( ( m_nLeftColumn > 0 )
[ # # ]
1042 : 0 : && ( accumulatedWidthPixel - m_aColumnWidths[ m_nLeftColumn - 1 ].getStart() <= gridWidthPixel )
1043 : : )
1044 : : {
1045 : 0 : --m_nLeftColumn;
1046 : : }
1047 : :
1048 : : // now adjust the column metrics, since they currently ignore the horizontal scroll position
1049 [ # # ]: 0 : if ( m_nLeftColumn > 0 )
1050 : : {
1051 : 0 : const long offsetPixel = m_aColumnWidths[ 0 ].getStart() - m_aColumnWidths[ m_nLeftColumn ].getStart();
1052 [ # # ][ # # ]: 0 : for ( ColumnPositions::iterator colPos = m_aColumnWidths.begin();
1053 : 0 : colPos != m_aColumnWidths.end();
1054 : : ++colPos
1055 : : )
1056 : : {
1057 : 0 : colPos->move( offsetPixel );
1058 : : }
1059 [ # # ]: 0 : }
1060 : : }
1061 : :
1062 : : //------------------------------------------------------------------------------------------------------------------
1063 : : namespace
1064 : : {
1065 : : //..............................................................................................................
1066 : : /// determines whether a scrollbar is needed for the given values
1067 : 0 : bool lcl_determineScrollbarNeed( long const i_position, ScrollbarVisibility const i_visibility,
1068 : : long const i_availableSpace, long const i_neededSpace )
1069 : : {
1070 [ # # ]: 0 : if ( i_visibility == ScrollbarShowNever )
1071 : 0 : return false;
1072 [ # # ]: 0 : if ( i_visibility == ScrollbarShowAlways )
1073 : 0 : return true;
1074 [ # # ]: 0 : if ( i_position > 0 )
1075 : 0 : return true;
1076 [ # # ]: 0 : if ( i_availableSpace >= i_neededSpace )
1077 : 0 : return false;
1078 : 0 : return true;
1079 : : }
1080 : :
1081 : : //..............................................................................................................
1082 : 0 : void lcl_setButtonRepeat( Window& _rWindow, sal_uLong _nDelay )
1083 : : {
1084 [ # # ]: 0 : AllSettings aSettings = _rWindow.GetSettings();
1085 [ # # ]: 0 : MouseSettings aMouseSettings = aSettings.GetMouseSettings();
1086 : :
1087 [ # # ]: 0 : aMouseSettings.SetButtonRepeat( _nDelay );
1088 [ # # ]: 0 : aSettings.SetMouseSettings( aMouseSettings );
1089 : :
1090 [ # # ][ # # ]: 0 : _rWindow.SetSettings( aSettings, sal_True );
[ # # ]
1091 : 0 : }
1092 : :
1093 : : //..............................................................................................................
1094 : 0 : void lcl_updateScrollbar( Window& _rParent, ScrollBar*& _rpBar,
1095 : : bool const i_needBar, long _nVisibleUnits,
1096 : : long _nPosition, long _nLineSize, long _nRange,
1097 : : bool _bHorizontal, const Link& _rScrollHandler )
1098 : : {
1099 : : // do we currently have the scrollbar?
1100 : 0 : bool bHaveBar = _rpBar != NULL;
1101 : :
1102 : : // do we need to correct the scrollbar visibility?
1103 [ # # ][ # # ]: 0 : if ( bHaveBar && !i_needBar )
1104 : : {
1105 [ # # ]: 0 : if ( _rpBar->IsTracking() )
1106 : 0 : _rpBar->EndTracking();
1107 [ # # ]: 0 : DELETEZ( _rpBar );
1108 : : }
1109 [ # # ][ # # ]: 0 : else if ( !bHaveBar && i_needBar )
1110 : : {
1111 : : _rpBar = new ScrollBar(
1112 : : &_rParent,
1113 : : WB_DRAG | ( _bHorizontal ? WB_HSCROLL : WB_VSCROLL )
1114 [ # # ][ # # ]: 0 : );
1115 : 0 : _rpBar->SetScrollHdl( _rScrollHandler );
1116 : : // get some speed into the scrolling ....
1117 : 0 : lcl_setButtonRepeat( *_rpBar, 0 );
1118 : : }
1119 : :
1120 [ # # ]: 0 : if ( _rpBar )
1121 : : {
1122 [ # # ]: 0 : _rpBar->SetRange( Range( 0, _nRange ) );
1123 : 0 : _rpBar->SetVisibleSize( _nVisibleUnits );
1124 : 0 : _rpBar->SetPageSize( _nVisibleUnits );
1125 : 0 : _rpBar->SetLineSize( _nLineSize );
1126 : 0 : _rpBar->SetThumbPos( _nPosition );
1127 : 0 : _rpBar->Show();
1128 : : }
1129 : 0 : }
1130 : :
1131 : : //..............................................................................................................
1132 : : /** returns the number of rows fitting into the given range,
1133 : : for the given row height. Partially fitting rows are counted, too, if the
1134 : : respective parameter says so.
1135 : : */
1136 : 0 : TableSize lcl_getRowsFittingInto( long _nOverallHeight, long _nRowHeightPixel, bool _bAcceptPartialRow = false )
1137 : : {
1138 : : return _bAcceptPartialRow
1139 : : ? ( _nOverallHeight + ( _nRowHeightPixel - 1 ) ) / _nRowHeightPixel
1140 [ # # ]: 0 : : _nOverallHeight / _nRowHeightPixel;
1141 : : }
1142 : :
1143 : : //..............................................................................................................
1144 : : /** returns the number of columns fitting into the given area,
1145 : : with the first visible column as given. Partially fitting columns are counted, too,
1146 : : if the respective parameter says so.
1147 : : */
1148 : 0 : TableSize lcl_getColumnsVisibleWithin( const Rectangle& _rArea, ColPos _nFirstVisibleColumn,
1149 : : const TableControl_Impl& _rControl, bool _bAcceptPartialRow )
1150 : : {
1151 : 0 : TableSize visibleColumns = 0;
1152 [ # # ]: 0 : TableColumnGeometry aColumn( _rControl, _rArea, _nFirstVisibleColumn );
1153 [ # # ][ # # ]: 0 : while ( aColumn.isValid() )
1154 : : {
1155 [ # # ]: 0 : if ( !_bAcceptPartialRow )
1156 [ # # ]: 0 : if ( aColumn.getRect().Right() > _rArea.Right() )
1157 : : // this column is only partially visible, and this is not allowed
1158 : 0 : break;
1159 : :
1160 [ # # ]: 0 : aColumn.moveRight();
1161 : 0 : ++visibleColumns;
1162 : : }
1163 : 0 : return visibleColumns;
1164 : : }
1165 : :
1166 : : }
1167 : :
1168 : : //------------------------------------------------------------------------------------------------------------------
1169 : 0 : void TableControl_Impl::impl_ni_updateScrollbars()
1170 : : {
1171 [ # # ]: 0 : SuppressCursor aHideCursor( *this );
1172 : :
1173 : : // the width/height of a scrollbar, needed several times below
1174 : 0 : long const nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize();
1175 : :
1176 : : // determine the playground for the data cells (excluding headers)
1177 : : // TODO: what if the control is smaller than needed for the headers/scrollbars?
1178 [ # # ]: 0 : Rectangle aDataCellPlayground( Point( 0, 0 ), m_rAntiImpl.GetOutputSizePixel() );
1179 : 0 : aDataCellPlayground.Left() = m_nRowHeaderWidthPixel;
1180 : 0 : aDataCellPlayground.Top() = m_nColHeaderHeightPixel;
1181 [ # # ]: 0 : m_nRowCount = m_pModel->getRowCount();
1182 [ # # ]: 0 : m_nColumnCount = m_pModel->getColumnCount();
1183 : :
1184 [ # # ]: 0 : if ( m_aColumnWidths.empty() )
1185 [ # # ]: 0 : impl_ni_updateColumnWidths();
1186 : : OSL_ENSURE( m_aColumnWidths.size() == size_t( m_nColumnCount ), "TableControl_Impl::impl_ni_updateScrollbars: inconsistency!" );
1187 : 0 : const long nAllColumnsWidth = m_aColumnWidths.empty()
1188 : : ? 0
1189 [ # # ]: 0 : : m_aColumnWidths[ m_nColumnCount - 1 ].getEnd() - m_aColumnWidths[ 0 ].getStart();
1190 : :
1191 [ # # ]: 0 : const ScrollbarVisibility eVertScrollbar = m_pModel->getVerticalScrollbarVisibility();
1192 [ # # ]: 0 : const ScrollbarVisibility eHorzScrollbar = m_pModel->getHorizontalScrollbarVisibility();
1193 : :
1194 : : // do we need a vertical scrollbar?
1195 : : bool bNeedVerticalScrollbar = lcl_determineScrollbarNeed(
1196 [ # # ]: 0 : m_nTopRow, eVertScrollbar, aDataCellPlayground.GetHeight(), m_nRowHeightPixel * m_nRowCount );
1197 : 0 : bool bFirstRoundVScrollNeed = false;
1198 [ # # ]: 0 : if ( bNeedVerticalScrollbar )
1199 : : {
1200 : 0 : aDataCellPlayground.Right() -= nScrollbarMetrics;
1201 : 0 : bFirstRoundVScrollNeed = true;
1202 : : }
1203 : : // do we need a horizontal scrollbar?
1204 [ # # ]: 0 : const bool bNeedHorizontalScrollbar = lcl_determineScrollbarNeed( m_nLeftColumn, eHorzScrollbar, aDataCellPlayground.GetWidth(), nAllColumnsWidth );
1205 [ # # ]: 0 : if ( bNeedHorizontalScrollbar )
1206 : : {
1207 : 0 : aDataCellPlayground.Bottom() -= nScrollbarMetrics;
1208 : :
1209 : : // now that we just found that we need a horizontal scrollbar,
1210 : : // the need for a vertical one may have changed, since the horizontal
1211 : : // SB might just occupy enough space so that not all rows do fit
1212 : : // anymore
1213 [ # # ]: 0 : if ( !bFirstRoundVScrollNeed )
1214 : : {
1215 : : bNeedVerticalScrollbar = lcl_determineScrollbarNeed(
1216 [ # # ]: 0 : m_nTopRow, eVertScrollbar, aDataCellPlayground.GetHeight(), m_nRowHeightPixel * m_nRowCount );
1217 [ # # ]: 0 : if ( bNeedVerticalScrollbar )
1218 : : {
1219 : 0 : aDataCellPlayground.Right() -= nScrollbarMetrics;
1220 : : }
1221 : : }
1222 : : }
1223 : : // create or destroy the vertical scrollbar, as needed
1224 : : lcl_updateScrollbar(
1225 : : m_rAntiImpl,
1226 : : m_pVScroll,
1227 : : bNeedVerticalScrollbar,
1228 : : lcl_getRowsFittingInto( aDataCellPlayground.GetHeight(), m_nRowHeightPixel ),
1229 : : // visible units
1230 : : m_nTopRow, // current position
1231 : : 1, // line size
1232 : : m_nRowCount, // range
1233 : : false, // vertical
1234 : : LINK( this, TableControl_Impl, OnScroll ) // scroll handler
1235 [ # # ][ # # ]: 0 : );
[ # # ]
1236 : : // position it
1237 [ # # ]: 0 : if ( m_pVScroll )
1238 : : {
1239 : : Rectangle aScrollbarArea(
1240 : 0 : Point( aDataCellPlayground.Right() + 1, 0 ),
1241 : 0 : Size( nScrollbarMetrics, aDataCellPlayground.Bottom() + 1 )
1242 [ # # ]: 0 : );
1243 : : m_pVScroll->SetPosSizePixel(
1244 [ # # ][ # # ]: 0 : aScrollbarArea.TopLeft(), aScrollbarArea.GetSize() );
1245 : : }
1246 : :
1247 : : // create or destroy the horizontal scrollbar, as needed
1248 : : lcl_updateScrollbar(
1249 : : m_rAntiImpl,
1250 : : m_pHScroll,
1251 : : bNeedHorizontalScrollbar,
1252 : : lcl_getColumnsVisibleWithin( aDataCellPlayground, m_nLeftColumn, *this, false ),
1253 : : // visible units
1254 : : m_nLeftColumn, // current position
1255 : : 1, // line size
1256 : : m_nColumnCount, // range
1257 : : true, // horizontal
1258 : : LINK( this, TableControl_Impl, OnScroll ) // scroll handler
1259 [ # # ][ # # ]: 0 : );
[ # # ]
1260 : : // position it
1261 [ # # ]: 0 : if ( m_pHScroll )
1262 : : {
1263 [ # # ]: 0 : TableSize const nVisibleUnits = lcl_getColumnsVisibleWithin( aDataCellPlayground, m_nLeftColumn, *this, false );
1264 : 0 : TableMetrics const nRange = m_nColumnCount;
1265 [ # # ]: 0 : if( m_nLeftColumn + nVisibleUnits == nRange - 1 )
1266 : : {
1267 [ # # ][ # # ]: 0 : if ( m_aColumnWidths[ nRange - 1 ].getStart() - m_aColumnWidths[ m_nLeftColumn ].getEnd() + m_aColumnWidths[ nRange-1 ].getWidth() > aDataCellPlayground.GetWidth() )
1268 : : {
1269 [ # # ]: 0 : m_pHScroll->SetVisibleSize( nVisibleUnits -1 );
1270 : 0 : m_pHScroll->SetPageSize( nVisibleUnits - 1 );
1271 : : }
1272 : : }
1273 : : Rectangle aScrollbarArea(
1274 : 0 : Point( 0, aDataCellPlayground.Bottom() + 1 ),
1275 : 0 : Size( aDataCellPlayground.Right() + 1, nScrollbarMetrics )
1276 [ # # ]: 0 : );
1277 : : m_pHScroll->SetPosSizePixel(
1278 [ # # ][ # # ]: 0 : aScrollbarArea.TopLeft(), aScrollbarArea.GetSize() );
1279 : : }
1280 : :
1281 : : // the corner window connecting the two scrollbars in the lower right corner
1282 : 0 : bool bHaveScrollCorner = NULL != m_pScrollCorner;
1283 [ # # ][ # # ]: 0 : bool bNeedScrollCorner = ( NULL != m_pHScroll ) && ( NULL != m_pVScroll );
1284 [ # # ][ # # ]: 0 : if ( bHaveScrollCorner && !bNeedScrollCorner )
1285 : : {
1286 [ # # ][ # # ]: 0 : DELETEZ( m_pScrollCorner );
1287 : : }
1288 [ # # ][ # # ]: 0 : else if ( !bHaveScrollCorner && bNeedScrollCorner )
1289 : : {
1290 [ # # ][ # # ]: 0 : m_pScrollCorner = new ScrollBarBox( &m_rAntiImpl );
1291 [ # # ]: 0 : m_pScrollCorner->SetSizePixel( Size( nScrollbarMetrics, nScrollbarMetrics ) );
1292 [ # # ]: 0 : m_pScrollCorner->SetPosPixel( Point( aDataCellPlayground.Right() + 1, aDataCellPlayground.Bottom() + 1 ) );
1293 [ # # ]: 0 : m_pScrollCorner->Show();
1294 : : }
1295 [ # # ][ # # ]: 0 : else if(bHaveScrollCorner && bNeedScrollCorner)
1296 : : {
1297 [ # # ]: 0 : m_pScrollCorner->SetPosPixel( Point( aDataCellPlayground.Right() + 1, aDataCellPlayground.Bottom() + 1 ) );
1298 [ # # ]: 0 : m_pScrollCorner->Show();
1299 : : }
1300 : :
1301 : : // resize the data window
1302 : 0 : m_pDataWindow->SetSizePixel( Size(
1303 [ # # ]: 0 : aDataCellPlayground.GetWidth() + m_nRowHeaderWidthPixel,
1304 [ # # ]: 0 : aDataCellPlayground.GetHeight() + m_nColHeaderHeightPixel
1305 [ # # ][ # # ]: 0 : ) );
1306 : 0 : }
1307 : :
1308 : : //------------------------------------------------------------------------------------------------------------------
1309 : 0 : void TableControl_Impl::onResize()
1310 : : {
1311 : : DBG_CHECK_ME();
1312 : :
1313 : 0 : impl_ni_updateColumnWidths();
1314 : 0 : impl_ni_updateScrollbars();
1315 : 0 : checkCursorPosition();
1316 : 0 : }
1317 : :
1318 : : //------------------------------------------------------------------------------------------------------------------
1319 : 0 : void TableControl_Impl::doPaintContent( const Rectangle& _rUpdateRect )
1320 : : {
1321 : : DBG_CHECK_ME();
1322 : :
1323 [ # # ][ # # ]: 0 : if ( !getModel() )
[ # # ]
1324 : : return;
1325 [ # # ][ # # ]: 0 : PTableRenderer pRenderer = getModel()->getRenderer();
[ # # ]
1326 : : DBG_ASSERT( !!pRenderer, "TableDataWindow::doPaintContent: invalid renderer!" );
1327 [ # # ]: 0 : if ( !pRenderer )
1328 : : return;
1329 : :
1330 : : // our current style settings, to be passed to the renderer
1331 : 0 : const StyleSettings& rStyle = m_rAntiImpl.GetSettings().GetStyleSettings();
1332 [ # # ]: 0 : m_nRowCount = m_pModel->getRowCount();
1333 : : // the area occupied by all (at least partially) visible cells, including
1334 : : // headers
1335 [ # # ]: 0 : Rectangle const aAllCellsWithHeaders( impl_getAllVisibleCellsArea() );
1336 : :
1337 : : // ............................
1338 : : // draw the header column area
1339 [ # # ][ # # ]: 0 : if ( m_pModel->hasColumnHeaders() )
1340 : : {
1341 : : TableRowGeometry const aHeaderRow( *this, Rectangle( Point( 0, 0 ),
1342 [ # # ][ # # ]: 0 : aAllCellsWithHeaders.BottomRight() ), ROW_COL_HEADERS );
[ # # ]
1343 : 0 : Rectangle const aColRect(aHeaderRow.getRect());
1344 : 0 : pRenderer->PaintHeaderArea(
1345 : 0 : *m_pDataWindow, aColRect, true, false, rStyle
1346 [ # # ]: 0 : );
1347 : : // Note that strictly, aHeaderRow.getRect() also contains the intersection between column
1348 : : // and row header area. However, below we go to paint this intersection, again,
1349 : : // so this hopefully doesn't hurt if we already paint it here.
1350 : :
1351 [ # # ][ # # ]: 0 : for ( TableCellGeometry aCell( aHeaderRow, m_nLeftColumn );
[ # # ][ # # ]
1352 : : aCell.isValid();
1353 : : aCell.moveRight()
1354 : : )
1355 : : {
1356 [ # # ][ # # ]: 0 : if ( _rUpdateRect.GetIntersection( aCell.getRect() ).IsEmpty() )
[ # # ][ # # ]
1357 : 0 : continue;
1358 : :
1359 [ # # ]: 0 : bool isActiveColumn = ( aCell.getColumn() == getCurrentColumn() );
1360 : 0 : bool isSelectedColumn = false;
1361 : 0 : pRenderer->PaintColumnHeader( aCell.getColumn(), isActiveColumn, isSelectedColumn,
1362 [ # # ][ # # ]: 0 : *m_pDataWindow, aCell.getRect(), rStyle );
1363 : : }
1364 : : }
1365 : : // the area occupied by the row header, if any
1366 [ # # ]: 0 : Rectangle aRowHeaderArea;
1367 [ # # ][ # # ]: 0 : if ( m_pModel->hasRowHeaders() )
1368 : : {
1369 : 0 : aRowHeaderArea = aAllCellsWithHeaders;
1370 : 0 : aRowHeaderArea.Right() = m_nRowHeaderWidthPixel - 1;
1371 : :
1372 [ # # ]: 0 : TableSize const nVisibleRows = impl_getVisibleRows( true );
1373 : 0 : TableSize nActualRows = nVisibleRows;
1374 [ # # ]: 0 : if ( m_nTopRow + nActualRows > m_nRowCount )
1375 : 0 : nActualRows = m_nRowCount - m_nTopRow;
1376 : 0 : aRowHeaderArea.Bottom() = m_nColHeaderHeightPixel + m_nRowHeightPixel * nActualRows - 1;
1377 : :
1378 [ # # ]: 0 : pRenderer->PaintHeaderArea( *m_pDataWindow, aRowHeaderArea, false, true, rStyle );
1379 : : // Note that strictly, aRowHeaderArea also contains the intersection between column
1380 : : // and row header area. However, below we go to paint this intersection, again,
1381 : : // so this hopefully doesn't hurt if we already paint it here.
1382 : :
1383 [ # # ][ # # ]: 0 : if ( m_pModel->hasColumnHeaders() )
1384 : : {
1385 : : TableCellGeometry const aIntersection( *this, Rectangle( Point( 0, 0 ),
1386 [ # # ][ # # ]: 0 : aAllCellsWithHeaders.BottomRight() ), COL_ROW_HEADERS, ROW_COL_HEADERS );
[ # # ]
1387 [ # # ]: 0 : Rectangle const aInters( aIntersection.getRect() );
1388 : 0 : pRenderer->PaintHeaderArea(
1389 : 0 : *m_pDataWindow, aInters, true, true, rStyle
1390 [ # # ]: 0 : );
1391 : : }
1392 : : }
1393 : :
1394 : : // ............................
1395 : : // draw the table content row by row
1396 : :
1397 [ # # ][ # # ]: 0 : TableSize colCount = getModel()->getColumnCount();
[ # # ]
1398 : :
1399 : : // paint all rows
1400 [ # # ]: 0 : Rectangle const aAllDataCellsArea( impl_getAllVisibleDataCellArea() );
1401 [ # # ][ # # ]: 0 : for ( TableRowGeometry aRowIterator( *this, aAllCellsWithHeaders, getTopRow() );
[ # # ][ # # ]
1402 : : aRowIterator.isValid();
1403 : : aRowIterator.moveDown() )
1404 : : {
1405 [ # # ][ # # ]: 0 : if ( _rUpdateRect.GetIntersection( aRowIterator.getRect() ).IsEmpty() )
[ # # ]
1406 : 0 : continue;
1407 : :
1408 [ # # ]: 0 : bool const isActiveRow = ( aRowIterator.getRow() == getCurrentRow() );
1409 [ # # ]: 0 : bool const isSelectedRow = isRowSelected( aRowIterator.getRow() );
1410 : :
1411 [ # # ]: 0 : Rectangle const aRect = aRowIterator.getRect().GetIntersection( aAllDataCellsArea );
1412 : :
1413 : : // give the redenderer a chance to prepare the row
1414 : 0 : pRenderer->PrepareRow(
1415 : : aRowIterator.getRow(), isActiveRow, isSelectedRow,
1416 : 0 : *m_pDataWindow, aRect, rStyle
1417 [ # # ]: 0 : );
1418 : :
1419 : : // paint the row header
1420 [ # # ][ # # ]: 0 : if ( m_pModel->hasRowHeaders() )
1421 : : {
1422 [ # # ]: 0 : const Rectangle aCurrentRowHeader( aRowHeaderArea.GetIntersection( aRowIterator.getRect() ) );
1423 : 0 : pRenderer->PaintRowHeader( isActiveRow, isSelectedRow, *m_pDataWindow, aCurrentRowHeader,
1424 [ # # ]: 0 : rStyle );
1425 : : }
1426 : :
1427 [ # # ]: 0 : if ( !colCount )
1428 : 0 : continue;
1429 : :
1430 : : // paint all cells in this row
1431 [ # # ][ # # ]: 0 : for ( TableCellGeometry aCell( aRowIterator, m_nLeftColumn );
[ # # ][ # # ]
1432 : : aCell.isValid();
1433 : : aCell.moveRight()
1434 : : )
1435 : : {
1436 : 0 : bool isSelectedColumn = false;
1437 : 0 : pRenderer->PaintCell( aCell.getColumn(), isSelectedRow || isSelectedColumn, isActiveRow,
1438 [ # # ][ # # ]: 0 : *m_pDataWindow, aCell.getRect(), rStyle );
[ # # ][ # # ]
1439 : : }
1440 [ # # ][ # # ]: 0 : }
1441 : : }
1442 : : //------------------------------------------------------------------------------------------------------------------
1443 : 0 : void TableControl_Impl::hideCursor()
1444 : : {
1445 : : DBG_CHECK_ME();
1446 : :
1447 [ # # ]: 0 : if ( ++m_nCursorHidden == 1 )
1448 : 0 : impl_ni_doSwitchCursor( false );
1449 : 0 : }
1450 : :
1451 : : //------------------------------------------------------------------------------------------------------------------
1452 : 0 : void TableControl_Impl::showCursor()
1453 : : {
1454 : : DBG_CHECK_ME();
1455 : :
1456 : : DBG_ASSERT( m_nCursorHidden > 0, "TableControl_Impl::showCursor: cursor not hidden!" );
1457 [ # # ]: 0 : if ( --m_nCursorHidden == 0 )
1458 : 0 : impl_ni_doSwitchCursor( true );
1459 : 0 : }
1460 : :
1461 : : //------------------------------------------------------------------------------------------------------------------
1462 : 0 : bool TableControl_Impl::dispatchAction( TableControlAction _eAction )
1463 : : {
1464 : : DBG_CHECK_ME();
1465 : :
1466 : 0 : bool bSuccess = false;
1467 : 0 : bool selectionChanged = false;
1468 : :
1469 [ # # ]: 0 : Rectangle rCells;
1470 [ # # # # : 0 : switch ( _eAction )
# # # # #
# # # # #
# # # # ]
1471 : : {
1472 : : case cursorDown:
1473 [ # # ]: 0 : if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
1474 : : {
1475 : : //if other rows already selected, deselect them
1476 [ # # ]: 0 : if(!m_aSelectedRows.empty())
1477 : : {
1478 [ # # # # ]: 0 : for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin();
[ # # ]
1479 : 0 : it!=m_aSelectedRows.end();++it)
1480 : : {
1481 [ # # ][ # # ]: 0 : invalidateSelectedRegion(*it, *it, rCells);
[ # # ]
1482 : : }
1483 : 0 : m_aSelectedRows.clear();
1484 : : }
1485 [ # # ]: 0 : if(m_nCurRow < m_nRowCount-1)
1486 : : {
1487 : 0 : ++m_nCurRow;
1488 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1489 : : }
1490 : : else
1491 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1492 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1493 [ # # ]: 0 : ensureVisible(m_nCurColumn,m_nCurRow,false);
1494 : 0 : selectionChanged = true;
1495 : 0 : bSuccess = true;
1496 : : }
1497 : : else
1498 : : {
1499 [ # # ]: 0 : if ( m_nCurRow < m_nRowCount - 1 )
1500 [ # # ]: 0 : bSuccess = goTo( m_nCurColumn, m_nCurRow + 1 );
1501 : : }
1502 : 0 : break;
1503 : :
1504 : : case cursorUp:
1505 [ # # ]: 0 : if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
1506 : : {
1507 [ # # ]: 0 : if(!m_aSelectedRows.empty())
1508 : : {
1509 [ # # # # ]: 0 : for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin();
[ # # ]
1510 : 0 : it!=m_aSelectedRows.end();++it)
1511 : : {
1512 [ # # ][ # # ]: 0 : invalidateSelectedRegion(*it, *it, rCells);
[ # # ]
1513 : : }
1514 : 0 : m_aSelectedRows.clear();
1515 : : }
1516 [ # # ]: 0 : if(m_nCurRow>0)
1517 : : {
1518 : 0 : --m_nCurRow;
1519 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1520 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1521 : : }
1522 : : else
1523 : : {
1524 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1525 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1526 : : }
1527 [ # # ]: 0 : ensureVisible(m_nCurColumn,m_nCurRow,false);
1528 : 0 : selectionChanged = true;
1529 : 0 : bSuccess = true;
1530 : : }
1531 : : else
1532 : : {
1533 [ # # ]: 0 : if ( m_nCurRow > 0 )
1534 [ # # ]: 0 : bSuccess = goTo( m_nCurColumn, m_nCurRow - 1 );
1535 : : }
1536 : 0 : break;
1537 : : case cursorLeft:
1538 [ # # ]: 0 : if ( m_nCurColumn > 0 )
1539 [ # # ]: 0 : bSuccess = goTo( m_nCurColumn - 1, m_nCurRow );
1540 : : else
1541 [ # # ][ # # ]: 0 : if ( ( m_nCurColumn == 0) && ( m_nCurRow > 0 ) )
1542 [ # # ]: 0 : bSuccess = goTo( m_nColumnCount - 1, m_nCurRow - 1 );
1543 : 0 : break;
1544 : :
1545 : : case cursorRight:
1546 [ # # ]: 0 : if ( m_nCurColumn < m_nColumnCount - 1 )
1547 [ # # ]: 0 : bSuccess = goTo( m_nCurColumn + 1, m_nCurRow );
1548 : : else
1549 [ # # ][ # # ]: 0 : if ( ( m_nCurColumn == m_nColumnCount - 1 ) && ( m_nCurRow < m_nRowCount - 1 ) )
1550 [ # # ]: 0 : bSuccess = goTo( 0, m_nCurRow + 1 );
1551 : 0 : break;
1552 : :
1553 : : case cursorToLineStart:
1554 [ # # ]: 0 : bSuccess = goTo( 0, m_nCurRow );
1555 : 0 : break;
1556 : :
1557 : : case cursorToLineEnd:
1558 [ # # ]: 0 : bSuccess = goTo( m_nColumnCount - 1, m_nCurRow );
1559 : 0 : break;
1560 : :
1561 : : case cursorToFirstLine:
1562 [ # # ]: 0 : bSuccess = goTo( m_nCurColumn, 0 );
1563 : 0 : break;
1564 : :
1565 : : case cursorToLastLine:
1566 [ # # ]: 0 : bSuccess = goTo( m_nCurColumn, m_nRowCount - 1 );
1567 : 0 : break;
1568 : :
1569 : : case cursorPageUp:
1570 : : {
1571 [ # # ][ # # ]: 0 : RowPos nNewRow = ::std::max( (RowPos)0, m_nCurRow - impl_getVisibleRows( false ) );
1572 [ # # ]: 0 : bSuccess = goTo( m_nCurColumn, nNewRow );
1573 : : }
1574 : 0 : break;
1575 : :
1576 : : case cursorPageDown:
1577 : : {
1578 [ # # ][ # # ]: 0 : RowPos nNewRow = ::std::min( m_nRowCount - 1, m_nCurRow + impl_getVisibleRows( false ) );
1579 [ # # ]: 0 : bSuccess = goTo( m_nCurColumn, nNewRow );
1580 : : }
1581 : 0 : break;
1582 : :
1583 : : case cursorTopLeft:
1584 [ # # ]: 0 : bSuccess = goTo( 0, 0 );
1585 : 0 : break;
1586 : :
1587 : : case cursorBottomRight:
1588 [ # # ]: 0 : bSuccess = goTo( m_nColumnCount - 1, m_nRowCount - 1 );
1589 : 0 : break;
1590 : :
1591 : : case cursorSelectRow:
1592 : : {
1593 [ # # ]: 0 : if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
1594 : 0 : return bSuccess = false;
1595 : : //pos is the position of the current row in the vector of selected rows, if current row is selected
1596 [ # # ]: 0 : int pos = getRowSelectedNumber(m_aSelectedRows, m_nCurRow);
1597 : : //if current row is selected, it should be deselected, when ALT+SPACE are pressed
1598 [ # # ]: 0 : if(pos>-1)
1599 : : {
1600 [ # # ][ # # ]: 0 : m_aSelectedRows.erase(m_aSelectedRows.begin()+pos);
1601 [ # # ][ # # ]: 0 : if(m_aSelectedRows.empty() && m_nAnchor != -1)
[ # # ]
1602 : 0 : m_nAnchor = -1;
1603 : : }
1604 : : //else select the row->put it in the vector
1605 : : else
1606 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1607 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1608 : 0 : selectionChanged = true;
1609 : 0 : bSuccess = true;
1610 : : }
1611 : 0 : break;
1612 : : case cursorSelectRowUp:
1613 : : {
1614 [ # # ]: 0 : if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
1615 : 0 : return bSuccess = false;
1616 [ # # ]: 0 : else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
1617 : : {
1618 : : //if there are other selected rows, deselect them
1619 : 0 : return false;
1620 : : }
1621 : : else
1622 : : {
1623 : : //there are other selected rows
1624 [ # # ]: 0 : if(!m_aSelectedRows.empty())
1625 : : {
1626 : : //the anchor wasn't set -> a region is not selected, that's why clear all selection
1627 : : //and select the current row
1628 [ # # ]: 0 : if(m_nAnchor==-1)
1629 : : {
1630 [ # # # # ]: 0 : for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin();
[ # # ]
1631 : 0 : it!=m_aSelectedRows.end();++it)
1632 : : {
1633 [ # # ][ # # ]: 0 : invalidateSelectedRegion(*it, *it, rCells);
[ # # ]
1634 : : }
1635 : 0 : m_aSelectedRows.clear();
1636 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1637 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1638 : : }
1639 : : else
1640 : : {
1641 : : //a region is already selected, prevRow is last selected row and the row above - nextRow - should be selected
1642 [ # # ]: 0 : int prevRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow);
1643 [ # # ]: 0 : int nextRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow-1);
1644 [ # # ]: 0 : if(prevRow>-1)
1645 : : {
1646 : : //if m_nCurRow isn't the upper one, can move up, otherwise not
1647 [ # # ]: 0 : if(m_nCurRow>0)
1648 : 0 : m_nCurRow--;
1649 : : else
1650 : 0 : return bSuccess = true;
1651 : : //if nextRow already selected, deselect it, otherwise select it
1652 [ # # ][ # # ]: 0 : if(nextRow>-1 && m_aSelectedRows[nextRow] == m_nCurRow)
[ # # ][ # # ]
1653 : : {
1654 [ # # ][ # # ]: 0 : m_aSelectedRows.erase(m_aSelectedRows.begin()+prevRow);
1655 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow+1, m_nCurRow+1, rCells);
1656 : : }
1657 : : else
1658 : : {
1659 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1660 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1661 : : }
1662 : : }
1663 : : else
1664 : : {
1665 [ # # ]: 0 : if(m_nCurRow>0)
1666 : : {
1667 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1668 : 0 : m_nCurRow--;
1669 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1670 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow+1, m_nCurRow, rCells);
1671 : : }
1672 : : }
1673 : : }
1674 : : }
1675 : : else
1676 : : {
1677 : : //if nothing is selected and the current row isn't the upper one
1678 : : //select the current and one row above
1679 : : //otherwise select only the upper row
1680 [ # # ]: 0 : if(m_nCurRow>0)
1681 : : {
1682 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1683 : 0 : m_nCurRow--;
1684 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1685 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow+1, m_nCurRow, rCells);
1686 : : }
1687 : : else
1688 : : {
1689 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1690 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1691 : : }
1692 : : }
1693 [ # # ]: 0 : m_pSelEngine->SetAnchor(sal_True);
1694 : 0 : m_nAnchor = m_nCurRow;
1695 [ # # ]: 0 : ensureVisible(m_nCurColumn, m_nCurRow, false);
1696 : 0 : selectionChanged = true;
1697 : 0 : bSuccess = true;
1698 : : }
1699 : : }
1700 : 0 : break;
1701 : : case cursorSelectRowDown:
1702 : : {
1703 [ # # ]: 0 : if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
1704 : 0 : bSuccess = false;
1705 [ # # ]: 0 : else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
1706 : : {
1707 : 0 : bSuccess = false;
1708 : : }
1709 : : else
1710 : : {
1711 [ # # ]: 0 : if(!m_aSelectedRows.empty())
1712 : : {
1713 : : //the anchor wasn't set -> a region is not selected, that's why clear all selection
1714 : : //and select the current row
1715 [ # # ]: 0 : if(m_nAnchor==-1)
1716 : : {
1717 [ # # # # ]: 0 : for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin();
[ # # ]
1718 : 0 : it!=m_aSelectedRows.end();++it)
1719 : : {
1720 [ # # ][ # # ]: 0 : invalidateSelectedRegion(*it, *it, rCells);
[ # # ]
1721 : : }
1722 : 0 : m_aSelectedRows.clear();
1723 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1724 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1725 : : }
1726 : : else
1727 : : {
1728 : : //a region is already selected, prevRow is last selected row and the row beneath - nextRow - should be selected
1729 [ # # ]: 0 : int prevRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow);
1730 [ # # ]: 0 : int nextRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow+1);
1731 [ # # ]: 0 : if(prevRow>-1)
1732 : : {
1733 : : //if m_nCurRow isn't the last one, can move down, otherwise not
1734 [ # # ]: 0 : if(m_nCurRow<m_nRowCount-1)
1735 : 0 : m_nCurRow++;
1736 : : else
1737 : 0 : return bSuccess = true;
1738 : : //if next row already selected, deselect it, otherwise select it
1739 [ # # ][ # # ]: 0 : if(nextRow>-1 && m_aSelectedRows[nextRow] == m_nCurRow)
[ # # ][ # # ]
1740 : : {
1741 [ # # ][ # # ]: 0 : m_aSelectedRows.erase(m_aSelectedRows.begin()+prevRow);
1742 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow-1, m_nCurRow-1, rCells);
1743 : : }
1744 : : else
1745 : : {
1746 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1747 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1748 : : }
1749 : : }
1750 : : else
1751 : : {
1752 [ # # ]: 0 : if(m_nCurRow<m_nRowCount-1)
1753 : : {
1754 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1755 : 0 : m_nCurRow++;
1756 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1757 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow-1, m_nCurRow, rCells);
1758 : : }
1759 : : }
1760 : : }
1761 : : }
1762 : : else
1763 : : {
1764 : : //there wasn't any selection, select current and row beneath, otherwise only row beneath
1765 [ # # ]: 0 : if(m_nCurRow<m_nRowCount-1)
1766 : : {
1767 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1768 : 0 : m_nCurRow++;
1769 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1770 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow-1, m_nCurRow, rCells);
1771 : : }
1772 : : else
1773 : : {
1774 [ # # ]: 0 : m_aSelectedRows.push_back(m_nCurRow);
1775 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
1776 : : }
1777 : : }
1778 [ # # ]: 0 : m_pSelEngine->SetAnchor(sal_True);
1779 : 0 : m_nAnchor = m_nCurRow;
1780 [ # # ]: 0 : ensureVisible(m_nCurColumn, m_nCurRow, false);
1781 : 0 : selectionChanged = true;
1782 : 0 : bSuccess = true;
1783 : : }
1784 : : }
1785 : 0 : break;
1786 : :
1787 : : case cursorSelectRowAreaTop:
1788 : : {
1789 [ # # ]: 0 : if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
1790 : 0 : bSuccess = false;
1791 [ # # ]: 0 : else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
1792 : 0 : bSuccess = false;
1793 : : else
1794 : : {
1795 : : //select the region between the current and the upper row
1796 : 0 : RowPos iter = m_nCurRow;
1797 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, 0, rCells);
1798 : : //put the rows in vector
1799 [ # # ]: 0 : while(iter>=0)
1800 : : {
1801 [ # # ][ # # ]: 0 : if ( !isRowSelected( iter ) )
1802 [ # # ]: 0 : m_aSelectedRows.push_back(iter);
1803 : 0 : --iter;
1804 : : }
1805 : 0 : m_nCurRow = 0;
1806 : 0 : m_nAnchor = m_nCurRow;
1807 [ # # ]: 0 : m_pSelEngine->SetAnchor(sal_True);
1808 [ # # ]: 0 : ensureVisible(m_nCurColumn, 0, false);
1809 : 0 : selectionChanged = true;
1810 : 0 : bSuccess = true;
1811 : : }
1812 : : }
1813 : 0 : break;
1814 : :
1815 : : case cursorSelectRowAreaBottom:
1816 : : {
1817 [ # # ]: 0 : if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
1818 : 0 : return bSuccess = false;
1819 [ # # ]: 0 : else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
1820 : 0 : return bSuccess = false;
1821 : : //select the region between the current and the last row
1822 : 0 : RowPos iter = m_nCurRow;
1823 [ # # ]: 0 : invalidateSelectedRegion(m_nCurRow, m_nRowCount-1, rCells);
1824 : : //put the rows in the vector
1825 [ # # ]: 0 : while(iter<=m_nRowCount)
1826 : : {
1827 [ # # ][ # # ]: 0 : if ( !isRowSelected( iter ) )
1828 [ # # ]: 0 : m_aSelectedRows.push_back(iter);
1829 : 0 : ++iter;
1830 : : }
1831 : 0 : m_nCurRow = m_nRowCount-1;
1832 : 0 : m_nAnchor = m_nCurRow;
1833 [ # # ]: 0 : m_pSelEngine->SetAnchor(sal_True);
1834 [ # # ]: 0 : ensureVisible(m_nCurColumn, m_nRowCount-1, false);
1835 : 0 : selectionChanged = true;
1836 : 0 : bSuccess = true;
1837 : : }
1838 : 0 : break;
1839 : : default:
1840 : : OSL_FAIL( "TableControl_Impl::dispatchAction: unsupported action!" );
1841 : 0 : break;
1842 : : }
1843 : :
1844 [ # # ][ # # ]: 0 : if ( bSuccess && selectionChanged )
1845 : : {
1846 [ # # ]: 0 : m_rAntiImpl.Select();
1847 : : }
1848 : :
1849 : 0 : return bSuccess;
1850 : : }
1851 : :
1852 : : //------------------------------------------------------------------------------------------------------------------
1853 : 0 : void TableControl_Impl::impl_ni_doSwitchCursor( bool _bShow )
1854 : : {
1855 [ # # ][ # # ]: 0 : PTableRenderer pRenderer = !!m_pModel ? m_pModel->getRenderer() : PTableRenderer();
[ # # ]
1856 [ # # ]: 0 : if ( !!pRenderer )
1857 : : {
1858 [ # # ]: 0 : Rectangle aCellRect;
1859 [ # # ]: 0 : impl_getCellRect( m_nCurColumn, m_nCurRow, aCellRect );
1860 [ # # ]: 0 : if ( _bShow )
1861 [ # # ]: 0 : pRenderer->ShowCellCursor( *m_pDataWindow, aCellRect );
1862 : : else
1863 [ # # ]: 0 : pRenderer->HideCellCursor( *m_pDataWindow, aCellRect );
1864 [ # # ]: 0 : }
1865 : 0 : }
1866 : :
1867 : : //------------------------------------------------------------------------------------------------------------------
1868 : 0 : void TableControl_Impl::impl_getCellRect( ColPos _nColumn, RowPos _nRow, Rectangle& _rCellRect ) const
1869 : : {
1870 : : DBG_CHECK_ME();
1871 : :
1872 [ # # ][ # # ]: 0 : if ( !m_pModel
[ # # ][ # # ]
1873 : : || ( COL_INVALID == _nColumn )
1874 : : || ( ROW_INVALID == _nRow )
1875 : : )
1876 : : {
1877 : 0 : _rCellRect.SetEmpty();
1878 : 0 : return;
1879 : : }
1880 : :
1881 [ # # ][ # # ]: 0 : TableCellGeometry aCell( *this, impl_getAllVisibleCellsArea(), _nColumn, _nRow );
1882 [ # # ]: 0 : _rCellRect = aCell.getRect();
1883 : : }
1884 : :
1885 : : //------------------------------------------------------------------------------------------------------------------
1886 : 0 : RowPos TableControl_Impl::getRowAtPoint( const Point& rPoint ) const
1887 : : {
1888 : : DBG_CHECK_ME();
1889 : 0 : return impl_getRowForAbscissa( rPoint.Y() );
1890 : : }
1891 : :
1892 : : //------------------------------------------------------------------------------------------------------------------
1893 : 0 : ColPos TableControl_Impl::getColAtPoint( const Point& rPoint ) const
1894 : : {
1895 : : DBG_CHECK_ME();
1896 : 0 : return impl_getColumnForOrdinate( rPoint.X() );
1897 : : }
1898 : :
1899 : : //------------------------------------------------------------------------------------------------------------------
1900 : 0 : TableCell TableControl_Impl::hitTest( Point const & i_point ) const
1901 : : {
1902 : 0 : TableCell aCell( getColAtPoint( i_point ), getRowAtPoint( i_point ) );
1903 [ # # ]: 0 : if ( aCell.nColumn > COL_ROW_HEADERS )
1904 : : {
1905 [ # # ]: 0 : PColumnModel const pColumn = m_pModel->getColumnModel( aCell.nColumn );
1906 : 0 : MutableColumnMetrics const & rColInfo( m_aColumnWidths[ aCell.nColumn ] );
1907 [ # # ][ # # ]: 0 : if ( ( rColInfo.getEnd() - 3 <= i_point.X() )
[ # # # # ]
1908 : 0 : && ( rColInfo.getEnd() >= i_point.X() )
1909 [ # # ]: 0 : && pColumn->isResizable()
1910 : : )
1911 : : {
1912 : 0 : aCell.eArea = ColumnDivider;
1913 [ # # ]: 0 : }
1914 : : }
1915 : 0 : return aCell;
1916 : : }
1917 : :
1918 : : //------------------------------------------------------------------------------------------------------------------
1919 : 0 : ColumnMetrics TableControl_Impl::getColumnMetrics( ColPos const i_column ) const
1920 : : {
1921 : : DBG_CHECK_ME();
1922 : :
1923 [ # # ][ # # ]: 0 : ENSURE_OR_RETURN( ( i_column >= 0 ) && ( i_column < m_pModel->getColumnCount() ),
[ # # ]
1924 : : "TableControl_Impl::getColumnMetrics: illegal column index!", ColumnMetrics() );
1925 : 0 : return (ColumnMetrics const &)m_aColumnWidths[ i_column ];
1926 : : }
1927 : :
1928 : : //------------------------------------------------------------------------------------------------------------------
1929 : 0 : PTableModel TableControl_Impl::getModel() const
1930 : : {
1931 : 0 : return m_pModel;
1932 : : }
1933 : :
1934 : : //------------------------------------------------------------------------------------------------------------------
1935 : 0 : RowPos TableControl_Impl::getCurrentColumn() const
1936 : : {
1937 : 0 : return m_nCurColumn;
1938 : : }
1939 : :
1940 : : //------------------------------------------------------------------------------------------------------------------
1941 : 0 : RowPos TableControl_Impl::getCurrentRow() const
1942 : : {
1943 : 0 : return m_nCurRow;
1944 : : }
1945 : :
1946 : : //------------------------------------------------------------------------------------------------------------------
1947 : 0 : ::Size TableControl_Impl::getTableSizePixel() const
1948 : : {
1949 : 0 : return m_pDataWindow->GetOutputSizePixel();
1950 : : }
1951 : :
1952 : : //------------------------------------------------------------------------------------------------------------------
1953 : 0 : void TableControl_Impl::setPointer( Pointer const & i_pointer )
1954 : : {
1955 : : DBG_CHECK_ME();
1956 : 0 : m_pDataWindow->SetPointer( i_pointer );
1957 : 0 : }
1958 : :
1959 : : //------------------------------------------------------------------------------------------------------------------
1960 : 0 : void TableControl_Impl::captureMouse()
1961 : : {
1962 : 0 : m_pDataWindow->CaptureMouse();
1963 : 0 : }
1964 : :
1965 : : //------------------------------------------------------------------------------------------------------------------
1966 : 0 : void TableControl_Impl::releaseMouse()
1967 : : {
1968 : 0 : m_pDataWindow->ReleaseMouse();
1969 : 0 : }
1970 : :
1971 : : //------------------------------------------------------------------------------------------------------------------
1972 : 0 : void TableControl_Impl::invalidate( TableArea const i_what )
1973 : : {
1974 [ # # # # : 0 : switch ( i_what )
# ]
1975 : : {
1976 : : case TableAreaColumnHeaders:
1977 [ # # ]: 0 : m_pDataWindow->Invalidate( calcHeaderRect( true ) );
1978 : 0 : break;
1979 : :
1980 : : case TableAreaRowHeaders:
1981 [ # # ]: 0 : m_pDataWindow->Invalidate( calcHeaderRect( false ) );
1982 : 0 : break;
1983 : :
1984 : : case TableAreaDataArea:
1985 [ # # ]: 0 : m_pDataWindow->Invalidate( impl_getAllVisibleDataCellArea() );
1986 : 0 : break;
1987 : :
1988 : : case TableAreaAll:
1989 : 0 : m_pDataWindow->Invalidate();
1990 : 0 : break;
1991 : : }
1992 : 0 : }
1993 : :
1994 : : //------------------------------------------------------------------------------------------------------------------
1995 : 0 : long TableControl_Impl::pixelWidthToAppFont( long const i_pixels ) const
1996 : : {
1997 [ # # ]: 0 : return m_pDataWindow->PixelToLogic( Size( i_pixels, 0 ), MAP_APPFONT ).Width();
1998 : : }
1999 : :
2000 : : //------------------------------------------------------------------------------------------------------------------
2001 : 0 : void TableControl_Impl::hideTracking()
2002 : : {
2003 : 0 : m_pDataWindow->HideTracking();
2004 : 0 : }
2005 : :
2006 : : //------------------------------------------------------------------------------------------------------------------
2007 : 0 : void TableControl_Impl::showTracking( Rectangle const & i_location, sal_uInt16 const i_flags )
2008 : : {
2009 : 0 : m_pDataWindow->ShowTracking( i_location, i_flags );
2010 : 0 : }
2011 : :
2012 : : //------------------------------------------------------------------------------------------------------------------
2013 : 0 : bool TableControl_Impl::activateCell( ColPos const i_col, RowPos const i_row )
2014 : : {
2015 : : DBG_CHECK_ME();
2016 : 0 : return goTo( i_col, i_row );
2017 : : }
2018 : :
2019 : : //------------------------------------------------------------------------------------------------------------------
2020 : 0 : void TableControl_Impl::invalidateSelectedRegion(RowPos _nPrevRow, RowPos _nCurRow, Rectangle& _rCellRect)
2021 : : {
2022 : : DBG_CHECK_ME();
2023 : : //get the visible area of the table control and set the Left and right border of the region to be repainted
2024 [ # # ]: 0 : Rectangle const aAllCells( impl_getAllVisibleCellsArea() );
2025 : 0 : _rCellRect.Left() = aAllCells.Left();
2026 : 0 : _rCellRect.Right() = aAllCells.Right();
2027 : : //if only one row is selected
2028 [ # # ]: 0 : if(_nPrevRow == _nCurRow)
2029 : : {
2030 [ # # ]: 0 : Rectangle aCellRect;
2031 [ # # ]: 0 : impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
2032 : 0 : _rCellRect.Top() = aCellRect.Top();
2033 : 0 : _rCellRect.Bottom() = aCellRect.Bottom();
2034 : : }
2035 : : //if the region is above the current row
2036 [ # # ]: 0 : else if(_nPrevRow < _nCurRow )
2037 : : {
2038 [ # # ]: 0 : Rectangle aCellRect;
2039 [ # # ]: 0 : impl_getCellRect( m_nCurColumn, _nPrevRow, aCellRect );
2040 : 0 : _rCellRect.Top() = aCellRect.Top();
2041 [ # # ]: 0 : impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
2042 : 0 : _rCellRect.Bottom() = aCellRect.Bottom();
2043 : : }
2044 : : //if the region is beneath the current row
2045 : : else
2046 : : {
2047 [ # # ]: 0 : Rectangle aCellRect;
2048 [ # # ]: 0 : impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
2049 : 0 : _rCellRect.Top() = aCellRect.Top();
2050 [ # # ]: 0 : impl_getCellRect( m_nCurColumn, _nPrevRow, aCellRect );
2051 : 0 : _rCellRect.Bottom() = aCellRect.Bottom();
2052 : : }
2053 [ # # ]: 0 : m_pDataWindow->Invalidate(_rCellRect);
2054 : 0 : }
2055 : : //------------------------------------------------------------------------------------------------------------------
2056 : 0 : void TableControl_Impl::invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow )
2057 : : {
2058 [ # # ]: 0 : if ( m_nCursorHidden == 2 )
2059 : : // WTF? what kind of hack is this?
2060 : 0 : --m_nCursorHidden;
2061 : :
2062 [ # # ]: 0 : RowPos const firstRow = i_firstRow < m_nTopRow ? m_nTopRow : i_firstRow;
2063 [ # # ]: 0 : RowPos const lastVisibleRow = m_nTopRow + impl_getVisibleRows( true ) - 1;
2064 [ # # ][ # # ]: 0 : RowPos const lastRow = ( ( i_lastRow == ROW_INVALID ) || ( i_lastRow > lastVisibleRow ) ) ? lastVisibleRow : i_lastRow;
2065 : :
2066 [ # # ]: 0 : Rectangle aInvalidateRect;
2067 : :
2068 [ # # ]: 0 : Rectangle const aVisibleCellsArea( impl_getAllVisibleCellsArea() );
2069 [ # # ]: 0 : TableRowGeometry aRow( *this, aVisibleCellsArea, firstRow, true );
2070 [ # # ][ # # ]: 0 : while ( aRow.isValid() && ( aRow.getRow() <= lastRow ) )
[ # # ][ # # ]
2071 : : {
2072 [ # # ]: 0 : aInvalidateRect.Union( aRow.getRect() );
2073 [ # # ]: 0 : aRow.moveDown();
2074 : : }
2075 : :
2076 [ # # ]: 0 : if ( i_lastRow == ROW_INVALID )
2077 : 0 : aInvalidateRect.Bottom() = m_pDataWindow->GetOutputSizePixel().Height();
2078 : :
2079 [ # # ]: 0 : m_pDataWindow->Invalidate( aInvalidateRect );
2080 : 0 : }
2081 : :
2082 : : //------------------------------------------------------------------------------
2083 : 0 : void TableControl_Impl::checkCursorPosition()
2084 : : {
2085 : : DBG_CHECK_ME();
2086 : :
2087 : 0 : TableSize nVisibleRows = impl_getVisibleRows(true);
2088 : 0 : TableSize nVisibleCols = impl_getVisibleColumns(true);
2089 [ # # ][ # # ]: 0 : if ( ( m_nTopRow + nVisibleRows > m_nRowCount )
2090 : : && ( m_nRowCount >= nVisibleRows )
2091 : : )
2092 : : {
2093 : 0 : --m_nTopRow;
2094 : : }
2095 : : else
2096 : : {
2097 : 0 : m_nTopRow = 0;
2098 : : }
2099 : :
2100 [ # # ][ # # ]: 0 : if ( ( m_nLeftColumn + nVisibleCols > m_nColumnCount )
2101 : : && ( m_nColumnCount >= nVisibleCols )
2102 : : )
2103 : : {
2104 : 0 : --m_nLeftColumn;
2105 : : }
2106 : : else
2107 : : {
2108 : 0 : m_nLeftColumn = 0;
2109 : : }
2110 : :
2111 : 0 : m_pDataWindow->Invalidate();
2112 : 0 : }
2113 : :
2114 : : //--------------------------------------------------------------------
2115 : 0 : TableSize TableControl_Impl::impl_getVisibleRows( bool _bAcceptPartialRow ) const
2116 : : {
2117 : : DBG_CHECK_ME();
2118 : :
2119 : : DBG_ASSERT( m_pDataWindow, "TableControl_Impl::impl_getVisibleRows: no data window!" );
2120 : :
2121 : : return lcl_getRowsFittingInto(
2122 : 0 : m_pDataWindow->GetOutputSizePixel().Height() - m_nColHeaderHeightPixel,
2123 : : m_nRowHeightPixel,
2124 : : _bAcceptPartialRow
2125 : 0 : );
2126 : : }
2127 : :
2128 : : //--------------------------------------------------------------------
2129 : 0 : TableSize TableControl_Impl::impl_getVisibleColumns( bool _bAcceptPartialCol ) const
2130 : : {
2131 : : DBG_CHECK_ME();
2132 : :
2133 : : DBG_ASSERT( m_pDataWindow, "TableControl_Impl::impl_getVisibleColumns: no data window!" );
2134 : :
2135 : : return lcl_getColumnsVisibleWithin(
2136 : 0 : Rectangle( Point( 0, 0 ), m_pDataWindow->GetOutputSizePixel() ),
2137 : : m_nLeftColumn,
2138 : : *this,
2139 : : _bAcceptPartialCol
2140 [ # # ][ # # ]: 0 : );
2141 : : }
2142 : :
2143 : : //--------------------------------------------------------------------
2144 : 0 : bool TableControl_Impl::goTo( ColPos _nColumn, RowPos _nRow )
2145 : : {
2146 : : DBG_CHECK_ME();
2147 : :
2148 : : // TODO: give veto listeners a chance
2149 : :
2150 [ # # ][ # # ]: 0 : if ( ( _nColumn < 0 ) || ( _nColumn >= m_nColumnCount )
[ # # ][ # # ]
2151 : : || ( _nRow < 0 ) || ( _nRow >= m_nRowCount )
2152 : : )
2153 : : {
2154 : : OSL_ENSURE( false, "TableControl_Impl::goTo: invalid row or column index!" );
2155 : 0 : return false;
2156 : : }
2157 : :
2158 [ # # ]: 0 : SuppressCursor aHideCursor( *this );
2159 : 0 : m_nCurColumn = _nColumn;
2160 : 0 : m_nCurRow = _nRow;
2161 : :
2162 : : // ensure that the new cell is visible
2163 [ # # ]: 0 : ensureVisible( m_nCurColumn, m_nCurRow, false );
2164 [ # # ]: 0 : return true;
2165 : : }
2166 : :
2167 : : //--------------------------------------------------------------------
2168 : 0 : void TableControl_Impl::ensureVisible( ColPos _nColumn, RowPos _nRow, bool _bAcceptPartialVisibility )
2169 : : {
2170 : : DBG_CHECK_ME();
2171 : : DBG_ASSERT( ( _nColumn >= 0 ) && ( _nColumn < m_nColumnCount )
2172 : : && ( _nRow >= 0 ) && ( _nRow < m_nRowCount ),
2173 : : "TableControl_Impl::ensureVisible: invalid coordinates!" );
2174 : :
2175 [ # # ]: 0 : SuppressCursor aHideCursor( *this );
2176 : :
2177 [ # # ]: 0 : if ( _nColumn < m_nLeftColumn )
2178 [ # # ]: 0 : impl_scrollColumns( _nColumn - m_nLeftColumn );
2179 : : else
2180 : : {
2181 [ # # ]: 0 : TableSize nVisibleColumns = impl_getVisibleColumns( _bAcceptPartialVisibility );
2182 [ # # ]: 0 : if ( _nColumn > m_nLeftColumn + nVisibleColumns - 1 )
2183 : : {
2184 [ # # ]: 0 : impl_scrollColumns( _nColumn - ( m_nLeftColumn + nVisibleColumns - 1 ) );
2185 : : // TODO: since not all columns have the same width, this might in theory result
2186 : : // in the column still not being visible.
2187 : : }
2188 : : }
2189 : :
2190 [ # # ]: 0 : if ( _nRow < m_nTopRow )
2191 [ # # ]: 0 : impl_scrollRows( _nRow - m_nTopRow );
2192 : : else
2193 : : {
2194 [ # # ]: 0 : TableSize nVisibleRows = impl_getVisibleRows( _bAcceptPartialVisibility );
2195 [ # # ]: 0 : if ( _nRow > m_nTopRow + nVisibleRows - 1 )
2196 [ # # ]: 0 : impl_scrollRows( _nRow - ( m_nTopRow + nVisibleRows - 1 ) );
2197 [ # # ]: 0 : }
2198 : 0 : }
2199 : :
2200 : : //--------------------------------------------------------------------
2201 : 0 : ::rtl::OUString TableControl_Impl::getCellContentAsString( RowPos const i_row, ColPos const i_col )
2202 : : {
2203 : 0 : ::com::sun::star::uno::Any content;
2204 [ # # ]: 0 : m_pModel->getCellContent( i_col, i_row, content );
2205 [ # # ]: 0 : return CellValueConversion::convertToString( content );
2206 : : }
2207 : :
2208 : : //--------------------------------------------------------------------
2209 : 0 : TableSize TableControl_Impl::impl_ni_ScrollRows( TableSize _nRowDelta )
2210 : : {
2211 : : // compute new top row
2212 : : RowPos nNewTopRow =
2213 : : ::std::max(
2214 [ # # ]: 0 : ::std::min( (RowPos)( m_nTopRow + _nRowDelta ), (RowPos)( m_nRowCount - 1 ) ),
2215 : : (RowPos)0
2216 [ # # ]: 0 : );
2217 : :
2218 : 0 : RowPos nOldTopRow = m_nTopRow;
2219 : 0 : m_nTopRow = nNewTopRow;
2220 : :
2221 : : // if updates are enabled currently, scroll the viewport
2222 [ # # ]: 0 : if ( m_nTopRow != nOldTopRow )
2223 : : {
2224 : : DBG_SUSPEND_INV( INV_SCROLL_POSITION );
2225 [ # # ]: 0 : SuppressCursor aHideCursor( *this );
2226 : : // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
2227 : : // which hides the cursor and then calls the listener)
2228 : : // Same for onEndScroll
2229 : :
2230 : : // scroll the view port, if possible
2231 : 0 : long nPixelDelta = m_nRowHeightPixel * ( m_nTopRow - nOldTopRow );
2232 : :
2233 [ # # ]: 0 : Rectangle aDataArea( Point( 0, m_nColHeaderHeightPixel ), m_pDataWindow->GetOutputSizePixel() );
2234 : :
2235 [ # # ][ # # ]: 0 : if ( m_pDataWindow->GetBackground().IsScrollable()
[ # # ][ # # ]
2236 [ # # ]: 0 : && abs( nPixelDelta ) < aDataArea.GetHeight()
2237 : : )
2238 : : {
2239 [ # # ]: 0 : m_pDataWindow->Scroll( 0, (long)-nPixelDelta, aDataArea, SCROLL_CLIP | SCROLL_UPDATE | SCROLL_CHILDREN);
2240 : : }
2241 : : else
2242 [ # # ]: 0 : m_pDataWindow->Invalidate( INVALIDATE_UPDATE );
2243 : :
2244 : : // update the position at the vertical scrollbar
2245 [ # # ][ # # ]: 0 : m_pVScroll->SetThumbPos( m_nTopRow );
2246 : : }
2247 : :
2248 : : // The scroll bar availaility might change when we scrolled. This is because we do not hide
2249 : : // the scrollbar when it is, in theory, unnecessary, but currently at a position > 0. In this case, it will
2250 : : // be auto-hidden when it's scrolled back to pos 0.
2251 [ # # ]: 0 : if ( m_nTopRow == 0 )
2252 [ # # ]: 0 : m_rAntiImpl.PostUserEvent( LINK( this, TableControl_Impl, OnUpdateScrollbars ) );
2253 : :
2254 : 0 : return (TableSize)( m_nTopRow - nOldTopRow );
2255 : : }
2256 : :
2257 : : //--------------------------------------------------------------------
2258 : 0 : TableSize TableControl_Impl::impl_scrollRows( TableSize const i_rowDelta )
2259 : : {
2260 : : DBG_CHECK_ME();
2261 : 0 : return impl_ni_ScrollRows( i_rowDelta );
2262 : : }
2263 : :
2264 : : //--------------------------------------------------------------------
2265 : 0 : TableSize TableControl_Impl::impl_ni_ScrollColumns( TableSize _nColumnDelta )
2266 : : {
2267 : : // compute new left column
2268 : : const ColPos nNewLeftColumn =
2269 : : ::std::max(
2270 [ # # ]: 0 : ::std::min( (ColPos)( m_nLeftColumn + _nColumnDelta ), (ColPos)( m_nColumnCount - 1 ) ),
2271 : : (ColPos)0
2272 [ # # ]: 0 : );
2273 : :
2274 : 0 : const ColPos nOldLeftColumn = m_nLeftColumn;
2275 : 0 : m_nLeftColumn = nNewLeftColumn;
2276 : :
2277 : : // if updates are enabled currently, scroll the viewport
2278 [ # # ]: 0 : if ( m_nLeftColumn != nOldLeftColumn )
2279 : : {
2280 : : DBG_SUSPEND_INV( INV_SCROLL_POSITION );
2281 [ # # ]: 0 : SuppressCursor aHideCursor( *this );
2282 : : // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
2283 : : // which hides the cursor and then calls the listener)
2284 : : // Same for onEndScroll
2285 : :
2286 : : // scroll the view port, if possible
2287 [ # # ]: 0 : const Rectangle aDataArea( Point( m_nRowHeaderWidthPixel, 0 ), m_pDataWindow->GetOutputSizePixel() );
2288 : :
2289 : : long nPixelDelta =
2290 : 0 : m_aColumnWidths[ nOldLeftColumn ].getStart()
2291 : 0 : - m_aColumnWidths[ m_nLeftColumn ].getStart();
2292 : :
2293 : : // update our column positions
2294 : : // Do this *before* scrolling, as SCROLL_UPDATE will trigger a paint, which already needs the correct
2295 : : // information in m_aColumnWidths
2296 [ # # ][ # # ]: 0 : for ( ColumnPositions::iterator colPos = m_aColumnWidths.begin();
2297 : 0 : colPos != m_aColumnWidths.end();
2298 : : ++colPos
2299 : : )
2300 : : {
2301 : 0 : colPos->move( nPixelDelta );
2302 : : }
2303 : :
2304 : : // scroll the window content (if supported and possible), or invalidate the complete window
2305 [ # # ][ # # ]: 0 : if ( m_pDataWindow->GetBackground().IsScrollable()
[ # # ][ # # ]
2306 [ # # ]: 0 : && abs( nPixelDelta ) < aDataArea.GetWidth()
2307 : : )
2308 : : {
2309 [ # # ]: 0 : m_pDataWindow->Scroll( nPixelDelta, 0, aDataArea, SCROLL_CLIP | SCROLL_UPDATE );
2310 : : }
2311 : : else
2312 [ # # ]: 0 : m_pDataWindow->Invalidate( INVALIDATE_UPDATE );
2313 : :
2314 : : // update the position at the horizontal scrollbar
2315 [ # # ][ # # ]: 0 : m_pHScroll->SetThumbPos( m_nLeftColumn );
2316 : : }
2317 : :
2318 : : // The scroll bar availaility might change when we scrolled. This is because we do not hide
2319 : : // the scrollbar when it is, in theory, unnecessary, but currently at a position > 0. In this case, it will
2320 : : // be auto-hidden when it's scrolled back to pos 0.
2321 [ # # ]: 0 : if ( m_nLeftColumn == 0 )
2322 [ # # ]: 0 : m_rAntiImpl.PostUserEvent( LINK( this, TableControl_Impl, OnUpdateScrollbars ) );
2323 : :
2324 : 0 : return (TableSize)( m_nLeftColumn - nOldLeftColumn );
2325 : : }
2326 : :
2327 : : //------------------------------------------------------------------------------------------------------------------
2328 : 0 : TableSize TableControl_Impl::impl_scrollColumns( TableSize const i_columnDelta )
2329 : : {
2330 : : DBG_CHECK_ME();
2331 : 0 : return impl_ni_ScrollColumns( i_columnDelta );
2332 : : }
2333 : :
2334 : : //------------------------------------------------------------------------------------------------------------------
2335 : 0 : SelectionEngine* TableControl_Impl::getSelEngine()
2336 : : {
2337 : 0 : return m_pSelEngine;
2338 : : }
2339 : :
2340 : : //------------------------------------------------------------------------------------------------------------------
2341 : 0 : ScrollBar* TableControl_Impl::getHorzScrollbar()
2342 : : {
2343 : 0 : return m_pHScroll;
2344 : : }
2345 : :
2346 : : //------------------------------------------------------------------------------------------------------------------
2347 : 0 : ScrollBar* TableControl_Impl::getVertScrollbar()
2348 : : {
2349 : 0 : return m_pVScroll;
2350 : : }
2351 : :
2352 : : //------------------------------------------------------------------------------------------------------------------
2353 : 0 : bool TableControl_Impl::isRowSelected( RowPos i_row ) const
2354 : : {
2355 [ # # ][ # # ]: 0 : return ::std::find( m_aSelectedRows.begin(), m_aSelectedRows.end(), i_row ) != m_aSelectedRows.end();
2356 : : }
2357 : :
2358 : : //------------------------------------------------------------------------------------------------------------------
2359 : 0 : RowPos TableControl_Impl::getSelectedRowIndex( size_t const i_selectionIndex ) const
2360 : : {
2361 [ # # ]: 0 : if ( i_selectionIndex < m_aSelectedRows.size() )
2362 : 0 : return m_aSelectedRows[ i_selectionIndex ];
2363 : 0 : return ROW_INVALID;
2364 : : }
2365 : :
2366 : : //------------------------------------------------------------------------------------------------------------------
2367 : 0 : int TableControl_Impl::getRowSelectedNumber(const ::std::vector<RowPos>& selectedRows, RowPos current)
2368 : : {
2369 [ # # ]: 0 : std::vector<RowPos>::const_iterator it = ::std::find(selectedRows.begin(),selectedRows.end(),current);
2370 [ # # ][ # # ]: 0 : if ( it != selectedRows.end() )
2371 : : {
2372 [ # # ]: 0 : return it - selectedRows.begin();
2373 : : }
2374 : 0 : return -1;
2375 : : }
2376 : :
2377 : : //--------------------------------------------------------------------
2378 : 0 : ColPos TableControl_Impl::impl_getColumnForOrdinate( long const i_ordinate ) const
2379 : : {
2380 : : DBG_CHECK_ME();
2381 : :
2382 [ # # ][ # # ]: 0 : if ( ( m_aColumnWidths.empty() ) || ( i_ordinate < 0 ) )
[ # # ]
2383 : 0 : return COL_INVALID;
2384 : :
2385 [ # # ]: 0 : if ( i_ordinate < m_nRowHeaderWidthPixel )
2386 : 0 : return COL_ROW_HEADERS;
2387 : :
2388 : 0 : long const ordinate = i_ordinate - m_nRowHeaderWidthPixel;
2389 : :
2390 : : ColumnPositions::const_iterator lowerBound = ::std::lower_bound(
2391 : : m_aColumnWidths.begin(),
2392 : : m_aColumnWidths.end(),
2393 : : MutableColumnMetrics(ordinate+1, ordinate+1),
2394 : : ColumnInfoPositionLess()
2395 [ # # ]: 0 : );
2396 [ # # ][ # # ]: 0 : if ( lowerBound == m_aColumnWidths.end() )
2397 : : {
2398 : : // point is *behind* the start of the last column ...
2399 [ # # ][ # # ]: 0 : if ( ordinate < m_aColumnWidths.rbegin()->getEnd() )
2400 : : // ... but still before its end
2401 : 0 : return m_nColumnCount - 1;
2402 : 0 : return COL_INVALID;
2403 : : }
2404 [ # # ]: 0 : return lowerBound - m_aColumnWidths.begin();
2405 : : }
2406 : :
2407 : : //--------------------------------------------------------------------
2408 : 0 : RowPos TableControl_Impl::impl_getRowForAbscissa( long const i_abscissa ) const
2409 : : {
2410 : : DBG_CHECK_ME();
2411 : :
2412 [ # # ]: 0 : if ( i_abscissa < 0 )
2413 : 0 : return ROW_INVALID;
2414 : :
2415 [ # # ]: 0 : if ( i_abscissa < m_nColHeaderHeightPixel )
2416 : 0 : return ROW_COL_HEADERS;
2417 : :
2418 : 0 : long const abscissa = i_abscissa - m_nColHeaderHeightPixel;
2419 : 0 : long const row = m_nTopRow + abscissa / m_nRowHeightPixel;
2420 [ # # ]: 0 : return row < m_pModel->getRowCount() ? row : ROW_INVALID;
2421 : : }
2422 : :
2423 : : //--------------------------------------------------------------------
2424 : 0 : bool TableControl_Impl::markRowAsDeselected( RowPos const i_rowIndex )
2425 : : {
2426 : : DBG_CHECK_ME();
2427 : :
2428 [ # # ]: 0 : ::std::vector< RowPos >::iterator selPos = ::std::find( m_aSelectedRows.begin(), m_aSelectedRows.end(), i_rowIndex );
2429 [ # # ][ # # ]: 0 : if ( selPos == m_aSelectedRows.end() )
2430 : 0 : return false;
2431 : :
2432 [ # # ]: 0 : m_aSelectedRows.erase( selPos );
2433 : 0 : return true;
2434 : : }
2435 : :
2436 : : //--------------------------------------------------------------------
2437 : 0 : bool TableControl_Impl::markRowAsSelected( RowPos const i_rowIndex )
2438 : : {
2439 : : DBG_CHECK_ME();
2440 : :
2441 [ # # ]: 0 : if ( isRowSelected( i_rowIndex ) )
2442 : 0 : return false;
2443 : :
2444 : 0 : SelectionMode const eSelMode = getSelEngine()->GetSelectionMode();
2445 [ # # # ]: 0 : switch ( eSelMode )
2446 : : {
2447 : : case SINGLE_SELECTION:
2448 [ # # ]: 0 : if ( !m_aSelectedRows.empty() )
2449 : : {
2450 : : OSL_ENSURE( m_aSelectedRows.size() == 1, "TableControl::markRowAsSelected: SingleSelection with more than one selected element?" );
2451 : 0 : m_aSelectedRows[0] = i_rowIndex;
2452 : 0 : break;
2453 : : }
2454 : : // fall through
2455 : :
2456 : : case MULTIPLE_SELECTION:
2457 : 0 : m_aSelectedRows.push_back( i_rowIndex );
2458 : 0 : break;
2459 : :
2460 : : default:
2461 : : OSL_ENSURE( false, "TableControl_Impl::markRowAsSelected: unsupported selection mode!" );
2462 : 0 : return false;
2463 : : }
2464 : :
2465 : 0 : return true;
2466 : : }
2467 : :
2468 : : //--------------------------------------------------------------------
2469 : 0 : bool TableControl_Impl::markAllRowsAsDeselected()
2470 : : {
2471 [ # # ]: 0 : if ( m_aSelectedRows.empty() )
2472 : 0 : return false;
2473 : :
2474 : 0 : m_aSelectedRows.clear();
2475 : 0 : return true;
2476 : : }
2477 : :
2478 : : //--------------------------------------------------------------------
2479 : 0 : bool TableControl_Impl::markAllRowsAsSelected()
2480 : : {
2481 : : DBG_CHECK_ME();
2482 : :
2483 : 0 : SelectionMode const eSelMode = getSelEngine()->GetSelectionMode();
2484 [ # # ]: 0 : ENSURE_OR_RETURN_FALSE( eSelMode == MULTIPLE_SELECTION, "TableControl_Impl::markAllRowsAsSelected: unsupported selection mode!" );
2485 : :
2486 [ # # ]: 0 : if ( m_aSelectedRows.size() == size_t( m_pModel->getRowCount() ) )
2487 : : {
2488 : : #if OSL_DEBUG_LEVEL > 0
2489 : : for ( TableSize row = 0; row < m_pModel->getRowCount(); ++row )
2490 : : {
2491 : : OSL_ENSURE( isRowSelected( row ), "TableControl_Impl::markAllRowsAsSelected: inconsistency in the selected rows!" );
2492 : : }
2493 : : #endif
2494 : : // already all rows marked as selected
2495 : 0 : return false;
2496 : : }
2497 : :
2498 : 0 : m_aSelectedRows.clear();
2499 [ # # ][ # # ]: 0 : for ( RowPos i=0; i < m_pModel->getRowCount(); ++i )
2500 [ # # ]: 0 : m_aSelectedRows.push_back(i);
2501 : :
2502 : 0 : return true;
2503 : : }
2504 : :
2505 : : //--------------------------------------------------------------------
2506 : 0 : Rectangle TableControl_Impl::calcHeaderRect(bool bColHeader)
2507 : : {
2508 [ # # ]: 0 : Rectangle const aRectTableWithHeaders( impl_getAllVisibleCellsArea() );
2509 [ # # ]: 0 : Size const aSizeTableWithHeaders( aRectTableWithHeaders.GetSize() );
2510 [ # # ]: 0 : if ( bColHeader )
2511 [ # # ]: 0 : return Rectangle( aRectTableWithHeaders.TopLeft(), Size( aSizeTableWithHeaders.Width(), m_nColHeaderHeightPixel ) );
2512 : : else
2513 [ # # ]: 0 : return Rectangle( aRectTableWithHeaders.TopLeft(), Size( m_nRowHeaderWidthPixel, aSizeTableWithHeaders.Height() ) );
2514 : : }
2515 : :
2516 : : //--------------------------------------------------------------------
2517 : 0 : Rectangle TableControl_Impl::calcTableRect()
2518 : : {
2519 : 0 : return impl_getAllVisibleDataCellArea();
2520 : : }
2521 : :
2522 : : //--------------------------------------------------------------------
2523 : 0 : IMPL_LINK( TableControl_Impl, OnUpdateScrollbars, void*, /**/ )
2524 : : {
2525 : : DBG_CHECK_ME();
2526 : 0 : impl_ni_updateScrollbars();
2527 : 0 : return 1L;
2528 : : }
2529 : :
2530 : : //--------------------------------------------------------------------
2531 : 0 : IMPL_LINK( TableControl_Impl, OnScroll, ScrollBar*, _pScrollbar )
2532 : : {
2533 : : DBG_ASSERT( ( _pScrollbar == m_pVScroll ) || ( _pScrollbar == m_pHScroll ),
2534 : : "TableControl_Impl::OnScroll: where did this come from?" );
2535 : :
2536 [ # # ]: 0 : if ( _pScrollbar == m_pVScroll )
2537 : 0 : impl_ni_ScrollRows( _pScrollbar->GetDelta() );
2538 : : else
2539 : 0 : impl_ni_ScrollColumns( _pScrollbar->GetDelta() );
2540 : :
2541 : 0 : return 0L;
2542 : : }
2543 : :
2544 : : //------------------------------------------------------------------------------------------------------------------
2545 : 0 : Reference< XAccessible > TableControl_Impl::getAccessible( Window& i_parentWindow )
2546 : : {
2547 : : DBG_TESTSOLARMUTEX();
2548 [ # # ]: 0 : if ( m_pAccessibleTable == NULL )
2549 : : {
2550 [ # # ]: 0 : Reference< XAccessible > const xAccParent = i_parentWindow.GetAccessible();
2551 [ # # ]: 0 : if ( xAccParent.is() )
2552 : : {
2553 [ # # ]: 0 : m_pAccessibleTable = m_aFactoryAccess.getFactory().createAccessibleTableControl(
2554 : : xAccParent, m_rAntiImpl
2555 [ # # ]: 0 : );
2556 : 0 : }
2557 : : }
2558 : :
2559 : 0 : Reference< XAccessible > xAccessible;
2560 [ # # ]: 0 : if ( m_pAccessibleTable )
2561 [ # # ][ # # ]: 0 : xAccessible = m_pAccessibleTable->getMyself();
2562 : 0 : return xAccessible;
2563 : : }
2564 : :
2565 : : //------------------------------------------------------------------------------------------------------------------
2566 : 0 : void TableControl_Impl::disposeAccessible()
2567 : : {
2568 [ # # ]: 0 : if ( m_pAccessibleTable )
2569 : 0 : m_pAccessibleTable->dispose();
2570 : 0 : m_pAccessibleTable = NULL;
2571 : 0 : }
2572 : :
2573 : : //------------------------------------------------------------------------------------------------------------------
2574 : 0 : bool TableControl_Impl::impl_isAccessibleAlive() const
2575 : : {
2576 : : DBG_CHECK_ME();
2577 [ # # ][ # # ]: 0 : return ( NULL != m_pAccessibleTable ) && m_pAccessibleTable->isAlive();
2578 : : }
2579 : :
2580 : : //------------------------------------------------------------------------------------------------------------------
2581 : 0 : void TableControl_Impl::impl_commitAccessibleEvent( sal_Int16 const i_eventID, Any const & i_newValue, Any const & i_oldValue )
2582 : : {
2583 : : DBG_CHECK_ME();
2584 [ # # ]: 0 : if ( impl_isAccessibleAlive() )
2585 : 0 : m_pAccessibleTable->commitEvent( i_eventID, i_newValue, i_oldValue );
2586 : 0 : }
2587 : :
2588 : : //==================================================================================================================
2589 : : //= TableFunctionSet
2590 : : //==================================================================================================================
2591 : : //------------------------------------------------------------------------------------------------------------------
2592 : 0 : TableFunctionSet::TableFunctionSet(TableControl_Impl* _pTableControl)
2593 : : :m_pTableControl( _pTableControl)
2594 : 0 : ,m_nCurrentRow( ROW_INVALID )
2595 : : {
2596 : 0 : }
2597 : : //------------------------------------------------------------------------------------------------------------------
2598 : 0 : TableFunctionSet::~TableFunctionSet()
2599 : : {
2600 [ # # ]: 0 : }
2601 : : //------------------------------------------------------------------------------------------------------------------
2602 : 0 : void TableFunctionSet::BeginDrag()
2603 : : {
2604 : 0 : }
2605 : : //------------------------------------------------------------------------------------------------------------------
2606 : 0 : void TableFunctionSet::CreateAnchor()
2607 : : {
2608 : 0 : m_pTableControl->setAnchor( m_pTableControl->getCurRow() );
2609 : 0 : }
2610 : :
2611 : : //------------------------------------------------------------------------------------------------------------------
2612 : 0 : void TableFunctionSet::DestroyAnchor()
2613 : : {
2614 : 0 : m_pTableControl->setAnchor( ROW_INVALID );
2615 : 0 : }
2616 : :
2617 : : //------------------------------------------------------------------------------------------------------------------
2618 : 0 : sal_Bool TableFunctionSet::SetCursorAtPoint(const Point& rPoint, sal_Bool bDontSelectAtCursor)
2619 : : {
2620 : 0 : sal_Bool bHandled = sal_False;
2621 : : // newRow is the row which includes the point, getCurRow() is the last selected row, before the mouse click
2622 : 0 : RowPos newRow = m_pTableControl->getRowAtPoint( rPoint );
2623 [ # # ]: 0 : if ( newRow == ROW_COL_HEADERS )
2624 : 0 : newRow = m_pTableControl->getTopRow();
2625 : :
2626 : 0 : ColPos newCol = m_pTableControl->getColAtPoint( rPoint );
2627 [ # # ]: 0 : if ( newCol == COL_ROW_HEADERS )
2628 : 0 : newCol = m_pTableControl->getLeftColumn();
2629 : :
2630 [ # # ][ # # ]: 0 : if ( ( newRow == ROW_INVALID ) || ( newCol == COL_INVALID ) )
2631 : 0 : return sal_False;
2632 : :
2633 [ # # ]: 0 : if ( bDontSelectAtCursor )
2634 : : {
2635 [ # # ]: 0 : if ( m_pTableControl->getSelectedRowCount() > 1 )
2636 : 0 : m_pTableControl->getSelEngine()->AddAlways(sal_True);
2637 : 0 : bHandled = sal_True;
2638 : : }
2639 [ # # ]: 0 : else if ( m_pTableControl->getAnchor() == m_pTableControl->getCurRow() )
2640 : : {
2641 : : //selecting region,
2642 : 0 : int diff = m_pTableControl->getCurRow() - newRow;
2643 : : //selected region lies above the last selection
2644 [ # # ]: 0 : if( diff >= 0)
2645 : : {
2646 : : //put selected rows in vector
2647 [ # # ]: 0 : while ( m_pTableControl->getAnchor() >= newRow )
2648 : : {
2649 [ # # ]: 0 : m_pTableControl->markRowAsSelected( m_pTableControl->getAnchor() );
2650 : 0 : m_pTableControl->setAnchor( m_pTableControl->getAnchor() - 1 );
2651 : 0 : diff--;
2652 : : }
2653 : 0 : m_pTableControl->setAnchor( m_pTableControl->getAnchor() + 1 );
2654 : : }
2655 : : //selected region lies beneath the last selected row
2656 : : else
2657 : : {
2658 [ # # ]: 0 : while ( m_pTableControl->getAnchor() <= newRow )
2659 : : {
2660 [ # # ]: 0 : m_pTableControl->markRowAsSelected( m_pTableControl->getAnchor() );
2661 : 0 : m_pTableControl->setAnchor( m_pTableControl->getAnchor() + 1 );
2662 : 0 : diff++;
2663 : : }
2664 : 0 : m_pTableControl->setAnchor( m_pTableControl->getAnchor() - 1 );
2665 : : }
2666 [ # # ]: 0 : Rectangle aCellRect;
2667 [ # # ]: 0 : m_pTableControl->invalidateSelectedRegion( m_pTableControl->getCurRow(), newRow, aCellRect );
2668 : 0 : bHandled = sal_True;
2669 : : }
2670 : : //no region selected
2671 : : else
2672 : : {
2673 [ # # ]: 0 : if ( !m_pTableControl->hasRowSelection() )
2674 [ # # ]: 0 : m_pTableControl->markRowAsSelected( newRow );
2675 : : else
2676 : : {
2677 [ # # ][ # # ]: 0 : if ( m_pTableControl->getSelEngine()->GetSelectionMode() == SINGLE_SELECTION )
2678 : : {
2679 [ # # ]: 0 : DeselectAll();
2680 [ # # ]: 0 : m_pTableControl->markRowAsSelected( newRow );
2681 : : }
2682 : : else
2683 : : {
2684 [ # # ]: 0 : m_pTableControl->markRowAsSelected( newRow );
2685 : : }
2686 : : }
2687 [ # # ][ # # ]: 0 : if ( m_pTableControl->getSelectedRowCount() > 1 && m_pTableControl->getSelEngine()->GetSelectionMode() != SINGLE_SELECTION )
[ # # ][ # # ]
2688 [ # # ][ # # ]: 0 : m_pTableControl->getSelEngine()->AddAlways(sal_True);
2689 : :
2690 [ # # ]: 0 : Rectangle aCellRect;
2691 [ # # ]: 0 : m_pTableControl->invalidateSelectedRegion( newRow, newRow, aCellRect );
2692 : 0 : bHandled = sal_True;
2693 : : }
2694 : 0 : m_pTableControl->goTo( newCol, newRow );
2695 : 0 : return bHandled;
2696 : : }
2697 : : //------------------------------------------------------------------------------------------------------------------
2698 : 0 : sal_Bool TableFunctionSet::IsSelectionAtPoint( const Point& rPoint )
2699 : : {
2700 : 0 : m_pTableControl->getSelEngine()->AddAlways(sal_False);
2701 [ # # ]: 0 : if ( !m_pTableControl->hasRowSelection() )
2702 : 0 : return sal_False;
2703 : : else
2704 : : {
2705 : 0 : RowPos curRow = m_pTableControl->getRowAtPoint( rPoint );
2706 : 0 : m_pTableControl->setAnchor( ROW_INVALID );
2707 : 0 : bool selected = m_pTableControl->isRowSelected( curRow );
2708 : 0 : m_nCurrentRow = curRow;
2709 : 0 : return selected;
2710 : : }
2711 : : }
2712 : : //------------------------------------------------------------------------------------------------------------------
2713 : 0 : void TableFunctionSet::DeselectAtPoint( const Point& rPoint )
2714 : : {
2715 : : (void)rPoint;
2716 [ # # ]: 0 : Rectangle aCellRange;
2717 [ # # ]: 0 : m_pTableControl->invalidateSelectedRegion( m_nCurrentRow, m_nCurrentRow, aCellRange );
2718 [ # # ]: 0 : m_pTableControl->markRowAsDeselected( m_nCurrentRow );
2719 : 0 : }
2720 : :
2721 : : //------------------------------------------------------------------------------------------------------------------
2722 : 0 : void TableFunctionSet::DeselectAll()
2723 : : {
2724 [ # # ]: 0 : if ( m_pTableControl->hasRowSelection() )
2725 : : {
2726 [ # # ]: 0 : Rectangle aCellRange;
2727 [ # # ]: 0 : for ( size_t i=0; i<m_pTableControl->getSelectedRowCount(); ++i )
2728 : : {
2729 [ # # ]: 0 : RowPos const rowIndex = m_pTableControl->getSelectedRowIndex(i);
2730 [ # # ]: 0 : m_pTableControl->invalidateSelectedRegion( rowIndex, rowIndex, aCellRange );
2731 : : }
2732 : :
2733 : 0 : m_pTableControl->markAllRowsAsDeselected();
2734 : : }
2735 : 0 : }
2736 : :
2737 : : //......................................................................................................................
2738 [ + - ][ + - ]: 843 : } } // namespace svt::table
2739 : : //......................................................................................................................
2740 : :
2741 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|