summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/animation/qabstractanimation.cpp189
-rw-r--r--src/corelib/animation/qabstractanimation_p.h42
-rw-r--r--src/corelib/animation/qanimationgroup_p.h4
-rw-r--r--src/corelib/animation/qparallelanimationgroup.cpp8
-rw-r--r--src/corelib/animation/qpauseanimation.cpp1
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget.cpp2
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp11
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h2
-rw-r--r--src/gui/itemviews/qabstractitemview.cpp3
-rw-r--r--src/gui/itemviews/qtableview.cpp204
-rw-r--r--src/gui/itemviews/qtableview_p.h4
11 files changed, 340 insertions, 130 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
index 2769040..c775a00 100644
--- a/src/corelib/animation/qabstractanimation.cpp
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -144,6 +144,7 @@
#include "qabstractanimation.h"
#include "qanimationgroup.h"
+
#include <QtCore/qdebug.h>
#include "qabstractanimation_p.h"
@@ -176,7 +177,8 @@ Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer)
QUnifiedTimer::QUnifiedTimer() :
QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
- currentAnimationIdx(0), consistentTiming(false)
+ currentAnimationIdx(0), consistentTiming(false), isPauseTimerActive(false),
+ runningLeafAnimations(0)
{
}
@@ -192,50 +194,92 @@ QUnifiedTimer *QUnifiedTimer::instance()
return inst;
}
+void QUnifiedTimer::ensureTimerUpdate(QAbstractAnimation *animation)
+{
+ if (isPauseTimerActive) {
+ updateAnimationsTime();
+ } else {
+ // this code is needed when ensureTimerUpdate is called from setState because we update
+ // the currentTime when an animation starts running (otherwise we could remove it)
+ animation->setCurrentTime(animation->currentTime());
+ }
+}
+
+void QUnifiedTimer::updateAnimationsTime()
+{
+ // ignore consistentTiming in case the pause timer is active
+ const int delta = (consistentTiming && !isPauseTimerActive) ?
+ timingInterval : time.elapsed() - lastTick;
+ lastTick = time.elapsed();
+
+ //we make sure we only call update time if the time has actually changed
+ //it might happen in some cases that the time doesn't change because events are delayed
+ //when the CPU load is high
+ if (delta) {
+ for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
+ QAbstractAnimation *animation = animations.at(currentAnimationIdx);
+ int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime
+ + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
+ animation->setCurrentTime(elapsed);
+ }
+ currentAnimationIdx = 0;
+ }
+}
+
+void QUnifiedTimer::restartAnimationTimer()
+{
+ if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) {
+ int closestTimeToFinish = closestPauseAnimationTimeToFinish();
+ animationTimer.start(closestTimeToFinish, this);
+ isPauseTimerActive = true;
+ } else if (!animationTimer.isActive() || isPauseTimerActive) {
+ animationTimer.start(timingInterval, this);
+ isPauseTimerActive = false;
+ }
+}
+
void QUnifiedTimer::timerEvent(QTimerEvent *event)
{
if (event->timerId() == startStopAnimationTimer.timerId()) {
startStopAnimationTimer.stop();
+
//we transfer the waiting animations into the "really running" state
animations += animationsToStart;
animationsToStart.clear();
if (animations.isEmpty()) {
animationTimer.stop();
- } else if (!animationTimer.isActive()) {
- animationTimer.start(timingInterval, this);
- lastTick = 0;
- time.start();
- }
- } else if (event->timerId() == animationTimer.timerId()) {
- //this is simply the time we last received a tick
- const int oldLastTick = lastTick;
- lastTick = consistentTiming ? oldLastTick + timingInterval : time.elapsed();
-
- //we make sure we only call update time if the time has actually changed
- //it might happen in some cases that the time doesn't change because events are delayed
- //when the CPU load is high
- if (const int delta = lastTick - oldLastTick) {
- for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
- QAbstractAnimation *animation = animations.at(currentAnimationIdx);
- int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime
- + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
- animation->setCurrentTime(elapsed);
+ isPauseTimerActive = false;
+ // invalidate the start reference time
+ time = QTime();
+ } else {
+ restartAnimationTimer();
+ if (!time.isValid()) {
+ lastTick = 0;
+ time.start();
}
- currentAnimationIdx = 0;
}
+ } else if (event->timerId() == animationTimer.timerId()) {
+ // update current time on all top level animations
+ updateAnimationsTime();
+ restartAnimationTimer();
}
}
-void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation)
+void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
{
- Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
- QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
- animationsToStart << animation;
- startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this);
+ registerRunningAnimation(animation);
+ if (isTopLevel) {
+ Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
+ QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
+ animationsToStart << animation;
+ startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this);
+ }
}
void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
{
+ unregisterRunningAnimation(animation);
+
if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
return;
@@ -245,6 +289,7 @@ void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
// this is needed if we unregister an animation while its running
if (idx <= currentAnimationIdx)
--currentAnimationIdx;
+
if (animations.isEmpty())
startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this);
} else {
@@ -253,6 +298,46 @@ void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false;
}
+void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation)
+{
+ if (QAbstractAnimationPrivate::get(animation)->isGroup)
+ return;
+
+ if (QAbstractAnimationPrivate::get(animation)->isPause)
+ runningPauseAnimations << animation;
+ else
+ runningLeafAnimations++;
+}
+
+void QUnifiedTimer::unregisterRunningAnimation(QAbstractAnimation *animation)
+{
+ if (QAbstractAnimationPrivate::get(animation)->isGroup)
+ return;
+
+ if (QAbstractAnimationPrivate::get(animation)->isPause)
+ runningPauseAnimations.removeOne(animation);
+ else
+ runningLeafAnimations--;
+}
+
+int QUnifiedTimer::closestPauseAnimationTimeToFinish()
+{
+ int closestTimeToFinish = INT_MAX;
+ for (int i = 0; i < runningPauseAnimations.size(); ++i) {
+ QAbstractAnimation *animation = runningPauseAnimations.at(i);
+ int timeToFinish;
+
+ if (animation->direction() == QAbstractAnimation::Forward)
+ timeToFinish = animation->totalDuration() - QAbstractAnimationPrivate::get(animation)->totalCurrentTime;
+ else
+ timeToFinish = QAbstractAnimationPrivate::get(animation)->totalCurrentTime;
+
+ if (timeToFinish < closestTimeToFinish)
+ closestTimeToFinish = timeToFinish;
+ }
+ return closestTimeToFinish;
+}
+
void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
{
Q_Q(QAbstractAnimation);
@@ -270,7 +355,7 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
//here we reset the time if needed
//we don't call setCurrentTime because this might change the way the animation
//behaves: changing the state or changing the current value
- totalCurrentTime = currentTime =(direction == QAbstractAnimation::Forward) ?
+ totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ?
0 : (loopCount == -1 ? q->duration() : q->totalDuration());
}
@@ -292,22 +377,31 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
switch (state) {
case QAbstractAnimation::Paused:
+ if (hasRegisteredTimer)
+ // currentTime needs to be updated if pauseTimer is active
+ QUnifiedTimer::instance()->ensureTimerUpdate(q);
+ if (!guard)
+ return;
+ QUnifiedTimer::instance()->unregisterAnimation(q);
+ break;
case QAbstractAnimation::Running:
- //this ensures that the value is updated now that the animation is running
- if(oldState == QAbstractAnimation::Stopped) {
- q->setCurrentTime(currentTime);
- if (!guard)
- return;
- }
+ {
+ bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
+
+ // this ensures that the value is updated now that the animation is running
+ if (oldState == QAbstractAnimation::Stopped) {
+ if (isTopLevel)
+ // currentTime needs to be updated if pauseTimer is active
+ QUnifiedTimer::instance()->ensureTimerUpdate(q);
+ if (!guard)
+ return;
+ }
- // Register timer if our parent is not running.
- if (state == QAbstractAnimation::Running) {
- if (!group || group->state() == QAbstractAnimation::Stopped) {
- QUnifiedTimer::instance()->registerAnimation(q);
+ // test needed in case we stop in the setCurrentTime inside ensureTimerUpdate (zero duration)
+ if (state == QAbstractAnimation::Running) {
+ // register timer if our parent is not running
+ QUnifiedTimer::instance()->registerAnimation(q, isTopLevel);
}
- } else {
- //new state is paused
- QUnifiedTimer::instance()->unregisterAnimation(q);
}
break;
case QAbstractAnimation::Stopped:
@@ -452,7 +546,6 @@ void QAbstractAnimation::setDirection(Direction direction)
if (d->direction == direction)
return;
- d->direction = direction;
if (state() == Stopped) {
if (direction == Backward) {
d->currentTime = duration();
@@ -462,7 +555,19 @@ void QAbstractAnimation::setDirection(Direction direction)
d->currentLoop = 0;
}
}
+
+ // the commands order below is important: first we need to setCurrentTime with the old direction,
+ // then update the direction on this and all children and finally restart the pauseTimer if needed
+ if (d->hasRegisteredTimer)
+ QUnifiedTimer::instance()->ensureTimerUpdate(this);
+
+ d->direction = direction;
updateDirection(direction);
+
+ if (d->hasRegisteredTimer)
+ // needed to update the timer interval in case of a pause animation
+ QUnifiedTimer::instance()->restartAnimationTimer();
+
emit directionChanged(direction);
}
@@ -659,7 +764,7 @@ void QAbstractAnimation::stop()
/*!
Pauses the animation. When the animation is paused, state() returns Paused.
- The value of currentTime will remain unchanged until resume() or start()
+ The value of currentTime will remain unchanged until resume() or start()
is called. If you want to continue from the current time, call resume().
\sa start(), state(), resume()
diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h
index 1a79f40..bef0499 100644
--- a/src/corelib/animation/qabstractanimation_p.h
+++ b/src/corelib/animation/qabstractanimation_p.h
@@ -70,12 +70,14 @@ public:
QAbstractAnimationPrivate()
: state(QAbstractAnimation::Stopped),
direction(QAbstractAnimation::Forward),
- deleteWhenStopped(false),
totalCurrentTime(0),
currentTime(0),
loopCount(1),
currentLoop(0),
+ deleteWhenStopped(false),
hasRegisteredTimer(false),
+ isPause(false),
+ isGroup(false),
group(0)
{
}
@@ -89,7 +91,6 @@ public:
QAbstractAnimation::State state;
QAbstractAnimation::Direction direction;
- bool deleteWhenStopped;
void setState(QAbstractAnimation::State state);
int totalCurrentTime;
@@ -97,7 +98,10 @@ public:
int loopCount;
int currentLoop;
+ bool deleteWhenStopped;
bool hasRegisteredTimer;
+ bool isPause;
+ bool isGroup;
QAnimationGroup *group;
@@ -115,14 +119,14 @@ public:
//XXX this is needed by dui
static Q_CORE_EXPORT QUnifiedTimer *instance();
- void registerAnimation(QAbstractAnimation *animation);
+ void registerAnimation(QAbstractAnimation *animation, bool isTopLevel);
void unregisterAnimation(QAbstractAnimation *animation);
//defines the timing interval. Default is DEFAULT_TIMER_INTERVAL
void setTimingInterval(int interval)
{
timingInterval = interval;
- if (animationTimer.isActive()) {
+ if (animationTimer.isActive() && !isPauseTimerActive) {
//we changed the timing interval
animationTimer.start(timingInterval, this);
}
@@ -134,22 +138,46 @@ public:
*/
void setConsistentTiming(bool consistent) { consistentTiming = consistent; }
- int elapsedTime() const { return lastTick; }
+ /*
+ this is used for updating the currentTime of all animations in case the pause
+ timer is active or, otherwise, only of the animation passed as parameter.
+ */
+ void ensureTimerUpdate(QAbstractAnimation *animation);
+
+ /*
+ this will evaluate the need of restarting the pause timer in case there is still
+ some pause animations running.
+ */
+ void restartAnimationTimer();
protected:
void timerEvent(QTimerEvent *);
private:
- // timer used for all active animations
+ // timer used for all active (running) animations
QBasicTimer animationTimer;
- // timer used to delay the check if we should start/stop the global timer
+ // timer used to delay the check if we should start/stop the animation timer
QBasicTimer startStopAnimationTimer;
+
QTime time;
int lastTick;
int timingInterval;
int currentAnimationIdx;
bool consistentTiming;
+ // bool to indicate that only pause animations are active
+ bool isPauseTimerActive;
+
QList<QAbstractAnimation*> animations, animationsToStart;
+
+ // this is the count of running animations that are not a group neither a pause animation
+ int runningLeafAnimations;
+ QList<QAbstractAnimation*> runningPauseAnimations;
+
+ void registerRunningAnimation(QAbstractAnimation *animation);
+ void unregisterRunningAnimation(QAbstractAnimation *animation);
+
+ void updateAnimationsTime();
+ int closestPauseAnimationTimeToFinish();
};
QT_END_NAMESPACE
diff --git a/src/corelib/animation/qanimationgroup_p.h b/src/corelib/animation/qanimationgroup_p.h
index 45eab58..bb1cfb3 100644
--- a/src/corelib/animation/qanimationgroup_p.h
+++ b/src/corelib/animation/qanimationgroup_p.h
@@ -68,7 +68,9 @@ class QAnimationGroupPrivate : public QAbstractAnimationPrivate
Q_DECLARE_PUBLIC(QAnimationGroup)
public:
QAnimationGroupPrivate()
- { }
+ {
+ isGroup = true;
+ }
virtual void animationInsertedAt(int index) { Q_UNUSED(index) };
virtual void animationRemovedAt(int index);
diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp
index 2812854..0a04c14 100644
--- a/src/corelib/animation/qparallelanimationgroup.cpp
+++ b/src/corelib/animation/qparallelanimationgroup.cpp
@@ -136,7 +136,9 @@ void QParallelAnimationGroup::updateCurrentTime(int currentTime)
int dura = duration();
if (dura > 0) {
for (int i = 0; i < d->animations.size(); ++i) {
- d->animations.at(i)->setCurrentTime(dura); // will stop
+ QAbstractAnimation *animation = d->animations.at(i);
+ if (animation->state() != QAbstractAnimation::Stopped)
+ d->animations.at(i)->setCurrentTime(dura); // will stop
}
}
} else if (d->currentLoop < d->lastLoop) {
@@ -160,7 +162,7 @@ void QParallelAnimationGroup::updateCurrentTime(int currentTime)
QAbstractAnimation *animation = d->animations.at(i);
const int dura = animation->totalDuration();
//if the loopcount is bigger we should always start all animations
- if (d->currentLoop > d->lastLoop
+ if (d->currentLoop > d->lastLoop
//if we're at the end of the animation, we need to start it if it wasn't already started in this loop
//this happens in Backward direction where not all animations are started at the same time
|| d->shouldAnimationStart(animation, d->lastCurrentTime > dura /*startIfAtEnd*/)) {
@@ -283,7 +285,7 @@ bool QParallelAnimationGroupPrivate::shouldAnimationStart(QAbstractAnimation *an
void QParallelAnimationGroupPrivate::applyGroupState(QAbstractAnimation *animation)
{
- switch (state)
+ switch (state)
{
case QAbstractAnimation::Running:
animation->start();
diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp
index 2fd12aa..d90f001 100644
--- a/src/corelib/animation/qpauseanimation.cpp
+++ b/src/corelib/animation/qpauseanimation.cpp
@@ -75,6 +75,7 @@ class QPauseAnimationPrivate : public QAbstractAnimationPrivate
public:
QPauseAnimationPrivate() : QAbstractAnimationPrivate(), duration(0)
{
+ isPause = true;
}
int duration;
diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp
index 15b9ff3..b7a3962 100644
--- a/src/gui/graphicsview/qgraphicsproxywidget.cpp
+++ b/src/gui/graphicsview/qgraphicsproxywidget.cpp
@@ -973,7 +973,7 @@ void QGraphicsProxyWidget::hideEvent(QHideEvent *event)
void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
Q_D(QGraphicsProxyWidget);
- if (!event || !d->widget || !d->widget->isVisible())
+ if (!event || !d->widget || !d->widget->isVisible() || !hasFocus())
return;
// Find widget position and receiver.
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 0f33a66..0773559 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -420,8 +420,12 @@ void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
*/
void QGraphicsScenePrivate::_q_polishItems()
{
+ QSet<QGraphicsItem *>::Iterator it;
const QVariant booleanTrueVariant(true);
- foreach (QGraphicsItem *item, unpolishedItems) {
+ while (!unpolishedItems.isEmpty()) {
+ it = unpolishedItems.begin();
+ QGraphicsItem *item = *it;
+ unpolishedItems.erase(it);
if (!item->d_ptr->explicitlyHidden) {
item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant);
item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant);
@@ -431,7 +435,6 @@ void QGraphicsScenePrivate::_q_polishItems()
QApplication::sendEvent((QGraphicsWidget *)item, &event);
}
}
- unpolishedItems.clear();
}
void QGraphicsScenePrivate::_q_processDirtyItems()
@@ -549,7 +552,7 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
selectedItems.remove(item);
hoverItems.removeAll(item);
cachedItemsUnderMouse.removeAll(item);
- unpolishedItems.removeAll(item);
+ unpolishedItems.remove(item);
resetDirtyItem(item);
//We remove all references of item from the sceneEventFilter arrays
@@ -2484,7 +2487,7 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
if (!item->d_ptr->explicitlyHidden) {
if (d->unpolishedItems.isEmpty())
QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection);
- d->unpolishedItems << item;
+ d->unpolishedItems.insert(item);
}
// Reenable selectionChanged() for individual items
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index 5000860..8073695 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -108,7 +108,7 @@ public:
QPainterPath selectionArea;
int selectionChanging;
QSet<QGraphicsItem *> selectedItems;
- QList<QGraphicsItem *> unpolishedItems;
+ QSet<QGraphicsItem *> unpolishedItems;
QList<QGraphicsItem *> topLevelItems;
bool needSortTopLevelItems;
bool holesInTopLevelSiblingIndex;
diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp
index 37f4184..268e78e 100644
--- a/src/gui/itemviews/qabstractitemview.cpp
+++ b/src/gui/itemviews/qabstractitemview.cpp
@@ -2185,6 +2185,9 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event)
} else {
d->selectionModel->setCurrentIndex(newCurrent, command);
d->pressedPosition = visualRect(newCurrent).center() + d->offset();
+ // We copy the same behaviour as for mousePressEvent().
+ QRect rect(d->pressedPosition - d->offset(), QSize(1, 1));
+ setSelection(rect, command);
}
return;
}
diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp
index 15bd445..2d98258 100644
--- a/src/gui/itemviews/qtableview.cpp
+++ b/src/gui/itemviews/qtableview.cpp
@@ -779,8 +779,6 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter,
foreach (QSpanCollection::Span *span, visibleSpans) {
int row = span->top();
int col = span->left();
- if (isHidden(row, col))
- continue;
QModelIndex index = model->index(row, col, root);
if (!index.isValid())
continue;
@@ -1480,12 +1478,30 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
++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);
}
- int visualRow = d->visualRow(current.row());
+ // 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->visualColumn(current.column());
+ int visualColumn = d->visualCursor.x();
+ if (visualColumn > right)
+ visualColumn = right;
Q_ASSERT(visualColumn != -1);
if (isRightToLeft()) {
@@ -1496,22 +1512,33 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
}
switch (cursorAction) {
- case MoveUp:
+ 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
- --visualRow;
- while (visualRow > 0 && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn))
+ 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;
- if (d->hasSpans()) {
- int row = d->logicalRow(visualRow);
- QSpanCollection::Span span = d->span(row, current.column());
- visualRow = d->visualRow(span.top());
- visualColumn = d->visualColumn(span.left());
+ 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:
+ }
+ 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()));
@@ -1520,71 +1547,106 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
if (QApplication::keypadNavigationEnabled() && visualRow >= bottom)
visualRow = -1;
#endif
- ++visualRow;
- while (visualRow < bottom && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn))
+ 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;
- if (d->hasSpans()) {
- int row = d->logicalRow(visualRow);
- QSpanCollection::Span span = d->span(row, current.column());
- visualColumn = d->visualColumn(span.left());
+ 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: {
- int left = 0;
- while (d->isVisualColumnHiddenOrDisabled(visualRow, left) && left < right)
- ++left;
- if (visualColumn == left) {
- visualColumn = right;
- int top = 0;
- while (top < bottom && d->isVisualRowHiddenOrDisabled(top, visualColumn))
- ++top;
- if (visualRow == top)
+ }
+ 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 (visualRow > 0 && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn))
+ } else {
--visualRow;
- break;
- } // else MoveLeft
- }
- case MoveLeft:
- --visualColumn;
- while (visualColumn > 0 && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn))
- --visualColumn;
- if (d->hasSpans()) {
- int column = d->logicalColumn(visualColumn);
- QSpanCollection::Span span = d->span(current.row(), column);
- visualRow = d->visualRow(span.top());
- visualColumn = d->visualColumn(span.left());
- }
+ }
+ } while (!looped);
+ if (visualColumn < 0)
+ visualColumn = originalColumn;
break;
+ }
case MoveNext:
- if (visualColumn == right) {
- visualColumn = 0;
- while (visualColumn < right && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn))
+ 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;
- if (visualRow == bottom)
+ 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 (visualRow < bottom && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn))
+ } else {
++visualRow;
- break;
- } // else MoveRight
- case MoveRight:
- if (d->hasSpans()) {
- QSpanCollection::Span span = d->span(current.row(), current.column());
- visualColumn = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width()));
- }
- ++visualColumn;
- while (visualColumn < right && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn))
- ++visualColumn;
- if (d->hasSpans()) {
- int column = d->logicalColumn(visualColumn);
- QSpanCollection::Span span = d->span(current.row(), column);
- visualRow = d->visualRow(span.top());
- }
+ }
+ } while (!looped);
+ if (visualColumn > right)
+ visualColumn = originalColumn;
break;
+ }
case MoveHome:
visualColumn = 0;
while (visualColumn < right && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn))
@@ -1613,14 +1675,15 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
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 (!isIndexHidden(result) && d->isIndexEnabled(result))
- return d->model->index(logicalRow, logicalColumn, d->root);
+ if (!d->isRowHidden(logicalRow) && !d->isColumnHidden(logicalColumn) && d->isIndexEnabled(result))
+ return result;
return QModelIndex();
}
@@ -2375,7 +2438,8 @@ bool QTableView::isCornerButtonEnabled() const
QRect QTableView::visualRect(const QModelIndex &index) const
{
Q_D(const QTableView);
- if (!d->isIndexValid(index) || index.parent() != d->root || isIndexHidden(index) )
+ if (!d->isIndexValid(index) || index.parent() != d->root
+ || (!d->hasSpans() && isIndexHidden(index)))
return QRect();
d->executePostedLayout();
diff --git a/src/gui/itemviews/qtableview_p.h b/src/gui/itemviews/qtableview_p.h
index c785bd7..9fa14c2 100644
--- a/src/gui/itemviews/qtableview_p.h
+++ b/src/gui/itemviews/qtableview_p.h
@@ -135,7 +135,8 @@ public:
rowSectionAnchor(-1), columnSectionAnchor(-1),
columnResizeTimerID(0), rowResizeTimerID(0),
horizontalHeader(0), verticalHeader(0),
- sortingEnabled(false), geometryRecursionBlock(false)
+ sortingEnabled(false), geometryRecursionBlock(false),
+ visualCursor(QPoint())
{
wrapItemText = true;
#ifndef QT_NO_DRAGANDDROP
@@ -183,6 +184,7 @@ public:
QWidget *cornerWidget;
bool sortingEnabled;
bool geometryRecursionBlock;
+ QPoint visualCursor; // (Row,column) cell coordinates to track through span navigation.
QSpanCollection spans;