Coverage Report

Created: 2025-07-07 10:01

/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: */