1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the QtGui module of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "qtableview.h"
|
---|
43 |
|
---|
44 | #ifndef QT_NO_TABLEVIEW
|
---|
45 | #include <qheaderview.h>
|
---|
46 | #include <qitemdelegate.h>
|
---|
47 | #include <qapplication.h>
|
---|
48 | #include <qpainter.h>
|
---|
49 | #include <qstyle.h>
|
---|
50 | #include <qsize.h>
|
---|
51 | #include <qevent.h>
|
---|
52 | #include <qbitarray.h>
|
---|
53 | #include <qscrollbar.h>
|
---|
54 | #include <qabstractbutton.h>
|
---|
55 | #include <private/qtableview_p.h>
|
---|
56 | #ifndef QT_NO_ACCESSIBILITY
|
---|
57 | #include <qaccessible.h>
|
---|
58 | #endif
|
---|
59 |
|
---|
60 | QT_BEGIN_NAMESPACE
|
---|
61 |
|
---|
62 | /** \internal
|
---|
63 | Add a span to the collection. the collection takes the ownership.
|
---|
64 | */
|
---|
65 | void QSpanCollection::addSpan(QSpanCollection::Span *span)
|
---|
66 | {
|
---|
67 | spans.append(span);
|
---|
68 | Index::iterator it_y = index.lowerBound(-span->top());
|
---|
69 | if (it_y == index.end() || it_y.key() != -span->top()) {
|
---|
70 | //there is no spans that starts with the row in the index, so create a sublist for it.
|
---|
71 | SubIndex sub_index;
|
---|
72 | if (it_y != index.end()) {
|
---|
73 | //the previouslist is the list of spans that sarts _before_ the row of the span.
|
---|
74 | // and which may intersect this row.
|
---|
75 | const SubIndex previousList = it_y.value();
|
---|
76 | foreach(Span *s, previousList) {
|
---|
77 | //If a subspans intersect the row, we need to split it into subspans
|
---|
78 | if(s->bottom() >= span->top())
|
---|
79 | sub_index.insert(-s->left(), s);
|
---|
80 | }
|
---|
81 | }
|
---|
82 | it_y = index.insert(-span->top(), sub_index);
|
---|
83 | //we will insert span to *it_y in the later loop
|
---|
84 | }
|
---|
85 |
|
---|
86 | //insert the span as supspan in all the lists that intesects the span
|
---|
87 | while(-it_y.key() <= span->bottom()) {
|
---|
88 | (*it_y).insert(-span->left(), span);
|
---|
89 | if(it_y == index.begin())
|
---|
90 | break;
|
---|
91 | --it_y;
|
---|
92 | }
|
---|
93 | }
|
---|
94 |
|
---|
95 |
|
---|
96 | /** \internal
|
---|
97 | * Has to be called after the height and width of a span is changed.
|
---|
98 | *
|
---|
99 | * old_height is the height before the change
|
---|
100 | *
|
---|
101 | * if the size of the span is now 0x0 the span will be deleted.
|
---|
102 | */
|
---|
103 | void QSpanCollection::updateSpan(QSpanCollection::Span *span, int old_height)
|
---|
104 | {
|
---|
105 | if (old_height < span->height()) {
|
---|
106 | //add the span as subspan in all the lists that intersect the new covered columns
|
---|
107 | Index::iterator it_y = index.lowerBound(-(span->top() + old_height - 1));
|
---|
108 | Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list
|
---|
109 | while (-it_y.key() <= span->bottom()) {
|
---|
110 | (*it_y).insert(-span->left(), span);
|
---|
111 | if(it_y == index.begin())
|
---|
112 | break;
|
---|
113 | --it_y;
|
---|
114 | }
|
---|
115 | } else if (old_height > span->height()) {
|
---|
116 | //remove the span from all the subspans lists that intersect the columns not covered anymore
|
---|
117 | Index::iterator it_y = index.lowerBound(-qMax(span->bottom(), span->top())); //qMax useful if height is 0
|
---|
118 | Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list
|
---|
119 | while (-it_y.key() <= span->top() + old_height -1) {
|
---|
120 | if (-it_y.key() > span->bottom()) {
|
---|
121 | int removed = (*it_y).remove(-span->left());
|
---|
122 | Q_ASSERT(removed == 1); Q_UNUSED(removed);
|
---|
123 | if (it_y->isEmpty()) {
|
---|
124 | it_y = index.erase(it_y);
|
---|
125 | }
|
---|
126 | }
|
---|
127 | if(it_y == index.begin())
|
---|
128 | break;
|
---|
129 | --it_y;
|
---|
130 | }
|
---|
131 | }
|
---|
132 |
|
---|
133 | if (span->width() == 0 && span->height() == 0) {
|
---|
134 | spans.removeOne(span);
|
---|
135 | delete span;
|
---|
136 | }
|
---|
137 | }
|
---|
138 |
|
---|
139 | /** \internal
|
---|
140 | * \return a spans that spans over cell x,y (column,row) or 0 if there is none.
|
---|
141 | */
|
---|
142 | QSpanCollection::Span *QSpanCollection::spanAt(int x, int y) const
|
---|
143 | {
|
---|
144 | Index::const_iterator it_y = index.lowerBound(-y);
|
---|
145 | if (it_y == index.end())
|
---|
146 | return 0;
|
---|
147 | SubIndex::const_iterator it_x = (*it_y).lowerBound(-x);
|
---|
148 | if (it_x == (*it_y).end())
|
---|
149 | return 0;
|
---|
150 | Span *span = *it_x;
|
---|
151 | if (span->right() >= x && span->bottom() >= y)
|
---|
152 | return span;
|
---|
153 | return 0;
|
---|
154 | }
|
---|
155 |
|
---|
156 |
|
---|
157 | /** \internal
|
---|
158 | * remove and deletes all spans inside the collection
|
---|
159 | */
|
---|
160 | void QSpanCollection::clear()
|
---|
161 | {
|
---|
162 | qDeleteAll(spans);
|
---|
163 | index.clear();
|
---|
164 | spans.clear();
|
---|
165 | }
|
---|
166 |
|
---|
167 | /** \internal
|
---|
168 | * return a list to all the spans that spans over cells in the given rectangle
|
---|
169 | */
|
---|
170 | QList<QSpanCollection::Span *> QSpanCollection::spansInRect(int x, int y, int w, int h) const
|
---|
171 | {
|
---|
172 | QSet<Span *> list;
|
---|
173 | Index::const_iterator it_y = index.lowerBound(-y);
|
---|
174 | if(it_y == index.end())
|
---|
175 | --it_y;
|
---|
176 | while(-it_y.key() <= y + h) {
|
---|
177 | SubIndex::const_iterator it_x = (*it_y).lowerBound(-x);
|
---|
178 | if (it_x == (*it_y).end())
|
---|
179 | --it_x;
|
---|
180 | while(-it_x.key() <= x + w) {
|
---|
181 | Span *s = *it_x;
|
---|
182 | if (s->bottom() >= y && s->right() >= x)
|
---|
183 | list << s;
|
---|
184 | if (it_x == (*it_y).begin())
|
---|
185 | break;
|
---|
186 | --it_x;
|
---|
187 | }
|
---|
188 | if(it_y == index.begin())
|
---|
189 | break;
|
---|
190 | --it_y;
|
---|
191 | }
|
---|
192 | return list.toList();
|
---|
193 | }
|
---|
194 |
|
---|
195 | #undef DEBUG_SPAN_UPDATE
|
---|
196 |
|
---|
197 | #ifdef DEBUG_SPAN_UPDATE
|
---|
198 | QDebug operator<<(QDebug str, const QSpanCollection::Span &span)
|
---|
199 | {
|
---|
200 | str << "(" << span.top() << "," << span.left() << "," << span.bottom() << "," << span.right() << ")";
|
---|
201 | return str;
|
---|
202 | }
|
---|
203 | #endif
|
---|
204 |
|
---|
205 | /** \internal
|
---|
206 | * Updates the span collection after row insertion.
|
---|
207 | */
|
---|
208 | void QSpanCollection::updateInsertedRows(int start, int end)
|
---|
209 | {
|
---|
210 | #ifdef DEBUG_SPAN_UPDATE
|
---|
211 | qDebug() << Q_FUNC_INFO;
|
---|
212 | qDebug() << start << end;
|
---|
213 | qDebug() << index;
|
---|
214 | #endif
|
---|
215 | if (spans.isEmpty())
|
---|
216 | return;
|
---|
217 |
|
---|
218 | int delta = end - start + 1;
|
---|
219 | #ifdef DEBUG_SPAN_UPDATE
|
---|
220 | qDebug("Before");
|
---|
221 | #endif
|
---|
222 | for (SpanList::iterator it = spans.begin(); it != spans.end(); ++it) {
|
---|
223 | Span *span = *it;
|
---|
224 | #ifdef DEBUG_SPAN_UPDATE
|
---|
225 | qDebug() << span << *span;
|
---|
226 | #endif
|
---|
227 | if (span->m_bottom < start)
|
---|
228 | continue;
|
---|
229 | if (span->m_top >= start)
|
---|
230 | span->m_top += delta;
|
---|
231 | span->m_bottom += delta;
|
---|
232 | }
|
---|
233 |
|
---|
234 | #ifdef DEBUG_SPAN_UPDATE
|
---|
235 | qDebug("After");
|
---|
236 | foreach (QSpanCollection::Span *span, spans)
|
---|
237 | qDebug() << span << *span;
|
---|
238 | #endif
|
---|
239 |
|
---|
240 | for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
|
---|
241 | int y = -it_y.key();
|
---|
242 | if (y < start) {
|
---|
243 | ++it_y;
|
---|
244 | continue;
|
---|
245 | }
|
---|
246 |
|
---|
247 | index.insert(-y - delta, it_y.value());
|
---|
248 | it_y = index.erase(it_y);
|
---|
249 | }
|
---|
250 | #ifdef DEBUG_SPAN_UPDATE
|
---|
251 | qDebug() << index;
|
---|
252 | #endif
|
---|
253 | }
|
---|
254 |
|
---|
255 | /** \internal
|
---|
256 | * Updates the span collection after column insertion.
|
---|
257 | */
|
---|
258 | void QSpanCollection::updateInsertedColumns(int start, int end)
|
---|
259 | {
|
---|
260 | #ifdef DEBUG_SPAN_UPDATE
|
---|
261 | qDebug() << Q_FUNC_INFO;
|
---|
262 | qDebug() << start << end;
|
---|
263 | qDebug() << index;
|
---|
264 | #endif
|
---|
265 | if (spans.isEmpty())
|
---|
266 | return;
|
---|
267 |
|
---|
268 | int delta = end - start + 1;
|
---|
269 | #ifdef DEBUG_SPAN_UPDATE
|
---|
270 | qDebug("Before");
|
---|
271 | #endif
|
---|
272 | for (SpanList::iterator it = spans.begin(); it != spans.end(); ++it) {
|
---|
273 | Span *span = *it;
|
---|
274 | #ifdef DEBUG_SPAN_UPDATE
|
---|
275 | qDebug() << span << *span;
|
---|
276 | #endif
|
---|
277 | if (span->m_right < start)
|
---|
278 | continue;
|
---|
279 | if (span->m_left >= start)
|
---|
280 | span->m_left += delta;
|
---|
281 | span->m_right += delta;
|
---|
282 | }
|
---|
283 |
|
---|
284 | #ifdef DEBUG_SPAN_UPDATE
|
---|
285 | qDebug("After");
|
---|
286 | foreach (QSpanCollection::Span *span, spans)
|
---|
287 | qDebug() << span << *span;
|
---|
288 | #endif
|
---|
289 |
|
---|
290 | for (Index::iterator it_y = index.begin(); it_y != index.end(); ++it_y) {
|
---|
291 | SubIndex &subindex = it_y.value();
|
---|
292 | for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ) {
|
---|
293 | int x = -it.key();
|
---|
294 | if (x < start) {
|
---|
295 | ++it;
|
---|
296 | continue;
|
---|
297 | }
|
---|
298 | subindex.insert(-x - delta, it.value());
|
---|
299 | it = subindex.erase(it);
|
---|
300 | }
|
---|
301 | }
|
---|
302 | #ifdef DEBUG_SPAN_UPDATE
|
---|
303 | qDebug() << index;
|
---|
304 | #endif
|
---|
305 | }
|
---|
306 |
|
---|
307 | /** \internal
|
---|
308 | * Cleans a subindex from to be deleted spans. The update argument is used
|
---|
309 | * to move the spans inside the subindex, in case their anchor changed.
|
---|
310 | * \return true if no span in this subindex starts at y, and should thus be deleted.
|
---|
311 | */
|
---|
312 | bool QSpanCollection::cleanSpanSubIndex(QSpanCollection::SubIndex &subindex, int y, bool update)
|
---|
313 | {
|
---|
314 | if (subindex.isEmpty())
|
---|
315 | return true;
|
---|
316 |
|
---|
317 | bool should_be_deleted = true;
|
---|
318 | SubIndex::iterator it = subindex.end();
|
---|
319 | do {
|
---|
320 | --it;
|
---|
321 | int x = -it.key();
|
---|
322 | Span *span = it.value();
|
---|
323 | if (span->will_be_deleted) {
|
---|
324 | it = subindex.erase(it);
|
---|
325 | continue;
|
---|
326 | }
|
---|
327 | if (update && span->m_left != x) {
|
---|
328 | subindex.insert(-span->m_left, span);
|
---|
329 | it = subindex.erase(it);
|
---|
330 | }
|
---|
331 | if (should_be_deleted && span->m_top == y)
|
---|
332 | should_be_deleted = false;
|
---|
333 | } while (it != subindex.begin());
|
---|
334 |
|
---|
335 | return should_be_deleted;
|
---|
336 | }
|
---|
337 |
|
---|
338 | /** \internal
|
---|
339 | * Updates the span collection after row removal.
|
---|
340 | */
|
---|
341 | void QSpanCollection::updateRemovedRows(int start, int end)
|
---|
342 | {
|
---|
343 | #ifdef DEBUG_SPAN_UPDATE
|
---|
344 | qDebug() << Q_FUNC_INFO;
|
---|
345 | qDebug() << start << end;
|
---|
346 | qDebug() << index;
|
---|
347 | #endif
|
---|
348 | if (spans.isEmpty())
|
---|
349 | return;
|
---|
350 |
|
---|
351 | SpanList spansToBeDeleted;
|
---|
352 | int delta = end - start + 1;
|
---|
353 | #ifdef DEBUG_SPAN_UPDATE
|
---|
354 | qDebug("Before");
|
---|
355 | #endif
|
---|
356 | for (SpanList::iterator it = spans.begin(); it != spans.end(); ) {
|
---|
357 | Span *span = *it;
|
---|
358 | #ifdef DEBUG_SPAN_UPDATE
|
---|
359 | qDebug() << span << *span;
|
---|
360 | #endif
|
---|
361 | if (span->m_bottom < start) {
|
---|
362 | ++it;
|
---|
363 | continue;
|
---|
364 | }
|
---|
365 | if (span->m_top < start) {
|
---|
366 | if (span->m_bottom <= end)
|
---|
367 | span->m_bottom = start - 1;
|
---|
368 | else
|
---|
369 | span->m_bottom -= delta;
|
---|
370 | } else {
|
---|
371 | if (span->m_bottom > end) {
|
---|
372 | if (span->m_top <= end)
|
---|
373 | span->m_top = start;
|
---|
374 | else
|
---|
375 | span->m_top -= delta;
|
---|
376 | span->m_bottom -= delta;
|
---|
377 | } else {
|
---|
378 | span->will_be_deleted = true;
|
---|
379 | }
|
---|
380 | }
|
---|
381 | if (span->m_top == span->m_bottom && span->m_left == span->m_right)
|
---|
382 | span->will_be_deleted = true;
|
---|
383 | if (span->will_be_deleted) {
|
---|
384 | spansToBeDeleted.append(span);
|
---|
385 | it = spans.erase(it);
|
---|
386 | } else {
|
---|
387 | ++it;
|
---|
388 | }
|
---|
389 | }
|
---|
390 |
|
---|
391 | #ifdef DEBUG_SPAN_UPDATE
|
---|
392 | qDebug("After");
|
---|
393 | foreach (QSpanCollection::Span *span, spans)
|
---|
394 | qDebug() << span << *span;
|
---|
395 | #endif
|
---|
396 | if (spans.isEmpty()) {
|
---|
397 | qDeleteAll(spansToBeDeleted);
|
---|
398 | index.clear();
|
---|
399 | return;
|
---|
400 | }
|
---|
401 |
|
---|
402 | Index::iterator it_y = index.end();
|
---|
403 | do {
|
---|
404 | --it_y;
|
---|
405 | int y = -it_y.key();
|
---|
406 | SubIndex &subindex = it_y.value();
|
---|
407 | if (y < start) {
|
---|
408 | if (cleanSpanSubIndex(subindex, y))
|
---|
409 | it_y = index.erase(it_y);
|
---|
410 | } else if (y >= start && y <= end) {
|
---|
411 | bool span_at_start = false;
|
---|
412 | SubIndex spansToBeMoved;
|
---|
413 | for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ++it) {
|
---|
414 | Span *span = it.value();
|
---|
415 | if (span->will_be_deleted)
|
---|
416 | continue;
|
---|
417 | if (!span_at_start && span->m_top == start)
|
---|
418 | span_at_start = true;
|
---|
419 | spansToBeMoved.insert(it.key(), span);
|
---|
420 | }
|
---|
421 |
|
---|
422 | if (y == start && span_at_start)
|
---|
423 | subindex.clear();
|
---|
424 | else
|
---|
425 | it_y = index.erase(it_y);
|
---|
426 |
|
---|
427 | if (span_at_start) {
|
---|
428 | Index::iterator it_start;
|
---|
429 | if (y == start)
|
---|
430 | it_start = it_y;
|
---|
431 | else {
|
---|
432 | it_start = index.find(-start);
|
---|
433 | if (it_start == index.end())
|
---|
434 | it_start = index.insert(-start, SubIndex());
|
---|
435 | }
|
---|
436 | SubIndex &start_subindex = it_start.value();
|
---|
437 | for (SubIndex::iterator it = spansToBeMoved.begin(); it != spansToBeMoved.end(); ++it)
|
---|
438 | start_subindex.insert(it.key(), it.value());
|
---|
439 | }
|
---|
440 | } else {
|
---|
441 | if (y == end + 1) {
|
---|
442 | Index::iterator it_top = index.find(-y + delta);
|
---|
443 | if (it_top == index.end())
|
---|
444 | it_top = index.insert(-y + delta, SubIndex());
|
---|
445 | for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ) {
|
---|
446 | Span *span = it.value();
|
---|
447 | if (!span->will_be_deleted)
|
---|
448 | it_top.value().insert(it.key(), span);
|
---|
449 | ++it;
|
---|
450 | }
|
---|
451 | } else {
|
---|
452 | index.insert(-y + delta, subindex);
|
---|
453 | }
|
---|
454 | it_y = index.erase(it_y);
|
---|
455 | }
|
---|
456 | } while (it_y != index.begin());
|
---|
457 |
|
---|
458 | #ifdef DEBUG_SPAN_UPDATE
|
---|
459 | qDebug() << index;
|
---|
460 | qDebug("Deleted");
|
---|
461 | foreach (QSpanCollection::Span *span, spansToBeDeleted)
|
---|
462 | qDebug() << span << *span;
|
---|
463 | #endif
|
---|
464 | qDeleteAll(spansToBeDeleted);
|
---|
465 | }
|
---|
466 |
|
---|
467 | /** \internal
|
---|
468 | * Updates the span collection after column removal.
|
---|
469 | */
|
---|
470 | void QSpanCollection::updateRemovedColumns(int start, int end)
|
---|
471 | {
|
---|
472 | #ifdef DEBUG_SPAN_UPDATE
|
---|
473 | qDebug() << Q_FUNC_INFO;
|
---|
474 | qDebug() << start << end;
|
---|
475 | qDebug() << index;
|
---|
476 | #endif
|
---|
477 | if (spans.isEmpty())
|
---|
478 | return;
|
---|
479 |
|
---|
480 | SpanList toBeDeleted;
|
---|
481 | int delta = end - start + 1;
|
---|
482 | #ifdef DEBUG_SPAN_UPDATE
|
---|
483 | qDebug("Before");
|
---|
484 | #endif
|
---|
485 | for (SpanList::iterator it = spans.begin(); it != spans.end(); ) {
|
---|
486 | Span *span = *it;
|
---|
487 | #ifdef DEBUG_SPAN_UPDATE
|
---|
488 | qDebug() << span << *span;
|
---|
489 | #endif
|
---|
490 | if (span->m_right < start) {
|
---|
491 | ++it;
|
---|
492 | continue;
|
---|
493 | }
|
---|
494 | if (span->m_left < start) {
|
---|
495 | if (span->m_right <= end)
|
---|
496 | span->m_right = start - 1;
|
---|
497 | else
|
---|
498 | span->m_right -= delta;
|
---|
499 | } else {
|
---|
500 | if (span->m_right > end) {
|
---|
501 | if (span->m_left <= end)
|
---|
502 | span->m_left = start;
|
---|
503 | else
|
---|
504 | span->m_left -= delta;
|
---|
505 | span->m_right -= delta;
|
---|
506 | } else {
|
---|
507 | span->will_be_deleted = true;
|
---|
508 | }
|
---|
509 | }
|
---|
510 | if (span->m_top == span->m_bottom && span->m_left == span->m_right)
|
---|
511 | span->will_be_deleted = true;
|
---|
512 | if (span->will_be_deleted) {
|
---|
513 | toBeDeleted.append(span);
|
---|
514 | it = spans.erase(it);
|
---|
515 | } else {
|
---|
516 | ++it;
|
---|
517 | }
|
---|
518 | }
|
---|
519 |
|
---|
520 | #ifdef DEBUG_SPAN_UPDATE
|
---|
521 | qDebug("After");
|
---|
522 | foreach (QSpanCollection::Span *span, spans)
|
---|
523 | qDebug() << span << *span;
|
---|
524 | #endif
|
---|
525 | if (spans.isEmpty()) {
|
---|
526 | qDeleteAll(toBeDeleted);
|
---|
527 | index.clear();
|
---|
528 | return;
|
---|
529 | }
|
---|
530 |
|
---|
531 | for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
|
---|
532 | int y = -it_y.key();
|
---|
533 | if (cleanSpanSubIndex(it_y.value(), y, true))
|
---|
534 | it_y = index.erase(it_y);
|
---|
535 | else
|
---|
536 | ++it_y;
|
---|
537 | }
|
---|
538 |
|
---|
539 | #ifdef DEBUG_SPAN_UPDATE
|
---|
540 | qDebug() << index;
|
---|
541 | qDebug("Deleted");
|
---|
542 | foreach (QSpanCollection::Span *span, toBeDeleted)
|
---|
543 | qDebug() << span << *span;
|
---|
544 | #endif
|
---|
545 | qDeleteAll(toBeDeleted);
|
---|
546 | }
|
---|
547 |
|
---|
548 | #ifdef QT_BUILD_INTERNAL
|
---|
549 | /*!
|
---|
550 | \internal
|
---|
551 | Checks whether the span index structure is self-consistent, and consistent with the spans list.
|
---|
552 | */
|
---|
553 | bool QSpanCollection::checkConsistency() const
|
---|
554 | {
|
---|
555 | for (Index::const_iterator it_y = index.begin(); it_y != index.end(); ++it_y) {
|
---|
556 | int y = -it_y.key();
|
---|
557 | const SubIndex &subIndex = it_y.value();
|
---|
558 | for (SubIndex::const_iterator it = subIndex.begin(); it != subIndex.end(); ++it) {
|
---|
559 | int x = -it.key();
|
---|
560 | Span *span = it.value();
|
---|
561 | if (!spans.contains(span) || span->left() != x
|
---|
562 | || y < span->top() || y > span->bottom())
|
---|
563 | return false;
|
---|
564 | }
|
---|
565 | }
|
---|
566 |
|
---|
567 | foreach (const Span *span, spans) {
|
---|
568 | if (span->width() < 1 || span->height() < 1
|
---|
569 | || (span->width() == 1 && span->height() == 1))
|
---|
570 | return false;
|
---|
571 | for (int y = span->top(); y <= span->bottom(); ++y) {
|
---|
572 | Index::const_iterator it_y = index.find(-y);
|
---|
573 | if (it_y == index.end()) {
|
---|
574 | if (y == span->top())
|
---|
575 | return false;
|
---|
576 | else
|
---|
577 | continue;
|
---|
578 | }
|
---|
579 | const SubIndex &subIndex = it_y.value();
|
---|
580 | SubIndex::const_iterator it = subIndex.find(-span->left());
|
---|
581 | if (it == subIndex.end() || it.value() != span)
|
---|
582 | return false;
|
---|
583 | }
|
---|
584 | }
|
---|
585 | return true;
|
---|
586 | }
|
---|
587 | #endif
|
---|
588 |
|
---|
589 | class QTableCornerButton : public QAbstractButton
|
---|
590 | {
|
---|
591 | Q_OBJECT
|
---|
592 | public:
|
---|
593 | QTableCornerButton(QWidget *parent) : QAbstractButton(parent) {}
|
---|
594 | void paintEvent(QPaintEvent*) {
|
---|
595 | QStyleOptionHeader opt;
|
---|
596 | opt.init(this);
|
---|
597 | QStyle::State state = QStyle::State_None;
|
---|
598 | if (isEnabled())
|
---|
599 | state |= QStyle::State_Enabled;
|
---|
600 | if (isActiveWindow())
|
---|
601 | state |= QStyle::State_Active;
|
---|
602 | if (isDown())
|
---|
603 | state |= QStyle::State_Sunken;
|
---|
604 | opt.state = state;
|
---|
605 | opt.rect = rect();
|
---|
606 | opt.position = QStyleOptionHeader::OnlyOneSection;
|
---|
607 | QPainter painter(this);
|
---|
608 | style()->drawControl(QStyle::CE_Header, &opt, &painter, this);
|
---|
609 | }
|
---|
610 | };
|
---|
611 |
|
---|
612 | void QTableViewPrivate::init()
|
---|
613 | {
|
---|
614 | Q_Q(QTableView);
|
---|
615 |
|
---|
616 | q->setEditTriggers(editTriggers|QAbstractItemView::AnyKeyPressed);
|
---|
617 |
|
---|
618 | QHeaderView *vertical = new QHeaderView(Qt::Vertical, q);
|
---|
619 | vertical->setClickable(true);
|
---|
620 | vertical->setHighlightSections(true);
|
---|
621 | q->setVerticalHeader(vertical);
|
---|
622 |
|
---|
623 | QHeaderView *horizontal = new QHeaderView(Qt::Horizontal, q);
|
---|
624 | horizontal->setClickable(true);
|
---|
625 | horizontal->setHighlightSections(true);
|
---|
626 | q->setHorizontalHeader(horizontal);
|
---|
627 |
|
---|
628 | tabKeyNavigation = true;
|
---|
629 |
|
---|
630 | cornerWidget = new QTableCornerButton(q);
|
---|
631 | cornerWidget->setFocusPolicy(Qt::NoFocus);
|
---|
632 | QObject::connect(cornerWidget, SIGNAL(clicked()), q, SLOT(selectAll()));
|
---|
633 | }
|
---|
634 |
|
---|
635 | /*!
|
---|
636 | \internal
|
---|
637 | Trims away indices that are hidden in the treeview due to hidden horizontal or vertical sections.
|
---|
638 | */
|
---|
639 | void QTableViewPrivate::trimHiddenSelections(QItemSelectionRange *range) const
|
---|
640 | {
|
---|
641 | Q_ASSERT(range && range->isValid());
|
---|
642 |
|
---|
643 | int top = range->top();
|
---|
644 | int left = range->left();
|
---|
645 | int bottom = range->bottom();
|
---|
646 | int right = range->right();
|
---|
647 |
|
---|
648 | while (bottom >= top && verticalHeader->isSectionHidden(bottom))
|
---|
649 | --bottom;
|
---|
650 | while (right >= left && horizontalHeader->isSectionHidden(right))
|
---|
651 | --right;
|
---|
652 |
|
---|
653 | if (top > bottom || left > right) { // everything is hidden
|
---|
654 | *range = QItemSelectionRange();
|
---|
655 | return;
|
---|
656 | }
|
---|
657 |
|
---|
658 | while (verticalHeader->isSectionHidden(top) && top <= bottom)
|
---|
659 | ++top;
|
---|
660 | while (horizontalHeader->isSectionHidden(left) && left <= right)
|
---|
661 | ++left;
|
---|
662 |
|
---|
663 | if (top > bottom || left > right) { // everything is hidden
|
---|
664 | *range = QItemSelectionRange();
|
---|
665 | return;
|
---|
666 | }
|
---|
667 |
|
---|
668 | QModelIndex bottomRight = model->index(bottom, right, range->parent());
|
---|
669 | QModelIndex topLeft = model->index(top, left, range->parent());
|
---|
670 | *range = QItemSelectionRange(topLeft, bottomRight);
|
---|
671 | }
|
---|
672 |
|
---|
673 | /*!
|
---|
674 | \internal
|
---|
675 | Sets the span for the cell at (\a row, \a column).
|
---|
676 | */
|
---|
677 | void QTableViewPrivate::setSpan(int row, int column, int rowSpan, int columnSpan)
|
---|
678 | {
|
---|
679 | if (row < 0 || column < 0 || rowSpan <= 0 || columnSpan <= 0) {
|
---|
680 | qWarning() << "QTableView::setSpan: invalid span given: (" << row << ',' << column << ',' << rowSpan << ',' << columnSpan << ')';
|
---|
681 | return;
|
---|
682 | }
|
---|
683 | QSpanCollection::Span *sp = spans.spanAt(column, row);
|
---|
684 | if (sp) {
|
---|
685 | if (sp->top() != row || sp->left() != column) {
|
---|
686 | qWarning() << "QTableView::setSpan: span cannot overlap";
|
---|
687 | return;
|
---|
688 | }
|
---|
689 | if (rowSpan == 1 && columnSpan == 1) {
|
---|
690 | rowSpan = columnSpan = 0;
|
---|
691 | }
|
---|
692 | const int old_height = sp->height();
|
---|
693 | sp->m_bottom = row + rowSpan - 1;
|
---|
694 | sp->m_right = column + columnSpan - 1;
|
---|
695 | spans.updateSpan(sp, old_height);
|
---|
696 | return;
|
---|
697 | } else if (rowSpan == 1 && columnSpan == 1) {
|
---|
698 | qWarning() << "QTableView::setSpan: single cell span won't be added";
|
---|
699 | return;
|
---|
700 | }
|
---|
701 | sp = new QSpanCollection::Span(row, column, rowSpan, columnSpan);
|
---|
702 | spans.addSpan(sp);
|
---|
703 | }
|
---|
704 |
|
---|
705 | /*!
|
---|
706 | \internal
|
---|
707 | Gets the span information for the cell at (\a row, \a column).
|
---|
708 | */
|
---|
709 | QSpanCollection::Span QTableViewPrivate::span(int row, int column) const
|
---|
710 | {
|
---|
711 | QSpanCollection::Span *sp = spans.spanAt(column, row);
|
---|
712 | if (sp)
|
---|
713 | return *sp;
|
---|
714 |
|
---|
715 | return QSpanCollection::Span(row, column, 1, 1);
|
---|
716 | }
|
---|
717 |
|
---|
718 | /*!
|
---|
719 | \internal
|
---|
720 | Returns the logical index of the last section that's part of the span.
|
---|
721 | */
|
---|
722 | int QTableViewPrivate::sectionSpanEndLogical(const QHeaderView *header, int logical, int span) const
|
---|
723 | {
|
---|
724 | int visual = header->visualIndex(logical);
|
---|
725 | for (int i = 1; i < span; ) {
|
---|
726 | if (++visual >= header->count())
|
---|
727 | break;
|
---|
728 | logical = header->logicalIndex(visual);
|
---|
729 | ++i;
|
---|
730 | }
|
---|
731 | return logical;
|
---|
732 | }
|
---|
733 |
|
---|
734 | /*!
|
---|
735 | \internal
|
---|
736 | Returns the size of the span starting at logical index \a logical
|
---|
737 | and spanning \a span sections.
|
---|
738 | */
|
---|
739 | int QTableViewPrivate::sectionSpanSize(const QHeaderView *header, int logical, int span) const
|
---|
740 | {
|
---|
741 | int endLogical = sectionSpanEndLogical(header, logical, span);
|
---|
742 | return header->sectionPosition(endLogical)
|
---|
743 | - header->sectionPosition(logical)
|
---|
744 | + header->sectionSize(endLogical);
|
---|
745 | }
|
---|
746 |
|
---|
747 | /*!
|
---|
748 | \internal
|
---|
749 | Returns true if the section at logical index \a logical is part of the span
|
---|
750 | starting at logical index \a spanLogical and spanning \a span sections;
|
---|
751 | otherwise, returns false.
|
---|
752 | */
|
---|
753 | bool QTableViewPrivate::spanContainsSection(const QHeaderView *header, int logical, int spanLogical, int span) const
|
---|
754 | {
|
---|
755 | if (logical == spanLogical)
|
---|
756 | return true; // it's the start of the span
|
---|
757 | int visual = header->visualIndex(spanLogical);
|
---|
758 | for (int i = 1; i < span; ) {
|
---|
759 | if (++visual >= header->count())
|
---|
760 | break;
|
---|
761 | spanLogical = header->logicalIndex(visual);
|
---|
762 | if (logical == spanLogical)
|
---|
763 | return true;
|
---|
764 | ++i;
|
---|
765 | }
|
---|
766 | return false;
|
---|
767 | }
|
---|
768 |
|
---|
769 | /*!
|
---|
770 | \internal
|
---|
771 | Returns the visual rect for the given \a span.
|
---|
772 | */
|
---|
773 | QRect QTableViewPrivate::visualSpanRect(const QSpanCollection::Span &span) const
|
---|
774 | {
|
---|
775 | Q_Q(const QTableView);
|
---|
776 | // vertical
|
---|
777 | int row = span.top();
|
---|
778 | int rowp = verticalHeader->sectionViewportPosition(row);
|
---|
779 | int rowh = rowSpanHeight(row, span.height());
|
---|
780 | // horizontal
|
---|
781 | int column = span.left();
|
---|
782 | int colw = columnSpanWidth(column, span.width());
|
---|
783 | if (q->isRightToLeft())
|
---|
784 | column = span.right();
|
---|
785 | int colp = horizontalHeader->sectionViewportPosition(column);
|
---|
786 |
|
---|
787 | const int i = showGrid ? 1 : 0;
|
---|
788 | if (q->isRightToLeft())
|
---|
789 | return QRect(colp + i, rowp, colw - i, rowh - i);
|
---|
790 | return QRect(colp, rowp, colw - i, rowh - i);
|
---|
791 | }
|
---|
792 |
|
---|
793 | /*!
|
---|
794 | \internal
|
---|
795 | Draws the spanning cells within rect \a area, and clips them off as
|
---|
796 | preparation for the main drawing loop.
|
---|
797 | \a drawn is a QBitArray of visualRowCountxvisualCoulumnCount which say if particular cell has been drawn
|
---|
798 | */
|
---|
799 | void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter,
|
---|
800 | const QStyleOptionViewItemV4 &option, QBitArray *drawn,
|
---|
801 | int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn)
|
---|
802 | {
|
---|
803 | bool alternateBase = false;
|
---|
804 | QRegion region = viewport->rect();
|
---|
805 |
|
---|
806 | QList<QSpanCollection::Span *> visibleSpans;
|
---|
807 | bool sectionMoved = verticalHeader->sectionsMoved() || horizontalHeader->sectionsMoved();
|
---|
808 |
|
---|
809 | if (!sectionMoved) {
|
---|
810 | visibleSpans = spans.spansInRect(logicalColumn(firstVisualColumn), logicalRow(firstVisualRow),
|
---|
811 | lastVisualColumn - firstVisualColumn + 1, lastVisualRow - firstVisualRow + 1);
|
---|
812 | } else {
|
---|
813 | QSet<QSpanCollection::Span *> set;
|
---|
814 | for(int x = firstVisualColumn; x <= lastVisualColumn; x++)
|
---|
815 | for(int y = firstVisualRow; y <= lastVisualRow; y++)
|
---|
816 | set.insert(spans.spanAt(x,y));
|
---|
817 | set.remove(0);
|
---|
818 | visibleSpans = set.toList();
|
---|
819 | }
|
---|
820 |
|
---|
821 | foreach (QSpanCollection::Span *span, visibleSpans) {
|
---|
822 | int row = span->top();
|
---|
823 | int col = span->left();
|
---|
824 | QModelIndex index = model->index(row, col, root);
|
---|
825 | if (!index.isValid())
|
---|
826 | continue;
|
---|
827 | QRect rect = visualSpanRect(*span);
|
---|
828 | rect.translate(scrollDelayOffset);
|
---|
829 | if (!area.intersects(rect))
|
---|
830 | continue;
|
---|
831 | QStyleOptionViewItemV4 opt = option;
|
---|
832 | opt.rect = rect;
|
---|
833 | alternateBase = alternatingColors && (span->top() & 1);
|
---|
834 | if (alternateBase)
|
---|
835 | opt.features |= QStyleOptionViewItemV2::Alternate;
|
---|
836 | else
|
---|
837 | opt.features &= ~QStyleOptionViewItemV2::Alternate;
|
---|
838 | drawCell(painter, opt, index);
|
---|
839 | region -= rect;
|
---|
840 | for (int r = span->top(); r <= span->bottom(); ++r) {
|
---|
841 | const int vr = visualRow(r);
|
---|
842 | if (vr < firstVisualRow || vr > lastVisualRow)
|
---|
843 | continue;
|
---|
844 | for (int c = span->left(); c <= span->right(); ++c) {
|
---|
845 | const int vc = visualColumn(c);
|
---|
846 | if (vc < firstVisualColumn || vc > lastVisualColumn)
|
---|
847 | continue;
|
---|
848 | drawn->setBit((vr - firstVisualRow) * (lastVisualColumn - firstVisualColumn + 1)
|
---|
849 | + vc - firstVisualColumn);
|
---|
850 | }
|
---|
851 | }
|
---|
852 |
|
---|
853 | }
|
---|
854 | painter->setClipRegion(region);
|
---|
855 | }
|
---|
856 |
|
---|
857 | /*!
|
---|
858 | \internal
|
---|
859 | Updates spans after row insertion.
|
---|
860 | */
|
---|
861 | void QTableViewPrivate::_q_updateSpanInsertedRows(const QModelIndex &parent, int start, int end)
|
---|
862 | {
|
---|
863 | Q_UNUSED(parent)
|
---|
864 | spans.updateInsertedRows(start, end);
|
---|
865 | }
|
---|
866 |
|
---|
867 | /*!
|
---|
868 | \internal
|
---|
869 | Updates spans after column insertion.
|
---|
870 | */
|
---|
871 | void QTableViewPrivate::_q_updateSpanInsertedColumns(const QModelIndex &parent, int start, int end)
|
---|
872 | {
|
---|
873 | Q_UNUSED(parent)
|
---|
874 | spans.updateInsertedColumns(start, end);
|
---|
875 | }
|
---|
876 |
|
---|
877 | /*!
|
---|
878 | \internal
|
---|
879 | Updates spans after row removal.
|
---|
880 | */
|
---|
881 | void QTableViewPrivate::_q_updateSpanRemovedRows(const QModelIndex &parent, int start, int end)
|
---|
882 | {
|
---|
883 | Q_UNUSED(parent)
|
---|
884 | spans.updateRemovedRows(start, end);
|
---|
885 | }
|
---|
886 |
|
---|
887 | /*!
|
---|
888 | \internal
|
---|
889 | Updates spans after column removal.
|
---|
890 | */
|
---|
891 | void QTableViewPrivate::_q_updateSpanRemovedColumns(const QModelIndex &parent, int start, int end)
|
---|
892 | {
|
---|
893 | Q_UNUSED(parent)
|
---|
894 | spans.updateRemovedColumns(start, end);
|
---|
895 | }
|
---|
896 |
|
---|
897 | /*!
|
---|
898 | \internal
|
---|
899 | Draws a table cell.
|
---|
900 | */
|
---|
901 | void QTableViewPrivate::drawCell(QPainter *painter, const QStyleOptionViewItemV4 &option, const QModelIndex &index)
|
---|
902 | {
|
---|
903 | Q_Q(QTableView);
|
---|
904 | QStyleOptionViewItemV4 opt = option;
|
---|
905 |
|
---|
906 | if (selectionModel && selectionModel->isSelected(index))
|
---|
907 | opt.state |= QStyle::State_Selected;
|
---|
908 | if (index == hover)
|
---|
909 | opt.state |= QStyle::State_MouseOver;
|
---|
910 | if (option.state & QStyle::State_Enabled) {
|
---|
911 | QPalette::ColorGroup cg;
|
---|
912 | if ((model->flags(index) & Qt::ItemIsEnabled) == 0) {
|
---|
913 | opt.state &= ~QStyle::State_Enabled;
|
---|
914 | cg = QPalette::Disabled;
|
---|
915 | } else {
|
---|
916 | cg = QPalette::Normal;
|
---|
917 | }
|
---|
918 | opt.palette.setCurrentColorGroup(cg);
|
---|
919 | }
|
---|
920 |
|
---|
921 | if (index == q->currentIndex()) {
|
---|
922 | const bool focus = (q->hasFocus() || viewport->hasFocus()) && q->currentIndex().isValid();
|
---|
923 | if (focus)
|
---|
924 | opt.state |= QStyle::State_HasFocus;
|
---|
925 | }
|
---|
926 |
|
---|
927 | q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, q);
|
---|
928 |
|
---|
929 | if (const QWidget *widget = editorForIndex(index).editor) {
|
---|
930 | painter->save();
|
---|
931 | painter->setClipRect(widget->geometry());
|
---|
932 | q->itemDelegate(index)->paint(painter, opt, index);
|
---|
933 | painter->restore();
|
---|
934 | } else {
|
---|
935 | q->itemDelegate(index)->paint(painter, opt, index);
|
---|
936 | }
|
---|
937 | }
|
---|
938 |
|
---|
939 | /*!
|
---|
940 | \class QTableView
|
---|
941 |
|
---|
942 | \brief The QTableView class provides a default model/view
|
---|
943 | implementation of a table view.
|
---|
944 |
|
---|
945 | \ingroup model-view
|
---|
946 | \ingroup advanced
|
---|
947 |
|
---|
948 |
|
---|
949 | A QTableView implements a table view that displays items from a
|
---|
950 | model. This class is used to provide standard tables that were
|
---|
951 | previously provided by the QTable class, but using the more
|
---|
952 | flexible approach provided by Qt's model/view architecture.
|
---|
953 |
|
---|
954 | The QTableView class is one of the \l{Model/View Classes}
|
---|
955 | and is part of Qt's \l{Model/View Programming}{model/view framework}.
|
---|
956 |
|
---|
957 | QTableView implements the interfaces defined by the
|
---|
958 | QAbstractItemView class to allow it to display data provided by
|
---|
959 | models derived from the QAbstractItemModel class.
|
---|
960 |
|
---|
961 | \section1 Navigation
|
---|
962 |
|
---|
963 | You can navigate the cells in the table by clicking on a cell with the
|
---|
964 | mouse, or by using the arrow keys. Because QTableView enables
|
---|
965 | \l{QAbstractItemView::tabKeyNavigation}{tabKeyNavigation} by default, you
|
---|
966 | can also hit Tab and Backtab to move from cell to cell.
|
---|
967 |
|
---|
968 | \section1 Visual Appearance
|
---|
969 |
|
---|
970 | The table has a vertical header that can be obtained using the
|
---|
971 | verticalHeader() function, and a horizontal header that is available
|
---|
972 | through the horizontalHeader() function. The height of each row in the
|
---|
973 | table can be found by using rowHeight(); similarly, the width of
|
---|
974 | columns can be found using columnWidth(). Since both of these are plain
|
---|
975 | widgets, you can hide either of them using their hide() functions.
|
---|
976 |
|
---|
977 | Rows and columns can be hidden and shown with hideRow(), hideColumn(),
|
---|
978 | showRow(), and showColumn(). They can be selected with selectRow()
|
---|
979 | and selectColumn(). The table will show a grid depending on the
|
---|
980 | \l showGrid property.
|
---|
981 |
|
---|
982 | The items shown in a table view, like those in the other item views, are
|
---|
983 | rendered and edited using standard \l{QItemDelegate}{delegates}. However,
|
---|
984 | for some tasks it is sometimes useful to be able to insert widgets in a
|
---|
985 | table instead. Widgets are set for particular indexes with the
|
---|
986 | \l{QAbstractItemView::}{setIndexWidget()} function, and
|
---|
987 | later retrieved with \l{QAbstractItemView::}{indexWidget()}.
|
---|
988 |
|
---|
989 | \table
|
---|
990 | \row \o \inlineimage qtableview-resized.png
|
---|
991 | \o By default, the cells in a table do not expand to fill the available space.
|
---|
992 |
|
---|
993 | You can make the cells fill the available space by stretching the last
|
---|
994 | header section. Access the relevant header using horizontalHeader()
|
---|
995 | or verticalHeader() and set the header's \l{QHeaderView::}{stretchLastSection}
|
---|
996 | property.
|
---|
997 |
|
---|
998 | To distribute the available space according to the space requirement of
|
---|
999 | each column or row, call the view's resizeColumnsToContents() or
|
---|
1000 | resizeRowsToContents() functions.
|
---|
1001 | \endtable
|
---|
1002 |
|
---|
1003 | \section1 Coordinate Systems
|
---|
1004 |
|
---|
1005 | For some specialized forms of tables it is useful to be able to
|
---|
1006 | convert between row and column indexes and widget coordinates.
|
---|
1007 | The rowAt() function provides the y-coordinate within the view of the
|
---|
1008 | specified row; the row index can be used to obtain a corresponding
|
---|
1009 | y-coordinate with rowViewportPosition(). The columnAt() and
|
---|
1010 | columnViewportPosition() functions provide the equivalent conversion
|
---|
1011 | operations between x-coordinates and column indexes.
|
---|
1012 |
|
---|
1013 | \section1 Styles
|
---|
1014 |
|
---|
1015 | QTableView is styled appropriately for each platform. The following images show
|
---|
1016 | how it looks on three different platforms. Go to the \l{Qt Widget Gallery} to see
|
---|
1017 | its appearance in other styles.
|
---|
1018 |
|
---|
1019 | \table 100%
|
---|
1020 | \row \o \inlineimage windowsxp-tableview.png Screenshot of a Windows XP style table view
|
---|
1021 | \o \inlineimage macintosh-tableview.png Screenshot of a Macintosh style table view
|
---|
1022 | \o \inlineimage plastique-tableview.png Screenshot of a Plastique style table view
|
---|
1023 | \row \o A \l{Windows XP Style Widget Gallery}{Windows XP style} table view.
|
---|
1024 | \o A \l{Macintosh Style Widget Gallery}{Macintosh style} table view.
|
---|
1025 | \o A \l{Plastique Style Widget Gallery}{Plastique style} table view.
|
---|
1026 | \endtable
|
---|
1027 |
|
---|
1028 | \sa QTableWidget, {View Classes}, QAbstractItemModel, QAbstractItemView,
|
---|
1029 | {Chart Example}, {Pixelator Example}, {Table Model Example}
|
---|
1030 | */
|
---|
1031 |
|
---|
1032 | /*!
|
---|
1033 | Constructs a table view with a \a parent to represent the data.
|
---|
1034 |
|
---|
1035 | \sa QAbstractItemModel
|
---|
1036 | */
|
---|
1037 |
|
---|
1038 | QTableView::QTableView(QWidget *parent)
|
---|
1039 | : QAbstractItemView(*new QTableViewPrivate, parent)
|
---|
1040 | {
|
---|
1041 | Q_D(QTableView);
|
---|
1042 | d->init();
|
---|
1043 | }
|
---|
1044 |
|
---|
1045 | /*!
|
---|
1046 | \internal
|
---|
1047 | */
|
---|
1048 | QTableView::QTableView(QTableViewPrivate &dd, QWidget *parent)
|
---|
1049 | : QAbstractItemView(dd, parent)
|
---|
1050 | {
|
---|
1051 | Q_D(QTableView);
|
---|
1052 | d->init();
|
---|
1053 | }
|
---|
1054 |
|
---|
1055 | /*!
|
---|
1056 | Destroys the table view.
|
---|
1057 | */
|
---|
1058 | QTableView::~QTableView()
|
---|
1059 | {
|
---|
1060 | }
|
---|
1061 |
|
---|
1062 | /*!
|
---|
1063 | \reimp
|
---|
1064 | */
|
---|
1065 | void QTableView::setModel(QAbstractItemModel *model)
|
---|
1066 | {
|
---|
1067 | Q_D(QTableView);
|
---|
1068 | if (model == d->model)
|
---|
1069 | return;
|
---|
1070 | //let's disconnect from the old model
|
---|
1071 | if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
|
---|
1072 | disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
---|
1073 | this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
|
---|
1074 | disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
|
---|
1075 | this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
|
---|
1076 | disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
---|
1077 | this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
|
---|
1078 | disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
|
---|
1079 | this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
|
---|
1080 | }
|
---|
1081 | if (model) { //and connect to the new one
|
---|
1082 | connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
---|
1083 | this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
|
---|
1084 | connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
|
---|
1085 | this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
|
---|
1086 | connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
---|
1087 | this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
|
---|
1088 | connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
|
---|
1089 | this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
|
---|
1090 | }
|
---|
1091 | d->verticalHeader->setModel(model);
|
---|
1092 | d->horizontalHeader->setModel(model);
|
---|
1093 | QAbstractItemView::setModel(model);
|
---|
1094 | }
|
---|
1095 |
|
---|
1096 | /*!
|
---|
1097 | \reimp
|
---|
1098 | */
|
---|
1099 | void QTableView::setRootIndex(const QModelIndex &index)
|
---|
1100 | {
|
---|
1101 | Q_D(QTableView);
|
---|
1102 | if (index == d->root) {
|
---|
1103 | viewport()->update();
|
---|
1104 | return;
|
---|
1105 | }
|
---|
1106 | d->verticalHeader->setRootIndex(index);
|
---|
1107 | d->horizontalHeader->setRootIndex(index);
|
---|
1108 | QAbstractItemView::setRootIndex(index);
|
---|
1109 | }
|
---|
1110 |
|
---|
1111 | /*!
|
---|
1112 | \reimp
|
---|
1113 | */
|
---|
1114 | void QTableView::setSelectionModel(QItemSelectionModel *selectionModel)
|
---|
1115 | {
|
---|
1116 | Q_D(QTableView);
|
---|
1117 | Q_ASSERT(selectionModel);
|
---|
1118 | d->verticalHeader->setSelectionModel(selectionModel);
|
---|
1119 | d->horizontalHeader->setSelectionModel(selectionModel);
|
---|
1120 | QAbstractItemView::setSelectionModel(selectionModel);
|
---|
1121 | }
|
---|
1122 |
|
---|
1123 | /*!
|
---|
1124 | Returns the table view's horizontal header.
|
---|
1125 |
|
---|
1126 | \sa setHorizontalHeader(), verticalHeader(), QAbstractItemModel::headerData()
|
---|
1127 | */
|
---|
1128 | QHeaderView *QTableView::horizontalHeader() const
|
---|
1129 | {
|
---|
1130 | Q_D(const QTableView);
|
---|
1131 | return d->horizontalHeader;
|
---|
1132 | }
|
---|
1133 |
|
---|
1134 | /*!
|
---|
1135 | Returns the table view's vertical header.
|
---|
1136 |
|
---|
1137 | \sa setVerticalHeader(), horizontalHeader(), QAbstractItemModel::headerData()
|
---|
1138 | */
|
---|
1139 | QHeaderView *QTableView::verticalHeader() const
|
---|
1140 | {
|
---|
1141 | Q_D(const QTableView);
|
---|
1142 | return d->verticalHeader;
|
---|
1143 | }
|
---|
1144 |
|
---|
1145 | /*!
|
---|
1146 | Sets the widget to use for the horizontal header to \a header.
|
---|
1147 |
|
---|
1148 | \sa horizontalHeader() setVerticalHeader()
|
---|
1149 | */
|
---|
1150 | void QTableView::setHorizontalHeader(QHeaderView *header)
|
---|
1151 | {
|
---|
1152 | Q_D(QTableView);
|
---|
1153 |
|
---|
1154 | if (!header || header == d->horizontalHeader)
|
---|
1155 | return;
|
---|
1156 | if (d->horizontalHeader && d->horizontalHeader->parent() == this)
|
---|
1157 | delete d->horizontalHeader;
|
---|
1158 | d->horizontalHeader = header;
|
---|
1159 | d->horizontalHeader->setParent(this);
|
---|
1160 | if (!d->horizontalHeader->model()) {
|
---|
1161 | d->horizontalHeader->setModel(d->model);
|
---|
1162 | if (d->selectionModel)
|
---|
1163 | d->horizontalHeader->setSelectionModel(d->selectionModel);
|
---|
1164 | }
|
---|
1165 |
|
---|
1166 | connect(d->horizontalHeader,SIGNAL(sectionResized(int,int,int)),
|
---|
1167 | this, SLOT(columnResized(int,int,int)));
|
---|
1168 | connect(d->horizontalHeader, SIGNAL(sectionMoved(int,int,int)),
|
---|
1169 | this, SLOT(columnMoved(int,int,int)));
|
---|
1170 | connect(d->horizontalHeader, SIGNAL(sectionCountChanged(int,int)),
|
---|
1171 | this, SLOT(columnCountChanged(int,int)));
|
---|
1172 | connect(d->horizontalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectColumn(int)));
|
---|
1173 | connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectColumn(int)));
|
---|
1174 | connect(d->horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
|
---|
1175 | this, SLOT(resizeColumnToContents(int)));
|
---|
1176 | connect(d->horizontalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
|
---|
1177 |
|
---|
1178 | //update the sorting enabled states on the new header
|
---|
1179 | setSortingEnabled(d->sortingEnabled);
|
---|
1180 | }
|
---|
1181 |
|
---|
1182 | /*!
|
---|
1183 | Sets the widget to use for the vertical header to \a header.
|
---|
1184 |
|
---|
1185 | \sa verticalHeader() setHorizontalHeader()
|
---|
1186 | */
|
---|
1187 | void QTableView::setVerticalHeader(QHeaderView *header)
|
---|
1188 | {
|
---|
1189 | Q_D(QTableView);
|
---|
1190 |
|
---|
1191 | if (!header || header == d->verticalHeader)
|
---|
1192 | return;
|
---|
1193 | if (d->verticalHeader && d->verticalHeader->parent() == this)
|
---|
1194 | delete d->verticalHeader;
|
---|
1195 | d->verticalHeader = header;
|
---|
1196 | d->verticalHeader->setParent(this);
|
---|
1197 | if (!d->verticalHeader->model()) {
|
---|
1198 | d->verticalHeader->setModel(d->model);
|
---|
1199 | if (d->selectionModel)
|
---|
1200 | d->verticalHeader->setSelectionModel(d->selectionModel);
|
---|
1201 | }
|
---|
1202 |
|
---|
1203 | connect(d->verticalHeader, SIGNAL(sectionResized(int,int,int)),
|
---|
1204 | this, SLOT(rowResized(int,int,int)));
|
---|
1205 | connect(d->verticalHeader, SIGNAL(sectionMoved(int,int,int)),
|
---|
1206 | this, SLOT(rowMoved(int,int,int)));
|
---|
1207 | connect(d->verticalHeader, SIGNAL(sectionCountChanged(int,int)),
|
---|
1208 | this, SLOT(rowCountChanged(int,int)));
|
---|
1209 | connect(d->verticalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectRow(int)));
|
---|
1210 | connect(d->verticalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectRow(int)));
|
---|
1211 | connect(d->verticalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
|
---|
1212 | this, SLOT(resizeRowToContents(int)));
|
---|
1213 | connect(d->verticalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
|
---|
1214 | }
|
---|
1215 |
|
---|
1216 | /*!
|
---|
1217 | \internal
|
---|
1218 |
|
---|
1219 | Scroll the contents of the table view by (\a dx, \a dy).
|
---|
1220 | */
|
---|
1221 | void QTableView::scrollContentsBy(int dx, int dy)
|
---|
1222 | {
|
---|
1223 | Q_D(QTableView);
|
---|
1224 |
|
---|
1225 | d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
|
---|
1226 |
|
---|
1227 | dx = isRightToLeft() ? -dx : dx;
|
---|
1228 | if (dx) {
|
---|
1229 | if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
|
---|
1230 | int oldOffset = d->horizontalHeader->offset();
|
---|
1231 | if (horizontalScrollBar()->value() == horizontalScrollBar()->maximum())
|
---|
1232 | d->horizontalHeader->setOffsetToLastSection();
|
---|
1233 | else
|
---|
1234 | d->horizontalHeader->setOffsetToSectionPosition(horizontalScrollBar()->value());
|
---|
1235 | int newOffset = d->horizontalHeader->offset();
|
---|
1236 | dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset;
|
---|
1237 | } else {
|
---|
1238 | d->horizontalHeader->setOffset(horizontalScrollBar()->value());
|
---|
1239 | }
|
---|
1240 | }
|
---|
1241 | if (dy) {
|
---|
1242 | if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
|
---|
1243 | int oldOffset = d->verticalHeader->offset();
|
---|
1244 | if (verticalScrollBar()->value() == verticalScrollBar()->maximum())
|
---|
1245 | d->verticalHeader->setOffsetToLastSection();
|
---|
1246 | else
|
---|
1247 | d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value());
|
---|
1248 | int newOffset = d->verticalHeader->offset();
|
---|
1249 | dy = oldOffset - newOffset;
|
---|
1250 | } else {
|
---|
1251 | d->verticalHeader->setOffset(verticalScrollBar()->value());
|
---|
1252 | }
|
---|
1253 | }
|
---|
1254 | d->scrollContentsBy(dx, dy);
|
---|
1255 |
|
---|
1256 | if (d->showGrid) {
|
---|
1257 | //we need to update the first line of the previous top item in the view
|
---|
1258 | //because it has the grid drawn if the header is invisible.
|
---|
1259 | //It is strictly related to what's done at then end of the paintEvent
|
---|
1260 | if (dy > 0 && d->horizontalHeader->isHidden() && d->verticalScrollMode == ScrollPerItem) {
|
---|
1261 | d->viewport->update(0, dy, d->viewport->width(), dy);
|
---|
1262 | }
|
---|
1263 | if (dx > 0 && d->verticalHeader->isHidden() && d->horizontalScrollMode == ScrollPerItem) {
|
---|
1264 | d->viewport->update(dx, 0, dx, d->viewport->height());
|
---|
1265 | }
|
---|
1266 | }
|
---|
1267 | }
|
---|
1268 |
|
---|
1269 | /*!
|
---|
1270 | \reimp
|
---|
1271 | */
|
---|
1272 | QStyleOptionViewItem QTableView::viewOptions() const
|
---|
1273 | {
|
---|
1274 | QStyleOptionViewItem option = QAbstractItemView::viewOptions();
|
---|
1275 | option.showDecorationSelected = true;
|
---|
1276 | return option;
|
---|
1277 | }
|
---|
1278 |
|
---|
1279 | /*!
|
---|
1280 | Paints the table on receipt of the given paint event \a event.
|
---|
1281 | */
|
---|
1282 | void QTableView::paintEvent(QPaintEvent *event)
|
---|
1283 | {
|
---|
1284 | Q_D(QTableView);
|
---|
1285 | // setup temp variables for the painting
|
---|
1286 | QStyleOptionViewItemV4 option = d->viewOptionsV4();
|
---|
1287 | const QPoint offset = d->scrollDelayOffset;
|
---|
1288 | const bool showGrid = d->showGrid;
|
---|
1289 | const int gridSize = showGrid ? 1 : 0;
|
---|
1290 | const int gridHint = style()->styleHint(QStyle::SH_Table_GridLineColor, &option, this);
|
---|
1291 | const QColor gridColor = static_cast<QRgb>(gridHint);
|
---|
1292 | const QPen gridPen = QPen(gridColor, 0, d->gridStyle);
|
---|
1293 | const QHeaderView *verticalHeader = d->verticalHeader;
|
---|
1294 | const QHeaderView *horizontalHeader = d->horizontalHeader;
|
---|
1295 | const QStyle::State state = option.state;
|
---|
1296 | const bool alternate = d->alternatingColors;
|
---|
1297 | const bool rightToLeft = isRightToLeft();
|
---|
1298 |
|
---|
1299 | QPainter painter(d->viewport);
|
---|
1300 |
|
---|
1301 | // if there's nothing to do, clear the area and return
|
---|
1302 | if (horizontalHeader->count() == 0 || verticalHeader->count() == 0 || !d->itemDelegate)
|
---|
1303 | return;
|
---|
1304 |
|
---|
1305 | uint x = horizontalHeader->length() - horizontalHeader->offset() - (rightToLeft ? 0 : 1);
|
---|
1306 | uint y = verticalHeader->length() - verticalHeader->offset() - 1;
|
---|
1307 |
|
---|
1308 | const QRegion region = event->region().translated(offset);
|
---|
1309 | const QVector<QRect> rects = region.rects();
|
---|
1310 |
|
---|
1311 | //firstVisualRow is the visual index of the first visible row. lastVisualRow is the visual index of the last visible Row.
|
---|
1312 | //same goes for ...VisualColumn
|
---|
1313 | int firstVisualRow = qMax(verticalHeader->visualIndexAt(0),0);
|
---|
1314 | int lastVisualRow = verticalHeader->visualIndexAt(verticalHeader->viewport()->height());
|
---|
1315 | if (lastVisualRow == -1)
|
---|
1316 | lastVisualRow = d->model->rowCount(d->root) - 1;
|
---|
1317 |
|
---|
1318 | int firstVisualColumn = horizontalHeader->visualIndexAt(0);
|
---|
1319 | int lastVisualColumn = horizontalHeader->visualIndexAt(horizontalHeader->viewport()->width());
|
---|
1320 | if (rightToLeft)
|
---|
1321 | qSwap(firstVisualColumn, lastVisualColumn);
|
---|
1322 | if (firstVisualColumn == -1)
|
---|
1323 | firstVisualColumn = 0;
|
---|
1324 | if (lastVisualColumn == -1)
|
---|
1325 | lastVisualColumn = horizontalHeader->count() - 1;
|
---|
1326 |
|
---|
1327 | QBitArray drawn((lastVisualRow - firstVisualRow + 1) * (lastVisualColumn - firstVisualColumn + 1));
|
---|
1328 |
|
---|
1329 | if (d->hasSpans()) {
|
---|
1330 | d->drawAndClipSpans(region, &painter, option, &drawn,
|
---|
1331 | firstVisualRow, lastVisualRow, firstVisualColumn, lastVisualColumn);
|
---|
1332 | }
|
---|
1333 |
|
---|
1334 | for (int i = 0; i < rects.size(); ++i) {
|
---|
1335 | QRect dirtyArea = rects.at(i);
|
---|
1336 | dirtyArea.setBottom(qMin(dirtyArea.bottom(), int(y)));
|
---|
1337 | if (rightToLeft) {
|
---|
1338 | dirtyArea.setLeft(qMax(dirtyArea.left(), d->viewport->width() - int(x)));
|
---|
1339 | } else {
|
---|
1340 | dirtyArea.setRight(qMin(dirtyArea.right(), int(x)));
|
---|
1341 | }
|
---|
1342 |
|
---|
1343 | // get the horizontal start and end visual sections
|
---|
1344 | int left = horizontalHeader->visualIndexAt(dirtyArea.left());
|
---|
1345 | int right = horizontalHeader->visualIndexAt(dirtyArea.right());
|
---|
1346 | if (rightToLeft)
|
---|
1347 | qSwap(left, right);
|
---|
1348 | if (left == -1) left = 0;
|
---|
1349 | if (right == -1) right = horizontalHeader->count() - 1;
|
---|
1350 |
|
---|
1351 | // get the vertical start and end visual sections and if alternate color
|
---|
1352 | int bottom = verticalHeader->visualIndexAt(dirtyArea.bottom());
|
---|
1353 | if (bottom == -1) bottom = verticalHeader->count() - 1;
|
---|
1354 | int top = 0;
|
---|
1355 | bool alternateBase = false;
|
---|
1356 | if (alternate && verticalHeader->sectionsHidden()) {
|
---|
1357 | uint verticalOffset = verticalHeader->offset();
|
---|
1358 | int row = verticalHeader->logicalIndex(top);
|
---|
1359 | for (int y = 0;
|
---|
1360 | ((uint)(y += verticalHeader->sectionSize(top)) <= verticalOffset) && (top < bottom);
|
---|
1361 | ++top) {
|
---|
1362 | row = verticalHeader->logicalIndex(top);
|
---|
1363 | if (alternate && !verticalHeader->isSectionHidden(row))
|
---|
1364 | alternateBase = !alternateBase;
|
---|
1365 | }
|
---|
1366 | } else {
|
---|
1367 | top = verticalHeader->visualIndexAt(dirtyArea.top());
|
---|
1368 | alternateBase = (top & 1) && alternate;
|
---|
1369 | }
|
---|
1370 | if (top == -1 || top > bottom)
|
---|
1371 | continue;
|
---|
1372 |
|
---|
1373 | // Paint each row item
|
---|
1374 | for (int visualRowIndex = top; visualRowIndex <= bottom; ++visualRowIndex) {
|
---|
1375 | int row = verticalHeader->logicalIndex(visualRowIndex);
|
---|
1376 | if (verticalHeader->isSectionHidden(row))
|
---|
1377 | continue;
|
---|
1378 | int rowY = rowViewportPosition(row);
|
---|
1379 | rowY += offset.y();
|
---|
1380 | int rowh = rowHeight(row) - gridSize;
|
---|
1381 |
|
---|
1382 | // Paint each column item
|
---|
1383 | for (int visualColumnIndex = left; visualColumnIndex <= right; ++visualColumnIndex) {
|
---|
1384 | int currentBit = (visualRowIndex - firstVisualRow) * (lastVisualColumn - firstVisualColumn + 1)
|
---|
1385 | + visualColumnIndex - firstVisualColumn;
|
---|
1386 |
|
---|
1387 | if (currentBit < 0 || currentBit >= drawn.size() || drawn.testBit(currentBit))
|
---|
1388 | continue;
|
---|
1389 | drawn.setBit(currentBit);
|
---|
1390 |
|
---|
1391 | int col = horizontalHeader->logicalIndex(visualColumnIndex);
|
---|
1392 | if (horizontalHeader->isSectionHidden(col))
|
---|
1393 | continue;
|
---|
1394 | int colp = columnViewportPosition(col);
|
---|
1395 | colp += offset.x();
|
---|
1396 | int colw = columnWidth(col) - gridSize;
|
---|
1397 |
|
---|
1398 | const QModelIndex index = d->model->index(row, col, d->root);
|
---|
1399 | if (index.isValid()) {
|
---|
1400 | option.rect = QRect(colp + (showGrid && rightToLeft ? 1 : 0), rowY, colw, rowh);
|
---|
1401 | if (alternate) {
|
---|
1402 | if (alternateBase)
|
---|
1403 | option.features |= QStyleOptionViewItemV2::Alternate;
|
---|
1404 | else
|
---|
1405 | option.features &= ~QStyleOptionViewItemV2::Alternate;
|
---|
1406 | }
|
---|
1407 | d->drawCell(&painter, option, index);
|
---|
1408 | }
|
---|
1409 | }
|
---|
1410 | alternateBase = !alternateBase && alternate;
|
---|
1411 | }
|
---|
1412 |
|
---|
1413 | if (showGrid) {
|
---|
1414 | // Find the bottom right (the last rows/columns might be hidden)
|
---|
1415 | while (verticalHeader->isSectionHidden(verticalHeader->logicalIndex(bottom))) --bottom;
|
---|
1416 | QPen old = painter.pen();
|
---|
1417 | painter.setPen(gridPen);
|
---|
1418 | // Paint each row
|
---|
1419 | for (int visualIndex = top; visualIndex <= bottom; ++visualIndex) {
|
---|
1420 | int row = verticalHeader->logicalIndex(visualIndex);
|
---|
1421 | if (verticalHeader->isSectionHidden(row))
|
---|
1422 | continue;
|
---|
1423 | int rowY = rowViewportPosition(row);
|
---|
1424 | rowY += offset.y();
|
---|
1425 | int rowh = rowHeight(row) - gridSize;
|
---|
1426 | painter.drawLine(dirtyArea.left(), rowY + rowh, dirtyArea.right(), rowY + rowh);
|
---|
1427 | }
|
---|
1428 |
|
---|
1429 | // Paint each column
|
---|
1430 | for (int h = left; h <= right; ++h) {
|
---|
1431 | int col = horizontalHeader->logicalIndex(h);
|
---|
1432 | if (horizontalHeader->isSectionHidden(col))
|
---|
1433 | continue;
|
---|
1434 | int colp = columnViewportPosition(col);
|
---|
1435 | colp += offset.x();
|
---|
1436 | if (!rightToLeft)
|
---|
1437 | colp += columnWidth(col) - gridSize;
|
---|
1438 | painter.drawLine(colp, dirtyArea.top(), colp, dirtyArea.bottom());
|
---|
1439 | }
|
---|
1440 |
|
---|
1441 | //draw the top & left grid lines if the headers are not visible.
|
---|
1442 | //We do update this line when subsequent scroll happen (see scrollContentsBy)
|
---|
1443 | if (horizontalHeader->isHidden() && verticalScrollMode() == ScrollPerItem)
|
---|
1444 | painter.drawLine(dirtyArea.left(), 0, dirtyArea.right(), 0);
|
---|
1445 | if (verticalHeader->isHidden() && horizontalScrollMode() == ScrollPerItem)
|
---|
1446 | painter.drawLine(0, dirtyArea.top(), 0, dirtyArea.bottom());
|
---|
1447 | painter.setPen(old);
|
---|
1448 | }
|
---|
1449 | }
|
---|
1450 |
|
---|
1451 | #ifndef QT_NO_DRAGANDDROP
|
---|
1452 | // Paint the dropIndicator
|
---|
1453 | d->paintDropIndicator(&painter);
|
---|
1454 | #endif
|
---|
1455 | }
|
---|
1456 |
|
---|
1457 | /*!
|
---|
1458 | Returns the index position of the model item corresponding to the
|
---|
1459 | table item at position \a pos in contents coordinates.
|
---|
1460 | */
|
---|
1461 | QModelIndex QTableView::indexAt(const QPoint &pos) const
|
---|
1462 | {
|
---|
1463 | Q_D(const QTableView);
|
---|
1464 | d->executePostedLayout();
|
---|
1465 | int r = rowAt(pos.y());
|
---|
1466 | int c = columnAt(pos.x());
|
---|
1467 | if (r >= 0 && c >= 0) {
|
---|
1468 | if (d->hasSpans()) {
|
---|
1469 | QSpanCollection::Span span = d->span(r, c);
|
---|
1470 | r = span.top();
|
---|
1471 | c = span.left();
|
---|
1472 | }
|
---|
1473 | return d->model->index(r, c, d->root);
|
---|
1474 | }
|
---|
1475 | return QModelIndex();
|
---|
1476 | }
|
---|
1477 |
|
---|
1478 | /*!
|
---|
1479 | Returns the horizontal offset of the items in the table view.
|
---|
1480 |
|
---|
1481 | Note that the table view uses the horizontal header section
|
---|
1482 | positions to determine the positions of columns in the view.
|
---|
1483 |
|
---|
1484 | \sa verticalOffset()
|
---|
1485 | */
|
---|
1486 | int QTableView::horizontalOffset() const
|
---|
1487 | {
|
---|
1488 | Q_D(const QTableView);
|
---|
1489 | return d->horizontalHeader->offset();
|
---|
1490 | }
|
---|
1491 |
|
---|
1492 | /*!
|
---|
1493 | Returns the vertical offset of the items in the table view.
|
---|
1494 |
|
---|
1495 | Note that the table view uses the vertical header section
|
---|
1496 | positions to determine the positions of rows in the view.
|
---|
1497 |
|
---|
1498 | \sa horizontalOffset()
|
---|
1499 | */
|
---|
1500 | int QTableView::verticalOffset() const
|
---|
1501 | {
|
---|
1502 | Q_D(const QTableView);
|
---|
1503 | return d->verticalHeader->offset();
|
---|
1504 | }
|
---|
1505 |
|
---|
1506 | /*!
|
---|
1507 | \fn QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
|
---|
1508 |
|
---|
1509 | Moves the cursor in accordance with the given \a cursorAction, using the
|
---|
1510 | information provided by the \a modifiers.
|
---|
1511 |
|
---|
1512 | \sa QAbstractItemView::CursorAction
|
---|
1513 | */
|
---|
1514 | QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
|
---|
1515 | {
|
---|
1516 | Q_D(QTableView);
|
---|
1517 | Q_UNUSED(modifiers);
|
---|
1518 |
|
---|
1519 | int bottom = d->model->rowCount(d->root) - 1;
|
---|
1520 | // make sure that bottom is the bottommost *visible* row
|
---|
1521 | while (bottom >= 0 && isRowHidden(d->logicalRow(bottom)))
|
---|
1522 | --bottom;
|
---|
1523 |
|
---|
1524 | int right = d->model->columnCount(d->root) - 1;
|
---|
1525 |
|
---|
1526 | while (right >= 0 && isColumnHidden(d->logicalColumn(right)))
|
---|
1527 | --right;
|
---|
1528 |
|
---|
1529 | if (bottom == -1 || right == -1)
|
---|
1530 | return QModelIndex(); // model is empty
|
---|
1531 |
|
---|
1532 | QModelIndex current = currentIndex();
|
---|
1533 |
|
---|
1534 | if (!current.isValid()) {
|
---|
1535 | int row = 0;
|
---|
1536 | int column = 0;
|
---|
1537 | while (column < right && isColumnHidden(d->logicalColumn(column)))
|
---|
1538 | ++column;
|
---|
1539 | while (isRowHidden(d->logicalRow(row)) && row < bottom)
|
---|
1540 | ++row;
|
---|
1541 | d->visualCursor = QPoint(column, row);
|
---|
1542 | return d->model->index(d->logicalRow(row), d->logicalColumn(column), d->root);
|
---|
1543 | }
|
---|
1544 |
|
---|
1545 | // Update visual cursor if current index has changed.
|
---|
1546 | QPoint visualCurrent(d->visualColumn(current.column()), d->visualRow(current.row()));
|
---|
1547 | if (visualCurrent != d->visualCursor) {
|
---|
1548 | if (d->hasSpans()) {
|
---|
1549 | QSpanCollection::Span span = d->span(current.row(), current.column());
|
---|
1550 | if (span.top() > d->visualCursor.y() || d->visualCursor.y() > span.bottom()
|
---|
1551 | || span.left() > d->visualCursor.x() || d->visualCursor.x() > span.right())
|
---|
1552 | d->visualCursor = visualCurrent;
|
---|
1553 | } else {
|
---|
1554 | d->visualCursor = visualCurrent;
|
---|
1555 | }
|
---|
1556 | }
|
---|
1557 |
|
---|
1558 | int visualRow = d->visualCursor.y();
|
---|
1559 | if (visualRow > bottom)
|
---|
1560 | visualRow = bottom;
|
---|
1561 | Q_ASSERT(visualRow != -1);
|
---|
1562 | int visualColumn = d->visualCursor.x();
|
---|
1563 | if (visualColumn > right)
|
---|
1564 | visualColumn = right;
|
---|
1565 | Q_ASSERT(visualColumn != -1);
|
---|
1566 |
|
---|
1567 | if (isRightToLeft()) {
|
---|
1568 | if (cursorAction == MoveLeft)
|
---|
1569 | cursorAction = MoveRight;
|
---|
1570 | else if (cursorAction == MoveRight)
|
---|
1571 | cursorAction = MoveLeft;
|
---|
1572 | }
|
---|
1573 |
|
---|
1574 | switch (cursorAction) {
|
---|
1575 | case MoveUp: {
|
---|
1576 | int originalRow = visualRow;
|
---|
1577 | #ifdef QT_KEYPAD_NAVIGATION
|
---|
1578 | if (QApplication::keypadNavigationEnabled() && visualRow == 0)
|
---|
1579 | visualRow = d->visualRow(model()->rowCount() - 1) + 1;
|
---|
1580 | // FIXME? visualRow = bottom + 1;
|
---|
1581 | #endif
|
---|
1582 | int r = d->logicalRow(visualRow);
|
---|
1583 | int c = d->logicalColumn(visualColumn);
|
---|
1584 | if (r != -1 && d->hasSpans()) {
|
---|
1585 | QSpanCollection::Span span = d->span(r, c);
|
---|
1586 | if (span.width() > 1 || span.height() > 1)
|
---|
1587 | visualRow = d->visualRow(span.top());
|
---|
1588 | }
|
---|
1589 | while (visualRow >= 0) {
|
---|
1590 | --visualRow;
|
---|
1591 | r = d->logicalRow(visualRow);
|
---|
1592 | c = d->logicalColumn(visualColumn);
|
---|
1593 | if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c)))
|
---|
1594 | break;
|
---|
1595 | }
|
---|
1596 | if (visualRow < 0)
|
---|
1597 | visualRow = originalRow;
|
---|
1598 | break;
|
---|
1599 | }
|
---|
1600 | case MoveDown: {
|
---|
1601 | int originalRow = visualRow;
|
---|
1602 | if (d->hasSpans()) {
|
---|
1603 | QSpanCollection::Span span = d->span(current.row(), current.column());
|
---|
1604 | visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
|
---|
1605 | }
|
---|
1606 | #ifdef QT_KEYPAD_NAVIGATION
|
---|
1607 | if (QApplication::keypadNavigationEnabled() && visualRow >= bottom)
|
---|
1608 | visualRow = -1;
|
---|
1609 | #endif
|
---|
1610 | int r = d->logicalRow(visualRow);
|
---|
1611 | int c = d->logicalColumn(visualColumn);
|
---|
1612 | if (r != -1 && d->hasSpans()) {
|
---|
1613 | QSpanCollection::Span span = d->span(r, c);
|
---|
1614 | if (span.width() > 1 || span.height() > 1)
|
---|
1615 | visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
|
---|
1616 | }
|
---|
1617 | while (visualRow <= bottom) {
|
---|
1618 | ++visualRow;
|
---|
1619 | r = d->logicalRow(visualRow);
|
---|
1620 | c = d->logicalColumn(visualColumn);
|
---|
1621 | if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c)))
|
---|
1622 | break;
|
---|
1623 | }
|
---|
1624 | if (visualRow > bottom)
|
---|
1625 | visualRow = originalRow;
|
---|
1626 | break;
|
---|
1627 | }
|
---|
1628 | case MovePrevious:
|
---|
1629 | case MoveLeft: {
|
---|
1630 | int originalRow = visualRow;
|
---|
1631 | int originalColumn = visualColumn;
|
---|
1632 | bool firstTime = true;
|
---|
1633 | bool looped = false;
|
---|
1634 | bool wrapped = false;
|
---|
1635 | do {
|
---|
1636 | int r = d->logicalRow(visualRow);
|
---|
1637 | int c = d->logicalColumn(visualColumn);
|
---|
1638 | if (firstTime && c != -1 && d->hasSpans()) {
|
---|
1639 | firstTime = false;
|
---|
1640 | QSpanCollection::Span span = d->span(r, c);
|
---|
1641 | if (span.width() > 1 || span.height() > 1)
|
---|
1642 | visualColumn = d->visualColumn(span.left());
|
---|
1643 | }
|
---|
1644 | while (visualColumn >= 0) {
|
---|
1645 | --visualColumn;
|
---|
1646 | r = d->logicalRow(visualRow);
|
---|
1647 | c = d->logicalColumn(visualColumn);
|
---|
1648 | if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c)))
|
---|
1649 | break;
|
---|
1650 | if (wrapped && (originalRow < visualRow || (originalRow == visualRow && originalColumn <= visualColumn))) {
|
---|
1651 | looped = true;
|
---|
1652 | break;
|
---|
1653 | }
|
---|
1654 | }
|
---|
1655 | if (cursorAction == MoveLeft || visualColumn >= 0)
|
---|
1656 | break;
|
---|
1657 | visualColumn = right + 1;
|
---|
1658 | if (visualRow == 0) {
|
---|
1659 | wrapped = true;
|
---|
1660 | visualRow = bottom;
|
---|
1661 | } else {
|
---|
1662 | --visualRow;
|
---|
1663 | }
|
---|
1664 | } while (!looped);
|
---|
1665 | if (visualColumn < 0)
|
---|
1666 | visualColumn = originalColumn;
|
---|
1667 | break;
|
---|
1668 | }
|
---|
1669 | case MoveNext:
|
---|
1670 | case MoveRight: {
|
---|
1671 | int originalRow = visualRow;
|
---|
1672 | int originalColumn = visualColumn;
|
---|
1673 | bool firstTime = true;
|
---|
1674 | bool looped = false;
|
---|
1675 | bool wrapped = false;
|
---|
1676 | do {
|
---|
1677 | int r = d->logicalRow(visualRow);
|
---|
1678 | int c = d->logicalColumn(visualColumn);
|
---|
1679 | if (firstTime && c != -1 && d->hasSpans()) {
|
---|
1680 | firstTime = false;
|
---|
1681 | QSpanCollection::Span span = d->span(r, c);
|
---|
1682 | if (span.width() > 1 || span.height() > 1)
|
---|
1683 | visualColumn = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
|
---|
1684 | }
|
---|
1685 | while (visualColumn <= right) {
|
---|
1686 | ++visualColumn;
|
---|
1687 | r = d->logicalRow(visualRow);
|
---|
1688 | c = d->logicalColumn(visualColumn);
|
---|
1689 | if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c)))
|
---|
1690 | break;
|
---|
1691 | if (wrapped && (originalRow > visualRow || (originalRow == visualRow && originalColumn >= visualColumn))) {
|
---|
1692 | looped = true;
|
---|
1693 | break;
|
---|
1694 | }
|
---|
1695 | }
|
---|
1696 | if (cursorAction == MoveRight || visualColumn <= right)
|
---|
1697 | break;
|
---|
1698 | visualColumn = -1;
|
---|
1699 | if (visualRow == bottom) {
|
---|
1700 | wrapped = true;
|
---|
1701 | visualRow = 0;
|
---|
1702 | } else {
|
---|
1703 | ++visualRow;
|
---|
1704 | }
|
---|
1705 | } while (!looped);
|
---|
1706 | if (visualColumn > right)
|
---|
1707 | visualColumn = originalColumn;
|
---|
1708 | break;
|
---|
1709 | }
|
---|
1710 | case MoveHome:
|
---|
1711 | visualColumn = 0;
|
---|
1712 | while (visualColumn < right && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn))
|
---|
1713 | ++visualColumn;
|
---|
1714 | if (modifiers & Qt::ControlModifier) {
|
---|
1715 | visualRow = 0;
|
---|
1716 | while (visualRow < bottom && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn))
|
---|
1717 | ++visualRow;
|
---|
1718 | }
|
---|
1719 | break;
|
---|
1720 | case MoveEnd:
|
---|
1721 | visualColumn = right;
|
---|
1722 | if (modifiers & Qt::ControlModifier)
|
---|
1723 | visualRow = bottom;
|
---|
1724 | break;
|
---|
1725 | case MovePageUp: {
|
---|
1726 | int newRow = rowAt(visualRect(current).top() - d->viewport->height());
|
---|
1727 | if (newRow == -1)
|
---|
1728 | newRow = d->logicalRow(0);
|
---|
1729 | return d->model->index(newRow, current.column(), d->root);
|
---|
1730 | }
|
---|
1731 | case MovePageDown: {
|
---|
1732 | int newRow = rowAt(visualRect(current).bottom() + d->viewport->height());
|
---|
1733 | if (newRow == -1)
|
---|
1734 | newRow = d->logicalRow(bottom);
|
---|
1735 | return d->model->index(newRow, current.column(), d->root);
|
---|
1736 | }}
|
---|
1737 |
|
---|
1738 | d->visualCursor = QPoint(visualColumn, visualRow);
|
---|
1739 | int logicalRow = d->logicalRow(visualRow);
|
---|
1740 | int logicalColumn = d->logicalColumn(visualColumn);
|
---|
1741 | if (!d->model->hasIndex(logicalRow, logicalColumn, d->root))
|
---|
1742 | return QModelIndex();
|
---|
1743 |
|
---|
1744 | QModelIndex result = d->model->index(logicalRow, logicalColumn, d->root);
|
---|
1745 | if (!d->isRowHidden(logicalRow) && !d->isColumnHidden(logicalColumn) && d->isIndexEnabled(result))
|
---|
1746 | return result;
|
---|
1747 |
|
---|
1748 | return QModelIndex();
|
---|
1749 | }
|
---|
1750 |
|
---|
1751 | /*!
|
---|
1752 | \fn void QTableView::setSelection(const QRect &rect,
|
---|
1753 | QItemSelectionModel::SelectionFlags flags)
|
---|
1754 |
|
---|
1755 | Selects the items within the given \a rect and in accordance with
|
---|
1756 | the specified selection \a flags.
|
---|
1757 | */
|
---|
1758 | void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
|
---|
1759 | {
|
---|
1760 | Q_D(QTableView);
|
---|
1761 | QModelIndex tl = indexAt(QPoint(isRightToLeft() ? qMax(rect.left(), rect.right())
|
---|
1762 | : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom())));
|
---|
1763 | QModelIndex br = indexAt(QPoint(isRightToLeft() ? qMin(rect.left(), rect.right()) :
|
---|
1764 | qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom())));
|
---|
1765 | if (!d->selectionModel || !tl.isValid() || !br.isValid() || !d->isIndexEnabled(tl) || !d->isIndexEnabled(br))
|
---|
1766 | return;
|
---|
1767 |
|
---|
1768 | bool verticalMoved = verticalHeader()->sectionsMoved();
|
---|
1769 | bool horizontalMoved = horizontalHeader()->sectionsMoved();
|
---|
1770 |
|
---|
1771 | QItemSelection selection;
|
---|
1772 |
|
---|
1773 | if (d->hasSpans()) {
|
---|
1774 | bool expanded;
|
---|
1775 | int top = qMin(d->visualRow(tl.row()), d->visualRow(br.row()));
|
---|
1776 | int left = qMin(d->visualColumn(tl.column()), d->visualColumn(br.column()));
|
---|
1777 | int bottom = qMax(d->visualRow(tl.row()), d->visualRow(br.row()));
|
---|
1778 | int right = qMax(d->visualColumn(tl.column()), d->visualColumn(br.column()));
|
---|
1779 | do {
|
---|
1780 | expanded = false;
|
---|
1781 | foreach (QSpanCollection::Span *it, d->spans.spans) {
|
---|
1782 | const QSpanCollection::Span &span = *it;
|
---|
1783 | int t = d->visualRow(span.top());
|
---|
1784 | int l = d->visualColumn(span.left());
|
---|
1785 | int b = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
|
---|
1786 | int r = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
|
---|
1787 | if ((t > bottom) || (l > right) || (top > b) || (left > r))
|
---|
1788 | continue; // no intersect
|
---|
1789 | if (t < top) {
|
---|
1790 | top = t;
|
---|
1791 | expanded = true;
|
---|
1792 | }
|
---|
1793 | if (l < left) {
|
---|
1794 | left = l;
|
---|
1795 | expanded = true;
|
---|
1796 | }
|
---|
1797 | if (b > bottom) {
|
---|
1798 | bottom = b;
|
---|
1799 | expanded = true;
|
---|
1800 | }
|
---|
1801 | if (r > right) {
|
---|
1802 | right = r;
|
---|
1803 | expanded = true;
|
---|
1804 | }
|
---|
1805 | if (expanded)
|
---|
1806 | break;
|
---|
1807 | }
|
---|
1808 | } while (expanded);
|
---|
1809 | for (int horizontal = left; horizontal <= right; ++horizontal) {
|
---|
1810 | int column = d->logicalColumn(horizontal);
|
---|
1811 | for (int vertical = top; vertical <= bottom; ++vertical) {
|
---|
1812 | int row = d->logicalRow(vertical);
|
---|
1813 | QModelIndex index = d->model->index(row, column, d->root);
|
---|
1814 | selection.append(QItemSelectionRange(index));
|
---|
1815 | }
|
---|
1816 | }
|
---|
1817 | } else if (verticalMoved && horizontalMoved) {
|
---|
1818 | int top = d->visualRow(tl.row());
|
---|
1819 | int left = d->visualColumn(tl.column());
|
---|
1820 | int bottom = d->visualRow(br.row());
|
---|
1821 | int right = d->visualColumn(br.column());
|
---|
1822 | for (int horizontal = left; horizontal <= right; ++horizontal) {
|
---|
1823 | int column = d->logicalColumn(horizontal);
|
---|
1824 | for (int vertical = top; vertical <= bottom; ++vertical) {
|
---|
1825 | int row = d->logicalRow(vertical);
|
---|
1826 | QModelIndex index = d->model->index(row, column, d->root);
|
---|
1827 | selection.append(QItemSelectionRange(index));
|
---|
1828 | }
|
---|
1829 | }
|
---|
1830 | } else if (horizontalMoved) {
|
---|
1831 | int left = d->visualColumn(tl.column());
|
---|
1832 | int right = d->visualColumn(br.column());
|
---|
1833 | for (int visual = left; visual <= right; ++visual) {
|
---|
1834 | int column = d->logicalColumn(visual);
|
---|
1835 | QModelIndex topLeft = d->model->index(tl.row(), column, d->root);
|
---|
1836 | QModelIndex bottomRight = d->model->index(br.row(), column, d->root);
|
---|
1837 | selection.append(QItemSelectionRange(topLeft, bottomRight));
|
---|
1838 | }
|
---|
1839 | } else if (verticalMoved) {
|
---|
1840 | int top = d->visualRow(tl.row());
|
---|
1841 | int bottom = d->visualRow(br.row());
|
---|
1842 | for (int visual = top; visual <= bottom; ++visual) {
|
---|
1843 | int row = d->logicalRow(visual);
|
---|
1844 | QModelIndex topLeft = d->model->index(row, tl.column(), d->root);
|
---|
1845 | QModelIndex bottomRight = d->model->index(row, br.column(), d->root);
|
---|
1846 | selection.append(QItemSelectionRange(topLeft, bottomRight));
|
---|
1847 | }
|
---|
1848 | } else { // nothing moved
|
---|
1849 | QItemSelectionRange range(tl, br);
|
---|
1850 | if (!range.isEmpty())
|
---|
1851 | selection.append(range);
|
---|
1852 | }
|
---|
1853 |
|
---|
1854 | d->selectionModel->select(selection, command);
|
---|
1855 | }
|
---|
1856 |
|
---|
1857 | /*!
|
---|
1858 | \internal
|
---|
1859 |
|
---|
1860 | Returns the rectangle from the viewport of the items in the given
|
---|
1861 | \a selection.
|
---|
1862 |
|
---|
1863 | Since 4.7, the returned region only contains rectangles intersecting
|
---|
1864 | (or included in) the viewport.
|
---|
1865 | */
|
---|
1866 | QRegion QTableView::visualRegionForSelection(const QItemSelection &selection) const
|
---|
1867 | {
|
---|
1868 | Q_D(const QTableView);
|
---|
1869 |
|
---|
1870 | if (selection.isEmpty())
|
---|
1871 | return QRegion();
|
---|
1872 |
|
---|
1873 | QRegion selectionRegion;
|
---|
1874 | const QRect &viewportRect = d->viewport->rect();
|
---|
1875 | bool verticalMoved = verticalHeader()->sectionsMoved();
|
---|
1876 | bool horizontalMoved = horizontalHeader()->sectionsMoved();
|
---|
1877 |
|
---|
1878 | if ((verticalMoved && horizontalMoved) || (d->hasSpans() && (verticalMoved || horizontalMoved))) {
|
---|
1879 | for (int i = 0; i < selection.count(); ++i) {
|
---|
1880 | QItemSelectionRange range = selection.at(i);
|
---|
1881 | if (range.parent() != d->root || !range.isValid())
|
---|
1882 | continue;
|
---|
1883 | for (int r = range.top(); r <= range.bottom(); ++r)
|
---|
1884 | for (int c = range.left(); c <= range.right(); ++c) {
|
---|
1885 | const QRect &rangeRect = visualRect(d->model->index(r, c, d->root));
|
---|
1886 | if (viewportRect.intersects(rangeRect))
|
---|
1887 | selectionRegion += rangeRect;
|
---|
1888 | }
|
---|
1889 | }
|
---|
1890 | } else if (horizontalMoved) {
|
---|
1891 | for (int i = 0; i < selection.count(); ++i) {
|
---|
1892 | QItemSelectionRange range = selection.at(i);
|
---|
1893 | if (range.parent() != d->root || !range.isValid())
|
---|
1894 | continue;
|
---|
1895 | int top = rowViewportPosition(range.top());
|
---|
1896 | int bottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom());
|
---|
1897 | if (top > bottom)
|
---|
1898 | qSwap<int>(top, bottom);
|
---|
1899 | int height = bottom - top;
|
---|
1900 | for (int c = range.left(); c <= range.right(); ++c) {
|
---|
1901 | const QRect rangeRect(columnViewportPosition(c), top, columnWidth(c), height);
|
---|
1902 | if (viewportRect.intersects(rangeRect))
|
---|
1903 | selectionRegion += rangeRect;
|
---|
1904 | }
|
---|
1905 | }
|
---|
1906 | } else if (verticalMoved) {
|
---|
1907 | for (int i = 0; i < selection.count(); ++i) {
|
---|
1908 | QItemSelectionRange range = selection.at(i);
|
---|
1909 | if (range.parent() != d->root || !range.isValid())
|
---|
1910 | continue;
|
---|
1911 | int left = columnViewportPosition(range.left());
|
---|
1912 | int right = columnViewportPosition(range.right()) + columnWidth(range.right());
|
---|
1913 | if (left > right)
|
---|
1914 | qSwap<int>(left, right);
|
---|
1915 | int width = right - left;
|
---|
1916 | for (int r = range.top(); r <= range.bottom(); ++r) {
|
---|
1917 | const QRect rangeRect(left, rowViewportPosition(r), width, rowHeight(r));
|
---|
1918 | if (viewportRect.intersects(rangeRect))
|
---|
1919 | selectionRegion += rangeRect;
|
---|
1920 | }
|
---|
1921 | }
|
---|
1922 | } else { // nothing moved
|
---|
1923 | const int gridAdjust = showGrid() ? 1 : 0;
|
---|
1924 | for (int i = 0; i < selection.count(); ++i) {
|
---|
1925 | QItemSelectionRange range = selection.at(i);
|
---|
1926 | if (range.parent() != d->root || !range.isValid())
|
---|
1927 | continue;
|
---|
1928 | d->trimHiddenSelections(&range);
|
---|
1929 |
|
---|
1930 | const int rtop = rowViewportPosition(range.top());
|
---|
1931 | const int rbottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom());
|
---|
1932 | int rleft;
|
---|
1933 | int rright;
|
---|
1934 | if (isLeftToRight()) {
|
---|
1935 | rleft = columnViewportPosition(range.left());
|
---|
1936 | rright = columnViewportPosition(range.right()) + columnWidth(range.right());
|
---|
1937 | } else {
|
---|
1938 | rleft = columnViewportPosition(range.right());
|
---|
1939 | rright = columnViewportPosition(range.left()) + columnWidth(range.left());
|
---|
1940 | }
|
---|
1941 | const QRect rangeRect(QPoint(rleft, rtop), QPoint(rright - 1 - gridAdjust, rbottom - 1 - gridAdjust));
|
---|
1942 | if (viewportRect.intersects(rangeRect))
|
---|
1943 | selectionRegion += rangeRect;
|
---|
1944 | if (d->hasSpans()) {
|
---|
1945 | foreach (QSpanCollection::Span *s,
|
---|
1946 | d->spans.spansInRect(range.left(), range.top(), range.width(), range.height())) {
|
---|
1947 | if (range.contains(s->top(), s->left(), range.parent())) {
|
---|
1948 | const QRect &visualSpanRect = d->visualSpanRect(*s);
|
---|
1949 | if (viewportRect.intersects(visualSpanRect))
|
---|
1950 | selectionRegion += visualSpanRect;
|
---|
1951 | }
|
---|
1952 | }
|
---|
1953 | }
|
---|
1954 | }
|
---|
1955 | }
|
---|
1956 |
|
---|
1957 | return selectionRegion;
|
---|
1958 | }
|
---|
1959 |
|
---|
1960 |
|
---|
1961 | /*!
|
---|
1962 | \reimp
|
---|
1963 | */
|
---|
1964 | QModelIndexList QTableView::selectedIndexes() const
|
---|
1965 | {
|
---|
1966 | Q_D(const QTableView);
|
---|
1967 | QModelIndexList viewSelected;
|
---|
1968 | QModelIndexList modelSelected;
|
---|
1969 | if (d->selectionModel)
|
---|
1970 | modelSelected = d->selectionModel->selectedIndexes();
|
---|
1971 | for (int i = 0; i < modelSelected.count(); ++i) {
|
---|
1972 | QModelIndex index = modelSelected.at(i);
|
---|
1973 | if (!isIndexHidden(index) && index.parent() == d->root)
|
---|
1974 | viewSelected.append(index);
|
---|
1975 | }
|
---|
1976 | return viewSelected;
|
---|
1977 | }
|
---|
1978 |
|
---|
1979 |
|
---|
1980 | /*!
|
---|
1981 | This slot is called whenever rows are added or deleted. The
|
---|
1982 | previous number of rows is specified by \a oldCount, and the new
|
---|
1983 | number of rows is specified by \a newCount.
|
---|
1984 | */
|
---|
1985 | void QTableView::rowCountChanged(int /*oldCount*/, int /*newCount*/ )
|
---|
1986 | {
|
---|
1987 | Q_D(QTableView);
|
---|
1988 | d->doDelayedItemsLayout();
|
---|
1989 | }
|
---|
1990 |
|
---|
1991 | /*!
|
---|
1992 | This slot is called whenever columns are added or deleted. The
|
---|
1993 | previous number of columns is specified by \a oldCount, and the new
|
---|
1994 | number of columns is specified by \a newCount.
|
---|
1995 | */
|
---|
1996 | void QTableView::columnCountChanged(int, int)
|
---|
1997 | {
|
---|
1998 | Q_D(QTableView);
|
---|
1999 | updateGeometries();
|
---|
2000 | if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem)
|
---|
2001 | d->horizontalHeader->setOffsetToSectionPosition(horizontalScrollBar()->value());
|
---|
2002 | else
|
---|
2003 | d->horizontalHeader->setOffset(horizontalScrollBar()->value());
|
---|
2004 | d->viewport->update();
|
---|
2005 | }
|
---|
2006 |
|
---|
2007 | /*!
|
---|
2008 | \reimp
|
---|
2009 | */
|
---|
2010 | void QTableView::updateGeometries()
|
---|
2011 | {
|
---|
2012 | Q_D(QTableView);
|
---|
2013 | if (d->geometryRecursionBlock)
|
---|
2014 | return;
|
---|
2015 | d->geometryRecursionBlock = true;
|
---|
2016 |
|
---|
2017 | int width = 0;
|
---|
2018 | if (!d->verticalHeader->isHidden()) {
|
---|
2019 | width = qMax(d->verticalHeader->minimumWidth(), d->verticalHeader->sizeHint().width());
|
---|
2020 | width = qMin(width, d->verticalHeader->maximumWidth());
|
---|
2021 | }
|
---|
2022 | int height = 0;
|
---|
2023 | if (!d->horizontalHeader->isHidden()) {
|
---|
2024 | height = qMax(d->horizontalHeader->minimumHeight(), d->horizontalHeader->sizeHint().height());
|
---|
2025 | height = qMin(height, d->horizontalHeader->maximumHeight());
|
---|
2026 | }
|
---|
2027 | bool reverse = isRightToLeft();
|
---|
2028 | if (reverse)
|
---|
2029 | setViewportMargins(0, height, width, 0);
|
---|
2030 | else
|
---|
2031 | setViewportMargins(width, height, 0, 0);
|
---|
2032 |
|
---|
2033 | // update headers
|
---|
2034 |
|
---|
2035 | QRect vg = d->viewport->geometry();
|
---|
2036 |
|
---|
2037 | int verticalLeft = reverse ? vg.right() + 1 : (vg.left() - width);
|
---|
2038 | d->verticalHeader->setGeometry(verticalLeft, vg.top(), width, vg.height());
|
---|
2039 | if (d->verticalHeader->isHidden())
|
---|
2040 | QMetaObject::invokeMethod(d->verticalHeader, "updateGeometries");
|
---|
2041 |
|
---|
2042 | int horizontalTop = vg.top() - height;
|
---|
2043 | d->horizontalHeader->setGeometry(vg.left(), horizontalTop, vg.width(), height);
|
---|
2044 | if (d->horizontalHeader->isHidden())
|
---|
2045 | QMetaObject::invokeMethod(d->horizontalHeader, "updateGeometries");
|
---|
2046 |
|
---|
2047 | // update cornerWidget
|
---|
2048 | if (d->horizontalHeader->isHidden() || d->verticalHeader->isHidden()) {
|
---|
2049 | d->cornerWidget->setHidden(true);
|
---|
2050 | } else {
|
---|
2051 | d->cornerWidget->setHidden(false);
|
---|
2052 | d->cornerWidget->setGeometry(verticalLeft, horizontalTop, width, height);
|
---|
2053 | }
|
---|
2054 |
|
---|
2055 | // update scroll bars
|
---|
2056 |
|
---|
2057 | // ### move this block into the if
|
---|
2058 | QSize vsize = d->viewport->size();
|
---|
2059 | QSize max = maximumViewportSize();
|
---|
2060 | uint horizontalLength = d->horizontalHeader->length();
|
---|
2061 | uint verticalLength = d->verticalHeader->length();
|
---|
2062 | if ((uint)max.width() >= horizontalLength && (uint)max.height() >= verticalLength)
|
---|
2063 | vsize = max;
|
---|
2064 |
|
---|
2065 | // horizontal scroll bar
|
---|
2066 | const int columnCount = d->horizontalHeader->count();
|
---|
2067 | const int viewportWidth = vsize.width();
|
---|
2068 | int columnsInViewport = 0;
|
---|
2069 | for (int width = 0, column = columnCount - 1; column >= 0; --column) {
|
---|
2070 | int logical = d->horizontalHeader->logicalIndex(column);
|
---|
2071 | if (!d->horizontalHeader->isSectionHidden(logical)) {
|
---|
2072 | width += d->horizontalHeader->sectionSize(logical);
|
---|
2073 | if (width > viewportWidth)
|
---|
2074 | break;
|
---|
2075 | ++columnsInViewport;
|
---|
2076 | }
|
---|
2077 | }
|
---|
2078 | columnsInViewport = qMax(columnsInViewport, 1); //there must be always at least 1 column
|
---|
2079 |
|
---|
2080 | if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
|
---|
2081 | const int visibleColumns = columnCount - d->horizontalHeader->hiddenSectionCount();
|
---|
2082 | horizontalScrollBar()->setRange(0, visibleColumns - columnsInViewport);
|
---|
2083 | horizontalScrollBar()->setPageStep(columnsInViewport);
|
---|
2084 | if (columnsInViewport >= visibleColumns)
|
---|
2085 | d->horizontalHeader->setOffset(0);
|
---|
2086 | horizontalScrollBar()->setSingleStep(1);
|
---|
2087 | } else { // ScrollPerPixel
|
---|
2088 | horizontalScrollBar()->setPageStep(vsize.width());
|
---|
2089 | horizontalScrollBar()->setRange(0, horizontalLength - vsize.width());
|
---|
2090 | horizontalScrollBar()->setSingleStep(qMax(vsize.width() / (columnsInViewport + 1), 2));
|
---|
2091 | }
|
---|
2092 |
|
---|
2093 | // vertical scroll bar
|
---|
2094 | const int rowCount = d->verticalHeader->count();
|
---|
2095 | const int viewportHeight = vsize.height();
|
---|
2096 | int rowsInViewport = 0;
|
---|
2097 | for (int height = 0, row = rowCount - 1; row >= 0; --row) {
|
---|
2098 | int logical = d->verticalHeader->logicalIndex(row);
|
---|
2099 | if (!d->verticalHeader->isSectionHidden(logical)) {
|
---|
2100 | height += d->verticalHeader->sectionSize(logical);
|
---|
2101 | if (height > viewportHeight)
|
---|
2102 | break;
|
---|
2103 | ++rowsInViewport;
|
---|
2104 | }
|
---|
2105 | }
|
---|
2106 | rowsInViewport = qMax(rowsInViewport, 1); //there must be always at least 1 row
|
---|
2107 |
|
---|
2108 | if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
|
---|
2109 | const int visibleRows = rowCount - d->verticalHeader->hiddenSectionCount();
|
---|
2110 | verticalScrollBar()->setRange(0, visibleRows - rowsInViewport);
|
---|
2111 | verticalScrollBar()->setPageStep(rowsInViewport);
|
---|
2112 | if (rowsInViewport >= visibleRows)
|
---|
2113 | d->verticalHeader->setOffset(0);
|
---|
2114 | verticalScrollBar()->setSingleStep(1);
|
---|
2115 | } else { // ScrollPerPixel
|
---|
2116 | verticalScrollBar()->setPageStep(vsize.height());
|
---|
2117 | verticalScrollBar()->setRange(0, verticalLength - vsize.height());
|
---|
2118 | verticalScrollBar()->setSingleStep(qMax(vsize.height() / (rowsInViewport + 1), 2));
|
---|
2119 | }
|
---|
2120 |
|
---|
2121 | d->geometryRecursionBlock = false;
|
---|
2122 | QAbstractItemView::updateGeometries();
|
---|
2123 | }
|
---|
2124 |
|
---|
2125 | /*!
|
---|
2126 | Returns the size hint for the given \a row's height or -1 if there
|
---|
2127 | is no model.
|
---|
2128 |
|
---|
2129 | If you need to set the height of a given row to a fixed value, call
|
---|
2130 | QHeaderView::resizeSection() on the table's vertical header.
|
---|
2131 |
|
---|
2132 | If you reimplement this function in a subclass, note that the value you
|
---|
2133 | return is only used when resizeRowToContents() is called. In that case,
|
---|
2134 | if a larger row height is required by either the vertical header or
|
---|
2135 | the item delegate, that width will be used instead.
|
---|
2136 |
|
---|
2137 | \sa QWidget::sizeHint, verticalHeader()
|
---|
2138 | */
|
---|
2139 | int QTableView::sizeHintForRow(int row) const
|
---|
2140 | {
|
---|
2141 | Q_D(const QTableView);
|
---|
2142 |
|
---|
2143 | if (!model())
|
---|
2144 | return -1;
|
---|
2145 |
|
---|
2146 | ensurePolished();
|
---|
2147 |
|
---|
2148 | int left = qMax(0, d->horizontalHeader->visualIndexAt(0));
|
---|
2149 | int right = d->horizontalHeader->visualIndexAt(d->viewport->width());
|
---|
2150 | if (right == -1) // the table don't have enough columns to fill the viewport
|
---|
2151 | right = d->model->columnCount(d->root) - 1;
|
---|
2152 |
|
---|
2153 | QStyleOptionViewItemV4 option = d->viewOptionsV4();
|
---|
2154 |
|
---|
2155 | int hint = 0;
|
---|
2156 | QModelIndex index;
|
---|
2157 | for (int column = left; column <= right; ++column) {
|
---|
2158 | int logicalColumn = d->horizontalHeader->logicalIndex(column);
|
---|
2159 | if (d->horizontalHeader->isSectionHidden(logicalColumn))
|
---|
2160 | continue;
|
---|
2161 | index = d->model->index(row, logicalColumn, d->root);
|
---|
2162 | if (d->wrapItemText) {// for wrapping boundaries
|
---|
2163 | option.rect.setY(rowViewportPosition(index.row()));
|
---|
2164 | option.rect.setHeight(rowHeight(index.row()));
|
---|
2165 | option.rect.setX(columnViewportPosition(index.column()));
|
---|
2166 | option.rect.setWidth(columnWidth(index.column()));
|
---|
2167 | }
|
---|
2168 |
|
---|
2169 | QWidget *editor = d->editorForIndex(index).editor;
|
---|
2170 | if (editor && d->persistent.contains(editor)) {
|
---|
2171 | hint = qMax(hint, editor->sizeHint().height());
|
---|
2172 | int min = editor->minimumSize().height();
|
---|
2173 | int max = editor->maximumSize().height();
|
---|
2174 | hint = qBound(min, hint, max);
|
---|
2175 | }
|
---|
2176 |
|
---|
2177 | hint = qMax(hint, itemDelegate(index)->sizeHint(option, index).height());
|
---|
2178 | }
|
---|
2179 |
|
---|
2180 | return d->showGrid ? hint + 1 : hint;
|
---|
2181 | }
|
---|
2182 |
|
---|
2183 | /*!
|
---|
2184 | Returns the size hint for the given \a column's width or -1 if
|
---|
2185 | there is no model.
|
---|
2186 |
|
---|
2187 | If you need to set the width of a given column to a fixed value, call
|
---|
2188 | QHeaderView::resizeSection() on the table's horizontal header.
|
---|
2189 |
|
---|
2190 | If you reimplement this function in a subclass, note that the value you
|
---|
2191 | return will be used when resizeColumnToContents() or
|
---|
2192 | QHeaderView::resizeSections() is called. If a larger column width is
|
---|
2193 | required by either the horizontal header or the item delegate, the larger
|
---|
2194 | width will be used instead.
|
---|
2195 |
|
---|
2196 | \sa QWidget::sizeHint, horizontalHeader()
|
---|
2197 | */
|
---|
2198 | int QTableView::sizeHintForColumn(int column) const
|
---|
2199 | {
|
---|
2200 | Q_D(const QTableView);
|
---|
2201 |
|
---|
2202 | if (!model())
|
---|
2203 | return -1;
|
---|
2204 |
|
---|
2205 | ensurePolished();
|
---|
2206 |
|
---|
2207 | int top = qMax(0, d->verticalHeader->visualIndexAt(0));
|
---|
2208 | int bottom = d->verticalHeader->visualIndexAt(d->viewport->height());
|
---|
2209 | if (!isVisible() || bottom == -1) // the table don't have enough rows to fill the viewport
|
---|
2210 | bottom = d->model->rowCount(d->root) - 1;
|
---|
2211 |
|
---|
2212 | QStyleOptionViewItemV4 option = d->viewOptionsV4();
|
---|
2213 |
|
---|
2214 | int hint = 0;
|
---|
2215 | QModelIndex index;
|
---|
2216 | for (int row = top; row <= bottom; ++row) {
|
---|
2217 | int logicalRow = d->verticalHeader->logicalIndex(row);
|
---|
2218 | if (d->verticalHeader->isSectionHidden(logicalRow))
|
---|
2219 | continue;
|
---|
2220 | index = d->model->index(logicalRow, column, d->root);
|
---|
2221 |
|
---|
2222 | QWidget *editor = d->editorForIndex(index).editor;
|
---|
2223 | if (editor && d->persistent.contains(editor)) {
|
---|
2224 | hint = qMax(hint, editor->sizeHint().width());
|
---|
2225 | int min = editor->minimumSize().width();
|
---|
2226 | int max = editor->maximumSize().width();
|
---|
2227 | hint = qBound(min, hint, max);
|
---|
2228 | }
|
---|
2229 |
|
---|
2230 | hint = qMax(hint, itemDelegate(index)->sizeHint(option, index).width());
|
---|
2231 | }
|
---|
2232 |
|
---|
2233 | return d->showGrid ? hint + 1 : hint;
|
---|
2234 | }
|
---|
2235 |
|
---|
2236 | /*!
|
---|
2237 | Returns the y-coordinate in contents coordinates of the given \a
|
---|
2238 | row.
|
---|
2239 | */
|
---|
2240 | int QTableView::rowViewportPosition(int row) const
|
---|
2241 | {
|
---|
2242 | Q_D(const QTableView);
|
---|
2243 | return d->verticalHeader->sectionViewportPosition(row);
|
---|
2244 | }
|
---|
2245 |
|
---|
2246 | /*!
|
---|
2247 | Returns the row in which the given y-coordinate, \a y, in contents
|
---|
2248 | coordinates is located.
|
---|
2249 |
|
---|
2250 | \note This function returns -1 if the given coordinate is not valid
|
---|
2251 | (has no row).
|
---|
2252 |
|
---|
2253 | \sa columnAt()
|
---|
2254 | */
|
---|
2255 | int QTableView::rowAt(int y) const
|
---|
2256 | {
|
---|
2257 | Q_D(const QTableView);
|
---|
2258 | return d->verticalHeader->logicalIndexAt(y);
|
---|
2259 | }
|
---|
2260 |
|
---|
2261 | /*!
|
---|
2262 | \since 4.1
|
---|
2263 |
|
---|
2264 | Sets the height of the given \a row to be \a height.
|
---|
2265 | */
|
---|
2266 | void QTableView::setRowHeight(int row, int height)
|
---|
2267 | {
|
---|
2268 | Q_D(const QTableView);
|
---|
2269 | d->verticalHeader->resizeSection(row, height);
|
---|
2270 | }
|
---|
2271 |
|
---|
2272 | /*!
|
---|
2273 | Returns the height of the given \a row.
|
---|
2274 |
|
---|
2275 | \sa resizeRowToContents(), columnWidth()
|
---|
2276 | */
|
---|
2277 | int QTableView::rowHeight(int row) const
|
---|
2278 | {
|
---|
2279 | Q_D(const QTableView);
|
---|
2280 | return d->verticalHeader->sectionSize(row);
|
---|
2281 | }
|
---|
2282 |
|
---|
2283 | /*!
|
---|
2284 | Returns the x-coordinate in contents coordinates of the given \a
|
---|
2285 | column.
|
---|
2286 | */
|
---|
2287 | int QTableView::columnViewportPosition(int column) const
|
---|
2288 | {
|
---|
2289 | Q_D(const QTableView);
|
---|
2290 | return d->horizontalHeader->sectionViewportPosition(column);
|
---|
2291 | }
|
---|
2292 |
|
---|
2293 | /*!
|
---|
2294 | Returns the column in which the given x-coordinate, \a x, in contents
|
---|
2295 | coordinates is located.
|
---|
2296 |
|
---|
2297 | \note This function returns -1 if the given coordinate is not valid
|
---|
2298 | (has no column).
|
---|
2299 |
|
---|
2300 | \sa rowAt()
|
---|
2301 | */
|
---|
2302 | int QTableView::columnAt(int x) const
|
---|
2303 | {
|
---|
2304 | Q_D(const QTableView);
|
---|
2305 | return d->horizontalHeader->logicalIndexAt(x);
|
---|
2306 | }
|
---|
2307 |
|
---|
2308 | /*!
|
---|
2309 | \since 4.1
|
---|
2310 |
|
---|
2311 | Sets the width of the given \a column to be \a width.
|
---|
2312 | */
|
---|
2313 | void QTableView::setColumnWidth(int column, int width)
|
---|
2314 | {
|
---|
2315 | Q_D(const QTableView);
|
---|
2316 | d->horizontalHeader->resizeSection(column, width);
|
---|
2317 | }
|
---|
2318 |
|
---|
2319 | /*!
|
---|
2320 | Returns the width of the given \a column.
|
---|
2321 |
|
---|
2322 | \sa resizeColumnToContents(), rowHeight()
|
---|
2323 | */
|
---|
2324 | int QTableView::columnWidth(int column) const
|
---|
2325 | {
|
---|
2326 | Q_D(const QTableView);
|
---|
2327 | return d->horizontalHeader->sectionSize(column);
|
---|
2328 | }
|
---|
2329 |
|
---|
2330 | /*!
|
---|
2331 | Returns true if the given \a row is hidden; otherwise returns false.
|
---|
2332 |
|
---|
2333 | \sa isColumnHidden()
|
---|
2334 | */
|
---|
2335 | bool QTableView::isRowHidden(int row) const
|
---|
2336 | {
|
---|
2337 | Q_D(const QTableView);
|
---|
2338 | return d->verticalHeader->isSectionHidden(row);
|
---|
2339 | }
|
---|
2340 |
|
---|
2341 | /*!
|
---|
2342 | If \a hide is true \a row will be hidden, otherwise it will be shown.
|
---|
2343 |
|
---|
2344 | \sa setColumnHidden()
|
---|
2345 | */
|
---|
2346 | void QTableView::setRowHidden(int row, bool hide)
|
---|
2347 | {
|
---|
2348 | Q_D(QTableView);
|
---|
2349 | if (row < 0 || row >= d->verticalHeader->count())
|
---|
2350 | return;
|
---|
2351 | d->verticalHeader->setSectionHidden(row, hide);
|
---|
2352 | }
|
---|
2353 |
|
---|
2354 | /*!
|
---|
2355 | Returns true if the given \a column is hidden; otherwise returns false.
|
---|
2356 |
|
---|
2357 | \sa isRowHidden()
|
---|
2358 | */
|
---|
2359 | bool QTableView::isColumnHidden(int column) const
|
---|
2360 | {
|
---|
2361 | Q_D(const QTableView);
|
---|
2362 | return d->horizontalHeader->isSectionHidden(column);
|
---|
2363 | }
|
---|
2364 |
|
---|
2365 | /*!
|
---|
2366 | If \a hide is true the given \a column will be hidden; otherwise it
|
---|
2367 | will be shown.
|
---|
2368 |
|
---|
2369 | \sa setRowHidden()
|
---|
2370 | */
|
---|
2371 | void QTableView::setColumnHidden(int column, bool hide)
|
---|
2372 | {
|
---|
2373 | Q_D(QTableView);
|
---|
2374 | if (column < 0 || column >= d->horizontalHeader->count())
|
---|
2375 | return;
|
---|
2376 | d->horizontalHeader->setSectionHidden(column, hide);
|
---|
2377 | }
|
---|
2378 |
|
---|
2379 | /*!
|
---|
2380 | \since 4.2
|
---|
2381 | \property QTableView::sortingEnabled
|
---|
2382 | \brief whether sorting is enabled
|
---|
2383 |
|
---|
2384 | If this property is true, sorting is enabled for the table. If
|
---|
2385 | this property is false, sorting is not enabled. The default value
|
---|
2386 | is false.
|
---|
2387 |
|
---|
2388 | \note. Setting the property to true with setSortingEnabled()
|
---|
2389 | immediately triggers a call to sortByColumn() with the current
|
---|
2390 | sort section and order.
|
---|
2391 |
|
---|
2392 | \sa sortByColumn()
|
---|
2393 | */
|
---|
2394 |
|
---|
2395 | /*!
|
---|
2396 | If \a enabled true enables sorting for the table and immediately
|
---|
2397 | trigger a call to sortByColumn() with the current sort section and
|
---|
2398 | order
|
---|
2399 | */
|
---|
2400 | void QTableView::setSortingEnabled(bool enable)
|
---|
2401 | {
|
---|
2402 | Q_D(QTableView);
|
---|
2403 | d->sortingEnabled = enable;
|
---|
2404 | horizontalHeader()->setSortIndicatorShown(enable);
|
---|
2405 | if (enable) {
|
---|
2406 | disconnect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
|
---|
2407 | this, SLOT(_q_selectColumn(int)));
|
---|
2408 | disconnect(horizontalHeader(), SIGNAL(sectionPressed(int)),
|
---|
2409 | this, SLOT(selectColumn(int)));
|
---|
2410 | connect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
|
---|
2411 | this, SLOT(sortByColumn(int)), Qt::UniqueConnection);
|
---|
2412 | sortByColumn(horizontalHeader()->sortIndicatorSection(),
|
---|
2413 | horizontalHeader()->sortIndicatorOrder());
|
---|
2414 | } else {
|
---|
2415 | connect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
|
---|
2416 | this, SLOT(_q_selectColumn(int)), Qt::UniqueConnection);
|
---|
2417 | connect(horizontalHeader(), SIGNAL(sectionPressed(int)),
|
---|
2418 | this, SLOT(selectColumn(int)), Qt::UniqueConnection);
|
---|
2419 | disconnect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
|
---|
2420 | this, SLOT(sortByColumn(int)));
|
---|
2421 | }
|
---|
2422 | }
|
---|
2423 |
|
---|
2424 | bool QTableView::isSortingEnabled() const
|
---|
2425 | {
|
---|
2426 | Q_D(const QTableView);
|
---|
2427 | return d->sortingEnabled;
|
---|
2428 | }
|
---|
2429 |
|
---|
2430 | /*!
|
---|
2431 | \property QTableView::showGrid
|
---|
2432 | \brief whether the grid is shown
|
---|
2433 |
|
---|
2434 | If this property is true a grid is drawn for the table; if the
|
---|
2435 | property is false, no grid is drawn. The default value is true.
|
---|
2436 | */
|
---|
2437 | bool QTableView::showGrid() const
|
---|
2438 | {
|
---|
2439 | Q_D(const QTableView);
|
---|
2440 | return d->showGrid;
|
---|
2441 | }
|
---|
2442 |
|
---|
2443 | void QTableView::setShowGrid(bool show)
|
---|
2444 | {
|
---|
2445 | Q_D(QTableView);
|
---|
2446 | if (d->showGrid != show) {
|
---|
2447 | d->showGrid = show;
|
---|
2448 | d->viewport->update();
|
---|
2449 | }
|
---|
2450 | }
|
---|
2451 |
|
---|
2452 | /*!
|
---|
2453 | \property QTableView::gridStyle
|
---|
2454 | \brief the pen style used to draw the grid.
|
---|
2455 |
|
---|
2456 | This property holds the style used when drawing the grid (see \l{showGrid}).
|
---|
2457 | */
|
---|
2458 | Qt::PenStyle QTableView::gridStyle() const
|
---|
2459 | {
|
---|
2460 | Q_D(const QTableView);
|
---|
2461 | return d->gridStyle;
|
---|
2462 | }
|
---|
2463 |
|
---|
2464 | void QTableView::setGridStyle(Qt::PenStyle style)
|
---|
2465 | {
|
---|
2466 | Q_D(QTableView);
|
---|
2467 | if (d->gridStyle != style) {
|
---|
2468 | d->gridStyle = style;
|
---|
2469 | d->viewport->update();
|
---|
2470 | }
|
---|
2471 | }
|
---|
2472 |
|
---|
2473 | /*!
|
---|
2474 | \property QTableView::wordWrap
|
---|
2475 | \brief the item text word-wrapping policy
|
---|
2476 | \since 4.3
|
---|
2477 |
|
---|
2478 | If this property is true then the item text is wrapped where
|
---|
2479 | necessary at word-breaks; otherwise it is not wrapped at all.
|
---|
2480 | This property is true by default.
|
---|
2481 |
|
---|
2482 | Note that even of wrapping is enabled, the cell will not be
|
---|
2483 | expanded to fit all text. Ellipsis will be inserted according to
|
---|
2484 | the current \l{QAbstractItemView::}{textElideMode}.
|
---|
2485 |
|
---|
2486 | */
|
---|
2487 | void QTableView::setWordWrap(bool on)
|
---|
2488 | {
|
---|
2489 | Q_D(QTableView);
|
---|
2490 | if (d->wrapItemText == on)
|
---|
2491 | return;
|
---|
2492 | d->wrapItemText = on;
|
---|
2493 | QMetaObject::invokeMethod(d->verticalHeader, "resizeSections");
|
---|
2494 | QMetaObject::invokeMethod(d->horizontalHeader, "resizeSections");
|
---|
2495 | }
|
---|
2496 |
|
---|
2497 | bool QTableView::wordWrap() const
|
---|
2498 | {
|
---|
2499 | Q_D(const QTableView);
|
---|
2500 | return d->wrapItemText;
|
---|
2501 | }
|
---|
2502 |
|
---|
2503 | /*!
|
---|
2504 | \property QTableView::cornerButtonEnabled
|
---|
2505 | \brief whether the button in the top-left corner is enabled
|
---|
2506 | \since 4.3
|
---|
2507 |
|
---|
2508 | If this property is true then button in the top-left corner
|
---|
2509 | of the table view is enabled. Clicking on this button will
|
---|
2510 | select all the cells in the table view.
|
---|
2511 |
|
---|
2512 | This property is true by default.
|
---|
2513 | */
|
---|
2514 | void QTableView::setCornerButtonEnabled(bool enable)
|
---|
2515 | {
|
---|
2516 | Q_D(QTableView);
|
---|
2517 | d->cornerWidget->setEnabled(enable);
|
---|
2518 | }
|
---|
2519 |
|
---|
2520 | bool QTableView::isCornerButtonEnabled() const
|
---|
2521 | {
|
---|
2522 | Q_D(const QTableView);
|
---|
2523 | return d->cornerWidget->isEnabled();
|
---|
2524 | }
|
---|
2525 |
|
---|
2526 | /*!
|
---|
2527 | \internal
|
---|
2528 |
|
---|
2529 | Returns the rectangle on the viewport occupied by the given \a
|
---|
2530 | index.
|
---|
2531 | If the index is hidden in the view it will return a null QRect.
|
---|
2532 | */
|
---|
2533 | QRect QTableView::visualRect(const QModelIndex &index) const
|
---|
2534 | {
|
---|
2535 | Q_D(const QTableView);
|
---|
2536 | if (!d->isIndexValid(index) || index.parent() != d->root
|
---|
2537 | || (!d->hasSpans() && isIndexHidden(index)))
|
---|
2538 | return QRect();
|
---|
2539 |
|
---|
2540 | d->executePostedLayout();
|
---|
2541 |
|
---|
2542 | if (d->hasSpans()) {
|
---|
2543 | QSpanCollection::Span span = d->span(index.row(), index.column());
|
---|
2544 | return d->visualSpanRect(span);
|
---|
2545 | }
|
---|
2546 |
|
---|
2547 | int rowp = rowViewportPosition(index.row());
|
---|
2548 | int rowh = rowHeight(index.row());
|
---|
2549 | int colp = columnViewportPosition(index.column());
|
---|
2550 | int colw = columnWidth(index.column());
|
---|
2551 |
|
---|
2552 | const int i = showGrid() ? 1 : 0;
|
---|
2553 | return QRect(colp, rowp, colw - i, rowh - i);
|
---|
2554 | }
|
---|
2555 |
|
---|
2556 | /*!
|
---|
2557 | \internal
|
---|
2558 |
|
---|
2559 | Makes sure that the given \a item is visible in the table view,
|
---|
2560 | scrolling if necessary.
|
---|
2561 | */
|
---|
2562 | void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint)
|
---|
2563 | {
|
---|
2564 | Q_D(QTableView);
|
---|
2565 |
|
---|
2566 | // check if we really need to do anything
|
---|
2567 | if (!d->isIndexValid(index)
|
---|
2568 | || (d->model->parent(index) != d->root)
|
---|
2569 | || isRowHidden(index.row()) || isColumnHidden(index.column()))
|
---|
2570 | return;
|
---|
2571 |
|
---|
2572 | QSpanCollection::Span span;
|
---|
2573 | if (d->hasSpans())
|
---|
2574 | span = d->span(index.row(), index.column());
|
---|
2575 |
|
---|
2576 | // Adjust horizontal position
|
---|
2577 |
|
---|
2578 | int viewportWidth = d->viewport->width();
|
---|
2579 | int horizontalOffset = d->horizontalHeader->offset();
|
---|
2580 | int horizontalPosition = d->horizontalHeader->sectionPosition(index.column());
|
---|
2581 | int horizontalIndex = d->horizontalHeader->visualIndex(index.column());
|
---|
2582 | int cellWidth = d->hasSpans()
|
---|
2583 | ? d->columnSpanWidth(index.column(), span.width())
|
---|
2584 | : d->horizontalHeader->sectionSize(index.column());
|
---|
2585 |
|
---|
2586 | if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
|
---|
2587 |
|
---|
2588 | bool positionAtLeft = (horizontalPosition - horizontalOffset < 0);
|
---|
2589 | bool positionAtRight = (horizontalPosition - horizontalOffset + cellWidth > viewportWidth);
|
---|
2590 |
|
---|
2591 | if (hint == PositionAtCenter || positionAtRight) {
|
---|
2592 | int w = (hint == PositionAtCenter ? viewportWidth / 2 : viewportWidth);
|
---|
2593 | int x = cellWidth;
|
---|
2594 | while (horizontalIndex > 0) {
|
---|
2595 | x += columnWidth(d->horizontalHeader->logicalIndex(horizontalIndex-1));
|
---|
2596 | if (x > w)
|
---|
2597 | break;
|
---|
2598 | --horizontalIndex;
|
---|
2599 | }
|
---|
2600 | }
|
---|
2601 |
|
---|
2602 | if (positionAtRight || hint == PositionAtCenter || positionAtLeft) {
|
---|
2603 | int hiddenSections = 0;
|
---|
2604 | if (d->horizontalHeader->sectionsHidden()) {
|
---|
2605 | for (int s = horizontalIndex - 1; s >= 0; --s) {
|
---|
2606 | int column = d->horizontalHeader->logicalIndex(s);
|
---|
2607 | if (d->horizontalHeader->isSectionHidden(column))
|
---|
2608 | ++hiddenSections;
|
---|
2609 | }
|
---|
2610 | }
|
---|
2611 | horizontalScrollBar()->setValue(horizontalIndex - hiddenSections);
|
---|
2612 | }
|
---|
2613 |
|
---|
2614 | } else { // ScrollPerPixel
|
---|
2615 | if (hint == PositionAtCenter) {
|
---|
2616 | horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
|
---|
2617 | } else {
|
---|
2618 | if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
|
---|
2619 | horizontalScrollBar()->setValue(horizontalPosition);
|
---|
2620 | else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
|
---|
2621 | horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
|
---|
2622 | }
|
---|
2623 | }
|
---|
2624 |
|
---|
2625 | // Adjust vertical position
|
---|
2626 |
|
---|
2627 | int viewportHeight = d->viewport->height();
|
---|
2628 | int verticalOffset = d->verticalHeader->offset();
|
---|
2629 | int verticalPosition = d->verticalHeader->sectionPosition(index.row());
|
---|
2630 | int verticalIndex = d->verticalHeader->visualIndex(index.row());
|
---|
2631 | int cellHeight = d->hasSpans()
|
---|
2632 | ? d->rowSpanHeight(index.row(), span.height())
|
---|
2633 | : d->verticalHeader->sectionSize(index.row());
|
---|
2634 |
|
---|
2635 | if (verticalPosition - verticalOffset < 0 || cellHeight > viewportHeight) {
|
---|
2636 | if (hint == EnsureVisible)
|
---|
2637 | hint = PositionAtTop;
|
---|
2638 | } else if (verticalPosition - verticalOffset + cellHeight > viewportHeight) {
|
---|
2639 | if (hint == EnsureVisible)
|
---|
2640 | hint = PositionAtBottom;
|
---|
2641 | }
|
---|
2642 |
|
---|
2643 | if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
|
---|
2644 |
|
---|
2645 | if (hint == PositionAtBottom || hint == PositionAtCenter) {
|
---|
2646 | int h = (hint == PositionAtCenter ? viewportHeight / 2 : viewportHeight);
|
---|
2647 | int y = cellHeight;
|
---|
2648 | while (verticalIndex > 0) {
|
---|
2649 | int row = d->verticalHeader->logicalIndex(verticalIndex - 1);
|
---|
2650 | y += d->verticalHeader->sectionSize(row);
|
---|
2651 | if (y > h)
|
---|
2652 | break;
|
---|
2653 | --verticalIndex;
|
---|
2654 | }
|
---|
2655 | }
|
---|
2656 |
|
---|
2657 | if (hint == PositionAtBottom || hint == PositionAtCenter || hint == PositionAtTop) {
|
---|
2658 | int hiddenSections = 0;
|
---|
2659 | if (d->verticalHeader->sectionsHidden()) {
|
---|
2660 | for (int s = verticalIndex - 1; s >= 0; --s) {
|
---|
2661 | int row = d->verticalHeader->logicalIndex(s);
|
---|
2662 | if (d->verticalHeader->isSectionHidden(row))
|
---|
2663 | ++hiddenSections;
|
---|
2664 | }
|
---|
2665 | }
|
---|
2666 | verticalScrollBar()->setValue(verticalIndex - hiddenSections);
|
---|
2667 | }
|
---|
2668 |
|
---|
2669 | } else { // ScrollPerPixel
|
---|
2670 | if (hint == PositionAtTop) {
|
---|
2671 | verticalScrollBar()->setValue(verticalPosition);
|
---|
2672 | } else if (hint == PositionAtBottom) {
|
---|
2673 | verticalScrollBar()->setValue(verticalPosition - viewportHeight + cellHeight);
|
---|
2674 | } else if (hint == PositionAtCenter) {
|
---|
2675 | verticalScrollBar()->setValue(verticalPosition - ((viewportHeight - cellHeight) / 2));
|
---|
2676 | }
|
---|
2677 | }
|
---|
2678 |
|
---|
2679 | update(index);
|
---|
2680 | }
|
---|
2681 |
|
---|
2682 | /*!
|
---|
2683 | This slot is called to change the height of the given \a row. The
|
---|
2684 | old height is specified by \a oldHeight, and the new height by \a
|
---|
2685 | newHeight.
|
---|
2686 |
|
---|
2687 | \sa columnResized()
|
---|
2688 | */
|
---|
2689 | void QTableView::rowResized(int row, int, int)
|
---|
2690 | {
|
---|
2691 | Q_D(QTableView);
|
---|
2692 | d->rowsToUpdate.append(row);
|
---|
2693 | if (d->rowResizeTimerID == 0)
|
---|
2694 | d->rowResizeTimerID = startTimer(0);
|
---|
2695 | }
|
---|
2696 |
|
---|
2697 | /*!
|
---|
2698 | This slot is called to change the width of the given \a column.
|
---|
2699 | The old width is specified by \a oldWidth, and the new width by \a
|
---|
2700 | newWidth.
|
---|
2701 |
|
---|
2702 | \sa rowResized()
|
---|
2703 | */
|
---|
2704 | void QTableView::columnResized(int column, int, int)
|
---|
2705 | {
|
---|
2706 | Q_D(QTableView);
|
---|
2707 | d->columnsToUpdate.append(column);
|
---|
2708 | if (d->columnResizeTimerID == 0)
|
---|
2709 | d->columnResizeTimerID = startTimer(0);
|
---|
2710 | }
|
---|
2711 |
|
---|
2712 | /*!
|
---|
2713 | \reimp
|
---|
2714 | */
|
---|
2715 | void QTableView::timerEvent(QTimerEvent *event)
|
---|
2716 | {
|
---|
2717 | Q_D(QTableView);
|
---|
2718 |
|
---|
2719 | if (event->timerId() == d->columnResizeTimerID) {
|
---|
2720 | updateGeometries();
|
---|
2721 | killTimer(d->columnResizeTimerID);
|
---|
2722 | d->columnResizeTimerID = 0;
|
---|
2723 |
|
---|
2724 | QRect rect;
|
---|
2725 | int viewportHeight = d->viewport->height();
|
---|
2726 | int viewportWidth = d->viewport->width();
|
---|
2727 | if (d->hasSpans()) {
|
---|
2728 | rect = QRect(0, 0, viewportWidth, viewportHeight);
|
---|
2729 | } else {
|
---|
2730 | for (int i = d->columnsToUpdate.size()-1; i >= 0; --i) {
|
---|
2731 | int column = d->columnsToUpdate.at(i);
|
---|
2732 | int x = columnViewportPosition(column);
|
---|
2733 | if (isRightToLeft())
|
---|
2734 | rect |= QRect(0, 0, x + columnWidth(column), viewportHeight);
|
---|
2735 | else
|
---|
2736 | rect |= QRect(x, 0, viewportWidth - x, viewportHeight);
|
---|
2737 | }
|
---|
2738 | }
|
---|
2739 |
|
---|
2740 | d->viewport->update(rect.normalized());
|
---|
2741 | d->columnsToUpdate.clear();
|
---|
2742 | }
|
---|
2743 |
|
---|
2744 | if (event->timerId() == d->rowResizeTimerID) {
|
---|
2745 | updateGeometries();
|
---|
2746 | killTimer(d->rowResizeTimerID);
|
---|
2747 | d->rowResizeTimerID = 0;
|
---|
2748 |
|
---|
2749 | int viewportHeight = d->viewport->height();
|
---|
2750 | int viewportWidth = d->viewport->width();
|
---|
2751 | int top;
|
---|
2752 | if (d->hasSpans()) {
|
---|
2753 | top = 0;
|
---|
2754 | } else {
|
---|
2755 | top = viewportHeight;
|
---|
2756 | for (int i = d->rowsToUpdate.size()-1; i >= 0; --i) {
|
---|
2757 | int y = rowViewportPosition(d->rowsToUpdate.at(i));
|
---|
2758 | top = qMin(top, y);
|
---|
2759 | }
|
---|
2760 | }
|
---|
2761 |
|
---|
2762 | d->viewport->update(QRect(0, top, viewportWidth, viewportHeight - top));
|
---|
2763 | d->rowsToUpdate.clear();
|
---|
2764 | }
|
---|
2765 |
|
---|
2766 | QAbstractItemView::timerEvent(event);
|
---|
2767 | }
|
---|
2768 |
|
---|
2769 | /*!
|
---|
2770 | This slot is called to change the index of the given \a row in the
|
---|
2771 | table view. The old index is specified by \a oldIndex, and the new
|
---|
2772 | index by \a newIndex.
|
---|
2773 |
|
---|
2774 | \sa columnMoved()
|
---|
2775 | */
|
---|
2776 | void QTableView::rowMoved(int, int oldIndex, int newIndex)
|
---|
2777 | {
|
---|
2778 | Q_D(QTableView);
|
---|
2779 |
|
---|
2780 | updateGeometries();
|
---|
2781 | int logicalOldIndex = d->verticalHeader->logicalIndex(oldIndex);
|
---|
2782 | int logicalNewIndex = d->verticalHeader->logicalIndex(newIndex);
|
---|
2783 | if (d->hasSpans()) {
|
---|
2784 | d->viewport->update();
|
---|
2785 | } else {
|
---|
2786 | int oldTop = rowViewportPosition(logicalOldIndex);
|
---|
2787 | int newTop = rowViewportPosition(logicalNewIndex);
|
---|
2788 | int oldBottom = oldTop + rowHeight(logicalOldIndex);
|
---|
2789 | int newBottom = newTop + rowHeight(logicalNewIndex);
|
---|
2790 | int top = qMin(oldTop, newTop);
|
---|
2791 | int bottom = qMax(oldBottom, newBottom);
|
---|
2792 | int height = bottom - top;
|
---|
2793 | d->viewport->update(0, top, d->viewport->width(), height);
|
---|
2794 | }
|
---|
2795 | }
|
---|
2796 |
|
---|
2797 | /*!
|
---|
2798 | This slot is called to change the index of the given \a column in
|
---|
2799 | the table view. The old index is specified by \a oldIndex, and
|
---|
2800 | the new index by \a newIndex.
|
---|
2801 |
|
---|
2802 | \sa rowMoved()
|
---|
2803 | */
|
---|
2804 | void QTableView::columnMoved(int, int oldIndex, int newIndex)
|
---|
2805 | {
|
---|
2806 | Q_D(QTableView);
|
---|
2807 |
|
---|
2808 | updateGeometries();
|
---|
2809 | int logicalOldIndex = d->horizontalHeader->logicalIndex(oldIndex);
|
---|
2810 | int logicalNewIndex = d->horizontalHeader->logicalIndex(newIndex);
|
---|
2811 | if (d->hasSpans()) {
|
---|
2812 | d->viewport->update();
|
---|
2813 | } else {
|
---|
2814 | int oldLeft = columnViewportPosition(logicalOldIndex);
|
---|
2815 | int newLeft = columnViewportPosition(logicalNewIndex);
|
---|
2816 | int oldRight = oldLeft + columnWidth(logicalOldIndex);
|
---|
2817 | int newRight = newLeft + columnWidth(logicalNewIndex);
|
---|
2818 | int left = qMin(oldLeft, newLeft);
|
---|
2819 | int right = qMax(oldRight, newRight);
|
---|
2820 | int width = right - left;
|
---|
2821 | d->viewport->update(left, 0, width, d->viewport->height());
|
---|
2822 | }
|
---|
2823 | }
|
---|
2824 |
|
---|
2825 | /*!
|
---|
2826 | Selects the given \a row in the table view if the current
|
---|
2827 | SelectionMode and SelectionBehavior allows rows to be selected.
|
---|
2828 |
|
---|
2829 | \sa selectColumn()
|
---|
2830 | */
|
---|
2831 | void QTableView::selectRow(int row)
|
---|
2832 | {
|
---|
2833 | Q_D(QTableView);
|
---|
2834 | d->selectRow(row, true);
|
---|
2835 | }
|
---|
2836 |
|
---|
2837 | /*!
|
---|
2838 | Selects the given \a column in the table view if the current
|
---|
2839 | SelectionMode and SelectionBehavior allows columns to be selected.
|
---|
2840 |
|
---|
2841 | \sa selectRow()
|
---|
2842 | */
|
---|
2843 | void QTableView::selectColumn(int column)
|
---|
2844 | {
|
---|
2845 | Q_D(QTableView);
|
---|
2846 | d->selectColumn(column, true);
|
---|
2847 | }
|
---|
2848 |
|
---|
2849 | /*!
|
---|
2850 | Hide the given \a row.
|
---|
2851 |
|
---|
2852 | \sa showRow() hideColumn()
|
---|
2853 | */
|
---|
2854 | void QTableView::hideRow(int row)
|
---|
2855 | {
|
---|
2856 | Q_D(QTableView);
|
---|
2857 | d->verticalHeader->hideSection(row);
|
---|
2858 | }
|
---|
2859 |
|
---|
2860 | /*!
|
---|
2861 | Hide the given \a column.
|
---|
2862 |
|
---|
2863 | \sa showColumn() hideRow()
|
---|
2864 | */
|
---|
2865 | void QTableView::hideColumn(int column)
|
---|
2866 | {
|
---|
2867 | Q_D(QTableView);
|
---|
2868 | d->horizontalHeader->hideSection(column);
|
---|
2869 | }
|
---|
2870 |
|
---|
2871 | /*!
|
---|
2872 | Show the given \a row.
|
---|
2873 |
|
---|
2874 | \sa hideRow() showColumn()
|
---|
2875 | */
|
---|
2876 | void QTableView::showRow(int row)
|
---|
2877 | {
|
---|
2878 | Q_D(QTableView);
|
---|
2879 | d->verticalHeader->showSection(row);
|
---|
2880 | }
|
---|
2881 |
|
---|
2882 | /*!
|
---|
2883 | Show the given \a column.
|
---|
2884 |
|
---|
2885 | \sa hideColumn() showRow()
|
---|
2886 | */
|
---|
2887 | void QTableView::showColumn(int column)
|
---|
2888 | {
|
---|
2889 | Q_D(QTableView);
|
---|
2890 | d->horizontalHeader->showSection(column);
|
---|
2891 | }
|
---|
2892 |
|
---|
2893 | /*!
|
---|
2894 | Resizes the given \a row based on the size hints of the delegate
|
---|
2895 | used to render each item in the row.
|
---|
2896 | */
|
---|
2897 | void QTableView::resizeRowToContents(int row)
|
---|
2898 | {
|
---|
2899 | Q_D(QTableView);
|
---|
2900 | int content = sizeHintForRow(row);
|
---|
2901 | int header = d->verticalHeader->sectionSizeHint(row);
|
---|
2902 | d->verticalHeader->resizeSection(row, qMax(content, header));
|
---|
2903 | }
|
---|
2904 |
|
---|
2905 | /*!
|
---|
2906 | Resizes all rows based on the size hints of the delegate
|
---|
2907 | used to render each item in the rows.
|
---|
2908 | */
|
---|
2909 | void QTableView::resizeRowsToContents()
|
---|
2910 | {
|
---|
2911 | Q_D(QTableView);
|
---|
2912 | d->verticalHeader->resizeSections(QHeaderView::ResizeToContents);
|
---|
2913 | }
|
---|
2914 |
|
---|
2915 | /*!
|
---|
2916 | Resizes the given \a column based on the size hints of the delegate
|
---|
2917 | used to render each item in the column.
|
---|
2918 |
|
---|
2919 | \note Only visible columns will be resized. Reimplement sizeHintForColumn()
|
---|
2920 | to resize hidden columns as well.
|
---|
2921 | */
|
---|
2922 | void QTableView::resizeColumnToContents(int column)
|
---|
2923 | {
|
---|
2924 | Q_D(QTableView);
|
---|
2925 | int content = sizeHintForColumn(column);
|
---|
2926 | int header = d->horizontalHeader->sectionSizeHint(column);
|
---|
2927 | d->horizontalHeader->resizeSection(column, qMax(content, header));
|
---|
2928 | }
|
---|
2929 |
|
---|
2930 | /*!
|
---|
2931 | Resizes all columns based on the size hints of the delegate
|
---|
2932 | used to render each item in the columns.
|
---|
2933 | */
|
---|
2934 | void QTableView::resizeColumnsToContents()
|
---|
2935 | {
|
---|
2936 | Q_D(QTableView);
|
---|
2937 | d->horizontalHeader->resizeSections(QHeaderView::ResizeToContents);
|
---|
2938 | }
|
---|
2939 |
|
---|
2940 | /*!
|
---|
2941 | \obsolete
|
---|
2942 | \overload
|
---|
2943 |
|
---|
2944 | Sorts the model by the values in the given \a column.
|
---|
2945 | */
|
---|
2946 | void QTableView::sortByColumn(int column)
|
---|
2947 | {
|
---|
2948 | Q_D(QTableView);
|
---|
2949 | if (column == -1)
|
---|
2950 | return;
|
---|
2951 | d->model->sort(column, d->horizontalHeader->sortIndicatorOrder());
|
---|
2952 | }
|
---|
2953 |
|
---|
2954 | /*!
|
---|
2955 | \since 4.2
|
---|
2956 |
|
---|
2957 | Sorts the model by the values in the given \a column in the given \a order.
|
---|
2958 |
|
---|
2959 | \sa sortingEnabled
|
---|
2960 | */
|
---|
2961 | void QTableView::sortByColumn(int column, Qt::SortOrder order)
|
---|
2962 | {
|
---|
2963 | Q_D(QTableView);
|
---|
2964 | d->horizontalHeader->setSortIndicator(column, order);
|
---|
2965 | sortByColumn(column);
|
---|
2966 | }
|
---|
2967 |
|
---|
2968 | /*!
|
---|
2969 | \internal
|
---|
2970 | */
|
---|
2971 | void QTableView::verticalScrollbarAction(int action)
|
---|
2972 | {
|
---|
2973 | QAbstractItemView::verticalScrollbarAction(action);
|
---|
2974 | }
|
---|
2975 |
|
---|
2976 | /*!
|
---|
2977 | \internal
|
---|
2978 | */
|
---|
2979 | void QTableView::horizontalScrollbarAction(int action)
|
---|
2980 | {
|
---|
2981 | QAbstractItemView::horizontalScrollbarAction(action);
|
---|
2982 | }
|
---|
2983 |
|
---|
2984 | /*!
|
---|
2985 | \reimp
|
---|
2986 | */
|
---|
2987 | bool QTableView::isIndexHidden(const QModelIndex &index) const
|
---|
2988 | {
|
---|
2989 | Q_D(const QTableView);
|
---|
2990 | Q_ASSERT(d->isIndexValid(index));
|
---|
2991 | if (isRowHidden(index.row()) || isColumnHidden(index.column()))
|
---|
2992 | return true;
|
---|
2993 | if (d->hasSpans()) {
|
---|
2994 | QSpanCollection::Span span = d->span(index.row(), index.column());
|
---|
2995 | return !((span.top() == index.row()) && (span.left() == index.column()));
|
---|
2996 | }
|
---|
2997 | return false;
|
---|
2998 | }
|
---|
2999 |
|
---|
3000 | /*!
|
---|
3001 | \fn void QTableView::setSpan(int row, int column, int rowSpanCount, int columnSpanCount)
|
---|
3002 | \since 4.2
|
---|
3003 |
|
---|
3004 | Sets the span of the table element at (\a row, \a column) to the number of
|
---|
3005 | rows and columns specified by (\a rowSpanCount, \a columnSpanCount).
|
---|
3006 |
|
---|
3007 | \sa rowSpan(), columnSpan()
|
---|
3008 | */
|
---|
3009 | void QTableView::setSpan(int row, int column, int rowSpan, int columnSpan)
|
---|
3010 | {
|
---|
3011 | Q_D(QTableView);
|
---|
3012 | if (row < 0 || column < 0 || rowSpan < 0 || columnSpan < 0)
|
---|
3013 | return;
|
---|
3014 | d->setSpan(row, column, rowSpan, columnSpan);
|
---|
3015 | d->viewport->update();
|
---|
3016 | }
|
---|
3017 |
|
---|
3018 | /*!
|
---|
3019 | \since 4.2
|
---|
3020 |
|
---|
3021 | Returns the row span of the table element at (\a row, \a column).
|
---|
3022 | The default is 1.
|
---|
3023 |
|
---|
3024 | \sa setSpan(), columnSpan()
|
---|
3025 | */
|
---|
3026 | int QTableView::rowSpan(int row, int column) const
|
---|
3027 | {
|
---|
3028 | Q_D(const QTableView);
|
---|
3029 | return d->rowSpan(row, column);
|
---|
3030 | }
|
---|
3031 |
|
---|
3032 | /*!
|
---|
3033 | \since 4.2
|
---|
3034 |
|
---|
3035 | Returns the column span of the table element at (\a row, \a
|
---|
3036 | column). The default is 1.
|
---|
3037 |
|
---|
3038 | \sa setSpan(), rowSpan()
|
---|
3039 | */
|
---|
3040 | int QTableView::columnSpan(int row, int column) const
|
---|
3041 | {
|
---|
3042 | Q_D(const QTableView);
|
---|
3043 | return d->columnSpan(row, column);
|
---|
3044 | }
|
---|
3045 |
|
---|
3046 | /*!
|
---|
3047 | \since 4.4
|
---|
3048 |
|
---|
3049 | Removes all row and column spans in the table view.
|
---|
3050 |
|
---|
3051 | \sa setSpan()
|
---|
3052 | */
|
---|
3053 |
|
---|
3054 | void QTableView::clearSpans()
|
---|
3055 | {
|
---|
3056 | Q_D(QTableView);
|
---|
3057 | d->spans.clear();
|
---|
3058 | d->viewport->update();
|
---|
3059 | }
|
---|
3060 |
|
---|
3061 | void QTableViewPrivate::_q_selectRow(int row)
|
---|
3062 | {
|
---|
3063 | selectRow(row, false);
|
---|
3064 | }
|
---|
3065 |
|
---|
3066 | void QTableViewPrivate::_q_selectColumn(int column)
|
---|
3067 | {
|
---|
3068 | selectColumn(column, false);
|
---|
3069 | }
|
---|
3070 |
|
---|
3071 | void QTableViewPrivate::selectRow(int row, bool anchor)
|
---|
3072 | {
|
---|
3073 | Q_Q(QTableView);
|
---|
3074 |
|
---|
3075 | if (q->selectionBehavior() == QTableView::SelectColumns
|
---|
3076 | || (q->selectionMode() == QTableView::SingleSelection
|
---|
3077 | && q->selectionBehavior() == QTableView::SelectItems))
|
---|
3078 | return;
|
---|
3079 |
|
---|
3080 | if (row >= 0 && row < model->rowCount(root)) {
|
---|
3081 | int column = horizontalHeader->logicalIndexAt(q->isRightToLeft() ? viewport->width() : 0);
|
---|
3082 | QModelIndex index = model->index(row, column, root);
|
---|
3083 | QItemSelectionModel::SelectionFlags command = q->selectionCommand(index);
|
---|
3084 | selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
|
---|
3085 | if ((anchor && !(command & QItemSelectionModel::Current))
|
---|
3086 | || (q->selectionMode() == QTableView::SingleSelection))
|
---|
3087 | rowSectionAnchor = row;
|
---|
3088 |
|
---|
3089 | if (q->selectionMode() != QTableView::SingleSelection
|
---|
3090 | && command.testFlag(QItemSelectionModel::Toggle)) {
|
---|
3091 | if (anchor)
|
---|
3092 | ctrlDragSelectionFlag = verticalHeader->selectionModel()->selectedRows().contains(index)
|
---|
3093 | ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
|
---|
3094 | command &= ~QItemSelectionModel::Toggle;
|
---|
3095 | command |= ctrlDragSelectionFlag;
|
---|
3096 | if (!anchor)
|
---|
3097 | command |= QItemSelectionModel::Current;
|
---|
3098 | }
|
---|
3099 |
|
---|
3100 | QModelIndex tl = model->index(qMin(rowSectionAnchor, row), 0, root);
|
---|
3101 | QModelIndex br = model->index(qMax(rowSectionAnchor, row), model->columnCount(root) - 1, root);
|
---|
3102 | if (verticalHeader->sectionsMoved() && tl.row() != br.row())
|
---|
3103 | q->setSelection(q->visualRect(tl)|q->visualRect(br), command);
|
---|
3104 | else
|
---|
3105 | selectionModel->select(QItemSelection(tl, br), command);
|
---|
3106 | }
|
---|
3107 | }
|
---|
3108 |
|
---|
3109 | void QTableViewPrivate::selectColumn(int column, bool anchor)
|
---|
3110 | {
|
---|
3111 | Q_Q(QTableView);
|
---|
3112 |
|
---|
3113 | if (q->selectionBehavior() == QTableView::SelectRows
|
---|
3114 | || (q->selectionMode() == QTableView::SingleSelection
|
---|
3115 | && q->selectionBehavior() == QTableView::SelectItems))
|
---|
3116 | return;
|
---|
3117 |
|
---|
3118 | if (column >= 0 && column < model->columnCount(root)) {
|
---|
3119 | int row = verticalHeader->logicalIndexAt(0);
|
---|
3120 | QModelIndex index = model->index(row, column, root);
|
---|
3121 | QItemSelectionModel::SelectionFlags command = q->selectionCommand(index);
|
---|
3122 | selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
|
---|
3123 | if ((anchor && !(command & QItemSelectionModel::Current))
|
---|
3124 | || (q->selectionMode() == QTableView::SingleSelection))
|
---|
3125 | columnSectionAnchor = column;
|
---|
3126 |
|
---|
3127 | if (q->selectionMode() != QTableView::SingleSelection
|
---|
3128 | && command.testFlag(QItemSelectionModel::Toggle)) {
|
---|
3129 | if (anchor)
|
---|
3130 | ctrlDragSelectionFlag = horizontalHeader->selectionModel()->selectedColumns().contains(index)
|
---|
3131 | ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
|
---|
3132 | command &= ~QItemSelectionModel::Toggle;
|
---|
3133 | command |= ctrlDragSelectionFlag;
|
---|
3134 | if (!anchor)
|
---|
3135 | command |= QItemSelectionModel::Current;
|
---|
3136 | }
|
---|
3137 |
|
---|
3138 | QModelIndex tl = model->index(0, qMin(columnSectionAnchor, column), root);
|
---|
3139 | QModelIndex br = model->index(model->rowCount(root) - 1,
|
---|
3140 | qMax(columnSectionAnchor, column), root);
|
---|
3141 | if (horizontalHeader->sectionsMoved() && tl.column() != br.column())
|
---|
3142 | q->setSelection(q->visualRect(tl)|q->visualRect(br), command);
|
---|
3143 | else
|
---|
3144 | selectionModel->select(QItemSelection(tl, br), command);
|
---|
3145 | }
|
---|
3146 | }
|
---|
3147 |
|
---|
3148 | /*!
|
---|
3149 | \reimp
|
---|
3150 | */
|
---|
3151 | void QTableView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
---|
3152 | {
|
---|
3153 | #ifndef QT_NO_ACCESSIBILITY
|
---|
3154 | if (QAccessible::isActive()) {
|
---|
3155 | if (current.isValid()) {
|
---|
3156 | int entry = visualIndex(current) + 1;
|
---|
3157 | if (horizontalHeader())
|
---|
3158 | ++entry;
|
---|
3159 | QAccessible::updateAccessibility(viewport(), entry, QAccessible::Focus);
|
---|
3160 | }
|
---|
3161 | }
|
---|
3162 | #endif
|
---|
3163 | QAbstractItemView::currentChanged(current, previous);
|
---|
3164 | }
|
---|
3165 |
|
---|
3166 | /*!
|
---|
3167 | \reimp
|
---|
3168 | */
|
---|
3169 | void QTableView::selectionChanged(const QItemSelection &selected,
|
---|
3170 | const QItemSelection &deselected)
|
---|
3171 | {
|
---|
3172 | #ifndef QT_NO_ACCESSIBILITY
|
---|
3173 | if (QAccessible::isActive()) {
|
---|
3174 | // ### does not work properly for selection ranges.
|
---|
3175 | QModelIndex sel = selected.indexes().value(0);
|
---|
3176 | if (sel.isValid()) {
|
---|
3177 | int entry = visualIndex(sel);
|
---|
3178 | if (horizontalHeader())
|
---|
3179 | ++entry;
|
---|
3180 | QAccessible::updateAccessibility(viewport(), entry, QAccessible::Selection);
|
---|
3181 | }
|
---|
3182 | QModelIndex desel = deselected.indexes().value(0);
|
---|
3183 | if (desel.isValid()) {
|
---|
3184 | int entry = visualIndex(sel);
|
---|
3185 | if (horizontalHeader())
|
---|
3186 | ++entry;
|
---|
3187 | QAccessible::updateAccessibility(viewport(), entry, QAccessible::SelectionRemove);
|
---|
3188 | }
|
---|
3189 | }
|
---|
3190 | #endif
|
---|
3191 | QAbstractItemView::selectionChanged(selected, deselected);
|
---|
3192 | }
|
---|
3193 |
|
---|
3194 | int QTableView::visualIndex(const QModelIndex &index) const
|
---|
3195 | {
|
---|
3196 | return index.row();
|
---|
3197 | }
|
---|
3198 |
|
---|
3199 | QT_END_NAMESPACE
|
---|
3200 |
|
---|
3201 | #include "qtableview.moc"
|
---|
3202 |
|
---|
3203 | #include "moc_qtableview.cpp"
|
---|
3204 |
|
---|
3205 | #endif // QT_NO_TABLEVIEW
|
---|