Fixes warnings about unused variables
[profile/ivi/qtbase.git] / src / gui / itemviews / qtableview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
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     q->itemDelegate(index)->paint(painter, opt, index);
930 }
931
932 /*!
933     \class QTableView
934
935     \brief The QTableView class provides a default model/view
936     implementation of a table view.
937
938     \ingroup model-view
939     \ingroup advanced
940
941
942     A QTableView implements a table view that displays items from a
943     model. This class is used to provide standard tables that were
944     previously provided by the QTable class, but using the more
945     flexible approach provided by Qt's model/view architecture.
946
947     The QTableView class is one of the \l{Model/View Classes}
948     and is part of Qt's \l{Model/View Programming}{model/view framework}.
949
950     QTableView implements the interfaces defined by the
951     QAbstractItemView class to allow it to display data provided by
952     models derived from the QAbstractItemModel class.
953
954     \section1 Navigation
955
956     You can navigate the cells in the table by clicking on a cell with the
957     mouse, or by using the arrow keys. Because QTableView enables
958     \l{QAbstractItemView::tabKeyNavigation}{tabKeyNavigation} by default, you
959     can also hit Tab and Backtab to move from cell to cell.
960
961     \section1 Visual Appearance
962
963     The table has a vertical header that can be obtained using the
964     verticalHeader() function, and a horizontal header that is available
965     through the horizontalHeader() function. The height of each row in the
966     table can be found by using rowHeight(); similarly, the width of
967     columns can be found using columnWidth().  Since both of these are plain
968     widgets, you can hide either of them using their hide() functions.
969
970     Rows and columns can be hidden and shown with hideRow(), hideColumn(),
971     showRow(), and showColumn(). They can be selected with selectRow()
972     and selectColumn(). The table will show a grid depending on the
973     \l showGrid property.
974
975     The items shown in a table view, like those in the other item views, are
976     rendered and edited using standard \l{QItemDelegate}{delegates}. However,
977     for some tasks it is sometimes useful to be able to insert widgets in a
978     table instead. Widgets are set for particular indexes with the
979     \l{QAbstractItemView::}{setIndexWidget()} function, and
980     later retrieved with \l{QAbstractItemView::}{indexWidget()}.
981
982     \table
983     \row \o \inlineimage qtableview-resized.png
984     \o By default, the cells in a table do not expand to fill the available space.
985
986     You can make the cells fill the available space by stretching the last
987     header section. Access the relevant header using horizontalHeader()
988     or verticalHeader() and set the header's \l{QHeaderView::}{stretchLastSection}
989     property.
990
991     To distribute the available space according to the space requirement of
992     each column or row, call the view's resizeColumnsToContents() or
993     resizeRowsToContents() functions.
994     \endtable
995
996     \section1 Coordinate Systems
997
998     For some specialized forms of tables it is useful to be able to
999     convert between row and column indexes and widget coordinates.
1000     The rowAt() function provides the y-coordinate within the view of the
1001     specified row; the row index can be used to obtain a corresponding
1002     y-coordinate with rowViewportPosition(). The columnAt() and
1003     columnViewportPosition() functions provide the equivalent conversion
1004     operations between x-coordinates and column indexes.
1005
1006     \section1 Styles
1007
1008     QTableView is styled appropriately for each platform. The following images show
1009     how it looks on three different platforms. Go to the \l{Qt Widget Gallery} to see
1010     its appearance in other styles.
1011
1012     \table 100%
1013     \row \o \inlineimage windowsxp-tableview.png Screenshot of a Windows XP style table view
1014          \o \inlineimage macintosh-tableview.png Screenshot of a Macintosh style table view
1015          \o \inlineimage plastique-tableview.png Screenshot of a Plastique style table view
1016     \row \o A \l{Windows XP Style Widget Gallery}{Windows XP style} table view.
1017          \o A \l{Macintosh Style Widget Gallery}{Macintosh style} table view.
1018          \o A \l{Plastique Style Widget Gallery}{Plastique style} table view.
1019     \endtable
1020
1021     \sa QTableWidget, {View Classes}, QAbstractItemModel, QAbstractItemView,
1022         {Chart Example}, {Pixelator Example}, {Table Model Example}
1023 */
1024
1025 /*!
1026     Constructs a table view with a \a parent to represent the data.
1027
1028     \sa QAbstractItemModel
1029 */
1030
1031 QTableView::QTableView(QWidget *parent)
1032     : QAbstractItemView(*new QTableViewPrivate, parent)
1033 {
1034     Q_D(QTableView);
1035     d->init();
1036 }
1037
1038 /*!
1039   \internal
1040 */
1041 QTableView::QTableView(QTableViewPrivate &dd, QWidget *parent)
1042     : QAbstractItemView(dd, parent)
1043 {
1044     Q_D(QTableView);
1045     d->init();
1046 }
1047
1048 /*!
1049   Destroys the table view.
1050 */
1051 QTableView::~QTableView()
1052 {
1053 }
1054
1055 /*!
1056   \reimp
1057 */
1058 void QTableView::setModel(QAbstractItemModel *model)
1059 {
1060     Q_D(QTableView);
1061     if (model == d->model)
1062         return;
1063     //let's disconnect from the old model
1064     if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
1065         disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1066                 this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
1067         disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1068                 this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
1069         disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1070                 this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
1071         disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1072                 this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
1073     }
1074     if (model) { //and connect to the new one
1075         connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1076                 this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
1077         connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
1078                 this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
1079         connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1080                 this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
1081         connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
1082                 this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
1083     }
1084     d->verticalHeader->setModel(model);
1085     d->horizontalHeader->setModel(model);
1086     QAbstractItemView::setModel(model);
1087 }
1088
1089 /*!
1090   \reimp
1091 */
1092 void QTableView::setRootIndex(const QModelIndex &index)
1093 {
1094     Q_D(QTableView);
1095     if (index == d->root) {
1096         viewport()->update();
1097         return;
1098     }
1099     d->verticalHeader->setRootIndex(index);
1100     d->horizontalHeader->setRootIndex(index);
1101     QAbstractItemView::setRootIndex(index);
1102 }
1103
1104 /*!
1105   \reimp
1106 */
1107 void QTableView::doItemsLayout()
1108 {
1109     Q_D(QTableView);
1110     QAbstractItemView::doItemsLayout();
1111     if (verticalScrollMode() == QAbstractItemView::ScrollPerItem)
1112         d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value());
1113     else
1114         d->verticalHeader->setOffset(verticalScrollBar()->value());
1115     if (!d->verticalHeader->updatesEnabled())
1116         d->verticalHeader->setUpdatesEnabled(true);
1117 }
1118
1119 /*!
1120   \reimp
1121 */
1122 void QTableView::setSelectionModel(QItemSelectionModel *selectionModel)
1123 {
1124     Q_D(QTableView);
1125     Q_ASSERT(selectionModel);
1126     d->verticalHeader->setSelectionModel(selectionModel);
1127     d->horizontalHeader->setSelectionModel(selectionModel);
1128     QAbstractItemView::setSelectionModel(selectionModel);
1129 }
1130
1131 /*!
1132     Returns the table view's horizontal header.
1133
1134     \sa setHorizontalHeader(), verticalHeader(), QAbstractItemModel::headerData()
1135 */
1136 QHeaderView *QTableView::horizontalHeader() const
1137 {
1138     Q_D(const QTableView);
1139     return d->horizontalHeader;
1140 }
1141
1142 /*!
1143     Returns the table view's vertical header.
1144
1145     \sa setVerticalHeader(), horizontalHeader(), QAbstractItemModel::headerData()
1146 */
1147 QHeaderView *QTableView::verticalHeader() const
1148 {
1149     Q_D(const QTableView);
1150     return d->verticalHeader;
1151 }
1152
1153 /*!
1154     Sets the widget to use for the horizontal header to \a header.
1155
1156     \sa horizontalHeader() setVerticalHeader()
1157 */
1158 void QTableView::setHorizontalHeader(QHeaderView *header)
1159 {
1160     Q_D(QTableView);
1161
1162     if (!header || header == d->horizontalHeader)
1163         return;
1164     if (d->horizontalHeader && d->horizontalHeader->parent() == this)
1165         delete d->horizontalHeader;
1166     d->horizontalHeader = header;
1167     d->horizontalHeader->setParent(this);
1168     if (!d->horizontalHeader->model()) {
1169         d->horizontalHeader->setModel(d->model);
1170         if (d->selectionModel)
1171             d->horizontalHeader->setSelectionModel(d->selectionModel);
1172     }
1173
1174     connect(d->horizontalHeader,SIGNAL(sectionResized(int,int,int)),
1175             this, SLOT(columnResized(int,int,int)));
1176     connect(d->horizontalHeader, SIGNAL(sectionMoved(int,int,int)),
1177             this, SLOT(columnMoved(int,int,int)));
1178     connect(d->horizontalHeader, SIGNAL(sectionCountChanged(int,int)),
1179             this, SLOT(columnCountChanged(int,int)));
1180     connect(d->horizontalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectColumn(int)));
1181     connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectColumn(int)));
1182     connect(d->horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
1183             this, SLOT(resizeColumnToContents(int)));
1184     connect(d->horizontalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
1185
1186     //update the sorting enabled states on the new header
1187     setSortingEnabled(d->sortingEnabled);
1188 }
1189
1190 /*!
1191     Sets the widget to use for the vertical header to \a header.
1192
1193     \sa verticalHeader() setHorizontalHeader()
1194 */
1195 void QTableView::setVerticalHeader(QHeaderView *header)
1196 {
1197     Q_D(QTableView);
1198
1199     if (!header || header == d->verticalHeader)
1200         return;
1201     if (d->verticalHeader && d->verticalHeader->parent() == this)
1202         delete d->verticalHeader;
1203     d->verticalHeader = header;
1204     d->verticalHeader->setParent(this);
1205     if (!d->verticalHeader->model()) {
1206         d->verticalHeader->setModel(d->model);
1207         if (d->selectionModel)
1208             d->verticalHeader->setSelectionModel(d->selectionModel);
1209     }
1210
1211     connect(d->verticalHeader, SIGNAL(sectionResized(int,int,int)),
1212             this, SLOT(rowResized(int,int,int)));
1213     connect(d->verticalHeader, SIGNAL(sectionMoved(int,int,int)),
1214             this, SLOT(rowMoved(int,int,int)));
1215     connect(d->verticalHeader, SIGNAL(sectionCountChanged(int,int)),
1216             this, SLOT(rowCountChanged(int,int)));
1217     connect(d->verticalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectRow(int)));
1218     connect(d->verticalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectRow(int)));
1219     connect(d->verticalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
1220             this, SLOT(resizeRowToContents(int)));
1221     connect(d->verticalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
1222 }
1223
1224 /*!
1225     \internal
1226
1227     Scroll the contents of the table view by (\a dx, \a dy).
1228 */
1229 void QTableView::scrollContentsBy(int dx, int dy)
1230 {
1231     Q_D(QTableView);
1232
1233     d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
1234
1235     dx = isRightToLeft() ? -dx : dx;
1236     if (dx) {
1237         if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
1238             int oldOffset = d->horizontalHeader->offset();
1239             if (horizontalScrollBar()->value() == horizontalScrollBar()->maximum())
1240                 d->horizontalHeader->setOffsetToLastSection();
1241             else
1242                 d->horizontalHeader->setOffsetToSectionPosition(horizontalScrollBar()->value());
1243             int newOffset = d->horizontalHeader->offset();
1244             dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset;
1245         } else {
1246             d->horizontalHeader->setOffset(horizontalScrollBar()->value());
1247         }
1248     }
1249     if (dy) {
1250         if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
1251             int oldOffset = d->verticalHeader->offset();
1252             if (verticalScrollBar()->value() == verticalScrollBar()->maximum())
1253                 d->verticalHeader->setOffsetToLastSection();
1254             else
1255                 d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value());
1256             int newOffset = d->verticalHeader->offset();
1257             dy = oldOffset - newOffset;
1258         } else {
1259             d->verticalHeader->setOffset(verticalScrollBar()->value());
1260         }
1261     }
1262     d->scrollContentsBy(dx, dy);
1263
1264     if (d->showGrid) {
1265         //we need to update the first line of the previous top item in the view
1266         //because it has the grid drawn if the header is invisible.
1267         //It is strictly related to what's done at then end of the paintEvent
1268         if (dy > 0 && d->horizontalHeader->isHidden() && d->verticalScrollMode == ScrollPerItem) {
1269             d->viewport->update(0, dy, d->viewport->width(), dy);
1270         }
1271         if (dx > 0 && d->verticalHeader->isHidden() && d->horizontalScrollMode == ScrollPerItem) {
1272             d->viewport->update(dx, 0, dx, d->viewport->height());
1273         }
1274     }
1275 }
1276
1277 /*!
1278   \reimp
1279 */
1280 QStyleOptionViewItem QTableView::viewOptions() const
1281 {
1282     QStyleOptionViewItem option = QAbstractItemView::viewOptions();
1283     option.showDecorationSelected = true;
1284     return option;
1285 }
1286
1287 /*!
1288     Paints the table on receipt of the given paint event \a event.
1289 */
1290 void QTableView::paintEvent(QPaintEvent *event)
1291 {
1292     Q_D(QTableView);
1293     // setup temp variables for the painting
1294     QStyleOptionViewItemV4 option = d->viewOptionsV4();
1295     const QPoint offset = d->scrollDelayOffset;
1296     const bool showGrid = d->showGrid;
1297     const int gridSize = showGrid ? 1 : 0;
1298     const int gridHint = style()->styleHint(QStyle::SH_Table_GridLineColor, &option, this);
1299     const QColor gridColor = static_cast<QRgb>(gridHint);
1300     const QPen gridPen = QPen(gridColor, 0, d->gridStyle);
1301     const QHeaderView *verticalHeader = d->verticalHeader;
1302     const QHeaderView *horizontalHeader = d->horizontalHeader;
1303     const bool alternate = d->alternatingColors;
1304     const bool rightToLeft = isRightToLeft();
1305
1306     QPainter painter(d->viewport);
1307
1308     // if there's nothing to do, clear the area and return
1309     if (horizontalHeader->count() == 0 || verticalHeader->count() == 0 || !d->itemDelegate)
1310         return;
1311
1312     uint x = horizontalHeader->length() - horizontalHeader->offset() - (rightToLeft ? 0 : 1);
1313     uint y = verticalHeader->length() - verticalHeader->offset() - 1;
1314
1315     const QRegion region = event->region().translated(offset);
1316     const QVector<QRect> rects = region.rects();
1317
1318     //firstVisualRow is the visual index of the first visible row.  lastVisualRow is the visual index of the last visible Row.
1319     //same goes for ...VisualColumn
1320     int firstVisualRow = qMax(verticalHeader->visualIndexAt(0),0);
1321     int lastVisualRow = verticalHeader->visualIndexAt(verticalHeader->viewport()->height());
1322     if (lastVisualRow == -1)
1323         lastVisualRow = d->model->rowCount(d->root) - 1;
1324
1325     int firstVisualColumn = horizontalHeader->visualIndexAt(0);
1326     int lastVisualColumn = horizontalHeader->visualIndexAt(horizontalHeader->viewport()->width());
1327     if (rightToLeft)
1328         qSwap(firstVisualColumn, lastVisualColumn);
1329     if (firstVisualColumn == -1)
1330         firstVisualColumn = 0;
1331     if (lastVisualColumn == -1)
1332         lastVisualColumn = horizontalHeader->count() - 1;
1333
1334     QBitArray drawn((lastVisualRow - firstVisualRow + 1) * (lastVisualColumn - firstVisualColumn + 1));
1335
1336     if (d->hasSpans()) {
1337         d->drawAndClipSpans(region, &painter, option, &drawn,
1338                              firstVisualRow, lastVisualRow, firstVisualColumn, lastVisualColumn);
1339     }
1340
1341     for (int i = 0; i < rects.size(); ++i) {
1342         QRect dirtyArea = rects.at(i);
1343         dirtyArea.setBottom(qMin(dirtyArea.bottom(), int(y)));
1344         if (rightToLeft) {
1345             dirtyArea.setLeft(qMax(dirtyArea.left(), d->viewport->width() - int(x)));
1346         } else {
1347             dirtyArea.setRight(qMin(dirtyArea.right(), int(x)));
1348         }
1349
1350         // get the horizontal start and end visual sections
1351         int left = horizontalHeader->visualIndexAt(dirtyArea.left());
1352         int right = horizontalHeader->visualIndexAt(dirtyArea.right());
1353         if (rightToLeft)
1354             qSwap(left, right);
1355         if (left == -1) left = 0;
1356         if (right == -1) right = horizontalHeader->count() - 1;
1357
1358         // get the vertical start and end visual sections and if alternate color
1359         int bottom = verticalHeader->visualIndexAt(dirtyArea.bottom());
1360         if (bottom == -1) bottom = verticalHeader->count() - 1;
1361         int top = 0;
1362         bool alternateBase = false;
1363         if (alternate && verticalHeader->sectionsHidden()) {
1364             uint verticalOffset = verticalHeader->offset();
1365             int row = verticalHeader->logicalIndex(top);
1366             for (int y = 0;
1367                  ((uint)(y += verticalHeader->sectionSize(top)) <= verticalOffset) && (top < bottom);
1368                  ++top) {
1369                 row = verticalHeader->logicalIndex(top);
1370                 if (alternate && !verticalHeader->isSectionHidden(row))
1371                     alternateBase = !alternateBase;
1372             }
1373         } else {
1374             top = verticalHeader->visualIndexAt(dirtyArea.top());
1375             alternateBase = (top & 1) && alternate;
1376         }
1377         if (top == -1 || top > bottom)
1378             continue;
1379
1380         // Paint each row item
1381         for (int visualRowIndex = top; visualRowIndex <= bottom; ++visualRowIndex) {
1382             int row = verticalHeader->logicalIndex(visualRowIndex);
1383             if (verticalHeader->isSectionHidden(row))
1384                 continue;
1385             int rowY = rowViewportPosition(row);
1386             rowY += offset.y();
1387             int rowh = rowHeight(row) - gridSize;
1388
1389             // Paint each column item
1390             for (int visualColumnIndex = left; visualColumnIndex <= right; ++visualColumnIndex) {
1391                 int currentBit = (visualRowIndex - firstVisualRow) * (lastVisualColumn - firstVisualColumn + 1)
1392                         + visualColumnIndex - firstVisualColumn;
1393
1394                 if (currentBit < 0 || currentBit >= drawn.size() || drawn.testBit(currentBit))
1395                     continue;
1396                 drawn.setBit(currentBit);
1397
1398                 int col = horizontalHeader->logicalIndex(visualColumnIndex);
1399                 if (horizontalHeader->isSectionHidden(col))
1400                     continue;
1401                 int colp = columnViewportPosition(col);
1402                 colp += offset.x();
1403                 int colw = columnWidth(col) - gridSize;
1404
1405                 const QModelIndex index = d->model->index(row, col, d->root);
1406                 if (index.isValid()) {
1407                     option.rect = QRect(colp + (showGrid && rightToLeft ? 1 : 0), rowY, colw, rowh);
1408                     if (alternate) {
1409                         if (alternateBase)
1410                             option.features |= QStyleOptionViewItemV2::Alternate;
1411                         else
1412                             option.features &= ~QStyleOptionViewItemV2::Alternate;
1413                     }
1414                     d->drawCell(&painter, option, index);
1415                 }
1416             }
1417             alternateBase = !alternateBase && alternate;
1418         }
1419
1420         if (showGrid) {
1421             // Find the bottom right (the last rows/columns might be hidden)
1422             while (verticalHeader->isSectionHidden(verticalHeader->logicalIndex(bottom))) --bottom;
1423             QPen old = painter.pen();
1424             painter.setPen(gridPen);
1425             // Paint each row
1426             for (int visualIndex = top; visualIndex <= bottom; ++visualIndex) {
1427                 int row = verticalHeader->logicalIndex(visualIndex);
1428                 if (verticalHeader->isSectionHidden(row))
1429                     continue;
1430                 int rowY = rowViewportPosition(row);
1431                 rowY += offset.y();
1432                 int rowh = rowHeight(row) - gridSize;
1433                 painter.drawLine(dirtyArea.left(), rowY + rowh, dirtyArea.right(), rowY + rowh);
1434             }
1435
1436             // Paint each column
1437             for (int h = left; h <= right; ++h) {
1438                 int col = horizontalHeader->logicalIndex(h);
1439                 if (horizontalHeader->isSectionHidden(col))
1440                     continue;
1441                 int colp = columnViewportPosition(col);
1442                 colp += offset.x();
1443                 if (!rightToLeft)
1444                     colp +=  columnWidth(col) - gridSize;
1445                 painter.drawLine(colp, dirtyArea.top(), colp, dirtyArea.bottom());
1446             }
1447
1448             //draw the top & left grid lines if the headers are not visible.
1449             //We do update this line when subsequent scroll happen (see scrollContentsBy)
1450             if (horizontalHeader->isHidden() && verticalScrollMode() == ScrollPerItem)
1451                 painter.drawLine(dirtyArea.left(), 0, dirtyArea.right(), 0);
1452             if (verticalHeader->isHidden() && horizontalScrollMode() == ScrollPerItem)
1453                 painter.drawLine(0, dirtyArea.top(), 0, dirtyArea.bottom());
1454             painter.setPen(old);
1455         }
1456     }
1457
1458 #ifndef QT_NO_DRAGANDDROP
1459     // Paint the dropIndicator
1460     d->paintDropIndicator(&painter);
1461 #endif
1462 }
1463
1464 /*!
1465     Returns the index position of the model item corresponding to the
1466     table item at position \a pos in contents coordinates.
1467 */
1468 QModelIndex QTableView::indexAt(const QPoint &pos) const
1469 {
1470     Q_D(const QTableView);
1471     d->executePostedLayout();
1472     int r = rowAt(pos.y());
1473     int c = columnAt(pos.x());
1474     if (r >= 0 && c >= 0) {
1475         if (d->hasSpans()) {
1476             QSpanCollection::Span span = d->span(r, c);
1477             r = span.top();
1478             c = span.left();
1479         }
1480         return d->model->index(r, c, d->root);
1481     }
1482     return QModelIndex();
1483 }
1484
1485 /*!
1486     Returns the horizontal offset of the items in the table view.
1487
1488     Note that the table view uses the horizontal header section
1489     positions to determine the positions of columns in the view.
1490
1491     \sa verticalOffset()
1492 */
1493 int QTableView::horizontalOffset() const
1494 {
1495     Q_D(const QTableView);
1496     return d->horizontalHeader->offset();
1497 }
1498
1499 /*!
1500     Returns the vertical offset of the items in the table view.
1501
1502     Note that the table view uses the vertical header section
1503     positions to determine the positions of rows in the view.
1504
1505     \sa horizontalOffset()
1506 */
1507 int QTableView::verticalOffset() const
1508 {
1509     Q_D(const QTableView);
1510     return d->verticalHeader->offset();
1511 }
1512
1513 /*!
1514     \fn QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1515
1516     Moves the cursor in accordance with the given \a cursorAction, using the
1517     information provided by the \a modifiers.
1518
1519     \sa QAbstractItemView::CursorAction
1520 */
1521 QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
1522 {
1523     Q_D(QTableView);
1524     Q_UNUSED(modifiers);
1525
1526     int bottom = d->model->rowCount(d->root) - 1;
1527     // make sure that bottom is the bottommost *visible* row
1528     while (bottom >= 0 && isRowHidden(d->logicalRow(bottom)))
1529         --bottom;
1530
1531     int right = d->model->columnCount(d->root) - 1;
1532
1533     while (right >= 0 && isColumnHidden(d->logicalColumn(right)))
1534         --right;
1535
1536     if (bottom == -1 || right == -1)
1537         return QModelIndex(); // model is empty
1538
1539     QModelIndex current = currentIndex();
1540
1541     if (!current.isValid()) {
1542         int row = 0;
1543         int column = 0;
1544         while (column < right && isColumnHidden(d->logicalColumn(column)))
1545             ++column;
1546         while (isRowHidden(d->logicalRow(row)) && row < bottom)
1547             ++row;
1548         d->visualCursor = QPoint(column, row);
1549         return d->model->index(d->logicalRow(row), d->logicalColumn(column), d->root);
1550     }
1551
1552     // Update visual cursor if current index has changed.
1553     QPoint visualCurrent(d->visualColumn(current.column()), d->visualRow(current.row()));
1554     if (visualCurrent != d->visualCursor) {
1555         if (d->hasSpans()) {
1556             QSpanCollection::Span span = d->span(current.row(), current.column());
1557             if (span.top() > d->visualCursor.y() || d->visualCursor.y() > span.bottom()
1558                 || span.left() > d->visualCursor.x() || d->visualCursor.x() > span.right())
1559                 d->visualCursor = visualCurrent;
1560         } else {
1561             d->visualCursor = visualCurrent;
1562         }
1563     }
1564
1565     int visualRow = d->visualCursor.y();
1566     if (visualRow > bottom)
1567         visualRow = bottom;
1568     Q_ASSERT(visualRow != -1);
1569     int visualColumn = d->visualCursor.x();
1570     if (visualColumn > right)
1571         visualColumn = right;
1572     Q_ASSERT(visualColumn != -1);
1573
1574     if (isRightToLeft()) {
1575         if (cursorAction == MoveLeft)
1576             cursorAction = MoveRight;
1577         else if (cursorAction == MoveRight)
1578             cursorAction = MoveLeft;
1579     }
1580
1581     switch (cursorAction) {
1582     case MoveUp: {
1583         int originalRow = visualRow;
1584 #ifdef QT_KEYPAD_NAVIGATION
1585         if (QApplication::keypadNavigationEnabled() && visualRow == 0)
1586             visualRow = d->visualRow(model()->rowCount() - 1) + 1;
1587             // FIXME? visualRow = bottom + 1;
1588 #endif
1589         int r = d->logicalRow(visualRow);
1590         int c = d->logicalColumn(visualColumn);
1591         if (r != -1 && d->hasSpans()) {
1592             QSpanCollection::Span span = d->span(r, c);
1593             if (span.width() > 1 || span.height() > 1)
1594                 visualRow = d->visualRow(span.top());
1595         }
1596         while (visualRow >= 0) {
1597             --visualRow;
1598             r = d->logicalRow(visualRow);
1599             c = d->logicalColumn(visualColumn);
1600             if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c)))
1601                 break;
1602         }
1603         if (visualRow < 0)
1604             visualRow = originalRow;
1605         break;
1606     }
1607     case MoveDown: {
1608         int originalRow = visualRow;
1609         if (d->hasSpans()) {
1610             QSpanCollection::Span span = d->span(current.row(), current.column());
1611             visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
1612         }
1613 #ifdef QT_KEYPAD_NAVIGATION
1614         if (QApplication::keypadNavigationEnabled() && visualRow >= bottom)
1615             visualRow = -1;
1616 #endif
1617         int r = d->logicalRow(visualRow);
1618         int c = d->logicalColumn(visualColumn);
1619         if (r != -1 && d->hasSpans()) {
1620             QSpanCollection::Span span = d->span(r, c);
1621             if (span.width() > 1 || span.height() > 1)
1622                 visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
1623         }
1624         while (visualRow <= bottom) {
1625             ++visualRow;
1626             r = d->logicalRow(visualRow);
1627             c = d->logicalColumn(visualColumn);
1628             if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c)))
1629                 break;
1630         }
1631         if (visualRow > bottom)
1632             visualRow = originalRow;
1633         break;
1634     }
1635     case MovePrevious:
1636     case MoveLeft: {
1637         int originalRow = visualRow;
1638         int originalColumn = visualColumn;
1639         bool firstTime = true;
1640         bool looped = false;
1641         bool wrapped = false;
1642         do {
1643             int r = d->logicalRow(visualRow);
1644             int c = d->logicalColumn(visualColumn);
1645             if (firstTime && c != -1 && d->hasSpans()) {
1646                 firstTime = false;
1647                 QSpanCollection::Span span = d->span(r, c);
1648                 if (span.width() > 1 || span.height() > 1)
1649                     visualColumn = d->visualColumn(span.left());
1650             }
1651             while (visualColumn >= 0) {
1652                 --visualColumn;
1653                 r = d->logicalRow(visualRow);
1654                 c = d->logicalColumn(visualColumn);
1655                 if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c)))
1656                     break;
1657                 if (wrapped && (originalRow < visualRow || (originalRow == visualRow && originalColumn <= visualColumn))) {
1658                     looped = true;
1659                     break;
1660                 }
1661             }
1662             if (cursorAction == MoveLeft || visualColumn >= 0)
1663                 break;
1664             visualColumn = right + 1;
1665             if (visualRow == 0) {
1666                 wrapped = true;
1667                 visualRow = bottom;
1668             } else {
1669                 --visualRow;
1670             }
1671         } while (!looped);
1672         if (visualColumn < 0)
1673             visualColumn = originalColumn;
1674         break;
1675     }
1676     case MoveNext:
1677     case MoveRight: {
1678         int originalRow = visualRow;
1679         int originalColumn = visualColumn;
1680         bool firstTime = true;
1681         bool looped = false;
1682         bool wrapped = false;
1683         do {
1684             int r = d->logicalRow(visualRow);
1685             int c = d->logicalColumn(visualColumn);
1686             if (firstTime && c != -1 && d->hasSpans()) {
1687                 firstTime = false;
1688                 QSpanCollection::Span span = d->span(r, c);
1689                 if (span.width() > 1 || span.height() > 1)
1690                     visualColumn = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
1691             }
1692             while (visualColumn <= right) {
1693                 ++visualColumn;
1694                 r = d->logicalRow(visualRow);
1695                 c = d->logicalColumn(visualColumn);
1696                 if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c)))
1697                     break;
1698                 if (wrapped && (originalRow > visualRow || (originalRow == visualRow && originalColumn >= visualColumn))) {
1699                     looped = true;
1700                     break;
1701                 }
1702             }
1703             if (cursorAction == MoveRight || visualColumn <= right)
1704                 break;
1705             visualColumn = -1;
1706             if (visualRow == bottom) {
1707                 wrapped = true;
1708                 visualRow = 0;
1709             } else {
1710                 ++visualRow;
1711             }
1712         } while (!looped);
1713         if (visualColumn > right)
1714             visualColumn = originalColumn;
1715         break;
1716     }
1717     case MoveHome:
1718         visualColumn = 0;
1719         while (visualColumn < right && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn))
1720             ++visualColumn;
1721         if (modifiers & Qt::ControlModifier) {
1722             visualRow = 0;
1723             while (visualRow < bottom && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn))
1724                 ++visualRow;
1725         }
1726         break;
1727     case MoveEnd:
1728         visualColumn = right;
1729         if (modifiers & Qt::ControlModifier)
1730             visualRow = bottom;
1731         break;
1732     case MovePageUp: {
1733         int newRow = rowAt(visualRect(current).top() - d->viewport->height());
1734         if (newRow == -1)
1735             newRow = d->logicalRow(0);
1736         return d->model->index(newRow, current.column(), d->root);
1737     }
1738     case MovePageDown: {
1739         int newRow = rowAt(visualRect(current).bottom() + d->viewport->height());
1740         if (newRow == -1)
1741             newRow = d->logicalRow(bottom);
1742         return d->model->index(newRow, current.column(), d->root);
1743     }}
1744
1745     d->visualCursor = QPoint(visualColumn, visualRow);
1746     int logicalRow = d->logicalRow(visualRow);
1747     int logicalColumn = d->logicalColumn(visualColumn);
1748     if (!d->model->hasIndex(logicalRow, logicalColumn, d->root))
1749         return QModelIndex();
1750
1751     QModelIndex result = d->model->index(logicalRow, logicalColumn, d->root);
1752     if (!d->isRowHidden(logicalRow) && !d->isColumnHidden(logicalColumn) && d->isIndexEnabled(result))
1753         return result;
1754
1755     return QModelIndex();
1756 }
1757
1758 /*!
1759     \fn void QTableView::setSelection(const QRect &rect,
1760     QItemSelectionModel::SelectionFlags flags)
1761
1762     Selects the items within the given \a rect and in accordance with
1763     the specified selection \a flags.
1764 */
1765 void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
1766 {
1767     Q_D(QTableView);
1768     QModelIndex tl = indexAt(QPoint(isRightToLeft() ? qMax(rect.left(), rect.right())
1769                                     : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom())));
1770     QModelIndex br = indexAt(QPoint(isRightToLeft() ? qMin(rect.left(), rect.right()) :
1771                                     qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom())));
1772     if (!d->selectionModel || !tl.isValid() || !br.isValid() || !d->isIndexEnabled(tl) || !d->isIndexEnabled(br))
1773         return;
1774
1775     bool verticalMoved = verticalHeader()->sectionsMoved();
1776     bool horizontalMoved = horizontalHeader()->sectionsMoved();
1777
1778     QItemSelection selection;
1779
1780     if (d->hasSpans()) {
1781         bool expanded;
1782         int top = qMin(d->visualRow(tl.row()), d->visualRow(br.row()));
1783         int left = qMin(d->visualColumn(tl.column()), d->visualColumn(br.column()));
1784         int bottom = qMax(d->visualRow(tl.row()), d->visualRow(br.row()));
1785         int right = qMax(d->visualColumn(tl.column()), d->visualColumn(br.column()));
1786         do {
1787             expanded = false;
1788             foreach (QSpanCollection::Span *it, d->spans.spans) {
1789                 const QSpanCollection::Span &span = *it;
1790                 int t = d->visualRow(span.top());
1791                 int l = d->visualColumn(span.left());
1792                 int b = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
1793                 int r = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
1794                 if ((t > bottom) || (l > right) || (top > b) || (left > r))
1795                     continue; // no intersect
1796                 if (t < top) {
1797                     top = t;
1798                     expanded = true;
1799                 }
1800                 if (l < left) {
1801                     left = l;
1802                     expanded = true;
1803                 }
1804                 if (b > bottom) {
1805                     bottom = b;
1806                     expanded = true;
1807                 }
1808                 if (r > right) {
1809                     right = r;
1810                     expanded = true;
1811                 }
1812                 if (expanded)
1813                     break;
1814             }
1815         } while (expanded);
1816          for (int horizontal = left; horizontal <= right; ++horizontal) {
1817              int column = d->logicalColumn(horizontal);
1818              for (int vertical = top; vertical <= bottom; ++vertical) {
1819                  int row = d->logicalRow(vertical);
1820                  QModelIndex index = d->model->index(row, column, d->root);
1821                  selection.append(QItemSelectionRange(index));
1822              }
1823          }
1824     } else if (verticalMoved && horizontalMoved) {
1825          int top = d->visualRow(tl.row());
1826          int left = d->visualColumn(tl.column());
1827          int bottom = d->visualRow(br.row());
1828          int right = d->visualColumn(br.column());
1829          for (int horizontal = left; horizontal <= right; ++horizontal) {
1830              int column = d->logicalColumn(horizontal);
1831              for (int vertical = top; vertical <= bottom; ++vertical) {
1832                  int row = d->logicalRow(vertical);
1833                  QModelIndex index = d->model->index(row, column, d->root);
1834                  selection.append(QItemSelectionRange(index));
1835              }
1836          }
1837     } else if (horizontalMoved) {
1838         int left = d->visualColumn(tl.column());
1839         int right = d->visualColumn(br.column());
1840         for (int visual = left; visual <= right; ++visual) {
1841             int column = d->logicalColumn(visual);
1842             QModelIndex topLeft = d->model->index(tl.row(), column, d->root);
1843             QModelIndex bottomRight = d->model->index(br.row(), column, d->root);
1844             selection.append(QItemSelectionRange(topLeft, bottomRight));
1845         }
1846     } else if (verticalMoved) {
1847         int top = d->visualRow(tl.row());
1848         int bottom = d->visualRow(br.row());
1849         for (int visual = top; visual <= bottom; ++visual) {
1850             int row = d->logicalRow(visual);
1851             QModelIndex topLeft = d->model->index(row, tl.column(), d->root);
1852             QModelIndex bottomRight = d->model->index(row, br.column(), d->root);
1853             selection.append(QItemSelectionRange(topLeft, bottomRight));
1854         }
1855     } else { // nothing moved
1856         QItemSelectionRange range(tl, br);
1857         if (!range.isEmpty())
1858             selection.append(range);
1859     }
1860
1861     d->selectionModel->select(selection, command);
1862 }
1863
1864 /*!
1865     \internal
1866
1867     Returns the rectangle from the viewport of the items in the given
1868     \a selection.
1869
1870     Since 4.7, the returned region only contains rectangles intersecting
1871     (or included in) the viewport.
1872 */
1873 QRegion QTableView::visualRegionForSelection(const QItemSelection &selection) const
1874 {
1875     Q_D(const QTableView);
1876
1877     if (selection.isEmpty())
1878         return QRegion();
1879
1880     QRegion selectionRegion;
1881     const QRect &viewportRect = d->viewport->rect();
1882     bool verticalMoved = verticalHeader()->sectionsMoved();
1883     bool horizontalMoved = horizontalHeader()->sectionsMoved();
1884
1885     if ((verticalMoved && horizontalMoved) || (d->hasSpans() && (verticalMoved || horizontalMoved))) {
1886         for (int i = 0; i < selection.count(); ++i) {
1887             QItemSelectionRange range = selection.at(i);
1888             if (range.parent() != d->root || !range.isValid())
1889                 continue;
1890             for (int r = range.top(); r <= range.bottom(); ++r)
1891                 for (int c = range.left(); c <= range.right(); ++c) {
1892                     const QRect &rangeRect = visualRect(d->model->index(r, c, d->root));
1893                     if (viewportRect.intersects(rangeRect))
1894                         selectionRegion += rangeRect;
1895                 }
1896         }
1897     } else if (horizontalMoved) {
1898         for (int i = 0; i < selection.count(); ++i) {
1899             QItemSelectionRange range = selection.at(i);
1900             if (range.parent() != d->root || !range.isValid())
1901                 continue;
1902             int top = rowViewportPosition(range.top());
1903             int bottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom());
1904             if (top > bottom)
1905                 qSwap<int>(top, bottom);
1906             int height = bottom - top;
1907             for (int c = range.left(); c <= range.right(); ++c) {
1908                 const QRect rangeRect(columnViewportPosition(c), top, columnWidth(c), height);
1909                 if (viewportRect.intersects(rangeRect))
1910                     selectionRegion += rangeRect;
1911             }
1912         }
1913     } else if (verticalMoved) {
1914         for (int i = 0; i < selection.count(); ++i) {
1915             QItemSelectionRange range = selection.at(i);
1916             if (range.parent() != d->root || !range.isValid())
1917                 continue;
1918             int left = columnViewportPosition(range.left());
1919             int right = columnViewportPosition(range.right()) + columnWidth(range.right());
1920             if (left > right)
1921                 qSwap<int>(left, right);
1922             int width = right - left;
1923             for (int r = range.top(); r <= range.bottom(); ++r) {
1924                 const QRect rangeRect(left, rowViewportPosition(r), width, rowHeight(r));
1925                 if (viewportRect.intersects(rangeRect))
1926                     selectionRegion += rangeRect;
1927             }
1928         }
1929     } else { // nothing moved
1930         const int gridAdjust = showGrid() ? 1 : 0;
1931         for (int i = 0; i < selection.count(); ++i) {
1932             QItemSelectionRange range = selection.at(i);
1933             if (range.parent() != d->root || !range.isValid())
1934                 continue;
1935             d->trimHiddenSelections(&range);
1936
1937             const int rtop = rowViewportPosition(range.top());
1938             const int rbottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom());
1939             int rleft;
1940             int rright;
1941             if (isLeftToRight()) {
1942                 rleft = columnViewportPosition(range.left());
1943                 rright = columnViewportPosition(range.right()) + columnWidth(range.right());
1944             } else {
1945                 rleft = columnViewportPosition(range.right());
1946                 rright = columnViewportPosition(range.left()) + columnWidth(range.left());
1947             }
1948             const QRect rangeRect(QPoint(rleft, rtop), QPoint(rright - 1 - gridAdjust, rbottom - 1 - gridAdjust));
1949             if (viewportRect.intersects(rangeRect))
1950                 selectionRegion += rangeRect;
1951             if (d->hasSpans()) {
1952                 foreach (QSpanCollection::Span *s,
1953                          d->spans.spansInRect(range.left(), range.top(), range.width(), range.height())) {
1954                     if (range.contains(s->top(), s->left(), range.parent())) {
1955                         const QRect &visualSpanRect = d->visualSpanRect(*s);
1956                         if (viewportRect.intersects(visualSpanRect))
1957                             selectionRegion += visualSpanRect;
1958                     }
1959                 }
1960             }
1961         }
1962     }
1963
1964     return selectionRegion;
1965 }
1966
1967
1968 /*!
1969   \reimp
1970 */
1971 QModelIndexList QTableView::selectedIndexes() const
1972 {
1973     Q_D(const QTableView);
1974     QModelIndexList viewSelected;
1975     QModelIndexList modelSelected;
1976     if (d->selectionModel)
1977         modelSelected = d->selectionModel->selectedIndexes();
1978     for (int i = 0; i < modelSelected.count(); ++i) {
1979         QModelIndex index = modelSelected.at(i);
1980         if (!isIndexHidden(index) && index.parent() == d->root)
1981             viewSelected.append(index);
1982     }
1983     return viewSelected;
1984 }
1985
1986
1987 /*!
1988     This slot is called whenever rows are added or deleted. The
1989     previous number of rows is specified by \a oldCount, and the new
1990     number of rows is specified by \a newCount.
1991 */
1992 void QTableView::rowCountChanged(int oldCount, int newCount )
1993 {
1994     Q_D(QTableView);
1995     //when removing rows, we need to disable updates for the header until the geometries have been
1996     //updated and the offset has been adjusted, or we risk calling paintSection for all the sections
1997     if (newCount < oldCount)
1998         d->verticalHeader->setUpdatesEnabled(false);
1999     d->doDelayedItemsLayout();
2000 }
2001
2002 /*!
2003     This slot is called whenever columns are added or deleted. The
2004     previous number of columns is specified by \a oldCount, and the new
2005     number of columns is specified by \a newCount.
2006 */
2007 void QTableView::columnCountChanged(int, int)
2008 {
2009     Q_D(QTableView);
2010     updateGeometries();
2011     if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem)
2012         d->horizontalHeader->setOffsetToSectionPosition(horizontalScrollBar()->value());
2013     else
2014         d->horizontalHeader->setOffset(horizontalScrollBar()->value());
2015     d->viewport->update();
2016 }
2017
2018 /*!
2019     \reimp
2020 */
2021 void QTableView::updateGeometries()
2022 {
2023     Q_D(QTableView);
2024     if (d->geometryRecursionBlock)
2025         return;
2026     d->geometryRecursionBlock = true;
2027
2028     int width = 0;
2029     if (!d->verticalHeader->isHidden()) {
2030         width = qMax(d->verticalHeader->minimumWidth(), d->verticalHeader->sizeHint().width());
2031         width = qMin(width, d->verticalHeader->maximumWidth());
2032     }
2033     int height = 0;
2034     if (!d->horizontalHeader->isHidden()) {
2035         height = qMax(d->horizontalHeader->minimumHeight(), d->horizontalHeader->sizeHint().height());
2036         height = qMin(height, d->horizontalHeader->maximumHeight());
2037     }
2038     bool reverse = isRightToLeft();
2039      if (reverse)
2040          setViewportMargins(0, height, width, 0);
2041      else
2042          setViewportMargins(width, height, 0, 0);
2043
2044     // update headers
2045
2046     QRect vg = d->viewport->geometry();
2047
2048     int verticalLeft = reverse ? vg.right() + 1 : (vg.left() - width);
2049     d->verticalHeader->setGeometry(verticalLeft, vg.top(), width, vg.height());
2050     if (d->verticalHeader->isHidden())
2051         QMetaObject::invokeMethod(d->verticalHeader, "updateGeometries");
2052
2053     int horizontalTop = vg.top() - height;
2054     d->horizontalHeader->setGeometry(vg.left(), horizontalTop, vg.width(), height);
2055     if (d->horizontalHeader->isHidden())
2056         QMetaObject::invokeMethod(d->horizontalHeader, "updateGeometries");
2057
2058     // update cornerWidget
2059     if (d->horizontalHeader->isHidden() || d->verticalHeader->isHidden()) {
2060         d->cornerWidget->setHidden(true);
2061     } else {
2062         d->cornerWidget->setHidden(false);
2063         d->cornerWidget->setGeometry(verticalLeft, horizontalTop, width, height);
2064     }
2065
2066     // update scroll bars
2067
2068     // ### move this block into the if
2069     QSize vsize = d->viewport->size();
2070     QSize max = maximumViewportSize();
2071     uint horizontalLength = d->horizontalHeader->length();
2072     uint verticalLength = d->verticalHeader->length();
2073     if ((uint)max.width() >= horizontalLength && (uint)max.height() >= verticalLength)
2074         vsize = max;
2075
2076     // horizontal scroll bar
2077     const int columnCount = d->horizontalHeader->count();
2078     const int viewportWidth = vsize.width();
2079     int columnsInViewport = 0;
2080     for (int width = 0, column = columnCount - 1; column >= 0; --column) {
2081         int logical = d->horizontalHeader->logicalIndex(column);
2082         if (!d->horizontalHeader->isSectionHidden(logical)) {
2083             width += d->horizontalHeader->sectionSize(logical);
2084             if (width > viewportWidth)
2085                 break;
2086             ++columnsInViewport;
2087         }
2088     }
2089     columnsInViewport = qMax(columnsInViewport, 1); //there must be always at least 1 column
2090
2091     if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
2092         const int visibleColumns = columnCount - d->horizontalHeader->hiddenSectionCount();
2093         horizontalScrollBar()->setRange(0, visibleColumns - columnsInViewport);
2094         horizontalScrollBar()->setPageStep(columnsInViewport);
2095         if (columnsInViewport >= visibleColumns)
2096             d->horizontalHeader->setOffset(0);
2097         horizontalScrollBar()->setSingleStep(1);
2098     } else { // ScrollPerPixel
2099         horizontalScrollBar()->setPageStep(vsize.width());
2100         horizontalScrollBar()->setRange(0, horizontalLength - vsize.width());
2101         horizontalScrollBar()->setSingleStep(qMax(vsize.width() / (columnsInViewport + 1), 2));
2102     }
2103
2104     // vertical scroll bar
2105     const int rowCount = d->verticalHeader->count();
2106     const int viewportHeight = vsize.height();
2107     int rowsInViewport = 0;
2108     for (int height = 0, row = rowCount - 1; row >= 0; --row) {
2109         int logical = d->verticalHeader->logicalIndex(row);
2110         if (!d->verticalHeader->isSectionHidden(logical)) {
2111             height += d->verticalHeader->sectionSize(logical);
2112             if (height > viewportHeight)
2113                 break;
2114             ++rowsInViewport;
2115         }
2116     }
2117     rowsInViewport = qMax(rowsInViewport, 1); //there must be always at least 1 row
2118
2119     if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2120         const int visibleRows = rowCount - d->verticalHeader->hiddenSectionCount();
2121         verticalScrollBar()->setRange(0, visibleRows - rowsInViewport);
2122         verticalScrollBar()->setPageStep(rowsInViewport);
2123         if (rowsInViewport >= visibleRows)
2124             d->verticalHeader->setOffset(0);
2125         verticalScrollBar()->setSingleStep(1);
2126     } else { // ScrollPerPixel
2127         verticalScrollBar()->setPageStep(vsize.height());
2128         verticalScrollBar()->setRange(0, verticalLength - vsize.height());
2129         verticalScrollBar()->setSingleStep(qMax(vsize.height() / (rowsInViewport + 1), 2));
2130     }
2131
2132     d->geometryRecursionBlock = false;
2133     QAbstractItemView::updateGeometries();
2134 }
2135
2136 /*!
2137     Returns the size hint for the given \a row's height or -1 if there
2138     is no model.
2139
2140     If you need to set the height of a given row to a fixed value, call
2141     QHeaderView::resizeSection() on the table's vertical header.
2142
2143     If you reimplement this function in a subclass, note that the value you
2144     return is only used when resizeRowToContents() is called. In that case,
2145     if a larger row height is required by either the vertical header or
2146     the item delegate, that width will be used instead.
2147
2148     \sa QWidget::sizeHint, verticalHeader()
2149 */
2150 int QTableView::sizeHintForRow(int row) const
2151 {
2152     Q_D(const QTableView);
2153
2154     if (!model())
2155         return -1;
2156
2157     ensurePolished();
2158
2159     int left = qMax(0, d->horizontalHeader->visualIndexAt(0));
2160     int right = d->horizontalHeader->visualIndexAt(d->viewport->width());
2161     if (right == -1) // the table don't have enough columns to fill the viewport
2162         right = d->model->columnCount(d->root) - 1;
2163
2164     QStyleOptionViewItemV4 option = d->viewOptionsV4();
2165
2166     int hint = 0;
2167     QModelIndex index;
2168     for (int column = left; column <= right; ++column) {
2169         int logicalColumn = d->horizontalHeader->logicalIndex(column);
2170         if (d->horizontalHeader->isSectionHidden(logicalColumn))
2171             continue;
2172         index = d->model->index(row, logicalColumn, d->root);
2173         if (d->wrapItemText) {// for wrapping boundaries
2174             option.rect.setY(rowViewportPosition(index.row()));
2175             option.rect.setHeight(rowHeight(index.row()));
2176             option.rect.setX(columnViewportPosition(index.column()));
2177             option.rect.setWidth(columnWidth(index.column()));
2178         }
2179         
2180         QWidget *editor = d->editorForIndex(index).widget.data();
2181         if (editor && d->persistent.contains(editor)) {
2182             hint = qMax(hint, editor->sizeHint().height());
2183             int min = editor->minimumSize().height();
2184             int max = editor->maximumSize().height();
2185             hint = qBound(min, hint, max);
2186         }
2187         
2188         hint = qMax(hint, itemDelegate(index)->sizeHint(option, index).height());
2189     }
2190
2191     return d->showGrid ? hint + 1 : hint;
2192 }
2193
2194 /*!
2195     Returns the size hint for the given \a column's width or -1 if
2196     there is no model.
2197
2198     If you need to set the width of a given column to a fixed value, call
2199     QHeaderView::resizeSection() on the table's horizontal header.
2200
2201     If you reimplement this function in a subclass, note that the value you
2202     return will be used when resizeColumnToContents() or
2203     QHeaderView::resizeSections() is called. If a larger column width is
2204     required by either the horizontal header or the item delegate, the larger
2205     width will be used instead.
2206
2207     \sa QWidget::sizeHint, horizontalHeader()
2208 */
2209 int QTableView::sizeHintForColumn(int column) const
2210 {
2211     Q_D(const QTableView);
2212
2213     if (!model())
2214         return -1;
2215
2216     ensurePolished();
2217
2218     int top = qMax(0, d->verticalHeader->visualIndexAt(0));
2219     int bottom = d->verticalHeader->visualIndexAt(d->viewport->height());
2220     if (!isVisible() || bottom == -1) // the table don't have enough rows to fill the viewport
2221         bottom = d->model->rowCount(d->root) - 1;
2222
2223     QStyleOptionViewItemV4 option = d->viewOptionsV4();
2224
2225     int hint = 0;
2226     QModelIndex index;
2227     for (int row = top; row <= bottom; ++row) {
2228         int logicalRow = d->verticalHeader->logicalIndex(row);
2229         if (d->verticalHeader->isSectionHidden(logicalRow))
2230             continue;
2231         index = d->model->index(logicalRow, column, d->root);
2232         
2233         QWidget *editor = d->editorForIndex(index).widget.data();
2234         if (editor && d->persistent.contains(editor)) {
2235             hint = qMax(hint, editor->sizeHint().width());
2236             int min = editor->minimumSize().width();
2237             int max = editor->maximumSize().width();
2238             hint = qBound(min, hint, max);
2239         }
2240         
2241         hint = qMax(hint, itemDelegate(index)->sizeHint(option, index).width());
2242     }
2243
2244     return d->showGrid ? hint + 1 : hint;
2245 }
2246
2247 /*!
2248     Returns the y-coordinate in contents coordinates of the given \a
2249     row.
2250 */
2251 int QTableView::rowViewportPosition(int row) const
2252 {
2253     Q_D(const QTableView);
2254     return d->verticalHeader->sectionViewportPosition(row);
2255 }
2256
2257 /*!
2258     Returns the row in which the given y-coordinate, \a y, in contents
2259     coordinates is located.
2260
2261     \note This function returns -1 if the given coordinate is not valid
2262     (has no row).
2263
2264     \sa columnAt()
2265 */
2266 int QTableView::rowAt(int y) const
2267 {
2268     Q_D(const QTableView);
2269     return d->verticalHeader->logicalIndexAt(y);
2270 }
2271
2272 /*!
2273     \since 4.1
2274
2275     Sets the height of the given \a row to be \a height.
2276 */
2277 void QTableView::setRowHeight(int row, int height)
2278 {
2279     Q_D(const QTableView);
2280     d->verticalHeader->resizeSection(row, height);
2281 }
2282
2283 /*!
2284     Returns the height of the given \a row.
2285
2286     \sa resizeRowToContents(), columnWidth()
2287 */
2288 int QTableView::rowHeight(int row) const
2289 {
2290     Q_D(const QTableView);
2291     return d->verticalHeader->sectionSize(row);
2292 }
2293
2294 /*!
2295     Returns the x-coordinate in contents coordinates of the given \a
2296     column.
2297 */
2298 int QTableView::columnViewportPosition(int column) const
2299 {
2300     Q_D(const QTableView);
2301     return d->horizontalHeader->sectionViewportPosition(column);
2302 }
2303
2304 /*!
2305     Returns the column in which the given x-coordinate, \a x, in contents
2306     coordinates is located.
2307
2308     \note This function returns -1 if the given coordinate is not valid
2309     (has no column).
2310
2311     \sa rowAt()
2312 */
2313 int QTableView::columnAt(int x) const
2314 {
2315     Q_D(const QTableView);
2316     return d->horizontalHeader->logicalIndexAt(x);
2317 }
2318
2319 /*!
2320     \since 4.1
2321
2322     Sets the width of the given \a column to be \a width.
2323 */
2324 void QTableView::setColumnWidth(int column, int width)
2325 {
2326     Q_D(const QTableView);
2327     d->horizontalHeader->resizeSection(column, width);
2328 }
2329
2330 /*!
2331     Returns the width of the given \a column.
2332
2333     \sa resizeColumnToContents(), rowHeight()
2334 */
2335 int QTableView::columnWidth(int column) const
2336 {
2337     Q_D(const QTableView);
2338     return d->horizontalHeader->sectionSize(column);
2339 }
2340
2341 /*!
2342     Returns true if the given \a row is hidden; otherwise returns false.
2343
2344     \sa isColumnHidden()
2345 */
2346 bool QTableView::isRowHidden(int row) const
2347 {
2348     Q_D(const QTableView);
2349     return d->verticalHeader->isSectionHidden(row);
2350 }
2351
2352 /*!
2353     If \a hide is true \a row will be hidden, otherwise it will be shown.
2354
2355     \sa setColumnHidden()
2356 */
2357 void QTableView::setRowHidden(int row, bool hide)
2358 {
2359     Q_D(QTableView);
2360     if (row < 0 || row >= d->verticalHeader->count())
2361         return;
2362     d->verticalHeader->setSectionHidden(row, hide);
2363 }
2364
2365 /*!
2366     Returns true if the given \a column is hidden; otherwise returns false.
2367
2368     \sa isRowHidden()
2369 */
2370 bool QTableView::isColumnHidden(int column) const
2371 {
2372     Q_D(const QTableView);
2373     return d->horizontalHeader->isSectionHidden(column);
2374 }
2375
2376 /*!
2377   If \a hide is true the given \a column will be hidden; otherwise it
2378   will be shown.
2379
2380   \sa setRowHidden()
2381 */
2382 void QTableView::setColumnHidden(int column, bool hide)
2383 {
2384     Q_D(QTableView);
2385     if (column < 0 || column >= d->horizontalHeader->count())
2386         return;
2387     d->horizontalHeader->setSectionHidden(column, hide);
2388 }
2389
2390 /*!
2391     \since 4.2
2392     \property QTableView::sortingEnabled
2393     \brief whether sorting is enabled
2394
2395     If this property is true, sorting is enabled for the table.  If
2396     this property is false, sorting is not enabled. The default value
2397     is false.
2398
2399     \note. Setting the property to true with setSortingEnabled()
2400     immediately triggers a call to sortByColumn() with the current
2401     sort section and order.
2402
2403     \sa sortByColumn()
2404 */
2405
2406 /*!
2407   If \a enabled true enables sorting for the table and immediately
2408   trigger a call to sortByColumn() with the current sort section and
2409   order
2410  */
2411 void QTableView::setSortingEnabled(bool enable)
2412 {
2413     Q_D(QTableView);
2414     d->sortingEnabled = enable;
2415     horizontalHeader()->setSortIndicatorShown(enable);
2416     if (enable) {
2417         disconnect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
2418                    this, SLOT(_q_selectColumn(int)));
2419         disconnect(horizontalHeader(), SIGNAL(sectionPressed(int)),
2420                    this, SLOT(selectColumn(int)));
2421         connect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
2422                 this, SLOT(sortByColumn(int)), Qt::UniqueConnection);
2423         sortByColumn(horizontalHeader()->sortIndicatorSection(),
2424                      horizontalHeader()->sortIndicatorOrder());
2425     } else {
2426         connect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
2427                 this, SLOT(_q_selectColumn(int)), Qt::UniqueConnection);
2428         connect(horizontalHeader(), SIGNAL(sectionPressed(int)),
2429                 this, SLOT(selectColumn(int)), Qt::UniqueConnection);
2430         disconnect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
2431                    this, SLOT(sortByColumn(int)));
2432     }
2433 }
2434
2435 bool QTableView::isSortingEnabled() const
2436 {
2437     Q_D(const QTableView);
2438     return d->sortingEnabled;
2439 }
2440
2441 /*!
2442     \property QTableView::showGrid
2443     \brief whether the grid is shown
2444
2445     If this property is true a grid is drawn for the table; if the
2446     property is false, no grid is drawn. The default value is true.
2447 */
2448 bool QTableView::showGrid() const
2449 {
2450     Q_D(const QTableView);
2451     return d->showGrid;
2452 }
2453
2454 void QTableView::setShowGrid(bool show)
2455 {
2456     Q_D(QTableView);
2457     if (d->showGrid != show) {
2458         d->showGrid = show;
2459         d->viewport->update();
2460     }
2461 }
2462
2463 /*!
2464   \property QTableView::gridStyle
2465   \brief  the pen style used to draw the grid.
2466
2467   This property holds the style used when drawing the grid (see \l{showGrid}).
2468 */
2469 Qt::PenStyle QTableView::gridStyle() const
2470 {
2471     Q_D(const QTableView);
2472     return d->gridStyle;
2473 }
2474
2475 void QTableView::setGridStyle(Qt::PenStyle style)
2476 {
2477     Q_D(QTableView);
2478     if (d->gridStyle != style) {
2479         d->gridStyle = style;
2480         d->viewport->update();
2481     }
2482 }
2483
2484 /*!
2485     \property QTableView::wordWrap
2486     \brief the item text word-wrapping policy
2487     \since 4.3
2488
2489     If this property is true then the item text is wrapped where
2490     necessary at word-breaks; otherwise it is not wrapped at all.
2491     This property is true by default.
2492
2493     Note that even of wrapping is enabled, the cell will not be
2494     expanded to fit all text. Ellipsis will be inserted according to
2495     the current \l{QAbstractItemView::}{textElideMode}.
2496
2497 */
2498 void QTableView::setWordWrap(bool on)
2499 {
2500     Q_D(QTableView);
2501     if (d->wrapItemText == on)
2502         return;
2503     d->wrapItemText = on;
2504     QMetaObject::invokeMethod(d->verticalHeader, "resizeSections");
2505     QMetaObject::invokeMethod(d->horizontalHeader, "resizeSections");
2506 }
2507
2508 bool QTableView::wordWrap() const
2509 {
2510     Q_D(const QTableView);
2511     return d->wrapItemText;
2512 }
2513
2514 /*!
2515     \property QTableView::cornerButtonEnabled
2516     \brief whether the button in the top-left corner is enabled
2517     \since 4.3
2518
2519     If this property is true then button in the top-left corner
2520     of the table view is enabled. Clicking on this button will
2521     select all the cells in the table view.
2522
2523     This property is true by default.
2524 */
2525 void QTableView::setCornerButtonEnabled(bool enable)
2526 {
2527     Q_D(QTableView);
2528     d->cornerWidget->setEnabled(enable);
2529 }
2530
2531 bool QTableView::isCornerButtonEnabled() const
2532 {
2533     Q_D(const QTableView);
2534     return d->cornerWidget->isEnabled();
2535 }
2536
2537 /*!
2538     \internal
2539
2540     Returns the rectangle on the viewport occupied by the given \a
2541     index.
2542     If the index is hidden in the view it will return a null QRect.
2543 */
2544 QRect QTableView::visualRect(const QModelIndex &index) const
2545 {
2546     Q_D(const QTableView);
2547     if (!d->isIndexValid(index) || index.parent() != d->root
2548         || (!d->hasSpans() && isIndexHidden(index)))
2549         return QRect();
2550
2551     d->executePostedLayout();
2552
2553     if (d->hasSpans()) {
2554         QSpanCollection::Span span = d->span(index.row(), index.column());
2555         return d->visualSpanRect(span);
2556     }
2557
2558     int rowp = rowViewportPosition(index.row());
2559     int rowh = rowHeight(index.row());
2560     int colp = columnViewportPosition(index.column());
2561     int colw = columnWidth(index.column());
2562
2563     const int i = showGrid() ? 1 : 0;
2564     return QRect(colp, rowp, colw - i, rowh - i);
2565 }
2566
2567 /*!
2568     \internal
2569
2570     Makes sure that the given \a item is visible in the table view,
2571     scrolling if necessary.
2572 */
2573 void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint)
2574 {
2575     Q_D(QTableView);
2576
2577     // check if we really need to do anything
2578     if (!d->isIndexValid(index)
2579         || (d->model->parent(index) != d->root)
2580         || isRowHidden(index.row()) || isColumnHidden(index.column()))
2581         return;
2582
2583     QSpanCollection::Span span;
2584     if (d->hasSpans())
2585         span = d->span(index.row(), index.column());
2586
2587     // Adjust horizontal position
2588
2589     int viewportWidth = d->viewport->width();
2590     int horizontalOffset = d->horizontalHeader->offset();
2591     int horizontalPosition = d->horizontalHeader->sectionPosition(index.column());
2592     int horizontalIndex = d->horizontalHeader->visualIndex(index.column());
2593     int cellWidth = d->hasSpans()
2594                     ? d->columnSpanWidth(index.column(), span.width())
2595                     : d->horizontalHeader->sectionSize(index.column());
2596
2597     if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
2598
2599         bool positionAtLeft = (horizontalPosition - horizontalOffset < 0);
2600         bool positionAtRight = (horizontalPosition - horizontalOffset + cellWidth > viewportWidth);
2601
2602         if (hint == PositionAtCenter || positionAtRight) {
2603             int w = (hint == PositionAtCenter ? viewportWidth / 2 : viewportWidth);
2604             int x = cellWidth;
2605             while (horizontalIndex > 0) {
2606                 x += columnWidth(d->horizontalHeader->logicalIndex(horizontalIndex-1));
2607                 if (x > w)
2608                     break;
2609                 --horizontalIndex;
2610             }
2611         }
2612
2613         if (positionAtRight || hint == PositionAtCenter || positionAtLeft) {
2614             int hiddenSections = 0;
2615             if (d->horizontalHeader->sectionsHidden()) {
2616                 for (int s = horizontalIndex - 1; s >= 0; --s) {
2617                     int column = d->horizontalHeader->logicalIndex(s);
2618                     if (d->horizontalHeader->isSectionHidden(column))
2619                         ++hiddenSections;
2620                 }
2621             }
2622             horizontalScrollBar()->setValue(horizontalIndex - hiddenSections);
2623         }
2624
2625     } else { // ScrollPerPixel
2626         if (hint == PositionAtCenter) {
2627             horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
2628         } else {
2629             if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
2630                 horizontalScrollBar()->setValue(horizontalPosition);
2631             else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
2632                 horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
2633         }
2634     }
2635
2636     // Adjust vertical position
2637
2638     int viewportHeight = d->viewport->height();
2639     int verticalOffset = d->verticalHeader->offset();
2640     int verticalPosition = d->verticalHeader->sectionPosition(index.row());
2641     int verticalIndex = d->verticalHeader->visualIndex(index.row());
2642     int cellHeight = d->hasSpans()
2643                      ? d->rowSpanHeight(index.row(), span.height())
2644                      : d->verticalHeader->sectionSize(index.row());
2645
2646     if (verticalPosition - verticalOffset < 0 || cellHeight > viewportHeight) {
2647         if (hint == EnsureVisible)
2648             hint = PositionAtTop;
2649     } else if (verticalPosition - verticalOffset + cellHeight > viewportHeight) {
2650         if (hint == EnsureVisible)
2651             hint = PositionAtBottom;
2652     }
2653
2654     if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
2655
2656         if (hint == PositionAtBottom || hint == PositionAtCenter) {
2657             int h = (hint == PositionAtCenter ? viewportHeight / 2 : viewportHeight);
2658             int y = cellHeight;
2659             while (verticalIndex > 0) {
2660                 int row = d->verticalHeader->logicalIndex(verticalIndex - 1);
2661                 y += d->verticalHeader->sectionSize(row);
2662                 if (y > h)
2663                     break;
2664                 --verticalIndex;
2665             }
2666         }
2667
2668         if (hint == PositionAtBottom || hint == PositionAtCenter || hint == PositionAtTop) {
2669             int hiddenSections = 0;
2670             if (d->verticalHeader->sectionsHidden()) {
2671                 for (int s = verticalIndex - 1; s >= 0; --s) {
2672                     int row = d->verticalHeader->logicalIndex(s);
2673                     if (d->verticalHeader->isSectionHidden(row))
2674                         ++hiddenSections;
2675                 }
2676             }
2677             verticalScrollBar()->setValue(verticalIndex - hiddenSections);
2678         }
2679
2680     } else { // ScrollPerPixel
2681         if (hint == PositionAtTop) {
2682             verticalScrollBar()->setValue(verticalPosition);
2683         } else if (hint == PositionAtBottom) {
2684             verticalScrollBar()->setValue(verticalPosition - viewportHeight + cellHeight);
2685         } else if (hint == PositionAtCenter) {
2686             verticalScrollBar()->setValue(verticalPosition - ((viewportHeight - cellHeight) / 2));
2687         }
2688     }
2689
2690     update(index);
2691 }
2692
2693 /*!
2694     This slot is called to change the height of the given \a row. The
2695     old height is specified by \a oldHeight, and the new height by \a
2696     newHeight.
2697
2698     \sa columnResized()
2699 */
2700 void QTableView::rowResized(int row, int, int)
2701 {
2702     Q_D(QTableView);
2703     d->rowsToUpdate.append(row);
2704     if (d->rowResizeTimerID == 0)
2705         d->rowResizeTimerID = startTimer(0);
2706 }
2707
2708 /*!
2709     This slot is called to change the width of the given \a column.
2710     The old width is specified by \a oldWidth, and the new width by \a
2711     newWidth.
2712
2713     \sa rowResized()
2714 */
2715 void QTableView::columnResized(int column, int, int)
2716 {
2717     Q_D(QTableView);
2718     d->columnsToUpdate.append(column);
2719     if (d->columnResizeTimerID == 0)
2720         d->columnResizeTimerID = startTimer(0);
2721 }
2722
2723 /*!
2724  \reimp
2725  */
2726 void QTableView::timerEvent(QTimerEvent *event)
2727 {
2728     Q_D(QTableView);
2729
2730     if (event->timerId() == d->columnResizeTimerID) {
2731         updateGeometries();
2732         killTimer(d->columnResizeTimerID);
2733         d->columnResizeTimerID = 0;
2734
2735         QRect rect;
2736         int viewportHeight = d->viewport->height();
2737         int viewportWidth = d->viewport->width();
2738         if (d->hasSpans()) {
2739             rect = QRect(0, 0, viewportWidth, viewportHeight);
2740         } else {
2741             for (int i = d->columnsToUpdate.size()-1; i >= 0; --i) {
2742                 int column = d->columnsToUpdate.at(i);
2743                 int x = columnViewportPosition(column);
2744                 if (isRightToLeft())
2745                     rect |= QRect(0, 0, x + columnWidth(column), viewportHeight);
2746                 else
2747                     rect |= QRect(x, 0, viewportWidth - x, viewportHeight);
2748             }
2749         }
2750
2751         d->viewport->update(rect.normalized());
2752         d->columnsToUpdate.clear();
2753     }
2754
2755     if (event->timerId() == d->rowResizeTimerID) {
2756         updateGeometries();
2757         killTimer(d->rowResizeTimerID);
2758         d->rowResizeTimerID = 0;
2759
2760         int viewportHeight = d->viewport->height();
2761         int viewportWidth = d->viewport->width();
2762         int top;
2763         if (d->hasSpans()) {
2764             top = 0;
2765         } else {
2766             top = viewportHeight;
2767             for (int i = d->rowsToUpdate.size()-1; i >= 0; --i) {
2768                 int y = rowViewportPosition(d->rowsToUpdate.at(i));
2769                 top = qMin(top, y);
2770             }
2771         }
2772
2773         d->viewport->update(QRect(0, top, viewportWidth, viewportHeight - top));
2774         d->rowsToUpdate.clear();
2775     }
2776
2777     QAbstractItemView::timerEvent(event);
2778 }
2779
2780 /*!
2781     This slot is called to change the index of the given \a row in the
2782     table view. The old index is specified by \a oldIndex, and the new
2783     index by \a newIndex.
2784
2785     \sa columnMoved()
2786 */
2787 void QTableView::rowMoved(int, int oldIndex, int newIndex)
2788 {
2789     Q_D(QTableView);
2790
2791     updateGeometries();
2792     int logicalOldIndex = d->verticalHeader->logicalIndex(oldIndex);
2793     int logicalNewIndex = d->verticalHeader->logicalIndex(newIndex);
2794     if (d->hasSpans()) {
2795         d->viewport->update();
2796     } else {
2797         int oldTop = rowViewportPosition(logicalOldIndex);
2798         int newTop = rowViewportPosition(logicalNewIndex);
2799         int oldBottom = oldTop + rowHeight(logicalOldIndex);
2800         int newBottom = newTop + rowHeight(logicalNewIndex);
2801         int top = qMin(oldTop, newTop);
2802         int bottom = qMax(oldBottom, newBottom);
2803         int height = bottom - top;
2804         d->viewport->update(0, top, d->viewport->width(), height);
2805     }
2806 }
2807
2808 /*!
2809     This slot is called to change the index of the given \a column in
2810     the table view. The old index is specified by \a oldIndex, and
2811     the new index by \a newIndex.
2812
2813     \sa rowMoved()
2814 */
2815 void QTableView::columnMoved(int, int oldIndex, int newIndex)
2816 {
2817     Q_D(QTableView);
2818
2819     updateGeometries();
2820     int logicalOldIndex = d->horizontalHeader->logicalIndex(oldIndex);
2821     int logicalNewIndex = d->horizontalHeader->logicalIndex(newIndex);
2822     if (d->hasSpans()) {
2823         d->viewport->update();
2824     } else {
2825         int oldLeft = columnViewportPosition(logicalOldIndex);
2826         int newLeft = columnViewportPosition(logicalNewIndex);
2827         int oldRight = oldLeft + columnWidth(logicalOldIndex);
2828         int newRight = newLeft + columnWidth(logicalNewIndex);
2829         int left = qMin(oldLeft, newLeft);
2830         int right = qMax(oldRight, newRight);
2831         int width = right - left;
2832         d->viewport->update(left, 0, width, d->viewport->height());
2833     }
2834 }
2835
2836 /*!
2837     Selects the given \a row in the table view if the current
2838     SelectionMode and SelectionBehavior allows rows to be selected.
2839
2840     \sa selectColumn()
2841 */
2842 void QTableView::selectRow(int row)
2843 {
2844     Q_D(QTableView);
2845     d->selectRow(row, true);
2846 }
2847
2848 /*!
2849     Selects the given \a column in the table view if the current
2850     SelectionMode and SelectionBehavior allows columns to be selected.
2851
2852     \sa selectRow()
2853 */
2854 void QTableView::selectColumn(int column)
2855 {
2856     Q_D(QTableView);
2857     d->selectColumn(column, true);
2858 }
2859
2860 /*!
2861     Hide the given \a row.
2862
2863     \sa showRow() hideColumn()
2864 */
2865 void QTableView::hideRow(int row)
2866 {
2867     Q_D(QTableView);
2868     d->verticalHeader->hideSection(row);
2869 }
2870
2871 /*!
2872     Hide the given \a column.
2873
2874     \sa showColumn() hideRow()
2875 */
2876 void QTableView::hideColumn(int column)
2877 {
2878     Q_D(QTableView);
2879     d->horizontalHeader->hideSection(column);
2880 }
2881
2882 /*!
2883     Show the given \a row.
2884
2885     \sa hideRow() showColumn()
2886 */
2887 void QTableView::showRow(int row)
2888 {
2889     Q_D(QTableView);
2890     d->verticalHeader->showSection(row);
2891 }
2892
2893 /*!
2894     Show the given \a column.
2895
2896     \sa hideColumn() showRow()
2897 */
2898 void QTableView::showColumn(int column)
2899 {
2900     Q_D(QTableView);
2901     d->horizontalHeader->showSection(column);
2902 }
2903
2904 /*!
2905     Resizes the given \a row based on the size hints of the delegate
2906     used to render each item in the row.
2907 */
2908 void QTableView::resizeRowToContents(int row)
2909 {
2910     Q_D(QTableView);
2911     int content = sizeHintForRow(row);
2912     int header = d->verticalHeader->sectionSizeHint(row);
2913     d->verticalHeader->resizeSection(row, qMax(content, header));
2914 }
2915
2916 /*!
2917     Resizes all rows based on the size hints of the delegate
2918     used to render each item in the rows.
2919 */
2920 void QTableView::resizeRowsToContents()
2921 {
2922     Q_D(QTableView);
2923     d->verticalHeader->resizeSections(QHeaderView::ResizeToContents);
2924 }
2925
2926 /*!
2927     Resizes the given \a column based on the size hints of the delegate
2928     used to render each item in the column.
2929
2930     \note Only visible columns will be resized. Reimplement sizeHintForColumn()
2931     to resize hidden columns as well.
2932 */
2933 void QTableView::resizeColumnToContents(int column)
2934 {
2935     Q_D(QTableView);
2936     int content = sizeHintForColumn(column);
2937     int header = d->horizontalHeader->sectionSizeHint(column);
2938     d->horizontalHeader->resizeSection(column, qMax(content, header));
2939 }
2940
2941 /*!
2942     Resizes all columns based on the size hints of the delegate
2943     used to render each item in the columns.
2944 */
2945 void QTableView::resizeColumnsToContents()
2946 {
2947     Q_D(QTableView);
2948     d->horizontalHeader->resizeSections(QHeaderView::ResizeToContents);
2949 }
2950
2951 /*!
2952   \obsolete
2953   \overload
2954
2955   Sorts the model by the values in the given \a column.
2956 */
2957 void QTableView::sortByColumn(int column)
2958 {
2959     Q_D(QTableView);
2960     if (column == -1)
2961         return;
2962     d->model->sort(column, d->horizontalHeader->sortIndicatorOrder());
2963 }
2964
2965 /*!
2966   \since 4.2
2967
2968   Sorts the model by the values in the given \a column in the given \a order.
2969
2970   \sa sortingEnabled
2971  */
2972 void QTableView::sortByColumn(int column, Qt::SortOrder order)
2973 {
2974     Q_D(QTableView);
2975     d->horizontalHeader->setSortIndicator(column, order);
2976     sortByColumn(column);
2977 }
2978
2979 /*!
2980     \internal
2981 */
2982 void QTableView::verticalScrollbarAction(int action)
2983 {
2984     QAbstractItemView::verticalScrollbarAction(action);
2985 }
2986
2987 /*!
2988     \internal
2989 */
2990 void QTableView::horizontalScrollbarAction(int action)
2991 {
2992     QAbstractItemView::horizontalScrollbarAction(action);
2993 }
2994
2995 /*!
2996   \reimp
2997 */
2998 bool QTableView::isIndexHidden(const QModelIndex &index) const
2999 {
3000     Q_D(const QTableView);
3001     Q_ASSERT(d->isIndexValid(index));
3002     if (isRowHidden(index.row()) || isColumnHidden(index.column()))
3003         return true;
3004     if (d->hasSpans()) {
3005         QSpanCollection::Span span = d->span(index.row(), index.column());
3006         return !((span.top() == index.row()) && (span.left() == index.column()));
3007     }
3008     return false;
3009 }
3010
3011 /*!
3012     \fn void QTableView::setSpan(int row, int column, int rowSpanCount, int columnSpanCount)
3013     \since 4.2
3014
3015     Sets the span of the table element at (\a row, \a column) to the number of
3016     rows and columns specified by (\a rowSpanCount, \a columnSpanCount).
3017
3018     \sa rowSpan(), columnSpan()
3019 */
3020 void QTableView::setSpan(int row, int column, int rowSpan, int columnSpan)
3021 {
3022     Q_D(QTableView);
3023     if (row < 0 || column < 0 || rowSpan < 0 || columnSpan < 0)
3024         return;
3025     d->setSpan(row, column, rowSpan, columnSpan);
3026     d->viewport->update();
3027 }
3028
3029 /*!
3030   \since 4.2
3031
3032   Returns the row span of the table element at (\a row, \a column).
3033   The default is 1.
3034
3035   \sa setSpan(), columnSpan()
3036 */
3037 int QTableView::rowSpan(int row, int column) const
3038 {
3039     Q_D(const QTableView);
3040     return d->rowSpan(row, column);
3041 }
3042
3043 /*!
3044   \since 4.2
3045
3046   Returns the column span of the table element at (\a row, \a
3047   column). The default is 1.
3048
3049   \sa setSpan(), rowSpan()
3050 */
3051 int QTableView::columnSpan(int row, int column) const
3052 {
3053     Q_D(const QTableView);
3054     return d->columnSpan(row, column);
3055 }
3056
3057 /*!
3058   \since 4.4
3059
3060   Removes all row and column spans in the table view.
3061
3062   \sa setSpan()
3063 */
3064
3065 void QTableView::clearSpans()
3066 {
3067     Q_D(QTableView);
3068     d->spans.clear();
3069     d->viewport->update();
3070 }
3071
3072 void QTableViewPrivate::_q_selectRow(int row)
3073 {
3074     selectRow(row, false);
3075 }
3076
3077 void QTableViewPrivate::_q_selectColumn(int column)
3078 {
3079     selectColumn(column, false);
3080 }
3081
3082 void QTableViewPrivate::selectRow(int row, bool anchor)
3083 {
3084     Q_Q(QTableView);
3085
3086     if (q->selectionBehavior() == QTableView::SelectColumns
3087         || (q->selectionMode() == QTableView::SingleSelection
3088             && q->selectionBehavior() == QTableView::SelectItems))
3089         return;
3090
3091     if (row >= 0 && row < model->rowCount(root)) {
3092         int column = horizontalHeader->logicalIndexAt(q->isRightToLeft() ? viewport->width() : 0);
3093         QModelIndex index = model->index(row, column, root);
3094         QItemSelectionModel::SelectionFlags command = q->selectionCommand(index);
3095         selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
3096         if ((anchor && !(command & QItemSelectionModel::Current))
3097             || (q->selectionMode() == QTableView::SingleSelection))
3098             rowSectionAnchor = row;
3099
3100         if (q->selectionMode() != QTableView::SingleSelection
3101             && command.testFlag(QItemSelectionModel::Toggle)) {
3102             if (anchor)
3103                 ctrlDragSelectionFlag = verticalHeader->selectionModel()->selectedRows().contains(index)
3104                                     ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
3105             command &= ~QItemSelectionModel::Toggle;
3106             command |= ctrlDragSelectionFlag;
3107             if (!anchor)
3108                 command |= QItemSelectionModel::Current;
3109         }
3110
3111         QModelIndex tl = model->index(qMin(rowSectionAnchor, row), 0, root);
3112         QModelIndex br = model->index(qMax(rowSectionAnchor, row), model->columnCount(root) - 1, root);
3113         if (verticalHeader->sectionsMoved() && tl.row() != br.row())
3114             q->setSelection(q->visualRect(tl)|q->visualRect(br), command);
3115         else
3116             selectionModel->select(QItemSelection(tl, br), command);
3117     }
3118 }
3119
3120 void QTableViewPrivate::selectColumn(int column, bool anchor)
3121 {
3122     Q_Q(QTableView);
3123
3124     if (q->selectionBehavior() == QTableView::SelectRows
3125         || (q->selectionMode() == QTableView::SingleSelection
3126             && q->selectionBehavior() == QTableView::SelectItems))
3127         return;
3128
3129     if (column >= 0 && column < model->columnCount(root)) {
3130         int row = verticalHeader->logicalIndexAt(0);
3131         QModelIndex index = model->index(row, column, root);
3132         QItemSelectionModel::SelectionFlags command = q->selectionCommand(index);
3133         selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
3134         if ((anchor && !(command & QItemSelectionModel::Current))
3135             || (q->selectionMode() == QTableView::SingleSelection))
3136             columnSectionAnchor = column;
3137
3138         if (q->selectionMode() != QTableView::SingleSelection
3139             && command.testFlag(QItemSelectionModel::Toggle)) {
3140             if (anchor)
3141                 ctrlDragSelectionFlag = horizontalHeader->selectionModel()->selectedColumns().contains(index)
3142                                     ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
3143             command &= ~QItemSelectionModel::Toggle;
3144             command |= ctrlDragSelectionFlag;
3145             if (!anchor)
3146                 command |= QItemSelectionModel::Current;
3147         }
3148
3149         QModelIndex tl = model->index(0, qMin(columnSectionAnchor, column), root);
3150         QModelIndex br = model->index(model->rowCount(root) - 1,
3151                                       qMax(columnSectionAnchor, column), root);
3152         if (horizontalHeader->sectionsMoved() && tl.column() != br.column())
3153             q->setSelection(q->visualRect(tl)|q->visualRect(br), command);
3154         else
3155             selectionModel->select(QItemSelection(tl, br), command);
3156     }
3157 }
3158
3159 /*!
3160   \reimp
3161  */
3162 void QTableView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
3163 {
3164 #ifndef QT_NO_ACCESSIBILITY
3165     if (QAccessible::isActive()) {
3166         if (current.isValid()) {
3167             int entry = visualIndex(current) + 1;
3168             if (horizontalHeader())
3169                 ++entry;
3170             QAccessible::updateAccessibility(viewport(), entry, QAccessible::Focus);
3171         }
3172     }
3173 #endif
3174     QAbstractItemView::currentChanged(current, previous);
3175 }
3176
3177 /*!
3178   \reimp
3179  */
3180 void QTableView::selectionChanged(const QItemSelection &selected,
3181                                   const QItemSelection &deselected)
3182 {
3183 #ifndef QT_NO_ACCESSIBILITY
3184     if (QAccessible::isActive()) {
3185         // ### does not work properly for selection ranges.
3186         QModelIndex sel = selected.indexes().value(0);
3187         if (sel.isValid()) {
3188             int entry = visualIndex(sel);
3189             if (horizontalHeader())
3190                 ++entry;
3191             QAccessible::updateAccessibility(viewport(), entry, QAccessible::Selection);
3192         }
3193         QModelIndex desel = deselected.indexes().value(0);
3194         if (desel.isValid()) {
3195             int entry = visualIndex(sel);
3196             if (horizontalHeader())
3197                 ++entry;
3198             QAccessible::updateAccessibility(viewport(), entry, QAccessible::SelectionRemove);
3199         }
3200     }
3201 #endif
3202     QAbstractItemView::selectionChanged(selected, deselected);
3203 }
3204
3205 int QTableView::visualIndex(const QModelIndex &index) const
3206 {
3207     return index.row();
3208 }
3209
3210 QT_END_NAMESPACE
3211
3212 #include "qtableview.moc"
3213
3214 #include "moc_qtableview.cpp"
3215
3216 #endif // QT_NO_TABLEVIEW