src/gui/itemviews/qtableview.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/itemviews/qtableview.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,3113 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtableview.h"
+
+#ifndef QT_NO_TABLEVIEW
+#include <qheaderview.h>
+#include <qitemdelegate.h>
+#include <qapplication.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qsize.h>
+#include <qevent.h>
+#include <qbitarray.h>
+#include <qscrollbar.h>
+#include <qabstractbutton.h>
+#include <private/qtableview_p.h>
+#ifndef QT_NO_ACCESSIBILITY
+#include <qaccessible.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/** \internal
+  Add a span to the collection. the collection takes the ownership.
+  */
+void QSpanCollection::addSpan(QSpanCollection::Span *span)
+{
+    spans.append(span);
+    Index::iterator it_y = index.lowerBound(-span->top());
+    if (it_y == index.end() || it_y.key() != -span->top()) {
+        //there is no spans that starts with the row in the index, so create a sublist for it.
+        SubIndex sub_index;
+        if (it_y != index.end()) {
+            //the previouslist is the list of spans that sarts _before_ the row of the span.
+            // and which may intersect this row.
+            const SubIndex previousList = it_y.value();
+            foreach(Span *s, previousList) {
+                //If a subspans intersect the row, we need to split it into subspans
+                if(s->bottom() >= span->top())
+                    sub_index.insert(-s->left(), s);
+            }
+        }
+        it_y = index.insert(-span->top(), sub_index);
+        //we will insert span to *it_y in the later loop
+    }
+
+    //insert the span as supspan in all the lists that intesects the span
+    while(-it_y.key() <= span->bottom()) {
+        (*it_y).insert(-span->left(), span);
+        if(it_y == index.begin())
+            break;
+        --it_y;
+    }
+}
+
+
+/** \internal
+* Has to be called after the height and width of a span is changed.
+*
+* old_height is the height before the change
+*
+* if the size of the span is now 0x0 the span will be deleted.
+*/
+void QSpanCollection::updateSpan(QSpanCollection::Span *span, int old_height)
+{
+    if (old_height < span->height()) {
+        //add the span as subspan in all the lists that intersect the new covered columns
+        Index::iterator it_y = index.lowerBound(-(span->top() + old_height - 1));
+        Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list
+        while (-it_y.key() <= span->bottom()) {
+            (*it_y).insert(-span->left(), span);
+            if(it_y == index.begin())
+                break;
+            --it_y;
+        }
+    } else if (old_height > span->height()) {
+        //remove the span from all the subspans lists that intersect the columns not covered anymore
+        Index::iterator it_y = index.lowerBound(-span->bottom());
+        Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list
+        while (-it_y.key() <= span->top() + old_height -1) {
+            if(-it_y.key() != span->bottom()) {
+                (*it_y).remove(-span->left());
+                if (it_y->isEmpty()) {
+                    it_y = index.erase(it_y) - 1;
+                }
+            }
+            if(it_y == index.begin())
+                break;
+            --it_y;
+        }
+    }
+
+    if (span->width() == 0 && span->height() == 0) {
+        spans.removeOne(span);
+        delete span;
+    }
+}
+
+/** \internal
+ * \return a spans that spans over cell x,y  (column,row)  or 0 if there is none.
+ */
+QSpanCollection::Span *QSpanCollection::spanAt(int x, int y) const
+{
+    Index::const_iterator it_y = index.lowerBound(-y);
+    if (it_y == index.end())
+        return 0;
+    SubIndex::const_iterator it_x = (*it_y).lowerBound(-x);
+    if (it_x == (*it_y).end())
+        return 0;
+    Span *span = *it_x;
+    if (span->right() >= x && span->bottom() >= y)
+        return span;
+    return 0;
+}
+
+
+/** \internal
+* remove and deletes all spans inside the collection
+*/
+void QSpanCollection::clear()
+{
+    qDeleteAll(spans);
+    index.clear();
+    spans.clear();
+}
+
+/** \internal
+ * return a list to all the spans that spans over cells in the given rectangle
+ */
+QList<QSpanCollection::Span *> QSpanCollection::spansInRect(int x, int y, int w, int h) const
+{
+    QSet<Span *> list;
+    Index::const_iterator it_y = index.lowerBound(-y);
+    if(it_y == index.end())
+        --it_y;
+    while(-it_y.key() <= y + h) {
+        SubIndex::const_iterator it_x = (*it_y).lowerBound(-x);
+        if (it_x == (*it_y).end())
+            --it_x;
+        while(-it_x.key() <= x + w) {
+            Span *s = *it_x;
+            if (s->bottom() >= y && s->right() >= x)
+                list << s;
+            if (it_x == (*it_y).begin())
+                break;
+            --it_x;
+        }
+        if(it_y == index.begin())
+            break;
+        --it_y;
+    }
+    return list.toList();
+}
+
+#undef DEBUG_SPAN_UPDATE
+
+#ifdef DEBUG_SPAN_UPDATE
+QDebug operator<<(QDebug str, const QSpanCollection::Span &span)
+{
+    str << "(" << span.top() << "," << span.left() << "," << span.bottom() << "," << span.right() << ")";
+    return str;
+}
+#endif
+
+/** \internal
+* Updates the span collection after row insertion.
+*/
+void QSpanCollection::updateInsertedRows(int start, int end)
+{
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug() << Q_FUNC_INFO;
+    qDebug() << start << end;
+    qDebug() << index;
+#endif
+    if (spans.isEmpty())
+        return;
+
+    int delta = end - start + 1;
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug("Before");
+#endif
+    for (SpanList::iterator it = spans.begin(); it != spans.end(); ++it) {
+        Span *span = *it;
+#ifdef DEBUG_SPAN_UPDATE
+        qDebug() << span << *span;
+#endif
+        if (span->m_bottom < start)
+            continue;
+        if (span->m_top >= start)
+            span->m_top += delta;
+        span->m_bottom += delta;
+    }
+
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug("After");
+    foreach (QSpanCollection::Span *span, spans)
+        qDebug() << span << *span;
+#endif
+
+    for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
+        int y = -it_y.key();
+        if (y < start) {
+            ++it_y;
+            continue;
+        }
+
+        index.insert(-y - delta, it_y.value());
+        it_y = index.erase(it_y);
+    }
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug() << index;
+#endif
+}
+
+/** \internal
+* Updates the span collection after column insertion.
+*/
+void QSpanCollection::updateInsertedColumns(int start, int end)
+{
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug() << Q_FUNC_INFO;
+    qDebug() << start << end;
+    qDebug() << index;
+#endif
+    if (spans.isEmpty())
+        return;
+
+    int delta = end - start + 1;
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug("Before");
+#endif
+    for (SpanList::iterator it = spans.begin(); it != spans.end(); ++it) {
+        Span *span = *it;
+#ifdef DEBUG_SPAN_UPDATE
+        qDebug() << span << *span;
+#endif
+        if (span->m_right < start)
+            continue;
+        if (span->m_left >= start)
+            span->m_left += delta;
+        span->m_right += delta;
+    }
+
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug("After");
+    foreach (QSpanCollection::Span *span, spans)
+        qDebug() << span << *span;
+#endif
+
+    for (Index::iterator it_y = index.begin(); it_y != index.end(); ++it_y) {
+        SubIndex &subindex = it_y.value();
+        for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ) {
+            int x = -it.key();
+            if (x < start) {
+                ++it;
+                continue;
+            }
+            subindex.insert(-x - delta, it.value());
+            it = subindex.erase(it);
+        }
+    }
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug() << index;
+#endif
+}
+
+/** \internal
+* Cleans a subindex from to be deleted spans. The update argument is used
+* to move the spans inside the subindex, in case their anchor changed.
+* \return true if no span in this subindex starts at y, and should thus be deleted.
+*/
+bool QSpanCollection::cleanSpanSubIndex(QSpanCollection::SubIndex &subindex, int y, bool update)
+{
+    if (subindex.isEmpty())
+        return true;
+
+    bool should_be_deleted = true;
+    SubIndex::iterator it = subindex.end();
+    do {
+        --it;
+        int x = -it.key();
+        Span *span = it.value();
+        if (span->will_be_deleted) {
+            it = subindex.erase(it);
+            continue;
+        }
+        if (update && span->m_left != x) {
+            subindex.insert(-span->m_left, span);
+            it = subindex.erase(it);
+        }
+        if (should_be_deleted && span->m_top == y)
+            should_be_deleted = false;
+    } while (it != subindex.begin());
+
+    return should_be_deleted;
+}
+
+/** \internal
+* Updates the span collection after row removal.
+*/
+void QSpanCollection::updateRemovedRows(int start, int end)
+{
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug() << Q_FUNC_INFO;
+    qDebug() << start << end;
+    qDebug() << index;
+#endif
+    if (spans.isEmpty())
+        return;
+
+    SpanList spansToBeDeleted;
+    int delta = end - start + 1;
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug("Before");
+#endif
+    for (SpanList::iterator it = spans.begin(); it != spans.end(); ) {
+        Span *span = *it;
+#ifdef DEBUG_SPAN_UPDATE
+        qDebug() << span << *span;
+#endif
+        if (span->m_bottom < start) {
+            ++it;
+            continue;
+        }
+        if (span->m_top < start) {
+            if (span->m_bottom <= end)
+                span->m_bottom = start - 1;
+            else
+                span->m_bottom -= delta;
+        } else {
+            if (span->m_bottom > end) {
+                if (span->m_top <= end)
+                    span->m_top = start;
+                else
+                    span->m_top -= delta;
+                span->m_bottom -= delta;
+            } else {
+                span->will_be_deleted = true;
+            }
+        }
+        if (span->m_top == span->m_bottom && span->m_left == span->m_right)
+            span->will_be_deleted = true;
+        if (span->will_be_deleted) {
+            spansToBeDeleted.append(span);
+            it = spans.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug("After");
+    foreach (QSpanCollection::Span *span, spans)
+        qDebug() << span << *span;
+#endif
+    if (spans.isEmpty()) {
+        qDeleteAll(spansToBeDeleted);
+        index.clear();
+        return;
+    }
+
+    Index::iterator it_y = index.end();
+    do {
+        --it_y;
+        int y = -it_y.key();
+        SubIndex &subindex = it_y.value();
+        if (y < start) {
+            if (cleanSpanSubIndex(subindex, y))
+                it_y = index.erase(it_y);
+        } else if (y >= start && y <= end) {
+            bool span_at_start = false;
+            SubIndex spansToBeMoved;
+            for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ++it) {
+                Span *span = it.value();
+                if (span->will_be_deleted)
+                    continue;
+                if (!span_at_start && span->m_top == start)
+                    span_at_start = true;
+                spansToBeMoved.insert(it.key(), span);
+            }
+
+            if (y == start && span_at_start)
+                subindex.clear();
+            else
+                it_y = index.erase(it_y);
+
+            if (span_at_start) {
+                Index::iterator it_start;
+                if (y == start)
+                    it_start = it_y;
+                else {
+                    it_start = index.find(-start);
+                    if (it_start == index.end())
+                        it_start = index.insert(-start, SubIndex());
+                }
+                SubIndex &start_subindex = it_start.value();
+                for (SubIndex::iterator it = spansToBeMoved.begin(); it != spansToBeMoved.end(); ++it)
+                    start_subindex.insert(it.key(), it.value());
+            }
+        } else {
+            if (y == end + 1) {
+                Index::iterator it_top = index.find(-y + delta);
+                if (it_top == index.end())
+                    it_top = index.insert(-y + delta, SubIndex());
+                for (SubIndex::iterator it = subindex.begin(); it != subindex.end(); ) {
+                    Span *span = it.value();
+                    if (!span->will_be_deleted)
+                        it_top.value().insert(it.key(), span);
+                    ++it;
+                }
+            } else {
+                index.insert(-y + delta, subindex);
+            }
+            it_y = index.erase(it_y);
+        }
+    } while (it_y != index.begin());
+
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug() << index;
+    qDebug("Deleted");
+    foreach (QSpanCollection::Span *span, spansToBeDeleted)
+        qDebug() << span << *span;
+#endif
+    qDeleteAll(spansToBeDeleted);
+}
+
+/** \internal
+* Updates the span collection after column removal.
+*/
+void QSpanCollection::updateRemovedColumns(int start, int end)
+{
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug() << Q_FUNC_INFO;
+    qDebug() << start << end;
+    qDebug() << index;
+#endif
+    if (spans.isEmpty())
+        return;
+
+    SpanList toBeDeleted;
+    int delta = end - start + 1;
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug("Before");
+#endif
+    for (SpanList::iterator it = spans.begin(); it != spans.end(); ) {
+        Span *span = *it;
+#ifdef DEBUG_SPAN_UPDATE
+        qDebug() << span << *span;
+#endif
+        if (span->m_right < start) {
+            ++it;
+            continue;
+        }
+        if (span->m_left < start) {
+            if (span->m_right <= end)
+                span->m_right = start - 1;
+            else
+                span->m_right -= delta;
+        } else {
+            if (span->m_right > end) {
+                if (span->m_left <= end)
+                    span->m_left = start;
+                else
+                    span->m_left -= delta;
+                span->m_right -= delta;
+            } else {
+                span->will_be_deleted = true;
+            }
+        }
+        if (span->m_top == span->m_bottom && span->m_left == span->m_right)
+            span->will_be_deleted = true;
+        if (span->will_be_deleted) {
+            toBeDeleted.append(span);
+            it = spans.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug("After");
+    foreach (QSpanCollection::Span *span, spans)
+        qDebug() << span << *span;
+#endif
+    if (spans.isEmpty()) {
+        qDeleteAll(toBeDeleted);
+        index.clear();
+        return;
+    }
+
+    for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
+        int y = -it_y.key();
+        if (cleanSpanSubIndex(it_y.value(), y, true))
+            it_y = index.erase(it_y);
+        else
+            ++it_y;
+    }
+
+#ifdef DEBUG_SPAN_UPDATE
+    qDebug() << index;
+    qDebug("Deleted");
+    foreach (QSpanCollection::Span *span, toBeDeleted)
+        qDebug() << span << *span;
+#endif
+    qDeleteAll(toBeDeleted);
+}
+
+class QTableCornerButton : public QAbstractButton
+{
+    Q_OBJECT
+public:
+    QTableCornerButton(QWidget *parent) : QAbstractButton(parent) {}
+    void paintEvent(QPaintEvent*) {
+        QStyleOptionHeader opt;
+        opt.init(this);
+        QStyle::State state = QStyle::State_None;
+        if (isEnabled())
+            state |= QStyle::State_Enabled;
+        if (isActiveWindow())
+            state |= QStyle::State_Active;
+        if (isDown())
+            state |= QStyle::State_Sunken;
+        opt.state = state;
+        opt.rect = rect();
+        opt.position = QStyleOptionHeader::OnlyOneSection;
+        QPainter painter(this);
+        style()->drawControl(QStyle::CE_Header, &opt, &painter, this);
+    }
+};
+
+void QTableViewPrivate::init()
+{
+    Q_Q(QTableView);
+
+    q->setEditTriggers(editTriggers|QAbstractItemView::AnyKeyPressed);
+
+    QHeaderView *vertical = new QHeaderView(Qt::Vertical, q);
+    vertical->setClickable(true);
+    vertical->setHighlightSections(true);
+    q->setVerticalHeader(vertical);
+
+    QHeaderView *horizontal = new QHeaderView(Qt::Horizontal, q);
+    horizontal->setClickable(true);
+    horizontal->setHighlightSections(true);
+    q->setHorizontalHeader(horizontal);
+
+    tabKeyNavigation = true;
+
+    cornerWidget = new QTableCornerButton(q);
+    cornerWidget->setFocusPolicy(Qt::NoFocus);
+    QObject::connect(cornerWidget, SIGNAL(clicked()), q, SLOT(selectAll()));
+}
+
+/*!
+  \internal
+  Trims away indices that are hidden in the treeview due to hidden horizontal or vertical sections.
+*/
+void QTableViewPrivate::trimHiddenSelections(QItemSelectionRange *range) const
+{
+    Q_ASSERT(range && range->isValid());
+
+    int top = range->top();
+    int left = range->left();
+    int bottom = range->bottom();
+    int right = range->right();
+
+    while (bottom >= top && verticalHeader->isSectionHidden(bottom))
+        --bottom;
+    while (right >= left && horizontalHeader->isSectionHidden(right))
+        --right;
+
+    if (top > bottom || left > right) { // everything is hidden
+        *range = QItemSelectionRange();
+        return;
+    }
+
+    while (verticalHeader->isSectionHidden(top) && top <= bottom)
+        ++top;
+    while (horizontalHeader->isSectionHidden(left) && left <= right)
+        ++left;
+
+    if (top > bottom || left > right) { // everything is hidden
+        *range = QItemSelectionRange();
+        return;
+    }
+
+    QModelIndex bottomRight = model->index(bottom, right, range->parent());
+    QModelIndex topLeft = model->index(top, left, range->parent());
+    *range = QItemSelectionRange(topLeft, bottomRight);
+}
+
+/*!
+  \internal
+  Sets the span for the cell at (\a row, \a column).
+*/
+void QTableViewPrivate::setSpan(int row, int column, int rowSpan, int columnSpan)
+{
+    if (row < 0 || column < 0 || rowSpan <= 0 || columnSpan <= 0) {
+        qWarning() << "QTableView::setSpan: invalid span given: (" << row << ',' << column << ',' << rowSpan << ',' << columnSpan << ')';
+        return;
+    }
+    QSpanCollection::Span *sp = spans.spanAt(column, row);
+    if (sp) {
+        if (sp->top() != row || sp->left() != column) {
+            qWarning() << "QTableView::setSpan: span cannot overlap";
+            return;
+        }
+        if (rowSpan == 1 && columnSpan == 1) {
+            rowSpan = columnSpan = 0;
+        }
+        const int old_height = sp->height();
+        sp->m_bottom = row + rowSpan - 1;
+        sp->m_right = column + columnSpan - 1;
+        spans.updateSpan(sp, old_height);
+        return;
+    } else if (rowSpan == 1 && columnSpan == 1) {
+        qWarning() << "QTableView::setSpan: single cell span won't be added";
+        return;
+    }
+    sp = new QSpanCollection::Span(row, column, rowSpan, columnSpan);
+    spans.addSpan(sp);
+}
+
+/*!
+  \internal
+  Gets the span information for the cell at (\a row, \a column).
+*/
+QSpanCollection::Span QTableViewPrivate::span(int row, int column) const
+{
+    QSpanCollection::Span *sp = spans.spanAt(column, row);
+    if (sp)
+        return *sp;
+
+    return QSpanCollection::Span(row, column, 1, 1);
+}
+
+/*!
+  \internal
+  Returns the logical index of the last section that's part of the span.
+*/
+int QTableViewPrivate::sectionSpanEndLogical(const QHeaderView *header, int logical, int span) const
+{
+    int visual = header->visualIndex(logical);
+    for (int i = 1; i < span; ) {
+        if (++visual >= header->count())
+            break;
+        logical = header->logicalIndex(visual);
+        ++i;
+    }
+    return logical;
+}
+
+/*!
+  \internal
+  Returns the size of the span starting at logical index \a logical
+  and spanning \a span sections.
+*/
+int QTableViewPrivate::sectionSpanSize(const QHeaderView *header, int logical, int span) const
+{
+    int endLogical = sectionSpanEndLogical(header, logical, span);
+    return header->sectionPosition(endLogical)
+        - header->sectionPosition(logical)
+        + header->sectionSize(endLogical);
+}
+
+/*!
+  \internal
+  Returns true if the section at logical index \a logical is part of the span
+  starting at logical index \a spanLogical and spanning \a span sections;
+  otherwise, returns false.
+*/
+bool QTableViewPrivate::spanContainsSection(const QHeaderView *header, int logical, int spanLogical, int span) const
+{
+    if (logical == spanLogical)
+        return true; // it's the start of the span
+    int visual = header->visualIndex(spanLogical);
+    for (int i = 1; i < span; ) {
+        if (++visual >= header->count())
+            break;
+        spanLogical = header->logicalIndex(visual);
+        if (logical == spanLogical)
+            return true;
+        ++i;
+    }
+    return false;
+}
+
+/*!
+  \internal
+  Returns the visual rect for the given \a span.
+*/
+QRect QTableViewPrivate::visualSpanRect(const QSpanCollection::Span &span) const
+{
+    Q_Q(const QTableView);
+    // vertical
+    int row = span.top();
+    int rowp = verticalHeader->sectionViewportPosition(row);
+    int rowh = rowSpanHeight(row, span.height());
+    // horizontal
+    int column = span.left();
+    int colw = columnSpanWidth(column, span.width());
+    if (q->isRightToLeft())
+        column = span.right();
+    int colp = horizontalHeader->sectionViewportPosition(column);
+
+    const int i = showGrid ? 1 : 0;
+    if (q->isRightToLeft())
+        return QRect(colp + i, rowp, colw - i, rowh - i);
+    return QRect(colp, rowp, colw - i, rowh - i);
+}
+
+/*!
+  \internal
+  Draws the spanning cells within rect \a area, and clips them off as
+  preparation for the main drawing loop.
+  \a drawn is a QBitArray of visualRowCountxvisualCoulumnCount which say if particular cell has been drawn
+*/
+void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter,
+                                         const QStyleOptionViewItemV4 &option, QBitArray *drawn,
+                                         int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn)
+{
+    bool alternateBase = false;
+    QRegion region = viewport->rect();
+
+    QList<QSpanCollection::Span *> visibleSpans;
+    bool sectionMoved = verticalHeader->sectionsMoved() || horizontalHeader->sectionsMoved();
+
+    if (!sectionMoved) {
+        visibleSpans = spans.spansInRect(logicalColumn(firstVisualColumn), logicalRow(firstVisualRow),
+                                         lastVisualColumn - firstVisualColumn + 1, lastVisualRow - firstVisualRow + 1);
+    } else {
+        QSet<QSpanCollection::Span *> set;
+        for(int x = firstVisualColumn; x <= lastVisualColumn; x++)
+            for(int y = firstVisualRow; y <= lastVisualRow; y++)
+                set.insert(spans.spanAt(x,y));
+        set.remove(0);
+        visibleSpans = set.toList();
+    }
+
+    foreach (QSpanCollection::Span *span, visibleSpans) {
+        int row = span->top();
+        int col = span->left();
+        QModelIndex index = model->index(row, col, root);
+        if (!index.isValid())
+            continue;
+        QRect rect = visualSpanRect(*span);
+        rect.translate(scrollDelayOffset);
+        if (!area.intersects(rect))
+            continue;
+        QStyleOptionViewItemV4 opt = option;
+        opt.rect = rect;
+        alternateBase = alternatingColors && (span->top() & 1);
+        if (alternateBase)
+            opt.features |= QStyleOptionViewItemV2::Alternate;
+        else
+            opt.features &= ~QStyleOptionViewItemV2::Alternate;
+        drawCell(painter, opt, index);
+        region -= rect;
+        for (int r = span->top(); r <= span->bottom(); ++r) {
+            const int vr = visualRow(r);
+            if (vr < firstVisualRow || vr > lastVisualRow)
+                continue;
+            for (int c = span->left(); c <= span->right(); ++c) {
+                const int vc = visualColumn(c);
+                if (vc < firstVisualColumn  || vc > lastVisualColumn)
+                    continue;
+                drawn->setBit((vr - firstVisualRow) * (lastVisualColumn - firstVisualColumn + 1)
+                             + vc - firstVisualColumn);
+            }
+        }
+
+    }
+    painter->setClipRegion(region);
+}
+
+/*!
+  \internal
+  Updates spans after row insertion.
+*/
+void QTableViewPrivate::_q_updateSpanInsertedRows(const QModelIndex &parent, int start, int end)
+{
+    Q_UNUSED(parent)
+    spans.updateInsertedRows(start, end);
+}
+
+/*!
+  \internal
+  Updates spans after column insertion.
+*/
+void QTableViewPrivate::_q_updateSpanInsertedColumns(const QModelIndex &parent, int start, int end)
+{
+    Q_UNUSED(parent)
+    spans.updateInsertedColumns(start, end);
+}
+
+/*!
+  \internal
+  Updates spans after row removal.
+*/
+void QTableViewPrivate::_q_updateSpanRemovedRows(const QModelIndex &parent, int start, int end)
+{
+    Q_UNUSED(parent)
+    spans.updateRemovedRows(start, end);
+}
+
+/*!
+  \internal
+  Updates spans after column removal.
+*/
+void QTableViewPrivate::_q_updateSpanRemovedColumns(const QModelIndex &parent, int start, int end)
+{
+    Q_UNUSED(parent)
+    spans.updateRemovedColumns(start, end);
+}
+
+/*!
+  \internal
+  Draws a table cell.
+*/
+void QTableViewPrivate::drawCell(QPainter *painter, const QStyleOptionViewItemV4 &option, const QModelIndex &index)
+{
+    Q_Q(QTableView);
+    QStyleOptionViewItemV4 opt = option;
+
+    if (selectionModel && selectionModel->isSelected(index))
+        opt.state |= QStyle::State_Selected;
+    if (index == hover)
+        opt.state |= QStyle::State_MouseOver;
+    if (option.state & QStyle::State_Enabled) {
+        QPalette::ColorGroup cg;
+        if ((model->flags(index) & Qt::ItemIsEnabled) == 0) {
+            opt.state &= ~QStyle::State_Enabled;
+            cg = QPalette::Disabled;
+        } else {
+            cg = QPalette::Normal;
+        }
+        opt.palette.setCurrentColorGroup(cg);
+    }
+
+    if (index == q->currentIndex()) {
+        const bool focus = (q->hasFocus() || viewport->hasFocus()) && q->currentIndex().isValid();
+        if (focus)
+            opt.state |= QStyle::State_HasFocus;
+    }
+
+    q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, q);
+
+    if (const QWidget *widget = editorForIndex(index).editor) {
+        painter->save();
+        painter->setClipRect(widget->geometry());
+        q->itemDelegate(index)->paint(painter, opt, index);
+        painter->restore();
+    } else {
+        q->itemDelegate(index)->paint(painter, opt, index);
+    }
+}
+
+/*!
+    \class QTableView
+
+    \brief The QTableView class provides a default model/view
+    implementation of a table view.
+
+    \ingroup model-view
+    \ingroup advanced
+
+
+    A QTableView implements a table view that displays items from a
+    model. This class is used to provide standard tables that were
+    previously provided by the QTable class, but using the more
+    flexible approach provided by Qt's model/view architecture.
+
+    The QTableView class is one of the \l{Model/View Classes}
+    and is part of Qt's \l{Model/View Programming}{model/view framework}.
+
+    QTableView implements the interfaces defined by the
+    QAbstractItemView class to allow it to display data provided by
+    models derived from the QAbstractItemModel class.
+
+    \section1 Navigation
+
+    You can navigate the cells in the table by clicking on a cell with the
+    mouse, or by using the arrow keys. Because QTableView enables
+    \l{QAbstractItemView::tabKeyNavigation}{tabKeyNavigation} by default, you
+    can also hit Tab and Backtab to move from cell to cell.
+
+    \section1 Visual Appearance
+
+    The table has a vertical header that can be obtained using the
+    verticalHeader() function, and a horizontal header that is available
+    through the horizontalHeader() function. The height of each row in the
+    table can be found by using rowHeight(); similarly, the width of
+    columns can be found using columnWidth().  Since both of these are plain
+    widgets, you can hide either of them using their hide() functions.
+
+    Rows and columns can be hidden and shown with hideRow(), hideColumn(),
+    showRow(), and showColumn(). They can be selected with selectRow()
+    and selectColumn(). The table will show a grid depending on the
+    \l showGrid property.
+
+    The items shown in a table view, like those in the other item views, are
+    rendered and edited using standard \l{QItemDelegate}{delegates}. However,
+    for some tasks it is sometimes useful to be able to insert widgets in a
+    table instead. Widgets are set for particular indexes with the
+    \l{QAbstractItemView::}{setIndexWidget()} function, and
+    later retrieved with \l{QAbstractItemView::}{indexWidget()}.
+
+    \table
+    \row \o \inlineimage qtableview-resized.png
+    \o By default, the cells in a table do not expand to fill the available space.
+
+    You can make the cells fill the available space by stretching the last
+    header section. Access the relevant header using horizontalHeader()
+    or verticalHeader() and set the header's \l{QHeaderView::}{stretchLastSection}
+    property.
+
+    To distribute the available space according to the space requirement of
+    each column or row, call the view's resizeColumnsToContents() or
+    resizeRowsToContents() functions.
+    \endtable
+
+    \section1 Coordinate Systems
+
+    For some specialized forms of tables it is useful to be able to
+    convert between row and column indexes and widget coordinates.
+    The rowAt() function provides the y-coordinate within the view of the
+    specified row; the row index can be used to obtain a corresponding
+    y-coordinate with rowViewportPosition(). The columnAt() and
+    columnViewportPosition() functions provide the equivalent conversion
+    operations between x-coordinates and column indexes.
+
+    \section1 Styles
+
+    QTableView is styled appropriately for each platform. The following images show
+    how it looks on three different platforms. Go to the \l{Qt Widget Gallery} to see
+    its appearance in other styles.
+
+    \table 100%
+    \row \o \inlineimage windowsxp-tableview.png Screenshot of a Windows XP style table view
+         \o \inlineimage macintosh-tableview.png Screenshot of a Macintosh style table view
+         \o \inlineimage plastique-tableview.png Screenshot of a Plastique style table view
+    \row \o A \l{Windows XP Style Widget Gallery}{Windows XP style} table view.
+         \o A \l{Macintosh Style Widget Gallery}{Macintosh style} table view.
+         \o A \l{Plastique Style Widget Gallery}{Plastique style} table view.
+    \endtable
+
+    \sa QTableWidget, {View Classes}, QAbstractItemModel, QAbstractItemView,
+        {Chart Example}, {Pixelator Example}, {Table Model Example}
+*/
+
+/*!
+    Constructs a table view with a \a parent to represent the data.
+
+    \sa QAbstractItemModel
+*/
+
+QTableView::QTableView(QWidget *parent)
+    : QAbstractItemView(*new QTableViewPrivate, parent)
+{
+    Q_D(QTableView);
+    d->init();
+}
+
+/*!
+  \internal
+*/
+QTableView::QTableView(QTableViewPrivate &dd, QWidget *parent)
+    : QAbstractItemView(dd, parent)
+{
+    Q_D(QTableView);
+    d->init();
+}
+
+/*!
+  Destroys the table view.
+*/
+QTableView::~QTableView()
+{
+}
+
+/*!
+  \reimp
+*/
+void QTableView::setModel(QAbstractItemModel *model)
+{
+    Q_D(QTableView);
+    connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+            this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
+    connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
+            this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
+    connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+            this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
+    connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
+            this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
+    d->verticalHeader->setModel(model);
+    d->horizontalHeader->setModel(model);
+    QAbstractItemView::setModel(model);
+}
+
+/*!
+  \reimp
+*/
+void QTableView::setRootIndex(const QModelIndex &index)
+{
+    Q_D(QTableView);
+    if (index == d->root) {
+        viewport()->update();
+        return;
+    }
+    d->verticalHeader->setRootIndex(index);
+    d->horizontalHeader->setRootIndex(index);
+    QAbstractItemView::setRootIndex(index);
+}
+
+/*!
+  \reimp
+*/
+void QTableView::setSelectionModel(QItemSelectionModel *selectionModel)
+{
+    Q_D(QTableView);
+    Q_ASSERT(selectionModel);
+    d->verticalHeader->setSelectionModel(selectionModel);
+    d->horizontalHeader->setSelectionModel(selectionModel);
+    QAbstractItemView::setSelectionModel(selectionModel);
+}
+
+/*!
+    Returns the table view's horizontal header.
+
+    \sa setHorizontalHeader(), verticalHeader(), QAbstractItemModel::headerData()
+*/
+QHeaderView *QTableView::horizontalHeader() const
+{
+    Q_D(const QTableView);
+    return d->horizontalHeader;
+}
+
+/*!
+    Returns the table view's vertical header.
+
+    \sa setVerticalHeader(), horizontalHeader(), QAbstractItemModel::headerData()
+*/
+QHeaderView *QTableView::verticalHeader() const
+{
+    Q_D(const QTableView);
+    return d->verticalHeader;
+}
+
+/*!
+    Sets the widget to use for the horizontal header to \a header.
+
+    \sa horizontalHeader() setVerticalHeader()
+*/
+void QTableView::setHorizontalHeader(QHeaderView *header)
+{
+    Q_D(QTableView);
+
+    if (!header || header == d->horizontalHeader)
+        return;
+    if (d->horizontalHeader && d->horizontalHeader->parent() == this)
+        delete d->horizontalHeader;
+    d->horizontalHeader = header;
+    d->horizontalHeader->setParent(this);
+    if (!d->horizontalHeader->model()) {
+        d->horizontalHeader->setModel(d->model);
+        if (d->selectionModel)
+            d->horizontalHeader->setSelectionModel(d->selectionModel);
+    }
+
+    connect(d->horizontalHeader,SIGNAL(sectionResized(int,int,int)),
+            this, SLOT(columnResized(int,int,int)));
+    connect(d->horizontalHeader, SIGNAL(sectionMoved(int,int,int)),
+            this, SLOT(columnMoved(int,int,int)));
+    connect(d->horizontalHeader, SIGNAL(sectionCountChanged(int,int)),
+            this, SLOT(columnCountChanged(int,int)));
+    connect(d->horizontalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectColumn(int)));
+    connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectColumn(int)));
+    connect(d->horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
+            this, SLOT(resizeColumnToContents(int)));
+    connect(d->horizontalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
+
+    //update the sorting enabled states on the new header
+    setSortingEnabled(d->sortingEnabled);
+}
+
+/*!
+    Sets the widget to use for the vertical header to \a header.
+
+    \sa verticalHeader() setHorizontalHeader()
+*/
+void QTableView::setVerticalHeader(QHeaderView *header)
+{
+    Q_D(QTableView);
+
+    if (!header || header == d->verticalHeader)
+        return;
+    if (d->verticalHeader && d->verticalHeader->parent() == this)
+        delete d->verticalHeader;
+    d->verticalHeader = header;
+    d->verticalHeader->setParent(this);
+    if (!d->verticalHeader->model()) {
+        d->verticalHeader->setModel(d->model);
+        if (d->selectionModel)
+            d->verticalHeader->setSelectionModel(d->selectionModel);
+    }
+
+    connect(d->verticalHeader, SIGNAL(sectionResized(int,int,int)),
+            this, SLOT(rowResized(int,int,int)));
+    connect(d->verticalHeader, SIGNAL(sectionMoved(int,int,int)),
+            this, SLOT(rowMoved(int,int,int)));
+    connect(d->verticalHeader, SIGNAL(sectionCountChanged(int,int)),
+            this, SLOT(rowCountChanged(int,int)));
+    connect(d->verticalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectRow(int)));
+    connect(d->verticalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectRow(int)));
+    connect(d->verticalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
+            this, SLOT(resizeRowToContents(int)));
+    connect(d->verticalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
+}
+
+/*!
+    \internal
+
+    Scroll the contents of the table view by (\a dx, \a dy).
+*/
+void QTableView::scrollContentsBy(int dx, int dy)
+{
+    Q_D(QTableView);
+
+    d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
+
+    dx = isRightToLeft() ? -dx : dx;
+    if (dx) {
+        if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
+            int oldOffset = d->horizontalHeader->offset();
+            if (horizontalScrollBar()->value() == horizontalScrollBar()->maximum())
+                d->horizontalHeader->setOffsetToLastSection();
+            else
+                d->horizontalHeader->setOffsetToSectionPosition(horizontalScrollBar()->value());
+            int newOffset = d->horizontalHeader->offset();
+            dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset;
+        } else {
+            d->horizontalHeader->setOffset(horizontalScrollBar()->value());
+        }
+    }
+    if (dy) {
+        if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
+            int oldOffset = d->verticalHeader->offset();
+            if (verticalScrollBar()->value() == verticalScrollBar()->maximum())
+                d->verticalHeader->setOffsetToLastSection();
+            else
+                d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value());
+            int newOffset = d->verticalHeader->offset();
+            dy = oldOffset - newOffset;
+        } else {
+            d->verticalHeader->setOffset(verticalScrollBar()->value());
+        }
+    }
+    d->scrollContentsBy(dx, dy);
+
+    if (d->showGrid) {
+        //we need to update the first line of the previous top item in the view
+        //because it has the grid drawn if the header is invisible.
+        //It is strictly related to what's done at then end of the paintEvent
+        if (dy > 0 && d->horizontalHeader->isHidden() && d->verticalScrollMode == ScrollPerItem) {
+            d->viewport->update(0, dy, d->viewport->width(), dy);
+        }
+        if (dx > 0 && d->verticalHeader->isHidden() && d->horizontalScrollMode == ScrollPerItem) {
+            d->viewport->update(dx, 0, dx, d->viewport->height());
+        }
+    }
+}
+
+/*!
+  \reimp
+*/
+QStyleOptionViewItem QTableView::viewOptions() const
+{
+    QStyleOptionViewItem option = QAbstractItemView::viewOptions();
+    option.showDecorationSelected = true;
+    return option;
+}
+
+/*!
+    Paints the table on receipt of the given paint event \a event.
+*/
+void QTableView::paintEvent(QPaintEvent *event)
+{
+    Q_D(QTableView);
+    // setup temp variables for the painting
+    QStyleOptionViewItemV4 option = d->viewOptionsV4();
+    const QPoint offset = d->scrollDelayOffset;
+    const bool showGrid = d->showGrid;
+    const int gridSize = showGrid ? 1 : 0;
+    const int gridHint = style()->styleHint(QStyle::SH_Table_GridLineColor, &option, this);
+    const QColor gridColor = static_cast<QRgb>(gridHint);
+    const QPen gridPen = QPen(gridColor, 0, d->gridStyle);
+    const QHeaderView *verticalHeader = d->verticalHeader;
+    const QHeaderView *horizontalHeader = d->horizontalHeader;
+    const QStyle::State state = option.state;
+    const bool alternate = d->alternatingColors;
+    const bool rightToLeft = isRightToLeft();
+
+    QPainter painter(d->viewport);
+
+    // if there's nothing to do, clear the area and return
+    if (horizontalHeader->count() == 0 || verticalHeader->count() == 0 || !d->itemDelegate)
+        return;
+
+    uint x = horizontalHeader->length() - horizontalHeader->offset() - (rightToLeft ? 0 : 1);
+    uint y = verticalHeader->length() - verticalHeader->offset() - 1;
+
+    const QRegion region = event->region().translated(offset);
+    const QVector<QRect> rects = region.rects();
+
+    //firstVisualRow is the visual index of the first visible row.  lastVisualRow is the visual index of the last visible Row.
+    //same goes for ...VisualColumn
+    int firstVisualRow = qMax(verticalHeader->visualIndexAt(0),0);
+    int lastVisualRow = verticalHeader->visualIndexAt(verticalHeader->viewport()->height());
+    if (lastVisualRow == -1)
+        lastVisualRow = d->model->rowCount(d->root) - 1;
+
+    int firstVisualColumn = horizontalHeader->visualIndexAt(0);
+    int lastVisualColumn = horizontalHeader->visualIndexAt(horizontalHeader->viewport()->width());
+    if (rightToLeft)
+        qSwap(firstVisualColumn, lastVisualColumn);
+    if (firstVisualColumn == -1)
+        firstVisualColumn = 0;
+    if (lastVisualColumn == -1)
+        lastVisualColumn = horizontalHeader->count() - 1;
+
+    QBitArray drawn((lastVisualRow - firstVisualRow + 1) * (lastVisualColumn - firstVisualColumn + 1));
+
+    if (d->hasSpans()) {
+        d->drawAndClipSpans(region, &painter, option, &drawn,
+                             firstVisualRow, lastVisualRow, firstVisualColumn, lastVisualColumn);
+    }
+
+    for (int i = 0; i < rects.size(); ++i) {
+        QRect dirtyArea = rects.at(i);
+        dirtyArea.setBottom(qMin(dirtyArea.bottom(), int(y)));
+        if (rightToLeft) {
+            dirtyArea.setLeft(qMax(dirtyArea.left(), d->viewport->width() - int(x)));
+        } else {
+            dirtyArea.setRight(qMin(dirtyArea.right(), int(x)));
+        }
+
+        // get the horizontal start and end visual sections
+        int left = horizontalHeader->visualIndexAt(dirtyArea.left());
+        int right = horizontalHeader->visualIndexAt(dirtyArea.right());
+        if (rightToLeft)
+            qSwap(left, right);
+        if (left == -1) left = 0;
+        if (right == -1) right = horizontalHeader->count() - 1;
+
+        // get the vertical start and end visual sections and if alternate color
+        int bottom = verticalHeader->visualIndexAt(dirtyArea.bottom());
+        if (bottom == -1) bottom = verticalHeader->count() - 1;
+        int top = 0;
+        bool alternateBase = false;
+        if (alternate && verticalHeader->sectionsHidden()) {
+            uint verticalOffset = verticalHeader->offset();
+            int row = verticalHeader->logicalIndex(top);
+            for (int y = 0;
+                 ((uint)(y += verticalHeader->sectionSize(top)) <= verticalOffset) && (top < bottom);
+                 ++top) {
+                row = verticalHeader->logicalIndex(top);
+                if (alternate && !verticalHeader->isSectionHidden(row))
+                    alternateBase = !alternateBase;
+            }
+        } else {
+            top = verticalHeader->visualIndexAt(dirtyArea.top());
+            alternateBase = (top & 1) && alternate;
+        }
+        if (top == -1 || top > bottom)
+            continue;
+
+        // Paint each row item
+        for (int visualRowIndex = top; visualRowIndex <= bottom; ++visualRowIndex) {
+            int row = verticalHeader->logicalIndex(visualRowIndex);
+            if (verticalHeader->isSectionHidden(row))
+                continue;
+            int rowY = rowViewportPosition(row);
+            rowY += offset.y();
+            int rowh = rowHeight(row) - gridSize;
+
+            // Paint each column item
+            for (int visualColumnIndex = left; visualColumnIndex <= right; ++visualColumnIndex) {
+                int currentBit = (visualRowIndex - firstVisualRow) * (lastVisualColumn - firstVisualColumn + 1)
+                        + visualColumnIndex - firstVisualColumn;
+
+                if (currentBit < 0 || currentBit >= drawn.size() || drawn.testBit(currentBit))
+                    continue;
+                drawn.setBit(currentBit);
+
+                int col = horizontalHeader->logicalIndex(visualColumnIndex);
+                if (horizontalHeader->isSectionHidden(col))
+                    continue;
+                int colp = columnViewportPosition(col);
+                colp += offset.x();
+                int colw = columnWidth(col) - gridSize;
+
+                const QModelIndex index = d->model->index(row, col, d->root);
+                if (index.isValid()) {
+                    option.rect = QRect(colp + (showGrid && rightToLeft ? 1 : 0), rowY, colw, rowh);
+                    if (alternate) {
+                        if (alternateBase)
+                            option.features |= QStyleOptionViewItemV2::Alternate;
+                        else
+                            option.features &= ~QStyleOptionViewItemV2::Alternate;
+                    }
+                    d->drawCell(&painter, option, index);
+                }
+            }
+            alternateBase = !alternateBase && alternate;
+        }
+
+        if (showGrid) {
+            // Find the bottom right (the last rows/coloumns might be hidden)
+            while (verticalHeader->isSectionHidden(verticalHeader->logicalIndex(bottom))) --bottom;
+            QPen old = painter.pen();
+            painter.setPen(gridPen);
+            // Paint each row
+            for (int visualIndex = top; visualIndex <= bottom; ++visualIndex) {
+                int row = verticalHeader->logicalIndex(visualIndex);
+                if (verticalHeader->isSectionHidden(row))
+                    continue;
+                int rowY = rowViewportPosition(row);
+                rowY += offset.y();
+                int rowh = rowHeight(row) - gridSize;
+                painter.drawLine(dirtyArea.left(), rowY + rowh, dirtyArea.right(), rowY + rowh);
+            }
+
+            // Paint each column
+            for (int h = left; h <= right; ++h) {
+                int col = horizontalHeader->logicalIndex(h);
+                if (horizontalHeader->isSectionHidden(col))
+                    continue;
+                int colp = columnViewportPosition(col);
+                colp += offset.x();
+                if (!rightToLeft)
+                    colp +=  columnWidth(col) - gridSize;
+                painter.drawLine(colp, dirtyArea.top(), colp, dirtyArea.bottom());
+            }
+
+            //draw the top & left grid lines if the headers are not visible.
+            //We do update this line when subsequent scroll happen (see scrollContentsBy)
+            if (horizontalHeader->isHidden() && verticalScrollMode() == ScrollPerItem)
+                painter.drawLine(dirtyArea.left(), 0, dirtyArea.right(), 0);
+            if (verticalHeader->isHidden() && horizontalScrollMode() == ScrollPerItem)
+                painter.drawLine(0, dirtyArea.top(), 0, dirtyArea.bottom());
+            painter.setPen(old);
+        }
+    }
+
+#ifndef QT_NO_DRAGANDDROP
+    // Paint the dropIndicator
+    d->paintDropIndicator(&painter);
+#endif
+}
+
+/*!
+    Returns the index position of the model item corresponding to the
+    table item at position \a pos in contents coordinates.
+*/
+QModelIndex QTableView::indexAt(const QPoint &pos) const
+{
+    Q_D(const QTableView);
+    d->executePostedLayout();
+    int r = rowAt(pos.y());
+    int c = columnAt(pos.x());
+    if (r >= 0 && c >= 0) {
+        if (d->hasSpans()) {
+            QSpanCollection::Span span = d->span(r, c);
+            r = span.top();
+            c = span.left();
+        }
+        return d->model->index(r, c, d->root);
+    }
+    return QModelIndex();
+}
+
+/*!
+    Returns the horizontal offset of the items in the table view.
+
+    Note that the table view uses the horizontal header section
+    positions to determine the positions of columns in the view.
+
+    \sa verticalOffset()
+*/
+int QTableView::horizontalOffset() const
+{
+    Q_D(const QTableView);
+    return d->horizontalHeader->offset();
+}
+
+/*!
+    Returns the vertical offset of the items in the table view.
+
+    Note that the table view uses the vertical header section
+    positions to determine the positions of rows in the view.
+
+    \sa horizontalOffset()
+*/
+int QTableView::verticalOffset() const
+{
+    Q_D(const QTableView);
+    return d->verticalHeader->offset();
+}
+
+/*!
+    \fn QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
+
+    Moves the cursor in accordance with the given \a cursorAction, using the
+    information provided by the \a modifiers.
+
+    \sa QAbstractItemView::CursorAction
+*/
+QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
+{
+    Q_D(QTableView);
+    Q_UNUSED(modifiers);
+
+    int bottom = d->model->rowCount(d->root) - 1;
+    // make sure that bottom is the bottommost *visible* row
+    while (bottom >= 0 && isRowHidden(d->logicalRow(bottom)))
+        --bottom;
+
+    int right = d->model->columnCount(d->root) - 1;
+
+    while (right >= 0 && isColumnHidden(d->logicalColumn(right)))
+        --right;
+
+    if (bottom == -1 || right == -1)
+        return QModelIndex(); // model is empty
+
+    QModelIndex current = currentIndex();
+
+    if (!current.isValid()) {
+        int row = 0;
+        int column = 0;
+        while (column < right && isColumnHidden(d->logicalColumn(column)))
+            ++column;
+        while (isRowHidden(d->logicalRow(row)) && row < bottom)
+            ++row;
+        d->visualCursor = QPoint(column, row);
+        return d->model->index(d->logicalRow(row), d->logicalColumn(column), d->root);
+    }
+
+    // Update visual cursor if current index has changed.
+    QPoint visualCurrent(d->visualColumn(current.column()), d->visualRow(current.row()));
+    if (visualCurrent != d->visualCursor) {
+        if (d->hasSpans()) {
+            QSpanCollection::Span span = d->span(current.row(), current.column());
+            if (span.top() > d->visualCursor.y() || d->visualCursor.y() > span.bottom()
+                || span.left() > d->visualCursor.x() || d->visualCursor.x() > span.right())
+                d->visualCursor = visualCurrent;
+        } else {
+            d->visualCursor = visualCurrent;
+        }
+    }
+
+    int visualRow = d->visualCursor.y();
+    if (visualRow > bottom)
+        visualRow = bottom;
+    Q_ASSERT(visualRow != -1);
+    int visualColumn = d->visualCursor.x();
+    if (visualColumn > right)
+        visualColumn = right;
+    Q_ASSERT(visualColumn != -1);
+
+    if (isRightToLeft()) {
+        if (cursorAction == MoveLeft)
+            cursorAction = MoveRight;
+        else if (cursorAction == MoveRight)
+            cursorAction = MoveLeft;
+    }
+
+    switch (cursorAction) {
+    case MoveUp: {
+        int originalRow = visualRow;
+#ifdef QT_KEYPAD_NAVIGATION
+        if (QApplication::keypadNavigationEnabled() && visualRow == 0)
+            visualRow = d->visualRow(model()->rowCount() - 1) + 1;
+            // FIXME? visualRow = bottom + 1;
+#endif
+        int r = d->logicalRow(visualRow);
+        int c = d->logicalColumn(visualColumn);
+        if (r != -1 && d->hasSpans()) {
+            QSpanCollection::Span span = d->span(r, c);
+            if (span.width() > 1 || span.height() > 1)
+                visualRow = d->visualRow(span.top());
+        }
+        while (visualRow >= 0) {
+            --visualRow;
+            r = d->logicalRow(visualRow);
+            c = d->logicalColumn(visualColumn);
+            if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c)))
+                break;
+        }
+        if (visualRow < 0)
+            visualRow = originalRow;
+        break;
+    }
+    case MoveDown: {
+        int originalRow = visualRow;
+        if (d->hasSpans()) {
+            QSpanCollection::Span span = d->span(current.row(), current.column());
+            visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
+        }
+#ifdef QT_KEYPAD_NAVIGATION
+        if (QApplication::keypadNavigationEnabled() && visualRow >= bottom)
+            visualRow = -1;
+#endif
+        int r = d->logicalRow(visualRow);
+        int c = d->logicalColumn(visualColumn);
+        if (r != -1 && d->hasSpans()) {
+            QSpanCollection::Span span = d->span(r, c);
+            if (span.width() > 1 || span.height() > 1)
+                visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
+        }
+        while (visualRow <= bottom) {
+            ++visualRow;
+            r = d->logicalRow(visualRow);
+            c = d->logicalColumn(visualColumn);
+            if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c)))
+                break;
+        }
+        if (visualRow > bottom)
+            visualRow = originalRow;
+        break;
+    }
+    case MovePrevious:
+    case MoveLeft: {
+        int originalRow = visualRow;
+        int originalColumn = visualColumn;
+        bool firstTime = true;
+        bool looped = false;
+        bool wrapped = false;
+        do {
+            int r = d->logicalRow(visualRow);
+            int c = d->logicalColumn(visualColumn);
+            if (firstTime && c != -1 && d->hasSpans()) {
+                firstTime = false;
+                QSpanCollection::Span span = d->span(r, c);
+                if (span.width() > 1 || span.height() > 1)
+                    visualColumn = d->visualColumn(span.left());
+            }
+            while (visualColumn >= 0) {
+                --visualColumn;
+                r = d->logicalRow(visualRow);
+                c = d->logicalColumn(visualColumn);
+                if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c)))
+                    break;
+                if (wrapped && (originalRow < visualRow || (originalRow == visualRow && originalColumn <= visualColumn))) {
+                    looped = true;
+                    break;
+                }
+            }
+            if (cursorAction == MoveLeft || visualColumn >= 0)
+                break;
+            visualColumn = right + 1;
+            if (visualRow == 0) {
+                wrapped = true;
+                visualRow = bottom;
+            } else {
+                --visualRow;
+            }
+        } while (!looped);
+        if (visualColumn < 0)
+            visualColumn = originalColumn;
+        break;
+    }
+    case MoveNext:
+    case MoveRight: {
+        int originalRow = visualRow;
+        int originalColumn = visualColumn;
+        bool firstTime = true;
+        bool looped = false;
+        bool wrapped = false;
+        do {
+            int r = d->logicalRow(visualRow);
+            int c = d->logicalColumn(visualColumn);
+            if (firstTime && c != -1 && d->hasSpans()) {
+                firstTime = false;
+                QSpanCollection::Span span = d->span(r, c);
+                if (span.width() > 1 || span.height() > 1)
+                    visualColumn = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
+            }
+            while (visualColumn <= right) {
+                ++visualColumn;
+                r = d->logicalRow(visualRow);
+                c = d->logicalColumn(visualColumn);
+                if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c)))
+                    break;
+                if (wrapped && (originalRow > visualRow || (originalRow == visualRow && originalColumn >= visualColumn))) {
+                    looped = true;
+                    break;
+                }
+            }
+            if (cursorAction == MoveRight || visualColumn <= right)
+                break;
+            visualColumn = -1;
+            if (visualRow == bottom) {
+                wrapped = true;
+                visualRow = 0;
+            } else {
+                ++visualRow;
+            }
+        } while (!looped);
+        if (visualColumn > right)
+            visualColumn = originalColumn;
+        break;
+    }
+    case MoveHome:
+        visualColumn = 0;
+        while (visualColumn < right && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn))
+            ++visualColumn;
+        if (modifiers & Qt::ControlModifier) {
+            visualRow = 0;
+            while (visualRow < bottom && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn))
+                ++visualRow;
+        }
+        break;
+    case MoveEnd:
+        visualColumn = right;
+        if (modifiers & Qt::ControlModifier)
+            visualRow = bottom;
+        break;
+    case MovePageUp: {
+        int newRow = rowAt(visualRect(current).top() - d->viewport->height());
+        if (newRow == -1)
+            newRow = d->logicalRow(0);
+        return d->model->index(newRow, current.column(), d->root);
+    }
+    case MovePageDown: {
+        int newRow = rowAt(visualRect(current).bottom() + d->viewport->height());
+        if (newRow == -1)
+            newRow = d->logicalRow(bottom);
+        return d->model->index(newRow, current.column(), d->root);
+    }}
+
+    d->visualCursor = QPoint(visualColumn, visualRow);
+    int logicalRow = d->logicalRow(visualRow);
+    int logicalColumn = d->logicalColumn(visualColumn);
+    if (!d->model->hasIndex(logicalRow, logicalColumn, d->root))
+        return QModelIndex();
+
+    QModelIndex result = d->model->index(logicalRow, logicalColumn, d->root);
+    if (!d->isRowHidden(logicalRow) && !d->isColumnHidden(logicalColumn) && d->isIndexEnabled(result))
+        return result;
+
+    return QModelIndex();
+}
+
+/*!
+    \fn void QTableView::setSelection(const QRect &rect,
+    QItemSelectionModel::SelectionFlags flags)
+
+    Selects the items within the given \a rect and in accordance with
+    the specified selection \a flags.
+*/
+void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
+{
+    Q_D(QTableView);
+    QModelIndex tl = indexAt(QPoint(isRightToLeft() ? qMax(rect.left(), rect.right())
+                                    : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom())));
+    QModelIndex br = indexAt(QPoint(isRightToLeft() ? qMin(rect.left(), rect.right()) :
+                                    qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom())));
+    if (!d->selectionModel || !tl.isValid() || !br.isValid() || !d->isIndexEnabled(tl) || !d->isIndexEnabled(br))
+        return;
+
+    bool verticalMoved = verticalHeader()->sectionsMoved();
+    bool horizontalMoved = horizontalHeader()->sectionsMoved();
+
+    QItemSelection selection;
+
+    if (d->hasSpans()) {
+        bool expanded;
+        int top = qMin(d->visualRow(tl.row()), d->visualRow(br.row()));
+        int left = qMin(d->visualColumn(tl.column()), d->visualColumn(br.column()));
+        int bottom = qMax(d->visualRow(tl.row()), d->visualRow(br.row()));
+        int right = qMax(d->visualColumn(tl.column()), d->visualColumn(br.column()));
+        do {
+            expanded = false;
+            foreach (QSpanCollection::Span *it, d->spans.spans) {
+                const QSpanCollection::Span &span = *it;
+                int t = d->visualRow(span.top());
+                int l = d->visualColumn(span.left());
+                int b = d->visualRow(d->rowSpanEndLogical(span.top(), span.height()));
+                int r = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
+                if ((t > bottom) || (l > right) || (top > b) || (left > r))
+                    continue; // no intersect
+                if (t < top) {
+                    top = t;
+                    expanded = true;
+                }
+                if (l < left) {
+                    left = l;
+                    expanded = true;
+                }
+                if (b > bottom) {
+                    bottom = b;
+                    expanded = true;
+                }
+                if (r > right) {
+                    right = r;
+                    expanded = true;
+                }
+                if (expanded)
+                    break;
+            }
+        } while (expanded);
+         for (int horizontal = left; horizontal <= right; ++horizontal) {
+             int column = d->logicalColumn(horizontal);
+             for (int vertical = top; vertical <= bottom; ++vertical) {
+                 int row = d->logicalRow(vertical);
+                 QModelIndex index = d->model->index(row, column, d->root);
+                 selection.append(QItemSelectionRange(index));
+             }
+         }
+    } else if (verticalMoved && horizontalMoved) {
+         int top = d->visualRow(tl.row());
+         int left = d->visualColumn(tl.column());
+         int bottom = d->visualRow(br.row());
+         int right = d->visualColumn(br.column());
+         for (int horizontal = left; horizontal <= right; ++horizontal) {
+             int column = d->logicalColumn(horizontal);
+             for (int vertical = top; vertical <= bottom; ++vertical) {
+                 int row = d->logicalRow(vertical);
+                 QModelIndex index = d->model->index(row, column, d->root);
+                 selection.append(QItemSelectionRange(index));
+             }
+         }
+    } else if (horizontalMoved) {
+        int left = d->visualColumn(tl.column());
+        int right = d->visualColumn(br.column());
+        for (int visual = left; visual <= right; ++visual) {
+            int column = d->logicalColumn(visual);
+            QModelIndex topLeft = d->model->index(tl.row(), column, d->root);
+            QModelIndex bottomRight = d->model->index(br.row(), column, d->root);
+            selection.append(QItemSelectionRange(topLeft, bottomRight));
+        }
+    } else if (verticalMoved) {
+        int top = d->visualRow(tl.row());
+        int bottom = d->visualRow(br.row());
+        for (int visual = top; visual <= bottom; ++visual) {
+            int row = d->logicalRow(visual);
+            QModelIndex topLeft = d->model->index(row, tl.column(), d->root);
+            QModelIndex bottomRight = d->model->index(row, br.column(), d->root);
+            selection.append(QItemSelectionRange(topLeft, bottomRight));
+        }
+    } else { // nothing moved
+        selection.append(QItemSelectionRange(tl, br));
+    }
+
+    d->selectionModel->select(selection, command);
+}
+
+/*!
+    \internal
+
+    Returns the rectangle from the viewport of the items in the given
+    \a selection.
+*/
+QRegion QTableView::visualRegionForSelection(const QItemSelection &selection) const
+{
+    Q_D(const QTableView);
+
+    if (selection.isEmpty())
+        return QRegion();
+
+    QRegion selectionRegion;
+    bool verticalMoved = verticalHeader()->sectionsMoved();
+    bool horizontalMoved = horizontalHeader()->sectionsMoved();
+
+    if ((verticalMoved && horizontalMoved) || (d->hasSpans() && (verticalMoved || horizontalMoved))) {
+        for (int i = 0; i < selection.count(); ++i) {
+            QItemSelectionRange range = selection.at(i);
+            if (range.parent() != d->root || !range.isValid())
+                continue;
+            for (int r = range.top(); r <= range.bottom(); ++r)
+                for (int c = range.left(); c <= range.right(); ++c)
+                    selectionRegion += QRegion(visualRect(d->model->index(r, c, d->root)));
+        }
+    } else if (horizontalMoved) {
+        for (int i = 0; i < selection.count(); ++i) {
+            QItemSelectionRange range = selection.at(i);
+            if (range.parent() != d->root || !range.isValid())
+                continue;
+            int top = rowViewportPosition(range.top());
+            int bottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom());
+            if (top > bottom)
+                qSwap<int>(top, bottom);
+            int height = bottom - top;
+            for (int c = range.left(); c <= range.right(); ++c)
+                selectionRegion += QRegion(QRect(columnViewportPosition(c), top,
+                                                 columnWidth(c), height));
+        }
+    } else if (verticalMoved) {
+        for (int i = 0; i < selection.count(); ++i) {
+            QItemSelectionRange range = selection.at(i);
+            if (range.parent() != d->root || !range.isValid())
+                continue;
+            int left = columnViewportPosition(range.left());
+            int right = columnViewportPosition(range.right()) + columnWidth(range.right());
+            if (left > right)
+                qSwap<int>(left, right);
+            int width = right - left;
+            for (int r = range.top(); r <= range.bottom(); ++r)
+                selectionRegion += QRegion(QRect(left, rowViewportPosition(r),
+                                                 width, rowHeight(r)));
+        }
+    } else { // nothing moved
+        for (int i = 0; i < selection.count(); ++i) {
+            QItemSelectionRange range = selection.at(i);
+            if (range.parent() != d->root || !range.isValid())
+                continue;
+            d->trimHiddenSelections(&range);
+
+            const int rtop = rowViewportPosition(range.top());
+            const int rbottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom());
+            const int rleft = columnViewportPosition(range.left());
+            const int rright = columnViewportPosition(range.right()) + columnWidth(range.right());
+            selectionRegion += QRect(QPoint(rleft, rtop), QPoint(rright, rbottom));
+            if (d->hasSpans()) {
+                foreach (QSpanCollection::Span *s,
+                         d->spans.spansInRect(range.left(), range.top(), range.width(), range.height())) {
+                    if (range.contains(s->top(), s->left(), range.parent()))
+                        selectionRegion += d->visualSpanRect(*s);
+                }
+            }
+        }
+    }
+
+    return selectionRegion;
+}
+
+
+/*!
+  \reimp
+*/
+QModelIndexList QTableView::selectedIndexes() const
+{
+    Q_D(const QTableView);
+    QModelIndexList viewSelected;
+    QModelIndexList modelSelected;
+    if (d->selectionModel)
+        modelSelected = d->selectionModel->selectedIndexes();
+    for (int i = 0; i < modelSelected.count(); ++i) {
+        QModelIndex index = modelSelected.at(i);
+        if (!isIndexHidden(index) && index.parent() == d->root)
+            viewSelected.append(index);
+    }
+    return viewSelected;
+}
+
+
+/*!
+    This slot is called whenever rows are added or deleted. The
+    previous number of rows is specified by \a oldCount, and the new
+    number of rows is specified by \a newCount.
+*/
+void QTableView::rowCountChanged(int /*oldCount*/, int /*newCount*/ )
+{
+    Q_D(QTableView);
+    updateGeometries();
+    if (verticalScrollMode() == QAbstractItemView::ScrollPerItem)
+        d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value());
+    else
+        d->verticalHeader->setOffset(verticalScrollBar()->value());
+    d->viewport->update();
+}
+
+/*!
+    This slot is called whenever columns are added or deleted. The
+    previous number of columns is specified by \a oldCount, and the new
+    number of columns is specified by \a newCount.
+*/
+void QTableView::columnCountChanged(int, int)
+{
+    Q_D(QTableView);
+    updateGeometries();
+    if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem)
+        d->horizontalHeader->setOffsetToSectionPosition(horizontalScrollBar()->value());
+    else
+        d->horizontalHeader->setOffset(horizontalScrollBar()->value());
+    d->viewport->update();
+}
+
+/*!
+    \reimp
+*/
+void QTableView::updateGeometries()
+{
+    Q_D(QTableView);
+    if (d->geometryRecursionBlock)
+        return;
+    d->geometryRecursionBlock = true;
+
+    int width = 0;
+    if (!d->verticalHeader->isHidden()) {
+        width = qMax(d->verticalHeader->minimumWidth(), d->verticalHeader->sizeHint().width());
+        width = qMin(width, d->verticalHeader->maximumWidth());
+    }
+    int height = 0;
+    if (!d->horizontalHeader->isHidden()) {
+        height = qMax(d->horizontalHeader->minimumHeight(), d->horizontalHeader->sizeHint().height());
+        height = qMin(height, d->horizontalHeader->maximumHeight());
+    }
+    bool reverse = isRightToLeft();
+     if (reverse)
+         setViewportMargins(0, height, width, 0);
+     else
+         setViewportMargins(width, height, 0, 0);
+
+    // update headers
+
+    QRect vg = d->viewport->geometry();
+
+    int verticalLeft = reverse ? vg.right() + 1 : (vg.left() - width);
+    d->verticalHeader->setGeometry(verticalLeft, vg.top(), width, vg.height());
+    if (d->verticalHeader->isHidden())
+        QMetaObject::invokeMethod(d->verticalHeader, "updateGeometries");
+
+    int horizontalTop = vg.top() - height;
+    d->horizontalHeader->setGeometry(vg.left(), horizontalTop, vg.width(), height);
+    if (d->horizontalHeader->isHidden())
+        QMetaObject::invokeMethod(d->horizontalHeader, "updateGeometries");
+
+    // update cornerWidget
+    if (d->horizontalHeader->isHidden() || d->verticalHeader->isHidden()) {
+        d->cornerWidget->setHidden(true);
+    } else {
+        d->cornerWidget->setHidden(false);
+        d->cornerWidget->setGeometry(verticalLeft, horizontalTop, width, height);
+    }
+
+    // update scroll bars
+
+    // ### move this block into the if
+    QSize vsize = d->viewport->size();
+    QSize max = maximumViewportSize();
+    uint horizontalLength = d->horizontalHeader->length();
+    uint verticalLength = d->verticalHeader->length();
+    if ((uint)max.width() >= horizontalLength && (uint)max.height() >= verticalLength)
+        vsize = max;
+
+    // horizontal scroll bar
+    const int columnCount = d->horizontalHeader->count();
+    const int viewportWidth = vsize.width();
+    int columnsInViewport = 0;
+    for (int width = 0, column = columnCount - 1; column >= 0; --column) {
+        int logical = d->horizontalHeader->logicalIndex(column);
+        if (!d->horizontalHeader->isSectionHidden(logical)) {
+            width += d->horizontalHeader->sectionSize(logical);
+            if (width > viewportWidth)
+                break;
+            ++columnsInViewport;
+        }
+    }
+    columnsInViewport = qMax(columnsInViewport, 1); //there must be always at least 1 column
+
+    if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
+        const int visibleColumns = columnCount - d->horizontalHeader->hiddenSectionCount();
+        horizontalScrollBar()->setRange(0, visibleColumns - columnsInViewport);
+        horizontalScrollBar()->setPageStep(columnsInViewport);
+        if (columnsInViewport >= visibleColumns)
+            d->horizontalHeader->setOffset(0);
+        horizontalScrollBar()->setSingleStep(1);
+    } else { // ScrollPerPixel
+        horizontalScrollBar()->setPageStep(vsize.width());
+        horizontalScrollBar()->setRange(0, horizontalLength - vsize.width());
+        horizontalScrollBar()->setSingleStep(qMax(vsize.width() / (columnsInViewport + 1), 2));
+    }
+
+    // vertical scroll bar
+    const int rowCount = d->verticalHeader->count();
+    const int viewportHeight = vsize.height();
+    int rowsInViewport = 0;
+    for (int height = 0, row = rowCount - 1; row >= 0; --row) {
+        int logical = d->verticalHeader->logicalIndex(row);
+        if (!d->verticalHeader->isSectionHidden(logical)) {
+            height += d->verticalHeader->sectionSize(logical);
+            if (height > viewportHeight)
+                break;
+            ++rowsInViewport;
+        }
+    }
+    rowsInViewport = qMax(rowsInViewport, 1); //there must be always at least 1 row
+
+    if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
+        const int visibleRows = rowCount - d->verticalHeader->hiddenSectionCount();
+        verticalScrollBar()->setRange(0, visibleRows - rowsInViewport);
+        verticalScrollBar()->setPageStep(rowsInViewport);
+        if (rowsInViewport >= visibleRows)
+            d->verticalHeader->setOffset(0);
+        verticalScrollBar()->setSingleStep(1);
+    } else { // ScrollPerPixel
+        verticalScrollBar()->setPageStep(vsize.height());
+        verticalScrollBar()->setRange(0, verticalLength - vsize.height());
+        verticalScrollBar()->setSingleStep(qMax(vsize.height() / (rowsInViewport + 1), 2));
+    }
+
+    d->geometryRecursionBlock = false;
+    QAbstractItemView::updateGeometries();
+}
+
+/*!
+    Returns the size hint for the given \a row's height or -1 if there
+    is no model.
+
+    If you need to set the height of a given row to a fixed value, call
+    QHeaderView::resizeSection() on the table's vertical header.
+
+    If you reimplement this function in a subclass, note that the value you
+    return is only used when resizeRowToContents() is called. In that case,
+    if a larger row height is required by either the vertical header or
+    the item delegate, that width will be used instead.
+
+    \sa QWidget::sizeHint, verticalHeader()
+*/
+int QTableView::sizeHintForRow(int row) const
+{
+    Q_D(const QTableView);
+
+    if (!model())
+        return -1;
+
+    int left = qMax(0, columnAt(0));
+    int right = columnAt(d->viewport->width());
+    if (right == -1) // the table don't have enough columns to fill the viewport
+        right = d->model->columnCount(d->root) - 1;
+
+    QStyleOptionViewItemV4 option = d->viewOptionsV4();
+
+    int hint = 0;
+    QModelIndex index;
+    for (int column = left; column <= right; ++column) {
+        int logicalColumn = d->horizontalHeader->logicalIndex(column);
+        if (d->horizontalHeader->isSectionHidden(logicalColumn))
+            continue;
+        index = d->model->index(row, logicalColumn, d->root);
+        if (d->wrapItemText) {// for wrapping boundaries
+            option.rect.setY(rowViewportPosition(index.row()));
+            option.rect.setHeight(rowHeight(index.row()));
+            option.rect.setX(columnViewportPosition(index.column()));
+            option.rect.setWidth(columnWidth(index.column()));
+        }
+        
+        QWidget *editor = d->editorForIndex(index).editor;
+        if (editor && d->persistent.contains(editor)) {
+            hint = qMax(hint, editor->sizeHint().height());
+            int min = editor->minimumSize().height();
+            int max = editor->maximumSize().height();
+            hint = qBound(min, hint, max);
+        }
+        
+        hint = qMax(hint, itemDelegate(index)->sizeHint(option, index).height());
+    }
+
+    return d->showGrid ? hint + 1 : hint;
+}
+
+/*!
+    Returns the size hint for the given \a column's width or -1 if
+    there is no model.
+
+    If you need to set the width of a given column to a fixed value, call
+    QHeaderView::resizeSection() on the table's horizontal header.
+
+    If you reimplement this function in a subclass, note that the value you
+    return will be used when resizeColumnToContents() or
+    QHeaderView::resizeSections() is called. If a larger column width is
+    required by either the horizontal header or the item delegate, the larger
+    width will be used instead.
+
+    \sa QWidget::sizeHint, horizontalHeader()
+*/
+int QTableView::sizeHintForColumn(int column) const
+{
+    Q_D(const QTableView);
+
+    if (!model())
+        return -1;
+
+    int top = qMax(0, rowAt(0));
+    int bottom = rowAt(d->viewport->height());
+    if (!isVisible() || bottom == -1) // the table don't have enough rows to fill the viewport
+        bottom = d->model->rowCount(d->root) - 1;
+
+    QStyleOptionViewItemV4 option = d->viewOptionsV4();
+
+    int hint = 0;
+    QModelIndex index;
+    for (int row = top; row <= bottom; ++row) {
+        int logicalRow = d->verticalHeader->logicalIndex(row);
+        if (d->verticalHeader->isSectionHidden(logicalRow))
+            continue;
+        index = d->model->index(logicalRow, column, d->root);
+        
+        QWidget *editor = d->editorForIndex(index).editor;
+        if (editor && d->persistent.contains(editor)) {
+            hint = qMax(hint, editor->sizeHint().width());
+            int min = editor->minimumSize().width();
+            int max = editor->maximumSize().width();
+            hint = qBound(min, hint, max);
+        }
+        
+        hint = qMax(hint, itemDelegate(index)->sizeHint(option, index).width());
+    }
+
+    return d->showGrid ? hint + 1 : hint;
+}
+
+/*!
+    Returns the y-coordinate in contents coordinates of the given \a
+    row.
+*/
+int QTableView::rowViewportPosition(int row) const
+{
+    Q_D(const QTableView);
+    return d->verticalHeader->sectionViewportPosition(row);
+}
+
+/*!
+    Returns the row in which the given y-coordinate, \a y, in contents
+    coordinates is located.
+
+    \note This function returns -1 if the given coordinate is not valid
+    (has no row).
+
+    \sa columnAt()
+*/
+int QTableView::rowAt(int y) const
+{
+    Q_D(const QTableView);
+    return d->verticalHeader->logicalIndexAt(y);
+}
+
+/*!
+    \since 4.1
+
+    Sets the height of the given \a row to be \a height.
+*/
+void QTableView::setRowHeight(int row, int height)
+{
+    Q_D(const QTableView);
+    d->verticalHeader->resizeSection(row, height);
+}
+
+/*!
+    Returns the height of the given \a row.
+
+    \sa resizeRowToContents(), columnWidth()
+*/
+int QTableView::rowHeight(int row) const
+{
+    Q_D(const QTableView);
+    return d->verticalHeader->sectionSize(row);
+}
+
+/*!
+    Returns the x-coordinate in contents coordinates of the given \a
+    column.
+*/
+int QTableView::columnViewportPosition(int column) const
+{
+    Q_D(const QTableView);
+    return d->horizontalHeader->sectionViewportPosition(column);
+}
+
+/*!
+    Returns the column in which the given x-coordinate, \a x, in contents
+    coordinates is located.
+
+    \note This function returns -1 if the given coordinate is not valid
+    (has no column).
+
+    \sa rowAt()
+*/
+int QTableView::columnAt(int x) const
+{
+    Q_D(const QTableView);
+    return d->horizontalHeader->logicalIndexAt(x);
+}
+
+/*!
+    \since 4.1
+
+    Sets the width of the given \a column to be \a width.
+*/
+void QTableView::setColumnWidth(int column, int width)
+{
+    Q_D(const QTableView);
+    d->horizontalHeader->resizeSection(column, width);
+}
+
+/*!
+    Returns the width of the given \a column.
+
+    \sa resizeColumnToContents(), rowHeight()
+*/
+int QTableView::columnWidth(int column) const
+{
+    Q_D(const QTableView);
+    return d->horizontalHeader->sectionSize(column);
+}
+
+/*!
+    Returns true if the given \a row is hidden; otherwise returns false.
+
+    \sa isColumnHidden()
+*/
+bool QTableView::isRowHidden(int row) const
+{
+    Q_D(const QTableView);
+    return d->verticalHeader->isSectionHidden(row);
+}
+
+/*!
+    If \a hide is true \a row will be hidden, otherwise it will be shown.
+
+    \sa setColumnHidden()
+*/
+void QTableView::setRowHidden(int row, bool hide)
+{
+    Q_D(QTableView);
+    if (row < 0 || row >= d->verticalHeader->count())
+        return;
+    d->verticalHeader->setSectionHidden(row, hide);
+}
+
+/*!
+    Returns true if the given \a column is hidden; otherwise returns false.
+
+    \sa isRowHidden()
+*/
+bool QTableView::isColumnHidden(int column) const
+{
+    Q_D(const QTableView);
+    return d->horizontalHeader->isSectionHidden(column);
+}
+
+/*!
+  If \a hide is true the given \a column will be hidden; otherwise it
+  will be shown.
+
+  \sa setRowHidden()
+*/
+void QTableView::setColumnHidden(int column, bool hide)
+{
+    Q_D(QTableView);
+    if (column < 0 || column >= d->horizontalHeader->count())
+        return;
+    d->horizontalHeader->setSectionHidden(column, hide);
+}
+
+/*!
+    \since 4.2
+    \property QTableView::sortingEnabled
+    \brief whether sorting is enabled
+
+    If this property is true, sorting is enabled for the table; if the
+    property is false, sorting is not enabled. The default value is false.
+
+    \sa sortByColumn()
+*/
+
+void QTableView::setSortingEnabled(bool enable)
+{
+    Q_D(QTableView);
+    d->sortingEnabled = enable;
+    horizontalHeader()->setSortIndicatorShown(enable);
+    if (enable) {
+        disconnect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
+                   this, SLOT(_q_selectColumn(int)));
+        disconnect(horizontalHeader(), SIGNAL(sectionPressed(int)),
+                   this, SLOT(selectColumn(int)));
+        connect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
+                this, SLOT(sortByColumn(int)), Qt::UniqueConnection);
+        sortByColumn(horizontalHeader()->sortIndicatorSection(),
+                     horizontalHeader()->sortIndicatorOrder());
+    } else {
+        connect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
+                this, SLOT(_q_selectColumn(int)), Qt::UniqueConnection);
+        connect(horizontalHeader(), SIGNAL(sectionPressed(int)),
+                this, SLOT(selectColumn(int)), Qt::UniqueConnection);
+        disconnect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
+                   this, SLOT(sortByColumn(int)));
+    }
+}
+
+bool QTableView::isSortingEnabled() const
+{
+    Q_D(const QTableView);
+    return d->sortingEnabled;
+}
+
+/*!
+    \property QTableView::showGrid
+    \brief whether the grid is shown
+
+    If this property is true a grid is drawn for the table; if the
+    property is false, no grid is drawn. The default value is true.
+*/
+bool QTableView::showGrid() const
+{
+    Q_D(const QTableView);
+    return d->showGrid;
+}
+
+void QTableView::setShowGrid(bool show)
+{
+    Q_D(QTableView);
+    if (d->showGrid != show) {
+        d->showGrid = show;
+        d->viewport->update();
+    }
+}
+
+/*!
+  \property QTableView::gridStyle
+  \brief  the pen style used to draw the grid.
+
+  This property holds the style used when drawing the grid (see \l{showGrid}).
+*/
+Qt::PenStyle QTableView::gridStyle() const
+{
+    Q_D(const QTableView);
+    return d->gridStyle;
+}
+
+void QTableView::setGridStyle(Qt::PenStyle style)
+{
+    Q_D(QTableView);
+    if (d->gridStyle != style) {
+        d->gridStyle = style;
+        d->viewport->update();
+    }
+}
+
+/*!
+    \property QTableView::wordWrap
+    \brief the item text word-wrapping policy
+    \since 4.3
+
+    If this property is true then the item text is wrapped where
+    necessary at word-breaks; otherwise it is not wrapped at all.
+    This property is true by default.
+
+    Note that even of wrapping is enabled, the cell will not be
+    expanded to fit all text. Ellipsis will be inserted according to
+    the current \l{QAbstractItemView::}{textElideMode}.
+
+*/
+void QTableView::setWordWrap(bool on)
+{
+    Q_D(QTableView);
+    if (d->wrapItemText == on)
+        return;
+    d->wrapItemText = on;
+    QMetaObject::invokeMethod(d->verticalHeader, "resizeSections");
+    QMetaObject::invokeMethod(d->horizontalHeader, "resizeSections");
+}
+
+bool QTableView::wordWrap() const
+{
+    Q_D(const QTableView);
+    return d->wrapItemText;
+}
+
+/*!
+    \property QTableView::cornerButtonEnabled
+    \brief whether the button in the top-left corner is enabled
+    \since 4.3
+
+    If this property is true then button in the top-left corner
+    of the table view is enabled. Clicking on this button will
+    select all the cells in the table view.
+
+    This property is true by default.
+*/
+void QTableView::setCornerButtonEnabled(bool enable)
+{
+    Q_D(QTableView);
+    d->cornerWidget->setEnabled(enable);
+}
+
+bool QTableView::isCornerButtonEnabled() const
+{
+    Q_D(const QTableView);
+    return d->cornerWidget->isEnabled();
+}
+
+/*!
+    \internal
+
+    Returns the rectangle on the viewport occupied by the given \a
+    index.
+    If the index is hidden in the view it will return a null QRect.
+*/
+QRect QTableView::visualRect(const QModelIndex &index) const
+{
+    Q_D(const QTableView);
+    if (!d->isIndexValid(index) || index.parent() != d->root
+        || (!d->hasSpans() && isIndexHidden(index)))
+        return QRect();
+
+    d->executePostedLayout();
+
+    if (d->hasSpans()) {
+        QSpanCollection::Span span = d->span(index.row(), index.column());
+        return d->visualSpanRect(span);
+    }
+
+    int rowp = rowViewportPosition(index.row());
+    int rowh = rowHeight(index.row());
+    int colp = columnViewportPosition(index.column());
+    int colw = columnWidth(index.column());
+
+    const int i = showGrid() ? 1 : 0;
+    return QRect(colp, rowp, colw - i, rowh - i);
+}
+
+/*!
+    \internal
+
+    Makes sure that the given \a item is visible in the table view,
+    scrolling if necessary.
+*/
+void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint)
+{
+    Q_D(QTableView);
+
+    // check if we really need to do anything
+    if (!d->isIndexValid(index)
+        || (d->model->parent(index) != d->root)
+        || isIndexHidden(index))
+        return;
+
+    QSpanCollection::Span span;
+    if (d->hasSpans())
+        span = d->span(index.row(), index.column());
+
+    // Adjust horizontal position
+
+    int viewportWidth = d->viewport->width();
+    int horizontalOffset = d->horizontalHeader->offset();
+    int horizontalPosition = d->horizontalHeader->sectionPosition(index.column());
+    int horizontalIndex = d->horizontalHeader->visualIndex(index.column());
+    int cellWidth = d->hasSpans()
+                    ? d->columnSpanWidth(index.column(), span.width())
+                    : d->horizontalHeader->sectionSize(index.column());
+
+    if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
+
+        bool positionAtLeft = (horizontalPosition - horizontalOffset < 0);
+        bool positionAtRight = (horizontalPosition - horizontalOffset + cellWidth > viewportWidth);
+
+        if (hint == PositionAtCenter || positionAtRight) {
+            int w = (hint == PositionAtCenter ? viewportWidth / 2 : viewportWidth);
+            int x = cellWidth;
+            while (horizontalIndex > 0) {
+                x += columnWidth(d->horizontalHeader->logicalIndex(horizontalIndex-1));
+                if (x > w)
+                    break;
+                --horizontalIndex;
+            }
+        }
+
+        if (positionAtRight || hint == PositionAtCenter || positionAtLeft) {
+            int hiddenSections = 0;
+            if (d->horizontalHeader->sectionsHidden()) {
+                for (int s = horizontalIndex - 1; s >= 0; --s) {
+                    int column = d->horizontalHeader->logicalIndex(s);
+                    if (d->horizontalHeader->isSectionHidden(column))
+                        ++hiddenSections;
+                }
+            }
+            horizontalScrollBar()->setValue(horizontalIndex - hiddenSections);
+        }
+
+    } else { // ScrollPerPixel
+        if (hint == PositionAtCenter) {
+            horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
+        } else {
+            if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
+                horizontalScrollBar()->setValue(horizontalPosition);
+            else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
+                horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
+        }
+    }
+
+    // Adjust vertical position
+
+    int viewportHeight = d->viewport->height();
+    int verticalOffset = d->verticalHeader->offset();
+    int verticalPosition = d->verticalHeader->sectionPosition(index.row());
+    int verticalIndex = d->verticalHeader->visualIndex(index.row());
+    int cellHeight = d->hasSpans()
+                     ? d->rowSpanHeight(index.row(), span.height())
+                     : d->verticalHeader->sectionSize(index.row());
+
+    if (verticalPosition - verticalOffset < 0 || cellHeight > viewportHeight) {
+        if (hint == EnsureVisible)
+            hint = PositionAtTop;
+    } else if (verticalPosition - verticalOffset + cellHeight > viewportHeight) {
+        if (hint == EnsureVisible)
+            hint = PositionAtBottom;
+    }
+
+    if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
+
+        if (hint == PositionAtBottom || hint == PositionAtCenter) {
+            int h = (hint == PositionAtCenter ? viewportHeight / 2 : viewportHeight);
+            int y = cellHeight;
+            while (verticalIndex > 0) {
+                int row = d->verticalHeader->logicalIndex(verticalIndex - 1);
+                y += d->verticalHeader->sectionSize(row);
+                if (y > h)
+                    break;
+                --verticalIndex;
+            }
+        }
+
+        if (hint == PositionAtBottom || hint == PositionAtCenter || hint == PositionAtTop) {
+            int hiddenSections = 0;
+            if (d->verticalHeader->sectionsHidden()) {
+                for (int s = verticalIndex - 1; s >= 0; --s) {
+                    int row = d->verticalHeader->logicalIndex(s);
+                    if (d->verticalHeader->isSectionHidden(row))
+                        ++hiddenSections;
+                }
+            }
+            verticalScrollBar()->setValue(verticalIndex - hiddenSections);
+        }
+
+    } else { // ScrollPerPixel
+        if (hint == PositionAtTop) {
+            verticalScrollBar()->setValue(verticalPosition);
+        } else if (hint == PositionAtBottom) {
+            verticalScrollBar()->setValue(verticalPosition - viewportHeight + cellHeight);
+        } else if (hint == PositionAtCenter) {
+            verticalScrollBar()->setValue(verticalPosition - ((viewportHeight - cellHeight) / 2));
+        }
+    }
+
+    update(index);
+}
+
+/*!
+    This slot is called to change the height of the given \a row. The
+    old height is specified by \a oldHeight, and the new height by \a
+    newHeight.
+
+    \sa columnResized()
+*/
+void QTableView::rowResized(int row, int, int)
+{
+    Q_D(QTableView);
+    d->rowsToUpdate.append(row);
+    if (d->rowResizeTimerID == 0)
+        d->rowResizeTimerID = startTimer(0);
+}
+
+/*!
+    This slot is called to change the width of the given \a column.
+    The old width is specified by \a oldWidth, and the new width by \a
+    newWidth.
+
+    \sa rowResized()
+*/
+void QTableView::columnResized(int column, int, int)
+{
+    Q_D(QTableView);
+    d->columnsToUpdate.append(column);
+    if (d->columnResizeTimerID == 0)
+        d->columnResizeTimerID = startTimer(0);
+}
+
+/*!
+ \reimp
+ */
+void QTableView::timerEvent(QTimerEvent *event)
+{
+    Q_D(QTableView);
+
+    if (event->timerId() == d->columnResizeTimerID) {
+        updateGeometries();
+        killTimer(d->columnResizeTimerID);
+        d->columnResizeTimerID = 0;
+
+        QRect rect;
+        int viewportHeight = d->viewport->height();
+        int viewportWidth = d->viewport->width();
+        if (d->hasSpans()) {
+            rect = QRect(0, 0, viewportWidth, viewportHeight);
+        } else {
+            for (int i = d->columnsToUpdate.size()-1; i >= 0; --i) {
+                int column = d->columnsToUpdate.at(i);
+                int x = columnViewportPosition(column);
+                if (isRightToLeft())
+                    rect |= QRect(0, 0, x + columnWidth(column), viewportHeight);
+                else
+                    rect |= QRect(x, 0, viewportWidth - x, viewportHeight);
+            }
+        }
+
+        d->viewport->update(rect.normalized());
+        d->columnsToUpdate.clear();
+    }
+
+    if (event->timerId() == d->rowResizeTimerID) {
+        updateGeometries();
+        killTimer(d->rowResizeTimerID);
+        d->rowResizeTimerID = 0;
+
+        int viewportHeight = d->viewport->height();
+        int viewportWidth = d->viewport->width();
+        int top;
+        if (d->hasSpans()) {
+            top = 0;
+        } else {
+            top = viewportHeight;
+            for (int i = d->rowsToUpdate.size()-1; i >= 0; --i) {
+                int y = rowViewportPosition(d->rowsToUpdate.at(i));
+                top = qMin(top, y);
+            }
+        }
+
+        d->viewport->update(QRect(0, top, viewportWidth, viewportHeight - top));
+        d->rowsToUpdate.clear();
+    }
+
+    QAbstractItemView::timerEvent(event);
+}
+
+/*!
+    This slot is called to change the index of the given \a row in the
+    table view. The old index is specified by \a oldIndex, and the new
+    index by \a newIndex.
+
+    \sa columnMoved()
+*/
+void QTableView::rowMoved(int, int oldIndex, int newIndex)
+{
+    Q_D(QTableView);
+
+    updateGeometries();
+    int logicalOldIndex = d->verticalHeader->logicalIndex(oldIndex);
+    int logicalNewIndex = d->verticalHeader->logicalIndex(newIndex);
+    if (d->hasSpans()) {
+        d->viewport->update();
+    } else {
+        int oldTop = rowViewportPosition(logicalOldIndex);
+        int newTop = rowViewportPosition(logicalNewIndex);
+        int oldBottom = oldTop + rowHeight(logicalOldIndex);
+        int newBottom = newTop + rowHeight(logicalNewIndex);
+        int top = qMin(oldTop, newTop);
+        int bottom = qMax(oldBottom, newBottom);
+        int height = bottom - top;
+        d->viewport->update(0, top, d->viewport->width(), height);
+    }
+}
+
+/*!
+    This slot is called to change the index of the given \a column in
+    the table view. The old index is specified by \a oldIndex, and
+    the new index by \a newIndex.
+
+    \sa rowMoved()
+*/
+void QTableView::columnMoved(int, int oldIndex, int newIndex)
+{
+    Q_D(QTableView);
+
+    updateGeometries();
+    int logicalOldIndex = d->horizontalHeader->logicalIndex(oldIndex);
+    int logicalNewIndex = d->horizontalHeader->logicalIndex(newIndex);
+    if (d->hasSpans()) {
+        d->viewport->update();
+    } else {
+        int oldLeft = columnViewportPosition(logicalOldIndex);
+        int newLeft = columnViewportPosition(logicalNewIndex);
+        int oldRight = oldLeft + columnWidth(logicalOldIndex);
+        int newRight = newLeft + columnWidth(logicalNewIndex);
+        int left = qMin(oldLeft, newLeft);
+        int right = qMax(oldRight, newRight);
+        int width = right - left;
+        d->viewport->update(left, 0, width, d->viewport->height());
+    }
+}
+
+/*!
+    Selects the given \a row in the table view if the current
+    SelectionMode and SelectionBehavior allows rows to be selected.
+
+    \sa selectColumn()
+*/
+void QTableView::selectRow(int row)
+{
+    Q_D(QTableView);
+    d->selectRow(row, true);
+}
+
+/*!
+    Selects the given \a column in the table view if the current
+    SelectionMode and SelectionBehavior allows columns to be selected.
+
+    \sa selectRow()
+*/
+void QTableView::selectColumn(int column)
+{
+    Q_D(QTableView);
+    d->selectColumn(column, true);
+}
+
+/*!
+    Hide the given \a row.
+
+    \sa showRow() hideColumn()
+*/
+void QTableView::hideRow(int row)
+{
+    Q_D(QTableView);
+    d->verticalHeader->hideSection(row);
+}
+
+/*!
+    Hide the given \a column.
+
+    \sa showColumn() hideRow()
+*/
+void QTableView::hideColumn(int column)
+{
+    Q_D(QTableView);
+    d->horizontalHeader->hideSection(column);
+}
+
+/*!
+    Show the given \a row.
+
+    \sa hideRow() showColumn()
+*/
+void QTableView::showRow(int row)
+{
+    Q_D(QTableView);
+    d->verticalHeader->showSection(row);
+}
+
+/*!
+    Show the given \a column.
+
+    \sa hideColumn() showRow()
+*/
+void QTableView::showColumn(int column)
+{
+    Q_D(QTableView);
+    d->horizontalHeader->showSection(column);
+}
+
+/*!
+    Resizes the given \a row based on the size hints of the delegate
+    used to render each item in the row.
+*/
+void QTableView::resizeRowToContents(int row)
+{
+    Q_D(QTableView);
+    int content = sizeHintForRow(row);
+    int header = d->verticalHeader->sectionSizeHint(row);
+    d->verticalHeader->resizeSection(row, qMax(content, header));
+}
+
+/*!
+    Resizes all rows based on the size hints of the delegate
+    used to render each item in the rows.
+*/
+void QTableView::resizeRowsToContents()
+{
+    Q_D(QTableView);
+    d->verticalHeader->resizeSections(QHeaderView::ResizeToContents);
+}
+
+/*!
+    Resizes the given \a column based on the size hints of the delegate
+    used to render each item in the column.
+
+    \note Only visible columns will be resized. Reimplement sizeHintForColumn()
+    to resize hidden columns as well.
+*/
+void QTableView::resizeColumnToContents(int column)
+{
+    Q_D(QTableView);
+    int content = sizeHintForColumn(column);
+    int header = d->horizontalHeader->sectionSizeHint(column);
+    d->horizontalHeader->resizeSection(column, qMax(content, header));
+}
+
+/*!
+    Resizes all columns based on the size hints of the delegate
+    used to render each item in the columns.
+*/
+void QTableView::resizeColumnsToContents()
+{
+    Q_D(QTableView);
+    d->horizontalHeader->resizeSections(QHeaderView::ResizeToContents);
+}
+
+/*!
+  \obsolete
+  \overload
+
+  Sorts the model by the values in the given \a column.
+*/
+void QTableView::sortByColumn(int column)
+{
+    Q_D(QTableView);
+    if (column == -1)
+        return;
+    d->model->sort(column, d->horizontalHeader->sortIndicatorOrder());
+}
+
+/*!
+  \since 4.2
+
+  Sorts the model by the values in the given \a column in the given \a order.
+
+  \sa sortingEnabled
+ */
+void QTableView::sortByColumn(int column, Qt::SortOrder order)
+{
+    Q_D(QTableView);
+    d->horizontalHeader->setSortIndicator(column, order);
+    sortByColumn(column);
+}
+
+/*!
+    \internal
+*/
+void QTableView::verticalScrollbarAction(int action)
+{
+    QAbstractItemView::verticalScrollbarAction(action);
+}
+
+/*!
+    \internal
+*/
+void QTableView::horizontalScrollbarAction(int action)
+{
+    QAbstractItemView::horizontalScrollbarAction(action);
+}
+
+/*!
+  \reimp
+*/
+bool QTableView::isIndexHidden(const QModelIndex &index) const
+{
+    Q_D(const QTableView);
+    Q_ASSERT(d->isIndexValid(index));
+    if (isRowHidden(index.row()) || isColumnHidden(index.column()))
+        return true;
+    if (d->hasSpans()) {
+        QSpanCollection::Span span = d->span(index.row(), index.column());
+        return !((span.top() == index.row()) && (span.left() == index.column()));
+    }
+    return false;
+}
+
+/*!
+    \fn void QTableView::setSpan(int row, int column, int rowSpanCount, int columnSpanCount)
+    \since 4.2
+
+    Sets the span of the table element at (\a row, \a column) to the number of
+    rows and columns specified by (\a rowSpanCount, \a columnSpanCount).
+
+    \sa rowSpan(), columnSpan()
+*/
+void QTableView::setSpan(int row, int column, int rowSpan, int columnSpan)
+{
+    Q_D(QTableView);
+    if (row < 0 || column < 0 || rowSpan < 0 || columnSpan < 0)
+        return;
+    d->setSpan(row, column, rowSpan, columnSpan);
+    d->viewport->update();
+}
+
+/*!
+  \since 4.2
+
+  Returns the row span of the table element at (\a row, \a column).
+  The default is 1.
+
+  \sa setSpan(), columnSpan()
+*/
+int QTableView::rowSpan(int row, int column) const
+{
+    Q_D(const QTableView);
+    return d->rowSpan(row, column);
+}
+
+/*!
+  \since 4.2
+
+  Returns the column span of the table element at (\a row, \a
+  column). The default is 1.
+
+  \sa setSpan(), rowSpan()
+*/
+int QTableView::columnSpan(int row, int column) const
+{
+    Q_D(const QTableView);
+    return d->columnSpan(row, column);
+}
+
+/*!
+  \since 4.4
+
+  Removes all row and column spans in the table view.
+
+  \sa setSpan()
+*/
+
+void QTableView::clearSpans()
+{
+    Q_D(QTableView);
+    d->spans.clear();
+    d->viewport->update();
+}
+
+void QTableViewPrivate::_q_selectRow(int row)
+{
+    selectRow(row, false);
+}
+
+void QTableViewPrivate::_q_selectColumn(int column)
+{
+    selectColumn(column, false);
+}
+
+void QTableViewPrivate::selectRow(int row, bool anchor)
+{
+    Q_Q(QTableView);
+
+    if (q->selectionBehavior() == QTableView::SelectColumns
+        || (q->selectionMode() == QTableView::SingleSelection
+            && q->selectionBehavior() == QTableView::SelectItems))
+        return;
+
+    if (row >= 0 && row < model->rowCount(root)) {
+        int column = horizontalHeader->logicalIndexAt(q->isRightToLeft() ? viewport->width() : 0);
+        QModelIndex index = model->index(row, column, root);
+        QItemSelectionModel::SelectionFlags command = q->selectionCommand(index);
+        selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
+        if ((anchor && !(command & QItemSelectionModel::Current))
+            || (q->selectionMode() == QTableView::SingleSelection))
+            rowSectionAnchor = row;
+
+        if (q->selectionMode() != QTableView::SingleSelection
+            && command.testFlag(QItemSelectionModel::Toggle)) {
+            if (anchor)
+                ctrlDragSelectionFlag = verticalHeader->selectionModel()->selectedRows().contains(index)
+                                    ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
+            command &= ~QItemSelectionModel::Toggle;
+            command |= ctrlDragSelectionFlag;
+            if (!anchor)
+                command |= QItemSelectionModel::Current;
+        }
+
+        QModelIndex tl = model->index(qMin(rowSectionAnchor, row), 0, root);
+        QModelIndex br = model->index(qMax(rowSectionAnchor, row), model->columnCount(root) - 1, root);
+        if (verticalHeader->sectionsMoved() && tl.row() != br.row())
+            q->setSelection(q->visualRect(tl)|q->visualRect(br), command);
+        else
+            selectionModel->select(QItemSelection(tl, br), command);
+    }
+}
+
+void QTableViewPrivate::selectColumn(int column, bool anchor)
+{
+    Q_Q(QTableView);
+
+    if (q->selectionBehavior() == QTableView::SelectRows
+        || (q->selectionMode() == QTableView::SingleSelection
+            && q->selectionBehavior() == QTableView::SelectItems))
+        return;
+
+    if (column >= 0 && column < model->columnCount(root)) {
+        int row = verticalHeader->logicalIndexAt(0);
+        QModelIndex index = model->index(row, column, root);
+        QItemSelectionModel::SelectionFlags command = q->selectionCommand(index);
+        selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
+        if ((anchor && !(command & QItemSelectionModel::Current))
+            || (q->selectionMode() == QTableView::SingleSelection))
+            columnSectionAnchor = column;
+
+        if (q->selectionMode() != QTableView::SingleSelection
+            && command.testFlag(QItemSelectionModel::Toggle)) {
+            if (anchor)
+                ctrlDragSelectionFlag = horizontalHeader->selectionModel()->selectedColumns().contains(index)
+                                    ? QItemSelectionModel::Deselect : QItemSelectionModel::Select;
+            command &= ~QItemSelectionModel::Toggle;
+            command |= ctrlDragSelectionFlag;
+            if (!anchor)
+                command |= QItemSelectionModel::Current;
+        }
+
+        QModelIndex tl = model->index(0, qMin(columnSectionAnchor, column), root);
+        QModelIndex br = model->index(model->rowCount(root) - 1,
+                                      qMax(columnSectionAnchor, column), root);
+        if (horizontalHeader->sectionsMoved() && tl.column() != br.column())
+            q->setSelection(q->visualRect(tl)|q->visualRect(br), command);
+        else
+            selectionModel->select(QItemSelection(tl, br), command);
+    }
+}
+
+/*!
+  \reimp
+ */
+void QTableView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+#ifndef QT_NO_ACCESSIBILITY
+    if (QAccessible::isActive()) {
+        if (current.isValid()) {
+            int entry = visualIndex(current) + 1;
+            if (horizontalHeader())
+                ++entry;
+            QAccessible::updateAccessibility(viewport(), entry, QAccessible::Focus);
+        }
+    }
+#endif
+    QAbstractItemView::currentChanged(current, previous);
+}
+
+/*!
+  \reimp
+ */
+void QTableView::selectionChanged(const QItemSelection &selected,
+                                  const QItemSelection &deselected)
+{
+#ifndef QT_NO_ACCESSIBILITY
+    if (QAccessible::isActive()) {
+        // ### does not work properly for selection ranges.
+        QModelIndex sel = selected.indexes().value(0);
+        if (sel.isValid()) {
+            int entry = visualIndex(sel);
+            if (horizontalHeader())
+                ++entry;
+            QAccessible::updateAccessibility(viewport(), entry, QAccessible::Selection);
+        }
+        QModelIndex desel = deselected.indexes().value(0);
+        if (desel.isValid()) {
+            int entry = visualIndex(sel);
+            if (horizontalHeader())
+                ++entry;
+            QAccessible::updateAccessibility(viewport(), entry, QAccessible::SelectionRemove);
+        }
+    }
+#endif
+    QAbstractItemView::selectionChanged(selected, deselected);
+}
+
+int QTableView::visualIndex(const QModelIndex &index) const
+{
+    return index.row();
+}
+
+QT_END_NAMESPACE
+
+#include "qtableview.moc"
+
+#include "moc_qtableview.cpp"
+
+#endif // QT_NO_TABLEVIEW