blob: 57a55928b787eb6f8b3f7a19551b7bef951ca958 [file] [log] [blame]
/*
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2010 University of Szeged
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "MiniBrowserApplication.h"
#include "BrowserWindow.h"
#include "qquickwebview_p.h"
#include "utils.h"
#include <QRegExp>
#include <QEvent>
#include <QMouseEvent>
#include <QTouchEvent>
#include <QApplication>
static inline bool isTouchEvent(const QEvent* event)
{
switch (event->type()) {
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
return true;
default:
return false;
}
}
static inline bool isMouseEvent(const QEvent* event)
{
switch (event->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseMove:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
return true;
default:
return false;
}
}
MiniBrowserApplication::MiniBrowserApplication(int& argc, char** argv)
: QApplication(argc, argv)
, m_realTouchEventReceived(false)
, m_pendingFakeTouchEventCount(0)
, m_isRobotized(false)
, m_robotTimeoutSeconds(0)
, m_robotExtraTimeSeconds(0)
, m_windowOptions(this)
{
setOrganizationName("Nokia");
setApplicationName("QtMiniBrowser");
setApplicationVersion("0.1");
handleUserOptions();
}
bool MiniBrowserApplication::notify(QObject* target, QEvent* event)
{
// We try to be smart, if we received real touch event, we are probably on a device
// with touch screen, and we should not have touch mocking.
if (!event->spontaneous() || m_realTouchEventReceived || !m_windowOptions.touchMockingEnabled())
return QApplication::notify(target, event);
if (isTouchEvent(event) && static_cast<QTouchEvent*>(event)->deviceType() == QTouchEvent::TouchScreen) {
if (m_pendingFakeTouchEventCount)
--m_pendingFakeTouchEventCount;
else
m_realTouchEventReceived = true;
return QApplication::notify(target, event);
}
BrowserWindow* browserWindow = qobject_cast<BrowserWindow*>(target);
if (!browserWindow)
return QApplication::notify(target, event);
// In QML events are propagated through parents. But since the WebView
// may consume key events, a shortcut might never reach the top QQuickItem.
// Therefore we are checking here for shortcuts.
if (event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if ((keyEvent->key() == Qt::Key_R && keyEvent->modifiers() == Qt::ControlModifier) || keyEvent->key() == Qt::Key_F5) {
browserWindow->reload();
return true;
}
if ((keyEvent->key() == Qt::Key_L && keyEvent->modifiers() == Qt::ControlModifier) || keyEvent->key() == Qt::Key_F6) {
browserWindow->focusAddressBar();
return true;
}
}
if (event->type() == QEvent::KeyRelease && static_cast<QKeyEvent*>(event)->key() == Qt::Key_Control) {
foreach (int id, m_heldTouchPoints)
if (m_touchPoints.contains(id))
m_touchPoints[id].state = Qt::TouchPointReleased;
m_heldTouchPoints.clear();
sendTouchEvent(browserWindow);
}
if (isMouseEvent(event)) {
const QMouseEvent* const mouseEvent = static_cast<QMouseEvent*>(event);
QWindowSystemInterface::TouchPoint touchPoint;
touchPoint.area = QRectF(mouseEvent->globalPos() - QPointF(30, 40), QSizeF(60, 80));
touchPoint.pressure = 1;
switch (mouseEvent->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseButtonDblClick:
touchPoint.id = mouseEvent->button();
if (m_touchPoints.contains(touchPoint.id))
touchPoint.state = Qt::TouchPointMoved;
else
touchPoint.state = Qt::TouchPointPressed;
break;
case QEvent::MouseMove:
if (!mouseEvent->buttons() || !m_touchPoints.contains(mouseEvent->buttons()))
return QApplication::notify(target, event);
touchPoint.id = mouseEvent->buttons();
touchPoint.state = Qt::TouchPointMoved;
break;
case QEvent::MouseButtonRelease:
touchPoint.state = Qt::TouchPointReleased;
touchPoint.id = mouseEvent->button();
if (mouseEvent->modifiers().testFlag(Qt::ControlModifier)) {
m_heldTouchPoints.insert(touchPoint.id);
return QApplication::notify(target, event);
}
break;
default:
Q_ASSERT_X(false, "multi-touch mocking", "unhandled event type");
}
// Update current touch-point
m_touchPoints.insert(touchPoint.id, touchPoint);
// Update states for all other touch-points
for (QHash<int, QWindowSystemInterface::TouchPoint>::iterator it = m_touchPoints.begin(), end = m_touchPoints.end(); it != end; ++it) {
if (it.value().id != touchPoint.id)
it.value().state = Qt::TouchPointStationary;
}
sendTouchEvent(browserWindow);
}
return QApplication::notify(target, event);
}
void MiniBrowserApplication::sendTouchEvent(BrowserWindow* browserWindow)
{
static QTouchDevice* device = 0;
if (!device) {
device = new QTouchDevice;
device->setType(QTouchDevice::TouchScreen);
QWindowSystemInterface::registerTouchDevice(device);
}
m_pendingFakeTouchEventCount++;
QWindowSystemInterface::handleTouchEvent(browserWindow, device, m_touchPoints.values());
bool holdingControl = QApplication::keyboardModifiers().testFlag(Qt::ControlModifier);
if (QQuickWebViewExperimental::flickableViewportEnabled())
browserWindow->updateVisualMockTouchPoints(holdingControl ? m_touchPoints.values() : QList<QWindowSystemInterface::TouchPoint>());
// Get rid of touch-points that are no longer valid
foreach (const QWindowSystemInterface::TouchPoint& touchPoint, m_touchPoints) {
if (touchPoint.state == Qt::TouchPointReleased)
m_touchPoints.remove(touchPoint.id);
}
}
static void printHelp(const QString& programName)
{
qDebug() << "Usage:" << programName.toLatin1().data()
<< "[--desktop]"
<< "[-r list]"
<< "[--robot-timeout seconds]"
<< "[--robot-extra-time seconds]"
<< "[--window-size (width)x(height)]"
<< "[--maximize]"
<< "[-f] Full screen mode."
<< "[-v]"
<< "URL";
}
void MiniBrowserApplication::handleUserOptions()
{
QStringList args = arguments();
QFileInfo program(args.takeAt(0));
QString programName("MiniBrowser");
if (program.exists())
programName = program.baseName();
if (takeOptionFlag(&args, "--help")) {
printHelp(programName);
appQuit(0);
}
const bool useDesktopBehavior = takeOptionFlag(&args, "--desktop");
QQuickWebViewExperimental::setFlickableViewportEnabled(!useDesktopBehavior);
if (!useDesktopBehavior)
qputenv("QT_WEBKIT_USE_MOBILE_THEME", QByteArray("1"));
m_windowOptions.setPrintLoadedUrls(takeOptionFlag(&args, "-v"));
m_windowOptions.setStartMaximized(takeOptionFlag(&args, "--maximize"));
m_windowOptions.setStartFullScreen(takeOptionFlag(&args, "-f"));
if (args.contains("--window-size")) {
QString value = takeOptionValue(&args, "--window-size");
QStringList list = value.split(QRegExp("\\D+"), QString::SkipEmptyParts);
if (list.length() == 2)
m_windowOptions.setRequestedWindowSize(QSize(list.at(0).toInt(), list.at(1).toInt()));
}
if (args.contains("-r")) {
QString listFile = takeOptionValue(&args, "-r");
if (listFile.isEmpty())
appQuit(1, "-r needs a list file to start in robotized mode");
if (!QFile::exists(listFile))
appQuit(1, "The list file supplied to -r does not exist.");
m_isRobotized = true;
m_urls = QStringList(listFile);
// toInt() returns 0 if it fails parsing.
m_robotTimeoutSeconds = takeOptionValue(&args, "--robot-timeout").toInt();
m_robotExtraTimeSeconds = takeOptionValue(&args, "--robot-extra-time").toInt();
} else {
int urlArg;
while ((urlArg = args.indexOf(QRegExp("^[^-].*"))) != -1)
m_urls += args.takeAt(urlArg);
}
if (!args.isEmpty()) {
printHelp(programName);
appQuit(1, QString("Unknown argument(s): %1").arg(args.join(",")));
}
}