diff -r bf4420e9fa4d -r 2e16851ffecd browsercore/core/webdirectionalnavigation.cpp --- a/browsercore/core/webdirectionalnavigation.cpp Fri Jun 11 16:23:26 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,403 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". -* -* Initial Contributors: -* Nokia Corporation - initial contribution. -* -* Contributors: -* -* Description: -* -*/ - - -#include "qmath.h" -#include "qpainter.h" -#include "qwebpage.h" -#include "qwebview.h" -#include "qwebframe.h" -#include "qwebelement.h" -#include "webdirectionalnavigation.h" - -namespace WRT { - -const int KInitialSize = 20; -const int KNormalScrollRange = 40; -const int KFullStep = 14; -const double KMaxDistance = 1000000; - -/*! - \class WebDirectionalNavigation - \since cwrt 1.0 - \brief cwrt navigation. - - \sa WebNavigation, WebTouchNavigation, WebCursorNavigation, WebHtmlTabIndexedNavigation -*/ -WebDirectionalNavigation::WebDirectionalNavigation(QWebPage* webPage,QObject* view) : - m_webPage(webPage) -, m_view(view) -{ - install(); -} - -WebDirectionalNavigation::~WebDirectionalNavigation() -{ - uninstall(); -} - -void WebDirectionalNavigation::install() -{ - m_view->installEventFilter(this); - //initiallayoutCompleted(); -} - -void WebDirectionalNavigation::uninstall() -{ - if (m_view) - m_view->removeEventFilter(this); -} - -void WebDirectionalNavigation::initiallayoutCompleted() -{ - m_webElement = m_webPage->currentFrame()->findFirstElement(QString("a,input,select,textarea,object")); - if (!m_webElement.isNull()) { - m_webElement.setFocus(); - m_focusPoint = m_webElement.geometry().topLeft(); - setCurrentFrameScrollPosition(m_focusPoint); - } -} - -double WebDirectionalNavigation::calculateElementDistance(int direction, const QRect& possibleRect) -{ - // Roughly based on this algorithm http://www.w3.org/TR/WICD/#nav-distance-fkt - // Deviates in that the overlap is not calculated. Instead, if there is any overlap - // selection is restricted to x or y direction only. This helps for differnt size elments - // all lying on the same plane, but might mess up backtracking the naviation path. - - QRect focusedRect(0,0,1,1); - if (!m_webElement.isNull()) - focusedRect = QRect(m_webElement.geometry()); - - //calculate the next focuspoint - switch (direction) { - case Qt::Key_Up: - if (m_focusPoint.x() < focusedRect.x()) - m_focusPoint.setX(focusedRect.x()); - else if (m_focusPoint.x() > focusedRect.right()) - m_focusPoint.setX(focusedRect.right()); - m_focusPoint.setY(focusedRect.y()); - break; - case Qt::Key_Down: - if (m_focusPoint.x() < focusedRect.x()) - m_focusPoint.setX(focusedRect.x()); - else if (m_focusPoint.x() > focusedRect.right()) - m_focusPoint.setX(focusedRect.right()); - m_focusPoint.setY(focusedRect.bottom()); - break; - case Qt::Key_Right: - m_focusPoint.setX(focusedRect.right()); - if (m_focusPoint.y() < focusedRect.y()) - m_focusPoint.setY(focusedRect.y()); - else if (m_focusPoint.y() > focusedRect.bottom()) - m_focusPoint.setY(focusedRect.bottom()); - break; - case Qt::Key_Left: - m_focusPoint.setX(focusedRect.x()); - if (m_focusPoint.y() < focusedRect.y()) - m_focusPoint.setY(focusedRect.y()); - else if (m_focusPoint.y() > focusedRect.bottom()) - m_focusPoint.setY(focusedRect.bottom()); - break; - } - - // Make sure the rectangle falls within the search area - if (direction == Qt::Key_Up && possibleRect.bottom() > m_focusPoint.y() - || direction == Qt::Key_Down && possibleRect.y() < m_focusPoint.y() - || direction == Qt::Key_Right && possibleRect.x() < m_focusPoint.x() - || direction == Qt::Key_Left && possibleRect.right() > m_focusPoint.x()) - return KMaxDistance; - - // The absolute distance (dx or dy) on the navigation axis between the opposing edges of the currently focused - // element and each of the candidates. - double distanceX = 0; - double distanceY = 0; - - if (direction == Qt::Key_Up) { - // adjust the x distance based on the closest edge - if (m_focusPoint.x() < possibleRect.x()) - distanceX = possibleRect.x() - m_focusPoint.x(); - else if (m_focusPoint.x() > possibleRect.right()) - distanceX = m_focusPoint.x() - possibleRect.right(); - distanceY = m_focusPoint.y() - possibleRect.bottom(); - } else if (direction == Qt::Key_Down) { - // adjust the x distance based on the closest edge - if (m_focusPoint.x() < possibleRect.x()) - distanceX = possibleRect.x() - m_focusPoint.x(); - else if (m_focusPoint.x() > possibleRect.right()) - distanceX = m_focusPoint.x() - possibleRect.right(); - distanceY = possibleRect.y() - m_focusPoint.y(); - } else if (direction == Qt::Key_Right) { - distanceX = possibleRect.x() - m_focusPoint.x(); - // adjust the y distance based on the closest edge - if (m_focusPoint.y() < possibleRect.y()) - distanceY = possibleRect.y() - m_focusPoint.y(); - else if (m_focusPoint.y() > possibleRect.bottom()) - distanceY = m_focusPoint.y() - possibleRect.bottom(); - } else if (direction == Qt::Key_Left) { - distanceX = m_focusPoint.x() - possibleRect.right(); - // adjust the y distance based on the closest edge - if (m_focusPoint.y() < possibleRect.y()) - distanceY = possibleRect.y() - m_focusPoint.y(); - else if (m_focusPoint.y() > possibleRect.bottom()) - distanceY = m_focusPoint.y() - possibleRect.bottom(); - } - - // The absolute distance on the axis orthogonal to the navigation axis between - // the opposing edges of currently focused element and each of candidates - double displacement = 0; - - // The euclidean distance - double euclideanDist = sqrt(distanceX * distanceX + distanceY * distanceY); - - // Area of the document to search - QRect searchRect(m_webPage->currentFrame()->scrollPosition(),m_webPage->viewportSize()); - - if (direction == Qt::Key_Up || direction == Qt::Key_Down) { - // if the rectangles are on the same plane set the euclideanDist to zero to favor this navigation - if ((possibleRect.x() == focusedRect.x()) - || (possibleRect.right() > focusedRect.x() && possibleRect.right() < focusedRect.right()) - || (possibleRect.x() > focusedRect.x() && possibleRect.x() < focusedRect.right()) - || (possibleRect.x() > focusedRect.x() && possibleRect.right() < focusedRect.right()) - || (possibleRect.x() < focusedRect.x() && possibleRect.right() > focusedRect.right())) { - euclideanDist = 0; - distanceX = 0; - } else { - // displacement is added for being orthogonally far from the current rectangle. - if (possibleRect.x() > focusedRect.right()) - displacement = possibleRect.x() - focusedRect.right(); - if (possibleRect.right() < focusedRect.x()) - displacement = focusedRect.x() - possibleRect.right(); - - // This is a little sketchy, but if the rectangles are all - // touching set the displacment to 1 so rects on the same plane win - if (displacement == 0) - displacement = 1; - - // if the focus is within the view limit the diagonal search by half the search rectangle - if (searchRect.intersects(focusedRect) && (displacement > (searchRect.width()/2))) - return KMaxDistance; - - } - - } else if (direction == Qt::Key_Left || direction == Qt::Key_Right) { - - // if the rectangles are on the same plane set the euclideanDist to zero to favor this navigation - if ((possibleRect.y() == focusedRect.y()) - || (possibleRect.bottom() > focusedRect.y() && possibleRect.bottom() < focusedRect.bottom()) - || (possibleRect.y() > focusedRect.y() && possibleRect.y() < focusedRect.bottom()) - || (possibleRect.y() > focusedRect.y() && possibleRect.bottom() < focusedRect.bottom()) - || (possibleRect.y() < focusedRect.y() && possibleRect.bottom() > focusedRect.bottom())) { - euclideanDist = 0; - distanceY = 0; - } else { - // displacement is added for being orthogonally far from the current rectangle. - if (possibleRect.y() > focusedRect.bottom()) - displacement = possibleRect.y() - focusedRect.bottom(); - if (possibleRect.bottom() < focusedRect.y()) - displacement = focusedRect.y() - possibleRect.bottom(); - - // This is a little sketchy, but if the rectangles are all - // touching set the displacment to 1 so rects on the same plane win - if (displacement == 0) - displacement = 1; - - // if the focus is within the view limit the diagonal search by half the search rectangle - if (searchRect.intersects(focusedRect) && (displacement > (searchRect.height()/2))) - return KMaxDistance; - } - } - - return euclideanDist + distanceX + distanceY + 2 * (displacement); -} - - - -bool WebDirectionalNavigation::nextElementInDirection(int direction) -{ - double bestDistance = KMaxDistance; - QWebElement bestElement; -#if QT_VERSION < 0x040600 - QList elementList = m_webPage->currentFrame()->findAllElements(QString("a,input,select,textarea,object")); -#else - QList elementList = m_webPage->currentFrame()->findAllElements(QString("a,input,select,textarea,object")).toList(); -#endif - QList::iterator it; - for (it = elementList.begin(); it != elementList.end(); it++) { - QWebElement el(*it); - QRect nRect(el.geometry()); - if (nRect.isValid()) { - if (QRect(m_webPage->currentFrame()->scrollPosition(),m_webPage->viewportSize()).intersects(nRect)) { - double distance = calculateElementDistance (direction, nRect); - if (bestDistance > distance) { - bestDistance = distance; - bestElement = el; - } - } - } - } - - if (!bestElement.isNull() && bestElement != m_webElement) { - m_webElement.setStyleProperty("outline", m_webElementStyle); - m_webElement = bestElement; - m_webElement.setFocus(); - m_webElementStyle = m_webElement.styleProperty("outline", QWebElement::ComputedStyle); - m_webElement.setStyleProperty("outline", "3px ridge rgb(140,140,255)"); - scrollFrame(direction); - return true; - } - - scrollFrameOneDirection (direction, KNormalScrollRange); - return false; -} - - -bool WebDirectionalNavigation::eventFilter(QObject *object, QEvent *event) -{ - if (object == m_view) { - switch (event->type()) { - case QEvent::KeyPress: { - QKeyEvent* ev = static_cast(event); - if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down - || ev->key() == Qt::Key_Left || ev->key() == Qt::Key_Right ) - { - return true; - } - if (ev->key() == Qt::Key_Select ) - { - QKeyEvent rockerEnterEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); - m_webPage->event(&rockerEnterEvent); - return true; - } - } - break; - case QEvent::KeyRelease: { - QKeyEvent* ev = static_cast(event); - if (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down - || ev->key() == Qt::Key_Left || ev->key() == Qt::Key_Right ) - { - nextElementInDirection(ev->key()); - return true; - } - if (ev->key() == Qt::Key_Select ) - { - QKeyEvent rockerEnterEvent(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); - m_webPage->event(&rockerEnterEvent); - return true; - } - } - break; - default: - return false; - break; - } // end of switch statement - } // end of if statement - return false; -} - - -void WebDirectionalNavigation::scrollFrame(int direction) -{ - - int xadjust = m_webPage->viewportSize().width()/5; - int yadjust = m_webPage->viewportSize().height()/5; - - switch (direction) { - case Qt::Key_Left: { - int distanceX = xadjust - m_webElement.geometry().x(); - if (distanceX > 0) - scrollCurrentFrame(-distanceX,0); - } - break; - case Qt::Key_Right: { - int distanceX = m_webElement.geometry().right() - m_webPage->viewportSize().width()-xadjust; - if (distanceX > 0) - scrollCurrentFrame(distanceX,0); - } - break; - case Qt::Key_Up: { - int distanceY = yadjust - m_webElement.geometry().y(); - if (distanceY > 0) - scrollCurrentFrame(0,-distanceY); - } - break; - case Qt::Key_Down: { - int distanceY = m_webElement.geometry().bottom() - m_webPage->viewportSize().height()-yadjust; - if (distanceY > 0) - scrollCurrentFrame(0,distanceY); - } - break; - } -} - -void WebDirectionalNavigation::scrollFrameOneDirection (int direction, int distance) -{ - int dx = 0; - int dy = 0; - - switch (direction) { - case Qt::Key_Up: { - dy = -distance; - } - break; - case Qt::Key_Down: { - dy = +distance; - } - break; - case Qt::Key_Left: { - dx = -distance; - } - break; - case Qt::Key_Right: { - dx = distance; - } - break; - default: - break; - } - - scrollCurrentFrame(dx, dy); -} - -void WebDirectionalNavigation::scrollCurrentFrame (int dx, int dy) -{ - QPoint scrollPosition = m_webPage->currentFrame()->scrollPosition(); - m_webPage->currentFrame()->scroll(dx, dy); - - /* emit pageScrollPositionZero singal if it's mainFrame scrolling or scroll to top*/ - if (m_webPage->currentFrame() == m_webPage->mainFrame()) { - if (scrollPosition.y() == 0 || m_webPage->currentFrame()->scrollPosition().y() == 0) { - emit pageScrollPositionZero(); - } - } -} - -void WebDirectionalNavigation::setCurrentFrameScrollPosition (QPoint& pos) -{ - QPoint scrollPosition = m_webPage->currentFrame()->scrollPosition(); - m_webPage->currentFrame()->setScrollPosition(pos); - - /* emit pageScrollPositionZero singal if it's mainFrame scrolling or scroll to top*/ - if (m_webPage->currentFrame() == m_webPage->mainFrame()) { - if (scrollPosition.y() == 0 || m_webPage->currentFrame()->scrollPosition().y() == 0) { - emit pageScrollPositionZero(); - } - } -} - -} -