summaryrefslogtreecommitdiffstats
path: root/svtools/source/table/tablecontrol_impl.hxx
blob: 727dea92ba9467d49c6099441f2668ab2bd68f8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#pragma once

#include <table/tablemodel.hxx>
#include <table/tablecontrolinterface.hxx>

#include <vcl/svtaccessiblefactory.hxx>
#include <vcl/accessibletable.hxx>

#include <vcl/seleng.hxx>

#include <vector>

class ScrollBar;
class ScrollBarBox;

namespace svt::table
{
    struct MutableColumnMetrics : public ColumnMetrics
    {
        MutableColumnMetrics()
            :ColumnMetrics()
        {
        }

        MutableColumnMetrics( tools::Long const i_startPixel, tools::Long const i_endPixel )
            :ColumnMetrics( i_startPixel, i_endPixel )
        {
        }

        tools::Long getStart() const { return nStartPixel; }
        tools::Long getEnd() const { return nEndPixel; }

        void move( tools::Long const i_offset ) { nStartPixel += i_offset; nEndPixel += i_offset; }

        tools::Long getWidth() const { return nEndPixel - nStartPixel; }
    };

    struct ColumnInfoPositionLess
    {
        bool operator()( MutableColumnMetrics const& i_lhs, MutableColumnMetrics const& i_rhs )
        {
            return i_lhs.getEnd() < i_rhs.getStart();
        }
    };

    typedef ::std::vector< MutableColumnMetrics >    ColumnPositions;

    class TableControl;
    class TableDataWindow;
    class TableFunctionSet;


    //= TableControl_Impl

    class TableControl_Impl :public ITableControl
                            ,public ITableModelListener
    {
        friend class TableGeometry;
        friend class TableRowGeometry;
        friend class TableColumnGeometry;
        friend class SuspendInvariants;

    private:
        /// the control whose impl-instance we implement
        TableControl&           m_rAntiImpl;
        /// the model of the table control
        PTableModel             m_pModel;
        /// the input handler to use, usually the input handler as provided by ->m_pModel
        PTableInputHandler      m_pInputHandler;
        /// info about the widths of our columns
        ColumnPositions         m_aColumnWidths;

        /// the height of a single row in the table, measured in pixels
        tools::Long                    m_nRowHeightPixel;
        /// the height of the column header row in the table, measured in pixels
        tools::Long                    m_nColHeaderHeightPixel;
        /// the width of the row header column in the table, measured in pixels
        tools::Long                    m_nRowHeaderWidthPixel;

        /// the number of columns in the table control. Cached model value.
        TableSize               m_nColumnCount;

        /// the number of rows in the table control. Cached model value.
        TableSize               m_nRowCount;

        ColPos                  m_nCurColumn;
        RowPos                  m_nCurRow;
        ColPos                  m_nLeftColumn;
        RowPos                  m_nTopRow;

        sal_Int32               m_nCursorHidden;

        /** the window to contain all data content, including header bars

            The window's upper left corner is at position (0,0), relative to the
            table control, which is the direct parent of the data window.
        */
        VclPtr<TableDataWindow> m_pDataWindow;
        /// the vertical scrollbar, if any
        VclPtr<ScrollBar>       m_pVScroll;
        /// the horizontal scrollbar, if any
        VclPtr<ScrollBar>       m_pHScroll;
        VclPtr<ScrollBarBox>    m_pScrollCorner;
        //selection engine - for determining selection range, e.g. single, multiple
        std::unique_ptr<SelectionEngine> m_pSelEngine;
        //vector which contains the selected rows
        std::vector<RowPos>     m_aSelectedRows;
        //part of selection engine
        std::unique_ptr<TableFunctionSet> m_pTableFunctionSet;
        //part of selection engine
        RowPos                  m_nAnchor;
        bool                    m_bUpdatingColWidths;

        vcl::AccessibleFactoryAccess     m_aFactoryAccess;
        vcl::table::IAccessibleTableControl*    m_pAccessibleTable;

    public:
        void        setModel( const PTableModel& _pModel );

        const PTableInputHandler&   getInputHandler() const { return m_pInputHandler; }

        RowPos  getCurRow() const           { return m_nCurRow; }

        RowPos  getAnchor() const { return m_nAnchor; }
        void    setAnchor( RowPos const i_anchor ) { m_nAnchor = i_anchor; }

        RowPos  getTopRow() const       { return m_nTopRow; }
        ColPos  getLeftColumn() const { return m_nLeftColumn; }

        const TableControl&   getAntiImpl() const { return m_rAntiImpl; }
        TableControl&   getAntiImpl()       { return m_rAntiImpl; }

    public:
        explicit TableControl_Impl( TableControl& _rAntiImpl );
        virtual ~TableControl_Impl() override;

        /** to be called when the anti-impl instance has been resized
        */
        void    onResize();

        /** paints the table control content which intersects with the given rectangle
        */
        void    doPaintContent(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rUpdateRect);

        /** moves the cursor to the cell with the given coordinates

            To ease the caller's code, the coordinates must not necessarily denote a
            valid position. If they don't, <FALSE/> will be returned.
        */
        bool    goTo( ColPos _nColumn, RowPos _nRow );

        /** ensures that the given coordinate is visible
            @param _nColumn
                the column position which should be visible. Must be non-negative, and smaller
                than the column count.
            @param _nRow
                the row position which should be visibleMust be non-negative, and smaller
                than the row count.
        */
        void    ensureVisible( ColPos _nColumn, RowPos _nRow );

        /** retrieves the content of the given cell, converted to a string
        */
        OUString getCellContentAsString( RowPos const i_row, ColPos const i_col );

        /** returns the position of the current row in the selection vector */
        static int getRowSelectedNumber(const ::std::vector<RowPos>& selectedRows, RowPos current);

        void invalidateRect(const tools::Rectangle &rInvalidateRect);

        /** ??? */
        void    invalidateSelectedRegion( RowPos _nPrevRow, RowPos _nCurRow );

        /** invalidates the part of the data window which is covered by the given rows
            @param i_firstRow
                the index of the first row to include in the invalidation
            @param i_lastRow
                the index of the last row to include in the invalidation, or ROW_INVALID if the invalidation
                should happen down to the bottom of the data window.
        */
        void    invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow );

        /** invalidates the part of the data window which is covered by the given row
        */
        void    invalidateRow( RowPos const i_row ) { invalidateRowRange( i_row, i_row ); }

        /** invalidates all selected rows
        */
        void    invalidateSelectedRows();

        void    checkCursorPosition();

        bool    hasRowSelection() const { return !m_aSelectedRows.empty(); }
        size_t  getSelectedRowCount() const { return m_aSelectedRows.size(); }
        RowPos  getSelectedRowIndex( size_t const i_selectionIndex ) const;

        /** removes the given row index from m_aSelectedRows

            @return
                <TRUE/> if and only if the row was previously marked as selected
        */
        bool        markRowAsDeselected( RowPos const i_rowIndex );

        /** marks the given row as selected, by putting it into m_aSelectedRows
            @return
                <TRUE/> if and only if the row was previously <em>not</em> marked as selected
        */
        bool        markRowAsSelected( RowPos const i_rowIndex );

        /** marks all rows as deselected
            @return
                <TRUE/> if and only if the selection actually changed by this operation
        */
        bool        markAllRowsAsDeselected();

        /** marks all rows as selected
            @return
                <FALSE/> if and only if all rows were selected already.
        */
        bool        markAllRowsAsSelected();

        void commitAccessibleEvent( sal_Int16 const i_eventID );
        void commitCellEvent( sal_Int16 const i_eventID, const css::uno::Any& i_newValue, const css::uno::Any& i_oldValue );
        void commitTableEvent( sal_Int16 const i_eventID, const css::uno::Any& i_newValue, const css::uno::Any& i_oldValue );

        // ITableControl
        virtual void                hideCursor() override;
        virtual void                showCursor() override;
        virtual bool                dispatchAction( TableControlAction _eAction ) override;
        virtual SelectionEngine*    getSelEngine() override;
        virtual PTableModel         getModel() const override;
        virtual ColPos              getCurrentColumn() const override;
        virtual RowPos              getCurrentRow() const override;
        virtual void                activateCell( ColPos const i_col, RowPos const i_row ) override;
        virtual ::Size              getTableSizePixel() const override;
        virtual void                setPointer( PointerStyle i_pointer ) override;
        virtual void                captureMouse() override;
        virtual void                releaseMouse() override;
        virtual void                invalidate( TableArea const i_what ) override;
        virtual tools::Long                pixelWidthToAppFont( tools::Long const i_pixels ) const override;
        virtual void                hideTracking() override;
        virtual void                showTracking( tools::Rectangle const & i_location, ShowTrackFlags const i_flags ) override;
        RowPos                      getRowAtPoint( const Point& rPoint ) const;
        ColPos                      getColAtPoint( const Point& rPoint ) const;
        virtual TableCell           hitTest( const Point& rPoint ) const override;
        virtual ColumnMetrics       getColumnMetrics( ColPos const i_column ) const override;
        virtual bool                isRowSelected( RowPos i_row ) const override;


        tools::Long                        appFontWidthToPixel( tools::Long const i_appFontUnits ) const;

        TableDataWindow&        getDataWindow()       { return *m_pDataWindow; }
        const TableDataWindow&  getDataWindow() const { return *m_pDataWindow; }
        ScrollBar* getHorzScrollbar() { return m_pHScroll; }
        ScrollBar* getVertScrollbar() { return m_pVScroll; }

        tools::Rectangle calcHeaderRect( bool bColHeader );
        tools::Rectangle calcHeaderCellRect( bool bColHeader, sal_Int32 nPos );
        tools::Rectangle calcTableRect() const;
        tools::Rectangle calcCellRect( sal_Int32 nRow, sal_Int32 nCol ) const;

        // A11Y
        css::uno::Reference< css::accessibility::XAccessible >
                        getAccessible( vcl::Window& i_parentWindow );
        void            disposeAccessible();

        bool     isAccessibleAlive() const { return impl_isAccessibleAlive(); }

        // ITableModelListener
        virtual void    rowsInserted( RowPos first, RowPos last ) override;
        virtual void    rowsRemoved( RowPos first, RowPos last ) override;
        virtual void    columnInserted() override;
        virtual void    columnRemoved() override;
        virtual void    allColumnsRemoved() override;
        virtual void    cellsUpdated( RowPos const i_firstRow, RowPos const i_lastRow ) override;
        virtual void    columnChanged( ColPos const i_column, ColumnAttributeGroup const i_attributeGroup ) override;
        virtual void    tableMetricsChanged() override;

    private:
        bool            impl_isAccessibleAlive() const;
        void            impl_commitAccessibleEvent(
                            sal_Int16 const i_eventID,
                            css::uno::Any const & i_newValue
                        );

        /** toggles the cursor visibility

            The method is not bound to the classes public invariants, as it's used in
            situations where the they must not necessarily be fulfilled.
        */
        void        impl_ni_doSwitchCursor( bool _bOn );

        /** returns the number of visible rows.

            @param _bAcceptPartialRow
                specifies whether a possible only partially visible last row is
                counted, too.
        */
        TableSize   impl_getVisibleRows( bool _bAcceptPartialRow ) const;

        /** returns the number of visible columns

            The value may change with different horizontal scroll positions, as
            different columns have different widths. For instance, if your control is
            100 pixels wide, and has three columns of width 50, 50, 100, respectively,
            then this method will return either "2" or "1", depending on which column
            is the first visible one.

            @param _bAcceptPartialRow
                specifies whether a possible only partially visible last row is
                counted, too.
        */
        TableSize   impl_getVisibleColumns( bool _bAcceptPartialCol ) const;

        /** determines the rectangle occupied by the given cell
        */
        void        impl_getCellRect( ColPos _nColumn, RowPos _nRow, tools::Rectangle& _rCellRect ) const;

        /** updates all cached model values

            The method is not bound to the classes public invariants, as it's used in
            situations where the they must not necessarily be fulfilled.
        */
        void        impl_ni_updateCachedModelValues();

        /** updates the cached table metrics (row height etc.)
        */
        void        impl_ni_updateCachedTableMetrics();

        /** does a relayout of the table control

            Column widths, and consequently the availability of the vertical and horizontal scrollbar, are updated
            with a call to this method.

            @param i_assumeInflexibleColumnsUpToIncluding
                the index of a column up to which all columns should be considered as inflexible, or
                <code>COL_INVALID</code>.
        */
        void        impl_ni_relayout( ColPos const i_assumeInflexibleColumnsUpToIncluding = COL_INVALID );

