/src/libreoffice/toolkit/source/controls/table/tablecontrol_impl.hxx
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #pragma once |
21 | | |
22 | | #include <controls/table/AccessibleGridControl.hxx> |
23 | | #include <controls/table/tablemodel.hxx> |
24 | | #include <controls/table/tablecontrolinterface.hxx> |
25 | | |
26 | | #include <com/sun/star/accessibility/XAccessible.hpp> |
27 | | #include <vcl/seleng.hxx> |
28 | | |
29 | | #include <vector> |
30 | | |
31 | | class ScrollBar; |
32 | | class ScrollBarBox; |
33 | | |
34 | | namespace svt::table |
35 | | { |
36 | | struct MutableColumnMetrics : public ColumnMetrics |
37 | | { |
38 | | MutableColumnMetrics() |
39 | 0 | :ColumnMetrics() |
40 | 0 | { |
41 | 0 | } |
42 | | |
43 | | MutableColumnMetrics( tools::Long const i_startPixel, tools::Long const i_endPixel ) |
44 | 0 | :ColumnMetrics( i_startPixel, i_endPixel ) |
45 | 0 | { |
46 | 0 | } |
47 | | |
48 | 0 | tools::Long getStart() const { return nStartPixel; } |
49 | 0 | tools::Long getEnd() const { return nEndPixel; } |
50 | | |
51 | 0 | void move( tools::Long const i_offset ) { nStartPixel += i_offset; nEndPixel += i_offset; } |
52 | | |
53 | 0 | tools::Long getWidth() const { return nEndPixel - nStartPixel; } |
54 | | }; |
55 | | |
56 | | struct ColumnInfoPositionLess |
57 | | { |
58 | | bool operator()( MutableColumnMetrics const& i_lhs, MutableColumnMetrics const& i_rhs ) |
59 | 0 | { |
60 | 0 | return i_lhs.getEnd() < i_rhs.getStart(); |
61 | 0 | } |
62 | | }; |
63 | | |
64 | | typedef ::std::vector< MutableColumnMetrics > ColumnPositions; |
65 | | |
66 | | class TableControl; |
67 | | class TableDataWindow; |
68 | | class TableFunctionSet; |
69 | | |
70 | | |
71 | | //= TableControl_Impl |
72 | | |
73 | | class TableControl_Impl :public ITableControl |
74 | | ,public ITableModelListener |
75 | | { |
76 | | friend class TableGeometry; |
77 | | friend class TableRowGeometry; |
78 | | friend class TableColumnGeometry; |
79 | | friend class SuspendInvariants; |
80 | | |
81 | | private: |
82 | | /// the control whose impl-instance we implement |
83 | | TableControl& m_rAntiImpl; |
84 | | /// the model of the table control |
85 | | PTableModel m_pModel; |
86 | | /// the input handler to use, usually the input handler as provided by ->m_pModel |
87 | | PTableInputHandler m_pInputHandler; |
88 | | /// info about the widths of our columns |
89 | | ColumnPositions m_aColumnWidths; |
90 | | |
91 | | /// the height of a single row in the table, measured in pixels |
92 | | tools::Long m_nRowHeightPixel; |
93 | | /// the height of the column header row in the table, measured in pixels |
94 | | tools::Long m_nColHeaderHeightPixel; |
95 | | /// the width of the row header column in the table, measured in pixels |
96 | | tools::Long m_nRowHeaderWidthPixel; |
97 | | |
98 | | /// the number of columns in the table control. Cached model value. |
99 | | TableSize m_nColumnCount; |
100 | | |
101 | | /// the number of rows in the table control. Cached model value. |
102 | | TableSize m_nRowCount; |
103 | | |
104 | | ColPos m_nCurColumn; |
105 | | RowPos m_nCurRow; |
106 | | ColPos m_nLeftColumn; |
107 | | RowPos m_nTopRow; |
108 | | |
109 | | sal_Int32 m_nCursorHidden; |
110 | | |
111 | | /** the window to contain all data content, including header bars |
112 | | |
113 | | The window's upper left corner is at position (0,0), relative to the |
114 | | table control, which is the direct parent of the data window. |
115 | | */ |
116 | | VclPtr<TableDataWindow> m_pDataWindow; |
117 | | /// the vertical scrollbar, if any |
118 | | VclPtr<ScrollBar> m_pVScroll; |
119 | | /// the horizontal scrollbar, if any |
120 | | VclPtr<ScrollBar> m_pHScroll; |
121 | | VclPtr<ScrollBarBox> m_pScrollCorner; |
122 | | //selection engine - for determining selection range, e.g. single, multiple |
123 | | std::unique_ptr<SelectionEngine> m_pSelEngine; |
124 | | //vector which contains the selected rows |
125 | | std::vector<RowPos> m_aSelectedRows; |
126 | | //part of selection engine |
127 | | std::unique_ptr<TableFunctionSet> m_pTableFunctionSet; |
128 | | //part of selection engine |
129 | | RowPos m_nAnchor; |
130 | | bool m_bUpdatingColWidths; |
131 | | |
132 | | rtl::Reference<accessibility::AccessibleGridControl> m_xAccessibleTable; |
133 | | |
134 | | public: |
135 | | void setModel( const PTableModel& _pModel ); |
136 | | |
137 | 0 | const PTableInputHandler& getInputHandler() const { return m_pInputHandler; } |
138 | | |
139 | 0 | RowPos getCurRow() const { return m_nCurRow; } |
140 | | |
141 | 0 | RowPos getAnchor() const { return m_nAnchor; } |
142 | 0 | void setAnchor( RowPos const i_anchor ) { m_nAnchor = i_anchor; } |
143 | | |
144 | 0 | RowPos getTopRow() const { return m_nTopRow; } |
145 | 0 | ColPos getLeftColumn() const { return m_nLeftColumn; } |
146 | | |
147 | 0 | const TableControl& getAntiImpl() const { return m_rAntiImpl; } |
148 | 0 | TableControl& getAntiImpl() { return m_rAntiImpl; } |
149 | | |
150 | | public: |
151 | | explicit TableControl_Impl( TableControl& _rAntiImpl ); |
152 | | virtual ~TableControl_Impl() override; |
153 | | |
154 | | /** to be called when the anti-impl instance has been resized |
155 | | */ |
156 | | void onResize(); |
157 | | |
158 | | /** paints the table control content which intersects with the given rectangle |
159 | | */ |
160 | | void doPaintContent(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rUpdateRect); |
161 | | |
162 | | /** moves the cursor to the cell with the given coordinates |
163 | | |
164 | | To ease the caller's code, the coordinates must not necessarily denote a |
165 | | valid position. If they don't, <FALSE/> will be returned. |
166 | | */ |
167 | | bool goTo( ColPos _nColumn, RowPos _nRow ); |
168 | | |
169 | | /** ensures that the given coordinate is visible |
170 | | @param _nColumn |
171 | | the column position which should be visible. Must be non-negative, and smaller |
172 | | than the column count. |
173 | | @param _nRow |
174 | | the row position which should be visibleMust be non-negative, and smaller |
175 | | than the row count. |
176 | | */ |
177 | | void ensureVisible( ColPos _nColumn, RowPos _nRow ); |
178 | | |
179 | | /** retrieves the content of the given cell, converted to a string |
180 | | */ |
181 | | OUString getCellContentAsString( RowPos const i_row, ColPos const i_col ); |
182 | | |
183 | | /** returns the position of the current row in the selection vector */ |
184 | | static int getRowSelectedNumber(const ::std::vector<RowPos>& selectedRows, RowPos current); |
185 | | |
186 | | void invalidateRect(const tools::Rectangle &rInvalidateRect); |
187 | | |
188 | | /** ??? */ |
189 | | void invalidateSelectedRegion( RowPos _nPrevRow, RowPos _nCurRow ); |
190 | | |
191 | | /** invalidates the part of the data window which is covered by the given rows |
192 | | @param i_firstRow |
193 | | the index of the first row to include in the invalidation |
194 | | @param i_lastRow |
195 | | the index of the last row to include in the invalidation, or ROW_INVALID if the invalidation |
196 | | should happen down to the bottom of the data window. |
197 | | */ |
198 | | void invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow ); |
199 | | |
200 | | /** invalidates the part of the data window which is covered by the given row |
201 | | */ |
202 | 0 | void invalidateRow( RowPos const i_row ) { invalidateRowRange( i_row, i_row ); } |
203 | | |
204 | | /** invalidates all selected rows |
205 | | */ |
206 | | void invalidateSelectedRows(); |
207 | | |
208 | | void checkCursorPosition(); |
209 | | |
210 | 0 | bool hasRowSelection() const { return !m_aSelectedRows.empty(); } |
211 | 0 | size_t getSelectedRowCount() const { return m_aSelectedRows.size(); } |
212 | | RowPos getSelectedRowIndex( size_t const i_selectionIndex ) const; |
213 | | |
214 | | /** removes the given row index from m_aSelectedRows |
215 | | |
216 | | @return |
217 | | <TRUE/> if and only if the row was previously marked as selected |
218 | | */ |
219 | | bool markRowAsDeselected( RowPos const i_rowIndex ); |
220 | | |
221 | | /** marks the given row as selected, by putting it into m_aSelectedRows |
222 | | @return |
223 | | <TRUE/> if and only if the row was previously <em>not</em> marked as selected |
224 | | */ |
225 | | bool markRowAsSelected( RowPos const i_rowIndex ); |
226 | | |
227 | | /** marks all rows as deselected |
228 | | @return |
229 | | <TRUE/> if and only if the selection actually changed by this operation |
230 | | */ |
231 | | bool markAllRowsAsDeselected(); |
232 | | |
233 | | /** marks all rows as selected |
234 | | @return |
235 | | <FALSE/> if and only if all rows were selected already. |
236 | | */ |
237 | | bool markAllRowsAsSelected(); |
238 | | |
239 | | void commitAccessibleEvent( sal_Int16 const i_eventID ); |
240 | | void commitCellEvent( sal_Int16 const i_eventID, const css::uno::Any& i_newValue, const css::uno::Any& i_oldValue ); |
241 | | void commitTableEvent( sal_Int16 const i_eventID, const css::uno::Any& i_newValue, const css::uno::Any& i_oldValue ); |
242 | | |
243 | | // ITableControl |
244 | | virtual void hideCursor() override; |
245 | | virtual void showCursor() override; |
246 | | |
247 | | /** dispatches an action to the table control |
248 | | |
249 | | @return |
250 | | <TRUE/> if the action could be dispatched successfully, <FALSE/> otherwise. Usual |
251 | | failure conditions include some other instance vetoing the action, or impossibility |
252 | | to execute the action at all (for instance moving up one row when already positioned |
253 | | on the very first row). |
254 | | |
255 | | @see TableControlAction |
256 | | */ |
257 | | bool dispatchAction(TableControlAction _eAction); |
258 | | |
259 | | virtual SelectionEngine* getSelEngine() override; |
260 | | virtual PTableModel getModel() const override; |
261 | | virtual ColPos getCurrentColumn() const override; |
262 | | virtual RowPos getCurrentRow() const override; |
263 | | virtual void activateCell( ColPos const i_col, RowPos const i_row ) override; |
264 | | virtual ::Size getTableSizePixel() const override; |
265 | | virtual void setPointer( PointerStyle i_pointer ) override; |
266 | | virtual void captureMouse() override; |
267 | | virtual void releaseMouse() override; |
268 | | virtual void invalidate( TableArea const i_what ) override; |
269 | | virtual tools::Long pixelWidthToAppFont( tools::Long const i_pixels ) const override; |
270 | | virtual void hideTracking() override; |
271 | | virtual void showTracking( tools::Rectangle const & i_location, ShowTrackFlags const i_flags ) override; |
272 | | RowPos getRowAtPoint( const Point& rPoint ) const; |
273 | | ColPos getColAtPoint( const Point& rPoint ) const; |
274 | | virtual TableCell hitTest( const Point& rPoint ) const override; |
275 | | virtual ColumnMetrics getColumnMetrics( ColPos const i_column ) const override; |
276 | | virtual bool isRowSelected( RowPos i_row ) const override; |
277 | | |
278 | | |
279 | | tools::Long appFontWidthToPixel( tools::Long const i_appFontUnits ) const; |
280 | | |
281 | 0 | TableDataWindow& getDataWindow() { return *m_pDataWindow; } |
282 | 0 | const TableDataWindow& getDataWindow() const { return *m_pDataWindow; } |
283 | 0 | ScrollBar* getHorzScrollbar() { return m_pHScroll; } |
284 | 0 | ScrollBar* getVertScrollbar() { return m_pVScroll; } |
285 | | |
286 | | tools::Rectangle calcHeaderRect( bool bColHeader ); |
287 | | tools::Rectangle calcHeaderCellRect( bool bColHeader, sal_Int32 nPos ); |
288 | | tools::Rectangle calcTableRect() const; |
289 | | tools::Rectangle calcCellRect( sal_Int32 nRow, sal_Int32 nCol ) const; |
290 | | |
291 | | // A11Y |
292 | | const rtl::Reference<accessibility::AccessibleGridControl>& |
293 | | getAccessible(const css::uno::Reference<css::accessibility::XAccessible>& rxParent); |
294 | | void disposeAccessible(); |
295 | | |
296 | | // ITableModelListener |
297 | | virtual void rowsInserted( RowPos first, RowPos last ) override; |
298 | | virtual void rowsRemoved( RowPos first, RowPos last ) override; |
299 | | virtual void columnInserted() override; |
300 | | virtual void columnRemoved() override; |
301 | | virtual void allColumnsRemoved() override; |
302 | | virtual void cellsUpdated( RowPos const i_firstRow, RowPos const i_lastRow ) override; |
303 | | virtual void columnChanged( ColPos const i_column, ColumnAttributeGroup const i_attributeGroup ) override; |
304 | | virtual void tableMetricsChanged() override; |
305 | | |
306 | | private: |
307 | | void impl_commitAccessibleEvent( |
308 | | sal_Int16 const i_eventID, |
309 | | css::uno::Any const & i_newValue |
310 | | ); |
311 | | |
312 | | /** toggles the cursor visibility |
313 | | |
314 | | The method is not bound to the classes public invariants, as it's used in |
315 | | situations where the they must not necessarily be fulfilled. |
316 | | */ |
317 | | void impl_ni_doSwitchCursor( bool _bOn ); |
318 | | |
319 | | /** returns the number of visible rows. |
320 | | |
321 | | @param _bAcceptPartialRow |
322 | | specifies whether a possible only partially visible last row is |
323 | | counted, too. |
324 | | */ |
325 | | TableSize impl_getVisibleRows( bool _bAcceptPartialRow ) const; |
326 | | |
327 | | /** returns the number of visible columns |
328 | | |
329 | | The value may change with different horizontal scroll positions, as |
330 | | different columns have different widths. For instance, if your control is |
331 | | 100 pixels wide, and has three columns of width 50, 50, 100, respectively, |
332 | | then this method will return either "2" or "1", depending on which column |
333 | | is the first visible one. |
334 | | |
335 | | @param _bAcceptPartialRow |
336 | | specifies whether a possible only partially visible last row is |
337 | | counted, too. |
338 | | */ |
339 | | TableSize impl_getVisibleColumns( bool _bAcceptPartialCol ) const; |
340 | | |
341 | | /** updates all cached model values |
342 | | |
343 | | The method is not bound to the classes public invariants, as it's used in |
344 | | situations where the they must not necessarily be fulfilled. |
345 | | */ |
346 | | void impl_ni_updateCachedModelValues(); |
347 | | |
348 | | /** updates the cached table metrics (row height etc.) |
349 | | */ |
350 | | void impl_ni_updateCachedTableMetrics(); |
351 | | |
352 | | /** does a relayout of the table control |
353 | | |
354 | | Column widths, and consequently the availability of the vertical and horizontal scrollbar, are updated |
355 | | with a call to this method. |
356 | | |
357 | | @param i_assumeInflexibleColumnsUpToIncluding |
358 | | the index of a column up to which all columns should be considered as inflexible, or |
359 | | <code>COL_INVALID</code>. |
360 | | */ |
361 | | void impl_ni_relayout( ColPos const i_assumeInflexibleColumnsUpToIncluding = COL_INVALID ); |
362 | | |
363 | | /** calculates the new width of our columns, taking into account their min and max widths, and their relative |
364 | | flexibility. |
365 | | |
366 | | @param i_assumeInflexibleColumnsUpToIncluding |
367 | | the index of a column up to which all columns should be considered as inflexible, or |
368 | | <code>COL_INVALID</code>. |
369 | | |
370 | | @param i_assumeVerticalScrollbar |
371 | | controls whether or not we should assume the presence of a vertical scrollbar. If <true/>, and |
372 | | if the model has a VerticalScrollbarVisibility != ScrollbarShowNever, the method will leave |
373 | | space for a vertical scrollbar. |
374 | | |
375 | | @return |
376 | | the overall width of the grid, which is available for columns |
377 | | */ |
378 | | tools::Long impl_ni_calculateColumnWidths( |
379 | | ColPos const i_assumeInflexibleColumnsUpToIncluding, |
380 | | bool const i_assumeVerticalScrollbar, |
381 | | ::std::vector< tools::Long >& o_newColWidthsPixel |
382 | | ) const; |
383 | | |
384 | | /** positions all child windows, e.g. the both scrollbars, the corner window, and the data window |
385 | | */ |
386 | | void impl_ni_positionChildWindows( |
387 | | tools::Rectangle const & i_dataCellPlayground, |
388 | | bool const i_verticalScrollbar, |
389 | | bool const i_horizontalScrollbar |
390 | | ); |
391 | | |
392 | | /** scrolls the view by the given number of rows |
393 | | |
394 | | The method is not bound to the classes public invariants, as it's used in |
395 | | situations where the they must not necessarily be fulfilled. |
396 | | |
397 | | @return |
398 | | the number of rows by which the viewport was scrolled. This may differ |
399 | | from the given numbers to scroll in case the begin or the end of the |
400 | | row range were reached. |
401 | | */ |
402 | | TableSize impl_ni_ScrollRows( TableSize _nRowDelta ); |
403 | | |
404 | | /** equivalent to impl_ni_ScrollRows, but checks the instances invariants beforehand (in a non-product build only) |
405 | | */ |
406 | | TableSize impl_scrollRows( TableSize const i_rowDelta ); |
407 | | |
408 | | /** scrolls the view by the given number of columns |
409 | | |
410 | | The method is not bound to the classes public invariants, as it's used in |
411 | | situations where the they must not necessarily be fulfilled. |
412 | | |
413 | | @return |
414 | | the number of columns by which the viewport was scrolled. This may differ |
415 | | from the given numbers to scroll in case the begin or the end of the |
416 | | column range were reached. |
417 | | */ |
418 | | TableSize impl_ni_ScrollColumns( TableSize _nColumnDelta ); |
419 | | |
420 | | /** equivalent to impl_ni_ScrollColumns, but checks the instances invariants beforehand (in a non-product build only) |
421 | | */ |
422 | | TableSize impl_scrollColumns( TableSize const i_columnDelta ); |
423 | | |
424 | | /** retrieves the area occupied by the totality of (at least partially) visible cells |
425 | | |
426 | | The returned area includes row and column headers. Also, it takes into |
427 | | account the fact that there might be less columns than would normally |
428 | | find room in the control. |
429 | | |
430 | | As a result of respecting the partial visibility of rows and columns, |
431 | | the returned area might be larger than the data window's output size. |
432 | | */ |
433 | | tools::Rectangle impl_getAllVisibleCellsArea() const; |
434 | | |
435 | | /** retrieves the area occupied by all (at least partially) visible data cells. |
436 | | |
437 | | Effectively, the returned area is the same as returned by ->impl_getAllVisibleCellsArea, |
438 | | minus the row and column header areas. |
439 | | */ |
440 | | tools::Rectangle impl_getAllVisibleDataCellArea() const; |
441 | | |
442 | | /** retrieves the column which covers the given ordinate |
443 | | */ |
444 | | ColPos impl_getColumnForOrdinate( tools::Long const i_ordinate ) const; |
445 | | |
446 | | /** retrieves the row which covers the given abscissa |
447 | | */ |
448 | | RowPos impl_getRowForAbscissa( tools::Long const i_abscissa ) const; |
449 | | |
450 | | /// invalidates the window area occupied by the given column |
451 | | void impl_invalidateColumn( ColPos const i_column ); |
452 | | |
453 | | DECL_LINK( OnScroll, ScrollBar*, void ); |
454 | | DECL_LINK( OnUpdateScrollbars, void*, void ); |
455 | | }; |
456 | | |
457 | | //see seleng.hxx, seleng.cxx, FunctionSet overridables, part of selection engine |
458 | | class TableFunctionSet : public FunctionSet |
459 | | { |
460 | | private: |
461 | | TableControl_Impl* m_pTableControl; |
462 | | RowPos m_nCurrentRow; |
463 | | |
464 | | public: |
465 | | explicit TableFunctionSet(TableControl_Impl* _pTableControl); |
466 | | virtual ~TableFunctionSet() override; |
467 | | |
468 | | virtual void BeginDrag() override; |
469 | | virtual void CreateAnchor() override; |
470 | | virtual void DestroyAnchor() override; |
471 | | virtual void SetCursorAtPoint(const Point& rPoint, bool bDontSelectAtCursor = false) override; |
472 | | virtual bool IsSelectionAtPoint( const Point& rPoint ) override; |
473 | | virtual void DeselectAtPoint( const Point& rPoint ) override; |
474 | | virtual void DeselectAll() override; |
475 | | }; |
476 | | |
477 | | |
478 | | } // namespace svt::table |
479 | | |
480 | | |
481 | | |
482 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |