1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QTABLEVIEW_P_H
41 #define QTABLEVIEW_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtWidgets/private/qtwidgetsglobal_p.h>
55 #include <QtCore/QList>
56 #include <QtCore/QMap>
57 #include <QtCore/QSet>
58 #include <QtCore/QDebug>
59 #include "private/qabstractitemview_p.h"
60 
61 #include <list>
62 
63 QT_REQUIRE_CONFIG(tableview);
64 
65 QT_BEGIN_NAMESPACE
66 
67 /** \internal
68 *
69 * This is a list of span with a binary index to look up quickly a span at a certain index.
70 *
71 * The index is a map of map.
72 * spans are mentaly divided into sub spans so that the start of any subspans doesn't overlap
73 * with any other subspans. There is no real representation of the subspans.
74 * The key of the first map is the row where the subspan starts, the value of the first map is
75 * a list (map) of all subspans that starts at the same row.  It is indexed with its row
76 */
77 class Q_AUTOTEST_EXPORT QSpanCollection
78 {
79 public:
80     struct Span
81     {
82         int m_top;
83         int m_left;
84         int m_bottom;
85         int m_right;
86         bool will_be_deleted;
SpanSpan87         Span()
88         : m_top(-1), m_left(-1), m_bottom(-1), m_right(-1), will_be_deleted(false) { }
SpanSpan89         Span(int row, int column, int rowCount, int columnCount)
90         : m_top(row), m_left(column), m_bottom(row+rowCount-1), m_right(column+columnCount-1), will_be_deleted(false) { }
topSpan91         inline int top() const { return m_top; }
leftSpan92         inline int left() const { return m_left; }
bottomSpan93         inline int bottom() const { return m_bottom; }
rightSpan94         inline int right() const { return m_right; }
heightSpan95         inline int height() const { return m_bottom - m_top + 1; }
widthSpan96         inline int width() const { return m_right - m_left + 1; }
97     };
98 
~QSpanCollection()99     ~QSpanCollection()
100     {
101         qDeleteAll(spans);
102     }
103 
104     void addSpan(Span *span);
105     void updateSpan(Span *span, int old_height);
106     Span *spanAt(int x, int y) const;
107     void clear();
108     QSet<Span *> spansInRect(int x, int y, int w, int h) const;
109 
110     void updateInsertedRows(int start, int end);
111     void updateInsertedColumns(int start, int end);
112     void updateRemovedRows(int start, int end);
113     void updateRemovedColumns(int start, int end);
114 
115 #ifdef QT_BUILD_INTERNAL
116     bool checkConsistency() const;
117 #endif
118 
119     typedef std::list<Span *> SpanList;
120     SpanList spans; //lists of all spans
121 private:
122     //the indexes are negative so the QMap::lowerBound do what i need.
123     typedef QMap<int, Span *> SubIndex;
124     typedef QMap<int, SubIndex> Index;
125     Index index;
126 
127     bool cleanSpanSubIndex(SubIndex &subindex, int end, bool update = false);
128 };
129 
130 Q_DECLARE_TYPEINFO ( QSpanCollection::Span, Q_MOVABLE_TYPE);
131 
132 
133 class QTableViewPrivate : public QAbstractItemViewPrivate
134 {
Q_DECLARE_PUBLIC(QTableView)135     Q_DECLARE_PUBLIC(QTableView)
136 public:
137     QTableViewPrivate()
138         : showGrid(true), gridStyle(Qt::SolidLine),
139           rowSectionAnchor(-1), columnSectionAnchor(-1),
140           columnResizeTimerID(0), rowResizeTimerID(0),
141           horizontalHeader(nullptr), verticalHeader(nullptr),
142           sortingEnabled(false), geometryRecursionBlock(false),
143           visualCursor(QPoint())
144  {
145     wrapItemText = true;
146 #if QT_CONFIG(draganddrop)
147     overwrite = true;
148 #endif
149  }
150     void init();
151     void trimHiddenSelections(QItemSelectionRange *range) const;
152 
isHidden(int row,int col)153     inline bool isHidden(int row, int col) const {
154         return verticalHeader->isSectionHidden(row)
155             || horizontalHeader->isSectionHidden(col);
156     }
visualRow(int logicalRow)157     inline int visualRow(int logicalRow) const {
158         return verticalHeader->visualIndex(logicalRow);
159     }
visualColumn(int logicalCol)160     inline int visualColumn(int logicalCol) const {
161         return horizontalHeader->visualIndex(logicalCol);
162     }
logicalRow(int visualRow)163     inline int logicalRow(int visualRow) const {
164         return verticalHeader->logicalIndex(visualRow);
165     }
logicalColumn(int visualCol)166     inline int logicalColumn(int visualCol) const {
167         return horizontalHeader->logicalIndex(visualCol);
168     }
169 
accessibleTable2Index(const QModelIndex & index)170     inline int accessibleTable2Index(const QModelIndex &index) const {
171         const int vHeader = verticalHeader ? 1 : 0;
172         return (index.row() + (horizontalHeader ? 1 : 0)) * (index.model()->columnCount() + vHeader)
173             + index.column() + vHeader;
174     }
175 
176     int sectionSpanEndLogical(const QHeaderView *header, int logical, int span) const;
177     int sectionSpanSize(const QHeaderView *header, int logical, int span) const;
178     bool spanContainsSection(const QHeaderView *header, int logical, int spanLogical, int span) const;
179     void drawAndClipSpans(const QRegion &area, QPainter *painter,
180                           const QStyleOptionViewItem &option, QBitArray *drawn,
181                           int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn);
182     void drawCell(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index);
183     int widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option) const;
184     int heightHintForIndex(const QModelIndex &index, int hint, QStyleOptionViewItem &option) const;
185 
186     bool showGrid;
187     Qt::PenStyle gridStyle;
188     int rowSectionAnchor;
189     int columnSectionAnchor;
190     int columnResizeTimerID;
191     int rowResizeTimerID;
192     QVector<int> columnsToUpdate;
193     QVector<int> rowsToUpdate;
194     QHeaderView *horizontalHeader;
195     QHeaderView *verticalHeader;
196 #if QT_CONFIG(abstractbutton)
197     QWidget *cornerWidget;
198 #endif
199     bool sortingEnabled;
200     bool geometryRecursionBlock;
201     QPoint visualCursor;  // (Row,column) cell coordinates to track through span navigation.
202 
203     QSpanCollection spans;
204 
205     void setSpan(int row, int column, int rowSpan, int columnSpan);
206     QSpanCollection::Span span(int row, int column) const;
rowSpan(int row,int column)207     inline int rowSpan(int row, int column) const {
208         return span(row, column).height();
209     }
columnSpan(int row,int column)210     inline int columnSpan(int row, int column) const {
211         return span(row, column).width();
212     }
hasSpans()213     inline bool hasSpans() const {
214         return !spans.spans.empty();
215     }
rowSpanHeight(int row,int span)216     inline int rowSpanHeight(int row, int span) const {
217         return sectionSpanSize(verticalHeader, row, span);
218     }
columnSpanWidth(int column,int span)219     inline int columnSpanWidth(int column, int span) const {
220         return sectionSpanSize(horizontalHeader, column, span);
221     }
rowSpanEndLogical(int row,int span)222     inline int rowSpanEndLogical(int row, int span) const {
223         return sectionSpanEndLogical(verticalHeader, row, span);
224     }
columnSpanEndLogical(int column,int span)225     inline int columnSpanEndLogical(int column, int span) const {
226         return sectionSpanEndLogical(horizontalHeader, column, span);
227     }
228 
isRowHidden(int row)229     inline bool isRowHidden(int row) const {
230         return verticalHeader->isSectionHidden(row);
231     }
isColumnHidden(int column)232     inline bool isColumnHidden(int column) const {
233         return horizontalHeader->isSectionHidden(column);
234     }
isCellEnabled(int row,int column)235     inline bool isCellEnabled(int row, int column) const {
236         return isIndexEnabled(model->index(row, column, root));
237     }
238 
239     enum class SearchDirection
240     {
241         Increasing,
242         Decreasing
243     };
244     int nextActiveVisualRow(int rowToStart, int column, int limit,
245                             SearchDirection searchDirection) const;
246     int nextActiveVisualColumn(int row, int columnToStart, int limit,
247                                SearchDirection searchDirection) const;
248 
249     QRect visualSpanRect(const QSpanCollection::Span &span) const;
250 
251     void _q_selectRow(int row);
252     void _q_selectColumn(int column);
253 
254     void selectRow(int row, bool anchor);
255     void selectColumn(int column, bool anchor);
256 
257     void _q_updateSpanInsertedRows(const QModelIndex &parent, int start, int end);
258     void _q_updateSpanInsertedColumns(const QModelIndex &parent, int start, int end);
259     void _q_updateSpanRemovedRows(const QModelIndex &parent, int start, int end);
260     void _q_updateSpanRemovedColumns(const QModelIndex &parent, int start, int end);
261     void _q_sortIndicatorChanged(int column, Qt::SortOrder order);
262 };
263 
264 QT_END_NAMESPACE
265 
266 #endif // QTABLEVIEW_P_H
267