        /** calculates the new width of our columns, taking into account their min and max widths, and their relative
            flexibility.

            @param i_assumeInflexibleColumnsUpToIncluding
                the index of a column up to which all columns should be considered as inflexible, or
                <code>COL_INVALID</code>.

            @param i_assumeVerticalScrollbar
                controls whether or not we should assume the presence of a vertical scrollbar. If <true/>, and
                if the model has a VerticalScrollbarVisibility != ScrollbarShowNever, the method will leave
                space for a vertical scrollbar.

            @return
                the overall width of the grid, which is available for columns
        */
        tools::Long        impl_ni_calculateColumnWidths(
                        ColPos const i_assumeInflexibleColumnsUpToIncluding,
                        bool const i_assumeVerticalScrollbar,
                        ::std::vector< tools::Long >& o_newColWidthsPixel
                    ) const;

        /** positions all child windows, e.g. the both scrollbars, the corner window, and the data window
        */
        void        impl_ni_positionChildWindows(
                        tools::Rectangle const & i_dataCellPlayground,
                        bool const i_verticalScrollbar,
                        bool const i_horizontalScrollbar
                    );

        /** scrolls the view by the given number of rows

            The method is not bound to the classes public invariants, as it's used in
            situations where the they must not necessarily be fulfilled.

            @return
                the number of rows by which the viewport was scrolled. This may differ
                from the given numbers to scroll in case the begin or the end of the
                row range were reached.
        */
        TableSize   impl_ni_ScrollRows( TableSize _nRowDelta );

        /** equivalent to impl_ni_ScrollRows, but checks the instances invariants beforehand (in a non-product build only)
        */
        TableSize   impl_scrollRows( TableSize const i_rowDelta );

        /** scrolls the view by the given number of columns

            The method is not bound to the classes public invariants, as it's used in
            situations where the they must not necessarily be fulfilled.

            @return
                the number of columns by which the viewport was scrolled. This may differ
                from the given numbers to scroll in case the begin or the end of the
                column range were reached.
        */
        TableSize   impl_ni_ScrollColumns( TableSize _nColumnDelta );

        /** equivalent to impl_ni_ScrollColumns, but checks the instances invariants beforehand (in a non-product build only)
        */
        TableSize   impl_scrollColumns( TableSize const i_columnDelta );

        /** retrieves the area occupied by the totality of (at least partially) visible cells

            The returned area includes row and column headers. Also, it takes into
            account the fact that there might be less columns than would normally
            find room in the control.

            As a result of respecting the partial visibility of rows and columns,
            the returned area might be larger than the data window's output size.
        */
        tools::Rectangle   impl_getAllVisibleCellsArea() const;

        /** retrieves the area occupied by all (at least partially) visible data cells.

            Effectively, the returned area is the same as returned by ->impl_getAllVisibleCellsArea,
            minus the row and column header areas.
        */
        tools::Rectangle   impl_getAllVisibleDataCellArea() const;

        /** retrieves the column which covers the given ordinate
        */
        ColPos      impl_getColumnForOrdinate( tools::Long const i_ordinate ) const;

        /** retrieves the row which covers the given abscissa
        */
        RowPos      impl_getRowForAbscissa( tools::Long const i_abscissa ) const;

        /// invalidates the window area occupied by the given column
        void        impl_invalidateColumn( ColPos const i_column );

        DECL_LINK( OnScroll, ScrollBar*, void );
        DECL_LINK( OnUpdateScrollbars, void*, void );
    };

    //see seleng.hxx, seleng.cxx, FunctionSet overridables, part of selection engine
    class TableFunctionSet : public FunctionSet
    {
    private:
        TableControl_Impl*  m_pTableControl;
        RowPos              m_nCurrentRow;

    public:
        explicit TableFunctionSet(TableControl_Impl* _pTableControl);
        virtual ~TableFunctionSet() override;

        virtual void BeginDrag() override;
        virtual void CreateAnchor() override;
        virtual void DestroyAnchor() override;
        virtual void SetCursorAtPoint(const Point& rPoint, bool bDontSelectAtCursor = false) override;
        virtual bool IsSelectionAtPoint( const Point& rPoint ) override;
        virtual void DeselectAtPoint( const Point& rPoint ) override;
        virtual void DeselectAll() override;
    };


} // namespace svt::table



/* vim:set shiftwidth=4 softtabstop=4 expandtab: */