summaryrefslogtreecommitdiff
path: root/examples/webkitwidgets
diff options
context:
space:
mode:
authorhjk <qthjk@ovi.com>2012-12-10 17:21:29 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-12-10 18:37:29 +0100
commit129bcf57471d09f15cbfe6dc3ab397689e6eb245 (patch)
treeb4901c52b1f75212303be606e6c40530c2afcd53 /examples/webkitwidgets
parent539c47c9c93335196dbde56f7ba98de0e6600a38 (diff)
downloadqtwebkit-examples-129bcf57471d09f15cbfe6dc3ab397689e6eb245.tar.gz
Adjust webkit example project install targets.
This follows suit with aeb036e in qtbase. Change-Id: Ifc85b327df81d15f3579b911e07c95a3b7a3bb9d Reviewed-by: Michael Bruning <michael.bruning@digia.com> Reviewed-by: Pierre Rossi <pierre.rossi@gmail.com>
Diffstat (limited to 'examples/webkitwidgets')
-rw-r--r--examples/webkitwidgets/browser/Info_mac.plist43
-rw-r--r--examples/webkitwidgets/browser/addbookmarkdialog.ui98
-rw-r--r--examples/webkitwidgets/browser/autosaver.cpp94
-rw-r--r--examples/webkitwidgets/browser/autosaver.h76
-rw-r--r--examples/webkitwidgets/browser/bookmarks.cpp987
-rw-r--r--examples/webkitwidgets/browser/bookmarks.h309
-rw-r--r--examples/webkitwidgets/browser/bookmarks.ui106
-rw-r--r--examples/webkitwidgets/browser/browser.icnsbin0 -> 50218 bytes
-rw-r--r--examples/webkitwidgets/browser/browser.icobin0 -> 15374 bytes
-rw-r--r--examples/webkitwidgets/browser/browser.pro101
-rw-r--r--examples/webkitwidgets/browser/browser.rc2
-rw-r--r--examples/webkitwidgets/browser/browserapplication.cpp459
-rw-r--r--examples/webkitwidgets/browser/browserapplication.h119
-rw-r--r--examples/webkitwidgets/browser/browsermainwindow.cpp949
-rw-r--r--examples/webkitwidgets/browser/browsermainwindow.h168
-rw-r--r--examples/webkitwidgets/browser/chasewidget.cpp142
-rw-r--r--examples/webkitwidgets/browser/chasewidget.h85
-rw-r--r--examples/webkitwidgets/browser/cookiejar.cpp738
-rw-r--r--examples/webkitwidgets/browser/cookiejar.h204
-rw-r--r--examples/webkitwidgets/browser/cookies.ui106
-rw-r--r--examples/webkitwidgets/browser/cookiesexceptions.ui184
-rw-r--r--examples/webkitwidgets/browser/data/addtab.pngbin0 -> 469 bytes
-rw-r--r--examples/webkitwidgets/browser/data/browser.svg411
-rw-r--r--examples/webkitwidgets/browser/data/closetab.pngbin0 -> 516 bytes
-rw-r--r--examples/webkitwidgets/browser/data/data.qrc11
-rw-r--r--examples/webkitwidgets/browser/data/defaultbookmarks.xbel43
-rw-r--r--examples/webkitwidgets/browser/data/defaulticon.pngbin0 -> 1473 bytes
-rw-r--r--examples/webkitwidgets/browser/data/history.pngbin0 -> 1527 bytes
-rw-r--r--examples/webkitwidgets/browser/data/loading.gifbin0 -> 847 bytes
-rw-r--r--examples/webkitwidgets/browser/downloaditem.ui134
-rw-r--r--examples/webkitwidgets/browser/downloadmanager.cpp579
-rw-r--r--examples/webkitwidgets/browser/downloadmanager.h162
-rw-r--r--examples/webkitwidgets/browser/downloads.ui83
-rw-r--r--examples/webkitwidgets/browser/edittableview.cpp78
-rw-r--r--examples/webkitwidgets/browser/edittableview.h61
-rw-r--r--examples/webkitwidgets/browser/edittreeview.cpp77
-rw-r--r--examples/webkitwidgets/browser/edittreeview.h61
-rw-r--r--examples/webkitwidgets/browser/history.cpp1292
-rw-r--r--examples/webkitwidgets/browser/history.h350
-rw-r--r--examples/webkitwidgets/browser/history.ui106
-rw-r--r--examples/webkitwidgets/browser/htmls/htmls.qrc5
-rw-r--r--examples/webkitwidgets/browser/htmls/notfound.html63
-rw-r--r--examples/webkitwidgets/browser/main.cpp53
-rw-r--r--examples/webkitwidgets/browser/modelmenu.cpp227
-rw-r--r--examples/webkitwidgets/browser/modelmenu.h105
-rw-r--r--examples/webkitwidgets/browser/networkaccessmanager.cpp214
-rw-r--r--examples/webkitwidgets/browser/networkaccessmanager.h77
-rw-r--r--examples/webkitwidgets/browser/passworddialog.ui111
-rw-r--r--examples/webkitwidgets/browser/proxy.ui104
-rw-r--r--examples/webkitwidgets/browser/searchlineedit.cpp242
-rw-r--r--examples/webkitwidgets/browser/searchlineedit.h103
-rw-r--r--examples/webkitwidgets/browser/settings.cpp324
-rw-r--r--examples/webkitwidgets/browser/settings.h74
-rw-r--r--examples/webkitwidgets/browser/settings.ui614
-rw-r--r--examples/webkitwidgets/browser/squeezelabel.cpp61
-rw-r--r--examples/webkitwidgets/browser/squeezelabel.h60
-rw-r--r--examples/webkitwidgets/browser/tabwidget.cpp835
-rw-r--r--examples/webkitwidgets/browser/tabwidget.h224
-rw-r--r--examples/webkitwidgets/browser/toolbarsearch.cpp164
-rw-r--r--examples/webkitwidgets/browser/toolbarsearch.h84
-rw-r--r--examples/webkitwidgets/browser/urllineedit.cpp342
-rw-r--r--examples/webkitwidgets/browser/urllineedit.h115
-rw-r--r--examples/webkitwidgets/browser/webview.cpp316
-rw-r--r--examples/webkitwidgets/browser/webview.h119
-rw-r--r--examples/webkitwidgets/browser/xbel.cpp283
-rw-r--r--examples/webkitwidgets/browser/xbel.h112
-rw-r--r--examples/webkitwidgets/domtraversal/doc/images/webkit-domtraversal.pngbin0 -> 109327 bytes
-rw-r--r--examples/webkitwidgets/domtraversal/doc/src/domtraversal.qdoc125
-rw-r--r--examples/webkitwidgets/domtraversal/domtraversal.pro9
-rw-r--r--examples/webkitwidgets/domtraversal/main.cpp52
-rw-r--r--examples/webkitwidgets/domtraversal/window.cpp89
-rw-r--r--examples/webkitwidgets/domtraversal/window.h72
-rw-r--r--examples/webkitwidgets/domtraversal/window.ui89
-rw-r--r--examples/webkitwidgets/embedded/anomaly/README.TXT0
-rw-r--r--examples/webkitwidgets/embedded/anomaly/anomaly.pro28
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/AddressBar.cpp93
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/AddressBar.h75
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/BookmarksView.cpp70
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/BookmarksView.h66
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/BrowserView.cpp193
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/BrowserView.h94
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/BrowserWindow.cpp166
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/BrowserWindow.h86
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/ControlStrip.cpp112
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/ControlStrip.h74
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/HomeView.cpp76
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/HomeView.h76
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/Main.cpp64
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/TitleBar.cpp124
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/TitleBar.h70
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/ZoomStrip.cpp82
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/ZoomStrip.h70
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/anomaly.qrc10
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/flickcharm.cpp402
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/flickcharm.h70
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/images/button-close.pngbin0 -> 1833 bytes
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/images/edit-find.pngbin0 -> 1495 bytes
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/images/go-next.pngbin0 -> 1150 bytes
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/images/go-previous.pngbin0 -> 1135 bytes
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/images/list-add.pngbin0 -> 601 bytes
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/images/list-remove.pngbin0 -> 317 bytes
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/webview.cpp80
-rw-r--r--examples/webkitwidgets/embedded/anomaly/src/webview.h66
-rw-r--r--examples/webkitwidgets/embedded/embedded.pro2
-rw-r--r--examples/webkitwidgets/fancybrowser/doc/images/fancybrowser-example.pngbin0 -> 98031 bytes
-rw-r--r--examples/webkitwidgets/fancybrowser/doc/src/fancybrowser.qdoc138
-rw-r--r--examples/webkitwidgets/fancybrowser/fancybrowser.pro9
-rw-r--r--examples/webkitwidgets/fancybrowser/jquery.min.js19
-rw-r--r--examples/webkitwidgets/fancybrowser/jquery.qrc5
-rw-r--r--examples/webkitwidgets/fancybrowser/main.cpp55
-rw-r--r--examples/webkitwidgets/fancybrowser/mainwindow.cpp219
-rw-r--r--examples/webkitwidgets/fancybrowser/mainwindow.h81
-rw-r--r--examples/webkitwidgets/formextractor/doc/images/formextractor-example.pngbin0 -> 80692 bytes
-rw-r--r--examples/webkitwidgets/formextractor/doc/src/formextractor.qdoc37
-rwxr-xr-xexamples/webkitwidgets/formextractor/form.html46
-rw-r--r--examples/webkitwidgets/formextractor/formextractor.cpp86
-rw-r--r--examples/webkitwidgets/formextractor/formextractor.h64
-rw-r--r--examples/webkitwidgets/formextractor/formextractor.pro14
-rw-r--r--examples/webkitwidgets/formextractor/formextractor.qrc5
-rw-r--r--examples/webkitwidgets/formextractor/formextractor.ui159
-rw-r--r--examples/webkitwidgets/formextractor/main.cpp52
-rw-r--r--examples/webkitwidgets/formextractor/mainwindow.cpp87
-rw-r--r--examples/webkitwidgets/formextractor/mainwindow.h74
-rw-r--r--examples/webkitwidgets/framecapture/framecapture.cpp115
-rw-r--r--examples/webkitwidgets/framecapture/framecapture.h69
-rw-r--r--examples/webkitwidgets/framecapture/framecapture.pro9
-rw-r--r--examples/webkitwidgets/framecapture/main.cpp75
-rw-r--r--examples/webkitwidgets/imageanalyzer/README20
-rw-r--r--examples/webkitwidgets/imageanalyzer/imageanalyzer.cpp223
-rw-r--r--examples/webkitwidgets/imageanalyzer/imageanalyzer.h103
-rw-r--r--examples/webkitwidgets/imageanalyzer/imageanalyzer.pro14
-rw-r--r--examples/webkitwidgets/imageanalyzer/main.cpp53
-rw-r--r--examples/webkitwidgets/imageanalyzer/mainwindow.cpp80
-rw-r--r--examples/webkitwidgets/imageanalyzer/mainwindow.h68
-rw-r--r--examples/webkitwidgets/imageanalyzer/resources/imageanalyzer.qrc10
-rw-r--r--examples/webkitwidgets/imageanalyzer/resources/images/README2
-rw-r--r--examples/webkitwidgets/imageanalyzer/resources/images/bellaCoola.jpgbin0 -> 129886 bytes
-rw-r--r--examples/webkitwidgets/imageanalyzer/resources/images/flower.jpgbin0 -> 67126 bytes
-rw-r--r--examples/webkitwidgets/imageanalyzer/resources/images/mtRainier.jpgbin0 -> 104090 bytes
-rw-r--r--examples/webkitwidgets/imageanalyzer/resources/images/seaShell.jpgbin0 -> 82690 bytes
-rw-r--r--examples/webkitwidgets/imageanalyzer/resources/images/trees.jpgbin0 -> 98630 bytes
-rw-r--r--examples/webkitwidgets/imageanalyzer/resources/index.html133
-rw-r--r--examples/webkitwidgets/previewer/doc/images/previewer-example.pngbin0 -> 16323 bytes
-rw-r--r--examples/webkitwidgets/previewer/doc/images/previewer-ui.pngbin0 -> 10345 bytes
-rw-r--r--examples/webkitwidgets/previewer/doc/src/previewer.qdoc167
-rw-r--r--examples/webkitwidgets/previewer/main.cpp52
-rw-r--r--examples/webkitwidgets/previewer/mainwindow.cpp196
-rw-r--r--examples/webkitwidgets/previewer/mainwindow.h86
-rw-r--r--examples/webkitwidgets/previewer/previewer.cpp64
-rw-r--r--examples/webkitwidgets/previewer/previewer.h64
-rw-r--r--examples/webkitwidgets/previewer/previewer.pro11
-rw-r--r--examples/webkitwidgets/previewer/previewer.ui99
-rw-r--r--examples/webkitwidgets/scroller/plot/main.cpp221
-rw-r--r--examples/webkitwidgets/scroller/plot/plot.pro11
-rw-r--r--examples/webkitwidgets/scroller/plot/plotwidget.cpp199
-rw-r--r--examples/webkitwidgets/scroller/plot/plotwidget.h88
-rw-r--r--examples/webkitwidgets/scroller/plot/settingswidget.cpp689
-rw-r--r--examples/webkitwidgets/scroller/plot/settingswidget.h108
-rw-r--r--examples/webkitwidgets/scroller/scroller.pro2
-rw-r--r--examples/webkitwidgets/scroller/wheel/main.cpp122
-rw-r--r--examples/webkitwidgets/scroller/wheel/wheel.pro9
-rw-r--r--examples/webkitwidgets/scroller/wheel/wheelwidget.cpp275
-rw-r--r--examples/webkitwidgets/scroller/wheel/wheelwidget.h103
-rw-r--r--examples/webkitwidgets/simpleselector/main.cpp53
-rw-r--r--examples/webkitwidgets/simpleselector/simpleselector.pro9
-rw-r--r--examples/webkitwidgets/simpleselector/window.cpp80
-rw-r--r--examples/webkitwidgets/simpleselector/window.h63
-rw-r--r--examples/webkitwidgets/simpleselector/window.ui72
-rw-r--r--examples/webkitwidgets/webkitwidgets.pro12
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/forms/mainwindow.ui196
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/main.cpp52
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/mainwindow.cpp134
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/mainwindow.h63
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp458
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.h138
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.pro10
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries.qrc7
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries/statisticsInHTML.xq58
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries/wholeTree.xq3
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/xmlsyntaxhighlighter.cpp105
-rw-r--r--examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/xmlsyntaxhighlighter.h71
-rw-r--r--examples/webkitwidgets/xmlpatterns/xmlpatterns.pro2
182 files changed, 22410 insertions, 0 deletions
diff --git a/examples/webkitwidgets/browser/Info_mac.plist b/examples/webkitwidgets/browser/Info_mac.plist
new file mode 100644
index 0000000..a4731c2
--- /dev/null
+++ b/examples/webkitwidgets/browser/Info_mac.plist
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleIconFile</key>
+ <string>@ICON@</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleGetInfoString</key>
+ <string>Created by Qt/QMake</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.trolltech.DemoBrowser</string>
+ <key>CFBundleSignature</key>
+ <string>ttxt</string>
+ <key>CFBundleExecutable</key>
+ <string>@EXECUTABLE@</string>
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>html</string>
+ <string>htm</string>
+ <string>shtml</string>
+ <string>xht</string>
+ <string>xhtml</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>@ICON@</string>
+ <key>CFBundleTypeName</key>
+ <string>HTML Document</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>HTML</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ </dict>
+ </array>
+ <key>NOTE</key>
+ <string>DemoBrowser by Digia Plc and/or its subsidiary(-ies)</string>
+</dict>
+</plist>
diff --git a/examples/webkitwidgets/browser/addbookmarkdialog.ui b/examples/webkitwidgets/browser/addbookmarkdialog.ui
new file mode 100644
index 0000000..3460d7b
--- /dev/null
+++ b/examples/webkitwidgets/browser/addbookmarkdialog.ui
@@ -0,0 +1,98 @@
+<ui version="4.0" >
+ <class>AddBookmarkDialog</class>
+ <widget class="QDialog" name="AddBookmarkDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>240</width>
+ <height>168</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Add Bookmark</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Type a name for the bookmark, and choose where to keep it.</string>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="name" />
+ </item>
+ <item>
+ <widget class="QComboBox" name="location" />
+ </item>
+ <item>
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>2</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ <property name="centerButtons" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>AddBookmarkDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>AddBookmarkDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webkitwidgets/browser/autosaver.cpp b/examples/webkitwidgets/browser/autosaver.cpp
new file mode 100644
index 0000000..eefe1f7
--- /dev/null
+++ b/examples/webkitwidgets/browser/autosaver.cpp
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "autosaver.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QMetaObject>
+#include <QtDebug>
+
+#define AUTOSAVE_IN 1000 * 3 // seconds
+#define MAXWAIT 1000 * 15 // seconds
+
+AutoSaver::AutoSaver(QObject *parent) : QObject(parent)
+{
+ Q_ASSERT(parent);
+}
+
+AutoSaver::~AutoSaver()
+{
+ if (m_timer.isActive())
+ qWarning() << "AutoSaver: still active when destroyed, changes not saved.";
+}
+
+void AutoSaver::changeOccurred()
+{
+ if (m_firstChange.isNull())
+ m_firstChange.start();
+
+ if (m_firstChange.elapsed() > MAXWAIT) {
+ saveIfNeccessary();
+ } else {
+ m_timer.start(AUTOSAVE_IN, this);
+ }
+}
+
+void AutoSaver::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == m_timer.timerId()) {
+ saveIfNeccessary();
+ } else {
+ QObject::timerEvent(event);
+ }
+}
+
+void AutoSaver::saveIfNeccessary()
+{
+ if (!m_timer.isActive())
+ return;
+ m_timer.stop();
+ m_firstChange = QTime();
+ if (!QMetaObject::invokeMethod(parent(), "save", Qt::DirectConnection)) {
+ qWarning() << "AutoSaver: error invoking slot save() on parent";
+ }
+}
+
diff --git a/examples/webkitwidgets/browser/autosaver.h b/examples/webkitwidgets/browser/autosaver.h
new file mode 100644
index 0000000..a171937
--- /dev/null
+++ b/examples/webkitwidgets/browser/autosaver.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef AUTOSAVER_H
+#define AUTOSAVER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QBasicTimer>
+#include <QtCore/QTime>
+
+/*
+ This class will call the save() slot on the parent object when the parent changes.
+ It will wait several seconds after changed() to combining multiple changes and
+ prevent continuous writing to disk.
+ */
+class AutoSaver : public QObject {
+
+Q_OBJECT
+
+public:
+ AutoSaver(QObject *parent);
+ ~AutoSaver();
+ void saveIfNeccessary();
+
+public slots:
+ void changeOccurred();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private:
+ QBasicTimer m_timer;
+ QTime m_firstChange;
+
+};
+
+#endif // AUTOSAVER_H
+
diff --git a/examples/webkitwidgets/browser/bookmarks.cpp b/examples/webkitwidgets/browser/bookmarks.cpp
new file mode 100644
index 0000000..4431e98
--- /dev/null
+++ b/examples/webkitwidgets/browser/bookmarks.cpp
@@ -0,0 +1,987 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "bookmarks.h"
+
+#include "autosaver.h"
+#include "browserapplication.h"
+#include "history.h"
+#include "xbel.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QFile>
+#include <QtCore/QMimeData>
+
+#include <QtGui/QDesktopServices>
+#include <QtGui/QDragEnterEvent>
+#include <QtGui/QIcon>
+#include <QtWidgets/QFileDialog>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QMessageBox>
+#include <QtWidgets/QToolButton>
+
+#include <QWebSettings>
+
+#include <QtCore/QDebug>
+
+#define BOOKMARKBAR "Bookmarks Bar"
+#define BOOKMARKMENU "Bookmarks Menu"
+
+BookmarksManager::BookmarksManager(QObject *parent)
+ : QObject(parent)
+ , m_loaded(false)
+ , m_saveTimer(new AutoSaver(this))
+ , m_bookmarkRootNode(0)
+ , m_bookmarkModel(0)
+{
+ connect(this, SIGNAL(entryAdded(BookmarkNode*)),
+ m_saveTimer, SLOT(changeOccurred()));
+ connect(this, SIGNAL(entryRemoved(BookmarkNode*,int,BookmarkNode*)),
+ m_saveTimer, SLOT(changeOccurred()));
+ connect(this, SIGNAL(entryChanged(BookmarkNode*)),
+ m_saveTimer, SLOT(changeOccurred()));
+}
+
+BookmarksManager::~BookmarksManager()
+{
+ m_saveTimer->saveIfNeccessary();
+}
+
+void BookmarksManager::changeExpanded()
+{
+ m_saveTimer->changeOccurred();
+}
+
+void BookmarksManager::load()
+{
+ if (m_loaded)
+ return;
+ m_loaded = true;
+
+ QString dir = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
+ QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel");
+ if (!QFile::exists(bookmarkFile))
+ bookmarkFile = QLatin1String(":defaultbookmarks.xbel");
+
+ XbelReader reader;
+ m_bookmarkRootNode = reader.read(bookmarkFile);
+ if (reader.error() != QXmlStreamReader::NoError) {
+ QMessageBox::warning(0, QLatin1String("Loading Bookmark"),
+ tr("Error when loading bookmarks on line %1, column %2:\n"
+ "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
+ }
+
+ BookmarkNode *toolbar = 0;
+ BookmarkNode *menu = 0;
+ QList<BookmarkNode*> others;
+ for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
+ BookmarkNode *node = m_bookmarkRootNode->children().at(i);
+ if (node->type() == BookmarkNode::Folder) {
+ // Automatically convert
+ if (node->title == tr("Toolbar Bookmarks") && !toolbar) {
+ node->title = tr(BOOKMARKBAR);
+ }
+ if (node->title == tr(BOOKMARKBAR) && !toolbar) {
+ toolbar = node;
+ }
+
+ // Automatically convert
+ if (node->title == tr("Menu") && !menu) {
+ node->title = tr(BOOKMARKMENU);
+ }
+ if (node->title == tr(BOOKMARKMENU) && !menu) {
+ menu = node;
+ }
+ } else {
+ others.append(node);
+ }
+ m_bookmarkRootNode->remove(node);
+ }
+ Q_ASSERT(m_bookmarkRootNode->children().count() == 0);
+ if (!toolbar) {
+ toolbar = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
+ toolbar->title = tr(BOOKMARKBAR);
+ } else {
+ m_bookmarkRootNode->add(toolbar);
+ }
+
+ if (!menu) {
+ menu = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
+ menu->title = tr(BOOKMARKMENU);
+ } else {
+ m_bookmarkRootNode->add(menu);
+ }
+
+ for (int i = 0; i < others.count(); ++i)
+ menu->add(others.at(i));
+}
+
+void BookmarksManager::save() const
+{
+ if (!m_loaded)
+ return;
+
+ XbelWriter writer;
+ QString dir = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
+ QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel");
+ if (!writer.write(bookmarkFile, m_bookmarkRootNode))
+ qWarning() << "BookmarkManager: error saving to" << bookmarkFile;
+}
+
+void BookmarksManager::addBookmark(BookmarkNode *parent, BookmarkNode *node, int row)
+{
+ if (!m_loaded)
+ return;
+ Q_ASSERT(parent);
+ InsertBookmarksCommand *command = new InsertBookmarksCommand(this, parent, node, row);
+ m_commands.push(command);
+}
+
+void BookmarksManager::removeBookmark(BookmarkNode *node)
+{
+ if (!m_loaded)
+ return;
+
+ Q_ASSERT(node);
+ BookmarkNode *parent = node->parent();
+ int row = parent->children().indexOf(node);
+ RemoveBookmarksCommand *command = new RemoveBookmarksCommand(this, parent, row);
+ m_commands.push(command);
+}
+
+void BookmarksManager::setTitle(BookmarkNode *node, const QString &newTitle)
+{
+ if (!m_loaded)
+ return;
+
+ Q_ASSERT(node);
+ ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newTitle, true);
+ m_commands.push(command);
+}
+
+void BookmarksManager::setUrl(BookmarkNode *node, const QString &newUrl)
+{
+ if (!m_loaded)
+ return;
+
+ Q_ASSERT(node);
+ ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newUrl, false);
+ m_commands.push(command);
+}
+
+BookmarkNode *BookmarksManager::bookmarks()
+{
+ if (!m_loaded)
+ load();
+ return m_bookmarkRootNode;
+}
+
+BookmarkNode *BookmarksManager::menu()
+{
+ if (!m_loaded)
+ load();
+
+ for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
+ BookmarkNode *node = m_bookmarkRootNode->children().at(i);
+ if (node->title == tr(BOOKMARKMENU))
+ return node;
+ }
+ Q_ASSERT(false);
+ return 0;
+}
+
+BookmarkNode *BookmarksManager::toolbar()
+{
+ if (!m_loaded)
+ load();
+
+ for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
+ BookmarkNode *node = m_bookmarkRootNode->children().at(i);
+ if (node->title == tr(BOOKMARKBAR))
+ return node;
+ }
+ Q_ASSERT(false);
+ return 0;
+}
+
+BookmarksModel *BookmarksManager::bookmarksModel()
+{
+ if (!m_bookmarkModel)
+ m_bookmarkModel = new BookmarksModel(this, this);
+ return m_bookmarkModel;
+}
+
+void BookmarksManager::importBookmarks()
+{
+ QString fileName = QFileDialog::getOpenFileName(0, tr("Open File"),
+ QString(),
+ tr("XBEL (*.xbel *.xml)"));
+ if (fileName.isEmpty())
+ return;
+
+ XbelReader reader;
+ BookmarkNode *importRootNode = reader.read(fileName);
+ if (reader.error() != QXmlStreamReader::NoError) {
+ QMessageBox::warning(0, QLatin1String("Loading Bookmark"),
+ tr("Error when loading bookmarks on line %1, column %2:\n"
+ "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
+ }
+
+ importRootNode->setType(BookmarkNode::Folder);
+ importRootNode->title = (tr("Imported %1").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate)));
+ addBookmark(menu(), importRootNode);
+}
+
+void BookmarksManager::exportBookmarks()
+{
+ QString fileName = QFileDialog::getSaveFileName(0, tr("Save File"),
+ tr("%1 Bookmarks.xbel").arg(QCoreApplication::applicationName()),
+ tr("XBEL (*.xbel *.xml)"));
+ if (fileName.isEmpty())
+ return;
+
+ XbelWriter writer;
+ if (!writer.write(fileName, m_bookmarkRootNode))
+ QMessageBox::critical(0, tr("Export error"), tr("error saving bookmarks"));
+}
+
+RemoveBookmarksCommand::RemoveBookmarksCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *parent, int row)
+ : QUndoCommand(BookmarksManager::tr("Remove Bookmark"))
+ , m_row(row)
+ , m_bookmarkManagaer(m_bookmarkManagaer)
+ , m_node(parent->children().value(row))
+ , m_parent(parent)
+ , m_done(false)
+{
+}
+
+RemoveBookmarksCommand::~RemoveBookmarksCommand()
+{
+ if (m_done && !m_node->parent()) {
+ delete m_node;
+ }
+}
+
+void RemoveBookmarksCommand::undo()
+{
+ m_parent->add(m_node, m_row);
+ emit m_bookmarkManagaer->entryAdded(m_node);
+ m_done = false;
+}
+
+void RemoveBookmarksCommand::redo()
+{
+ m_parent->remove(m_node);
+ emit m_bookmarkManagaer->entryRemoved(m_parent, m_row, m_node);
+ m_done = true;
+}
+
+InsertBookmarksCommand::InsertBookmarksCommand(BookmarksManager *m_bookmarkManagaer,
+ BookmarkNode *parent, BookmarkNode *node, int row)
+ : RemoveBookmarksCommand(m_bookmarkManagaer, parent, row)
+{
+ setText(BookmarksManager::tr("Insert Bookmark"));
+ m_node = node;
+}
+
+ChangeBookmarkCommand::ChangeBookmarkCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *node,
+ const QString &newValue, bool title)
+ : QUndoCommand()
+ , m_bookmarkManagaer(m_bookmarkManagaer)
+ , m_title(title)
+ , m_newValue(newValue)
+ , m_node(node)
+{
+ if (m_title) {
+ m_oldValue = m_node->title;
+ setText(BookmarksManager::tr("Name Change"));
+ } else {
+ m_oldValue = m_node->url;
+ setText(BookmarksManager::tr("Address Change"));
+ }
+}
+
+void ChangeBookmarkCommand::undo()
+{
+ if (m_title)
+ m_node->title = m_oldValue;
+ else
+ m_node->url = m_oldValue;
+ emit m_bookmarkManagaer->entryChanged(m_node);
+}
+
+void ChangeBookmarkCommand::redo()
+{
+ if (m_title)
+ m_node->title = m_newValue;
+ else
+ m_node->url = m_newValue;
+ emit m_bookmarkManagaer->entryChanged(m_node);
+}
+
+BookmarksModel::BookmarksModel(BookmarksManager *bookmarkManager, QObject *parent)
+ : QAbstractItemModel(parent)
+ , m_endMacro(false)
+ , m_bookmarksManager(bookmarkManager)
+{
+ connect(bookmarkManager, SIGNAL(entryAdded(BookmarkNode*)),
+ this, SLOT(entryAdded(BookmarkNode*)));
+ connect(bookmarkManager, SIGNAL(entryRemoved(BookmarkNode*,int,BookmarkNode*)),
+ this, SLOT(entryRemoved(BookmarkNode*,int,BookmarkNode*)));
+ connect(bookmarkManager, SIGNAL(entryChanged(BookmarkNode*)),
+ this, SLOT(entryChanged(BookmarkNode*)));
+}
+
+QModelIndex BookmarksModel::index(BookmarkNode *node) const
+{
+ BookmarkNode *parent = node->parent();
+ if (!parent)
+ return QModelIndex();
+ return createIndex(parent->children().indexOf(node), 0, node);
+}
+
+void BookmarksModel::entryAdded(BookmarkNode *item)
+{
+ Q_ASSERT(item && item->parent());
+ int row = item->parent()->children().indexOf(item);
+ BookmarkNode *parent = item->parent();
+ // item was already added so remove beore beginInsertRows is called
+ parent->remove(item);
+ beginInsertRows(index(parent), row, row);
+ parent->add(item, row);
+ endInsertRows();
+}
+
+void BookmarksModel::entryRemoved(BookmarkNode *parent, int row, BookmarkNode *item)
+{
+ // item was already removed, re-add so beginRemoveRows works
+ parent->add(item, row);
+ beginRemoveRows(index(parent), row, row);
+ parent->remove(item);
+ endRemoveRows();
+}
+
+void BookmarksModel::entryChanged(BookmarkNode *item)
+{
+ QModelIndex idx = index(item);
+ emit dataChanged(idx, idx);
+}
+
+bool BookmarksModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (row < 0 || count <= 0 || row + count > rowCount(parent))
+ return false;
+
+ BookmarkNode *bookmarkNode = node(parent);
+ for (int i = row + count - 1; i >= row; --i) {
+ BookmarkNode *node = bookmarkNode->children().at(i);
+ if (node == m_bookmarksManager->menu()
+ || node == m_bookmarksManager->toolbar())
+ continue;
+
+ m_bookmarksManager->removeBookmark(node);
+ }
+ if (m_endMacro) {
+ m_bookmarksManager->undoRedoStack()->endMacro();
+ m_endMacro = false;
+ }
+ return true;
+}
+
+QVariant BookmarksModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ switch (section) {
+ case 0: return tr("Title");
+ case 1: return tr("Address");
+ }
+ }
+ return QAbstractItemModel::headerData(section, orientation, role);
+}
+
+QVariant BookmarksModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.model() != this)
+ return QVariant();
+
+ const BookmarkNode *bookmarkNode = node(index);
+ switch (role) {
+ case Qt::EditRole:
+ case Qt::DisplayRole:
+ if (bookmarkNode->type() == BookmarkNode::Separator) {
+ switch (index.column()) {
+ case 0: return QString(50, 0xB7);
+ case 1: return QString();
+ }
+ }
+
+ switch (index.column()) {
+ case 0: return bookmarkNode->title;
+ case 1: return bookmarkNode->url;
+ }
+ break;
+ case BookmarksModel::UrlRole:
+ return QUrl(bookmarkNode->url);
+ break;
+ case BookmarksModel::UrlStringRole:
+ return bookmarkNode->url;
+ break;
+ case BookmarksModel::TypeRole:
+ return bookmarkNode->type();
+ break;
+ case BookmarksModel::SeparatorRole:
+ return (bookmarkNode->type() == BookmarkNode::Separator);
+ break;
+ case Qt::DecorationRole:
+ if (index.column() == 0) {
+ if (bookmarkNode->type() == BookmarkNode::Folder)
+ return QApplication::style()->standardIcon(QStyle::SP_DirIcon);
+ return BrowserApplication::instance()->icon(bookmarkNode->url);
+ }
+ }
+
+ return QVariant();
+}
+
+int BookmarksModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.column() > 0) ? 0 : 2;
+}
+
+int BookmarksModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.column() > 0)
+ return 0;
+
+ if (!parent.isValid())
+ return m_bookmarksManager->bookmarks()->children().count();
+
+ const BookmarkNode *item = static_cast<BookmarkNode*>(parent.internalPointer());
+ return item->children().count();
+}
+
+QModelIndex BookmarksModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0 || column < 0 || row >= rowCount(parent) || column >= columnCount(parent))
+ return QModelIndex();
+
+ // get the parent node
+ BookmarkNode *parentNode = node(parent);
+ return createIndex(row, column, parentNode->children().at(row));
+}
+
+QModelIndex BookmarksModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ BookmarkNode *itemNode = node(index);
+ BookmarkNode *parentNode = (itemNode ? itemNode->parent() : 0);
+ if (!parentNode || parentNode == m_bookmarksManager->bookmarks())
+ return QModelIndex();
+
+ // get the parent's row
+ BookmarkNode *grandParentNode = parentNode->parent();
+ int parentRow = grandParentNode->children().indexOf(parentNode);
+ Q_ASSERT(parentRow >= 0);
+ return createIndex(parentRow, 0, parentNode);
+}
+
+bool BookmarksModel::hasChildren(const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return true;
+ const BookmarkNode *parentNode = node(parent);
+ return (parentNode->type() == BookmarkNode::Folder);
+}
+
+Qt::ItemFlags BookmarksModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+
+ BookmarkNode *bookmarkNode = node(index);
+
+ if (bookmarkNode != m_bookmarksManager->menu()
+ && bookmarkNode != m_bookmarksManager->toolbar()) {
+ flags |= Qt::ItemIsDragEnabled;
+ if (bookmarkNode->type() != BookmarkNode::Separator)
+ flags |= Qt::ItemIsEditable;
+ }
+ if (hasChildren(index))
+ flags |= Qt::ItemIsDropEnabled;
+ return flags;
+}
+
+Qt::DropActions BookmarksModel::supportedDropActions () const
+{
+ return Qt::CopyAction | Qt::MoveAction;
+}
+
+#define MIMETYPE QLatin1String("application/bookmarks.xbel")
+
+QStringList BookmarksModel::mimeTypes() const
+{
+ QStringList types;
+ types << MIMETYPE;
+ return types;
+}
+
+QMimeData *BookmarksModel::mimeData(const QModelIndexList &indexes) const
+{
+ QMimeData *mimeData = new QMimeData();
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+ foreach (QModelIndex index, indexes) {
+ if (index.column() != 0 || !index.isValid())
+ continue;
+ QByteArray encodedData;
+ QBuffer buffer(&encodedData);
+ buffer.open(QBuffer::ReadWrite);
+ XbelWriter writer;
+ const BookmarkNode *parentNode = node(index);
+ writer.write(&buffer, parentNode);
+ stream << encodedData;
+ }
+ mimeData->setData(MIMETYPE, data);
+ return mimeData;
+}
+
+bool BookmarksModel::dropMimeData(const QMimeData *data,
+ Qt::DropAction action, int row, int column, const QModelIndex &parent)
+{
+ if (action == Qt::IgnoreAction)
+ return true;
+
+ if (!data->hasFormat(MIMETYPE)
+ || column > 0)
+ return false;
+
+ QByteArray ba = data->data(MIMETYPE);
+ QDataStream stream(&ba, QIODevice::ReadOnly);
+ if (stream.atEnd())
+ return false;
+
+ QUndoStack *undoStack = m_bookmarksManager->undoRedoStack();
+ undoStack->beginMacro(QLatin1String("Move Bookmarks"));
+
+ while (!stream.atEnd()) {
+ QByteArray encodedData;
+ stream >> encodedData;
+ QBuffer buffer(&encodedData);
+ buffer.open(QBuffer::ReadOnly);
+
+ XbelReader reader;
+ BookmarkNode *rootNode = reader.read(&buffer);
+ QList<BookmarkNode*> children = rootNode->children();
+ for (int i = 0; i < children.count(); ++i) {
+ BookmarkNode *bookmarkNode = children.at(i);
+ rootNode->remove(bookmarkNode);
+ row = qMax(0, row);
+ BookmarkNode *parentNode = node(parent);
+ m_bookmarksManager->addBookmark(parentNode, bookmarkNode, row);
+ m_endMacro = true;
+ }
+ delete rootNode;
+ }
+ return true;
+}
+
+bool BookmarksModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid() || (flags(index) & Qt::ItemIsEditable) == 0)
+ return false;
+
+ BookmarkNode *item = node(index);
+
+ switch (role) {
+ case Qt::EditRole:
+ case Qt::DisplayRole:
+ if (index.column() == 0) {
+ m_bookmarksManager->setTitle(item, value.toString());
+ break;
+ }
+ if (index.column() == 1) {
+ m_bookmarksManager->setUrl(item, value.toString());
+ break;
+ }
+ return false;
+ case BookmarksModel::UrlRole:
+ m_bookmarksManager->setUrl(item, value.toUrl().toString());
+ break;
+ case BookmarksModel::UrlStringRole:
+ m_bookmarksManager->setUrl(item, value.toString());
+ break;
+ default:
+ break;
+ return false;
+ }
+
+ return true;
+}
+
+BookmarkNode *BookmarksModel::node(const QModelIndex &index) const
+{
+ BookmarkNode *itemNode = static_cast<BookmarkNode*>(index.internalPointer());
+ if (!itemNode)
+ return m_bookmarksManager->bookmarks();
+ return itemNode;
+}
+
+
+AddBookmarkProxyModel::AddBookmarkProxyModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+{
+}
+
+int AddBookmarkProxyModel::columnCount(const QModelIndex &parent) const
+{
+ return qMin(1, QSortFilterProxyModel::columnCount(parent));
+}
+
+bool AddBookmarkProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
+ return sourceModel()->hasChildren(idx);
+}
+
+AddBookmarkDialog::AddBookmarkDialog(const QString &url, const QString &title, QWidget *parent, BookmarksManager *bookmarkManager)
+ : QDialog(parent)
+ , m_url(url)
+ , m_bookmarksManager(bookmarkManager)
+{
+ setWindowFlags(Qt::Sheet);
+ if (!m_bookmarksManager)
+ m_bookmarksManager = BrowserApplication::bookmarksManager();
+ setupUi(this);
+ QTreeView *view = new QTreeView(this);
+ m_proxyModel = new AddBookmarkProxyModel(this);
+ BookmarksModel *model = m_bookmarksManager->bookmarksModel();
+ m_proxyModel->setSourceModel(model);
+ view->setModel(m_proxyModel);
+ view->expandAll();
+ view->header()->setStretchLastSection(true);
+ view->header()->hide();
+ view->setItemsExpandable(false);
+ view->setRootIsDecorated(false);
+ view->setIndentation(10);
+ location->setModel(m_proxyModel);
+ view->show();
+ location->setView(view);
+ BookmarkNode *menu = m_bookmarksManager->menu();
+ QModelIndex idx = m_proxyModel->mapFromSource(model->index(menu));
+ view->setCurrentIndex(idx);
+ location->setCurrentIndex(idx.row());
+ name->setText(title);
+}
+
+void AddBookmarkDialog::accept()
+{
+ QModelIndex index = location->view()->currentIndex();
+ index = m_proxyModel->mapToSource(index);
+ if (!index.isValid())
+ index = m_bookmarksManager->bookmarksModel()->index(0, 0);
+ BookmarkNode *parent = m_bookmarksManager->bookmarksModel()->node(index);
+ BookmarkNode *bookmark = new BookmarkNode(BookmarkNode::Bookmark);
+ bookmark->url = m_url;
+ bookmark->title = name->text();
+ m_bookmarksManager->addBookmark(parent, bookmark);
+ QDialog::accept();
+}
+
+BookmarksMenu::BookmarksMenu(QWidget *parent)
+ : ModelMenu(parent)
+ , m_bookmarksManager(0)
+{
+ connect(this, SIGNAL(activated(QModelIndex)),
+ this, SLOT(activated(QModelIndex)));
+ setMaxRows(-1);
+ setHoverRole(BookmarksModel::UrlStringRole);
+ setSeparatorRole(BookmarksModel::SeparatorRole);
+}
+
+void BookmarksMenu::activated(const QModelIndex &index)
+{
+ emit openUrl(index.data(BookmarksModel::UrlRole).toUrl());
+}
+
+bool BookmarksMenu::prePopulated()
+{
+ m_bookmarksManager = BrowserApplication::bookmarksManager();
+ setModel(m_bookmarksManager->bookmarksModel());
+ setRootIndex(m_bookmarksManager->bookmarksModel()->index(1, 0));
+ // initial actions
+ for (int i = 0; i < m_initialActions.count(); ++i)
+ addAction(m_initialActions.at(i));
+ if (!m_initialActions.isEmpty())
+ addSeparator();
+ createMenu(model()->index(0, 0), 1, this);
+ return true;
+}
+
+void BookmarksMenu::setInitialActions(QList<QAction*> actions)
+{
+ m_initialActions = actions;
+ for (int i = 0; i < m_initialActions.count(); ++i)
+ addAction(m_initialActions.at(i));
+}
+
+BookmarksDialog::BookmarksDialog(QWidget *parent, BookmarksManager *manager)
+ : QDialog(parent)
+{
+ m_bookmarksManager = manager;
+ if (!m_bookmarksManager)
+ m_bookmarksManager = BrowserApplication::bookmarksManager();
+ setupUi(this);
+
+ tree->setUniformRowHeights(true);
+ tree->setSelectionBehavior(QAbstractItemView::SelectRows);
+ tree->setSelectionMode(QAbstractItemView::ContiguousSelection);
+ tree->setTextElideMode(Qt::ElideMiddle);
+ m_bookmarksModel = m_bookmarksManager->bookmarksModel();
+ m_proxyModel = new TreeProxyModel(this);
+ connect(search, SIGNAL(textChanged(QString)),
+ m_proxyModel, SLOT(setFilterFixedString(QString)));
+ connect(removeButton, SIGNAL(clicked()), tree, SLOT(removeOne()));
+ m_proxyModel->setSourceModel(m_bookmarksModel);
+ tree->setModel(m_proxyModel);
+ tree->setDragDropMode(QAbstractItemView::InternalMove);
+ tree->setExpanded(m_proxyModel->index(0, 0), true);
+ tree->setAlternatingRowColors(true);
+ QFontMetrics fm(font());
+ int header = fm.width(QLatin1Char('m')) * 40;
+ tree->header()->resizeSection(0, header);
+ tree->header()->setStretchLastSection(true);
+ connect(tree, SIGNAL(activated(QModelIndex)),
+ this, SLOT(open()));
+ tree->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(tree, SIGNAL(customContextMenuRequested(QPoint)),
+ this, SLOT(customContextMenuRequested(QPoint)));
+ connect(addFolderButton, SIGNAL(clicked()),
+ this, SLOT(newFolder()));
+ expandNodes(m_bookmarksManager->bookmarks());
+ setAttribute(Qt::WA_DeleteOnClose);
+}
+
+BookmarksDialog::~BookmarksDialog()
+{
+ if (saveExpandedNodes(tree->rootIndex()))
+ m_bookmarksManager->changeExpanded();
+}
+
+bool BookmarksDialog::saveExpandedNodes(const QModelIndex &parent)
+{
+ bool changed = false;
+ for (int i = 0; i < m_proxyModel->rowCount(parent); ++i) {
+ QModelIndex child = m_proxyModel->index(i, 0, parent);
+ QModelIndex sourceIndex = m_proxyModel->mapToSource(child);
+ BookmarkNode *childNode = m_bookmarksModel->node(sourceIndex);
+ bool wasExpanded = childNode->expanded;
+ if (tree->isExpanded(child)) {
+ childNode->expanded = true;
+ changed |= saveExpandedNodes(child);
+ } else {
+ childNode->expanded = false;
+ }
+ changed |= (wasExpanded != childNode->expanded);
+ }
+ return changed;
+}
+
+void BookmarksDialog::expandNodes(BookmarkNode *node)
+{
+ for (int i = 0; i < node->children().count(); ++i) {
+ BookmarkNode *childNode = node->children()[i];
+ if (childNode->expanded) {
+ QModelIndex idx = m_bookmarksModel->index(childNode);
+ idx = m_proxyModel->mapFromSource(idx);
+ tree->setExpanded(idx, true);
+ expandNodes(childNode);
+ }
+ }
+}
+
+void BookmarksDialog::customContextMenuRequested(const QPoint &pos)
+{
+ QMenu menu;
+ QModelIndex index = tree->indexAt(pos);
+ index = index.sibling(index.row(), 0);
+ if (index.isValid() && !tree->model()->hasChildren(index)) {
+ menu.addAction(tr("Open"), this, SLOT(open()));
+ menu.addSeparator();
+ }
+ menu.addAction(tr("Delete"), tree, SLOT(removeOne()));
+ menu.exec(QCursor::pos());
+}
+
+void BookmarksDialog::open()
+{
+ QModelIndex index = tree->currentIndex();
+ if (!index.parent().isValid())
+ return;
+ emit openUrl(index.sibling(index.row(), 1).data(BookmarksModel::UrlRole).toUrl());
+}
+
+void BookmarksDialog::newFolder()
+{
+ QModelIndex currentIndex = tree->currentIndex();
+ QModelIndex idx = currentIndex;
+ if (idx.isValid() && !idx.model()->hasChildren(idx))
+ idx = idx.parent();
+ if (!idx.isValid())
+ idx = tree->rootIndex();
+ idx = m_proxyModel->mapToSource(idx);
+ BookmarkNode *parent = m_bookmarksManager->bookmarksModel()->node(idx);
+ BookmarkNode *node = new BookmarkNode(BookmarkNode::Folder);
+ node->title = tr("New Folder");
+ m_bookmarksManager->addBookmark(parent, node, currentIndex.row() + 1);
+}
+
+BookmarksToolBar::BookmarksToolBar(BookmarksModel *model, QWidget *parent)
+ : QToolBar(tr("Bookmark"), parent)
+ , m_bookmarksModel(model)
+{
+ connect(this, SIGNAL(actionTriggered(QAction*)), this, SLOT(triggered(QAction*)));
+ setRootIndex(model->index(0, 0));
+ connect(m_bookmarksModel, SIGNAL(modelReset()), this, SLOT(build()));
+ connect(m_bookmarksModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(build()));
+ connect(m_bookmarksModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(build()));
+ connect(m_bookmarksModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(build()));
+ setAcceptDrops(true);
+}
+
+void BookmarksToolBar::dragEnterEvent(QDragEnterEvent *event)
+{
+ const QMimeData *mimeData = event->mimeData();
+ if (mimeData->hasUrls())
+ event->acceptProposedAction();
+ QToolBar::dragEnterEvent(event);
+}
+
+void BookmarksToolBar::dropEvent(QDropEvent *event)
+{
+ const QMimeData *mimeData = event->mimeData();
+ if (mimeData->hasUrls() && mimeData->hasText()) {
+ QList<QUrl> urls = mimeData->urls();
+ QAction *action = actionAt(event->pos());
+ QString dropText;
+ if (action)
+ dropText = action->text();
+ int row = -1;
+ QModelIndex parentIndex = m_root;
+ for (int i = 0; i < m_bookmarksModel->rowCount(m_root); ++i) {
+ QModelIndex idx = m_bookmarksModel->index(i, 0, m_root);
+ QString title = idx.data().toString();
+ if (title == dropText) {
+ row = i;
+ if (m_bookmarksModel->hasChildren(idx)) {
+ parentIndex = idx;
+ row = -1;
+ }
+ break;
+ }
+ }
+ BookmarkNode *bookmark = new BookmarkNode(BookmarkNode::Bookmark);
+ bookmark->url = urls.at(0).toString();
+ bookmark->title = mimeData->text();
+
+ BookmarkNode *parent = m_bookmarksModel->node(parentIndex);
+ BookmarksManager *bookmarksManager = m_bookmarksModel->bookmarksManager();
+ bookmarksManager->addBookmark(parent, bookmark, row);
+ event->acceptProposedAction();
+ }
+ QToolBar::dropEvent(event);
+}
+
+
+void BookmarksToolBar::setRootIndex(const QModelIndex &index)
+{
+ m_root = index;
+ build();
+}
+
+QModelIndex BookmarksToolBar::rootIndex() const
+{
+ return m_root;
+}
+
+void BookmarksToolBar::build()
+{
+ clear();
+ for (int i = 0; i < m_bookmarksModel->rowCount(m_root); ++i) {
+ QModelIndex idx = m_bookmarksModel->index(i, 0, m_root);
+ if (m_bookmarksModel->hasChildren(idx)) {
+ QToolButton *button = new QToolButton(this);
+ button->setPopupMode(QToolButton::InstantPopup);
+ button->setArrowType(Qt::DownArrow);
+ button->setText(idx.data().toString());
+ ModelMenu *menu = new ModelMenu(this);
+ connect(menu, SIGNAL(activated(QModelIndex)),
+ this, SLOT(activated(QModelIndex)));
+ menu->setModel(m_bookmarksModel);
+ menu->setRootIndex(idx);
+ menu->addAction(new QAction(menu));
+ button->setMenu(menu);
+ button->setToolButtonStyle(Qt::ToolButtonTextOnly);
+ QAction *a = addWidget(button);
+ a->setText(idx.data().toString());
+ } else {
+ QAction *action = addAction(idx.data().toString());
+ action->setData(idx.data(BookmarksModel::UrlRole));
+ }
+ }
+}
+
+void BookmarksToolBar::triggered(QAction *action)
+{
+ QVariant v = action->data();
+ if (v.canConvert<QUrl>()) {
+ emit openUrl(v.toUrl());
+ }
+}
+
+void BookmarksToolBar::activated(const QModelIndex &index)
+{
+ emit openUrl(index.data(BookmarksModel::UrlRole).toUrl());
+}
+
diff --git a/examples/webkitwidgets/browser/bookmarks.h b/examples/webkitwidgets/browser/bookmarks.h
new file mode 100644
index 0000000..f7a2fa1
--- /dev/null
+++ b/examples/webkitwidgets/browser/bookmarks.h
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BOOKMARKS_H
+#define BOOKMARKS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QAbstractItemModel>
+
+#include <QtWidgets/QUndoCommand>
+
+/*!
+ Bookmark manager, owner of the bookmarks, loads, saves and basic tasks
+ */
+class AutoSaver;
+class BookmarkNode;
+class BookmarksModel;
+class BookmarksManager : public QObject
+{
+ Q_OBJECT
+
+signals:
+ void entryAdded(BookmarkNode *item);
+ void entryRemoved(BookmarkNode *parent, int row, BookmarkNode *item);
+ void entryChanged(BookmarkNode *item);
+
+public:
+ BookmarksManager(QObject *parent = 0);
+ ~BookmarksManager();
+
+ void addBookmark(BookmarkNode *parent, BookmarkNode *node, int row = -1);
+ void removeBookmark(BookmarkNode *node);
+ void setTitle(BookmarkNode *node, const QString &newTitle);
+ void setUrl(BookmarkNode *node, const QString &newUrl);
+ void changeExpanded();
+
+ BookmarkNode *bookmarks();
+ BookmarkNode *menu();
+ BookmarkNode *toolbar();
+
+ BookmarksModel *bookmarksModel();
+ QUndoStack *undoRedoStack() { return &m_commands; };
+
+public slots:
+ void importBookmarks();
+ void exportBookmarks();
+
+private slots:
+ void save() const;
+
+private:
+ void load();
+
+ bool m_loaded;
+ AutoSaver *m_saveTimer;
+ BookmarkNode *m_bookmarkRootNode;
+ BookmarksModel *m_bookmarkModel;
+ QUndoStack m_commands;
+
+ friend class RemoveBookmarksCommand;
+ friend class ChangeBookmarkCommand;
+};
+
+class RemoveBookmarksCommand : public QUndoCommand
+{
+
+public:
+ RemoveBookmarksCommand(BookmarksManager *m_bookmarkManagaer, BookmarkNode *parent, int row);
+ ~RemoveBookmarksCommand();
+ void undo();
+ void redo();
+
+protected:
+ int m_row;
+ BookmarksManager *m_bookmarkManagaer;
+ BookmarkNode *m_node;
+ BookmarkNode *m_parent;
+ bool m_done;
+};
+
+class InsertBookmarksCommand : public RemoveBookmarksCommand
+{
+
+public:
+ InsertBookmarksCommand(BookmarksManager *m_bookmarkManagaer,
+ BookmarkNode *parent, BookmarkNode *node, int row);
+ void undo() { RemoveBookmarksCommand::redo(); }
+ void redo() { RemoveBookmarksCommand::undo(); }
+
+};
+
+class ChangeBookmarkCommand : public QUndoCommand
+{
+
+public:
+ ChangeBookmarkCommand(BookmarksManager *m_bookmarkManagaer,
+ BookmarkNode *node, const QString &newValue, bool title);
+ void undo();
+ void redo();
+
+private:
+ BookmarksManager *m_bookmarkManagaer;
+ bool m_title;
+ QString m_oldValue;
+ QString m_newValue;
+ BookmarkNode *m_node;
+};
+
+/*!
+ BookmarksModel is a QAbstractItemModel wrapper around the BookmarkManager
+ */
+class BookmarksModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public slots:
+ void entryAdded(BookmarkNode *item);
+ void entryRemoved(BookmarkNode *parent, int row, BookmarkNode *item);
+ void entryChanged(BookmarkNode *item);
+
+public:
+ enum Roles {
+ TypeRole = Qt::UserRole + 1,
+ UrlRole = Qt::UserRole + 2,
+ UrlStringRole = Qt::UserRole + 3,
+ SeparatorRole = Qt::UserRole + 4
+ };
+
+ BookmarksModel(BookmarksManager *bookmarkManager, QObject *parent = 0);
+ inline BookmarksManager *bookmarksManager() const { return m_bookmarksManager; }
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex& index= QModelIndex()) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ Qt::DropActions supportedDropActions () const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ QMimeData *mimeData(const QModelIndexList &indexes) const;
+ QStringList mimeTypes() const;
+ bool dropMimeData(const QMimeData *data,
+ Qt::DropAction action, int row, int column, const QModelIndex &parent);
+ bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
+
+ BookmarkNode *node(const QModelIndex &index) const;
+ QModelIndex index(BookmarkNode *node) const;
+
+private:
+
+ bool m_endMacro;
+ BookmarksManager *m_bookmarksManager;
+};
+
+// Menu that is dynamically populated from the bookmarks
+#include "modelmenu.h"
+class BookmarksMenu : public ModelMenu
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ BookmarksMenu(QWidget *parent = 0);
+ void setInitialActions(QList<QAction*> actions);
+
+protected:
+ bool prePopulated();
+
+private slots:
+ void activated(const QModelIndex &index);
+
+private:
+ BookmarksManager *m_bookmarksManager;
+ QList<QAction*> m_initialActions;
+};
+
+/*
+ Proxy model that filters out the bookmarks so only the folders
+ are left behind. Used in the add bookmark dialog combobox.
+ */
+#include <QtCore/QSortFilterProxyModel>
+class AddBookmarkProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ AddBookmarkProxyModel(QObject * parent = 0);
+ int columnCount(const QModelIndex & parent = QModelIndex()) const;
+
+protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+};
+
+/*!
+ Add bookmark dialog
+ */
+#include "ui_addbookmarkdialog.h"
+class AddBookmarkDialog : public QDialog, public Ui_AddBookmarkDialog
+{
+ Q_OBJECT
+
+public:
+ AddBookmarkDialog(const QString &url, const QString &title, QWidget *parent = 0, BookmarksManager *bookmarkManager = 0);
+
+private slots:
+ void accept();
+
+private:
+ QString m_url;
+ BookmarksManager *m_bookmarksManager;
+ AddBookmarkProxyModel *m_proxyModel;
+};
+
+#include "ui_bookmarks.h"
+class TreeProxyModel;
+class BookmarksDialog : public QDialog, public Ui_BookmarksDialog
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ BookmarksDialog(QWidget *parent = 0, BookmarksManager *manager = 0);
+ ~BookmarksDialog();
+
+private slots:
+ void customContextMenuRequested(const QPoint &pos);
+ void open();
+ void newFolder();
+
+private:
+ void expandNodes(BookmarkNode *node);
+ bool saveExpandedNodes(const QModelIndex &parent);
+
+ BookmarksManager *m_bookmarksManager;
+ BookmarksModel *m_bookmarksModel;
+ TreeProxyModel *m_proxyModel;
+};
+
+#include <QtWidgets/QToolBar>
+class BookmarksToolBar : public QToolBar
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ BookmarksToolBar(BookmarksModel *model, QWidget *parent = 0);
+ void setRootIndex(const QModelIndex &index);
+ QModelIndex rootIndex() const;
+
+protected:
+ void dragEnterEvent(QDragEnterEvent *event);
+ void dropEvent(QDropEvent *event);
+
+private slots:
+ void triggered(QAction *action);
+ void activated(const QModelIndex &index);
+ void build();
+
+private:
+ BookmarksModel *m_bookmarksModel;
+ QPersistentModelIndex m_root;
+};
+
+#endif // BOOKMARKS_H
diff --git a/examples/webkitwidgets/browser/bookmarks.ui b/examples/webkitwidgets/browser/bookmarks.ui
new file mode 100644
index 0000000..c893e94
--- /dev/null
+++ b/examples/webkitwidgets/browser/bookmarks.ui
@@ -0,0 +1,106 @@
+<ui version="4.0" >
+ <class>BookmarksDialog</class>
+ <widget class="QDialog" name="BookmarksDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>758</width>
+ <height>450</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Bookmarks</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>252</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1" >
+ <widget class="SearchLineEdit" name="search" />
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="EditTreeView" name="tree" />
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addFolderButton" >
+ <property name="text" >
+ <string>Add Folder</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SearchLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>searchlineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>EditTreeView</class>
+ <extends>QTreeView</extends>
+ <header>edittreeview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>BookmarksDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>472</x>
+ <y>329</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>461</x>
+ <y>356</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webkitwidgets/browser/browser.icns b/examples/webkitwidgets/browser/browser.icns
new file mode 100644
index 0000000..f591ae4
--- /dev/null
+++ b/examples/webkitwidgets/browser/browser.icns
Binary files differ
diff --git a/examples/webkitwidgets/browser/browser.ico b/examples/webkitwidgets/browser/browser.ico
new file mode 100644
index 0000000..7f9be93
--- /dev/null
+++ b/examples/webkitwidgets/browser/browser.ico
Binary files differ
diff --git a/examples/webkitwidgets/browser/browser.pro b/examples/webkitwidgets/browser/browser.pro
new file mode 100644
index 0000000..505d7bd
--- /dev/null
+++ b/examples/webkitwidgets/browser/browser.pro
@@ -0,0 +1,101 @@
+TEMPLATE = app
+TARGET = browser
+QT += webkitwidgets network widgets printsupport
+
+CONFIG += qt warn_on
+!isEmpty(QT.uitools.name):!embedded: QT += uitools
+else: DEFINES += QT_NO_UITOOLS
+
+FORMS += \
+ addbookmarkdialog.ui \
+ bookmarks.ui \
+ cookies.ui \
+ cookiesexceptions.ui \
+ downloaditem.ui \
+ downloads.ui \
+ history.ui \
+ passworddialog.ui \
+ proxy.ui \
+ settings.ui
+
+HEADERS += \
+ autosaver.h \
+ bookmarks.h \
+ browserapplication.h \
+ browsermainwindow.h \
+ chasewidget.h \
+ cookiejar.h \
+ downloadmanager.h \
+ edittableview.h \
+ edittreeview.h \
+ history.h \
+ modelmenu.h \
+ networkaccessmanager.h \
+ searchlineedit.h \
+ settings.h \
+ squeezelabel.h \
+ tabwidget.h \
+ toolbarsearch.h \
+ urllineedit.h \
+ webview.h \
+ xbel.h
+
+SOURCES += \
+ autosaver.cpp \
+ bookmarks.cpp \
+ browserapplication.cpp \
+ browsermainwindow.cpp \
+ chasewidget.cpp \
+ cookiejar.cpp \
+ downloadmanager.cpp \
+ edittableview.cpp \
+ edittreeview.cpp \
+ history.cpp \
+ modelmenu.cpp \
+ networkaccessmanager.cpp \
+ searchlineedit.cpp \
+ settings.cpp \
+ squeezelabel.cpp \
+ tabwidget.cpp \
+ toolbarsearch.cpp \
+ urllineedit.cpp \
+ webview.cpp \
+ xbel.cpp \
+ main.cpp
+
+RESOURCES += data/data.qrc htmls/htmls.qrc
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+win32 {
+ RC_FILE = browser.rc
+}
+
+mac {
+ ICON = browser.icns
+ QMAKE_INFO_PLIST = Info_mac.plist
+ TARGET = Browser
+
+ # No 64-bit Flash on Mac, so build the browser 32-bit
+ contains(QT_CONFIG, x86) {
+ CONFIG -= x86_64
+ CONFIG += x86
+ }
+ contains(QT_CONFIG, ppc) {
+ CONFIG -= ppc64
+ CONFIG += ppc
+ }
+}
+
+wince*: {
+ DEPLOYMENT_PLUGIN += qjpeg qgif
+}
+
+EXAMPLE_FILES = Info_mac.plist browser.icns browser.ico browser.rc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/browser
+INSTALLS += target
diff --git a/examples/webkitwidgets/browser/browser.rc b/examples/webkitwidgets/browser/browser.rc
new file mode 100644
index 0000000..89a237c
--- /dev/null
+++ b/examples/webkitwidgets/browser/browser.rc
@@ -0,0 +1,2 @@
+IDI_ICON1 ICON DISCARDABLE "browser.ico"
+
diff --git a/examples/webkitwidgets/browser/browserapplication.cpp b/examples/webkitwidgets/browser/browserapplication.cpp
new file mode 100644
index 0000000..f08c489
--- /dev/null
+++ b/examples/webkitwidgets/browser/browserapplication.cpp
@@ -0,0 +1,459 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browserapplication.h"
+
+#include "bookmarks.h"
+#include "browsermainwindow.h"
+#include "cookiejar.h"
+#include "downloadmanager.h"
+#include "history.h"
+#include "networkaccessmanager.h"
+#include "tabwidget.h"
+#include "webview.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QDir>
+#include <QtCore/QLibraryInfo>
+#include <QtCore/QSettings>
+#include <QtCore/QTextStream>
+#include <QtCore/QTranslator>
+
+#include <QtGui/QDesktopServices>
+#include <QtGui/QFileOpenEvent>
+#include <QtWidgets/QMessageBox>
+
+#include <QtNetwork/QLocalServer>
+#include <QtNetwork/QLocalSocket>
+#include <QtNetwork/QNetworkProxy>
+#include <QtNetwork/QSslSocket>
+
+#include <QWebSettings>
+
+#include <QtCore/QDebug>
+
+DownloadManager *BrowserApplication::s_downloadManager = 0;
+HistoryManager *BrowserApplication::s_historyManager = 0;
+NetworkAccessManager *BrowserApplication::s_networkAccessManager = 0;
+BookmarksManager *BrowserApplication::s_bookmarksManager = 0;
+
+BrowserApplication::BrowserApplication(int &argc, char **argv)
+ : QApplication(argc, argv)
+ , m_localServer(0)
+{
+ QCoreApplication::setOrganizationName(QLatin1String("Qt"));
+ QCoreApplication::setApplicationName(QLatin1String("demobrowser"));
+ QCoreApplication::setApplicationVersion(QLatin1String("0.1"));
+#ifdef Q_WS_QWS
+ // Use a different server name for QWS so we can run an X11
+ // browser and a QWS browser in parallel on the same machine for
+ // debugging
+ QString serverName = QCoreApplication::applicationName() + QLatin1String("_qws");
+#else
+ QString serverName = QCoreApplication::applicationName();
+#endif
+ QLocalSocket socket;
+ socket.connectToServer(serverName);
+ if (socket.waitForConnected(500)) {
+ QTextStream stream(&socket);
+ QStringList args = QCoreApplication::arguments();
+ if (args.count() > 1)
+ stream << args.last();
+ else
+ stream << QString();
+ stream.flush();
+ socket.waitForBytesWritten();
+ return;
+ }
+
+#if defined(Q_WS_MAC)
+ QApplication::setQuitOnLastWindowClosed(false);
+#else
+ QApplication::setQuitOnLastWindowClosed(true);
+#endif
+
+ m_localServer = new QLocalServer(this);
+ connect(m_localServer, SIGNAL(newConnection()),
+ this, SLOT(newLocalSocketConnection()));
+ if (!m_localServer->listen(serverName)) {
+ if (m_localServer->serverError() == QAbstractSocket::AddressInUseError
+ && QFile::exists(m_localServer->serverName())) {
+ QFile::remove(m_localServer->serverName());
+ m_localServer->listen(serverName);
+ }
+ }
+
+#ifndef QT_NO_OPENSSL
+ if (!QSslSocket::supportsSsl()) {
+ QMessageBox::information(0, "Demo Browser",
+ "This system does not support OpenSSL. SSL websites will not be available.");
+ }
+#endif
+
+ QDesktopServices::setUrlHandler(QLatin1String("http"), this, "openUrl");
+ QString localSysName = QLocale::system().name();
+
+ installTranslator(QLatin1String("qt_") + localSysName);
+
+ QSettings settings;
+ settings.beginGroup(QLatin1String("sessions"));
+ m_lastSession = settings.value(QLatin1String("lastSession")).toByteArray();
+ settings.endGroup();
+
+#if defined(Q_WS_MAC)
+ connect(this, SIGNAL(lastWindowClosed()),
+ this, SLOT(lastWindowClosed()));
+#endif
+
+ QTimer::singleShot(0, this, SLOT(postLaunch()));
+}
+
+BrowserApplication::~BrowserApplication()
+{
+ delete s_downloadManager;
+ for (int i = 0; i < m_mainWindows.size(); ++i) {
+ BrowserMainWindow *window = m_mainWindows.at(i);
+ delete window;
+ }
+ delete s_networkAccessManager;
+ delete s_bookmarksManager;
+}
+
+#if defined(Q_WS_MAC)
+void BrowserApplication::lastWindowClosed()
+{
+ clean();
+ BrowserMainWindow *mw = new BrowserMainWindow;
+ mw->slotHome();
+ m_mainWindows.prepend(mw);
+}
+#endif
+
+BrowserApplication *BrowserApplication::instance()
+{
+ return (static_cast<BrowserApplication *>(QCoreApplication::instance()));
+}
+
+#if defined(Q_WS_MAC)
+#include <QtWidgets/QMessageBox>
+void BrowserApplication::quitBrowser()
+{
+ clean();
+ int tabCount = 0;
+ for (int i = 0; i < m_mainWindows.count(); ++i) {
+ tabCount =+ m_mainWindows.at(i)->tabWidget()->count();
+ }
+
+ if (tabCount > 1) {
+ int ret = QMessageBox::warning(mainWindow(), QString(),
+ tr("There are %1 windows and %2 tabs open\n"
+ "Do you want to quit anyway?").arg(m_mainWindows.count()).arg(tabCount),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No);
+ if (ret == QMessageBox::No)
+ return;
+ }
+
+ exit(0);
+}
+#endif
+
+/*!
+ Any actions that can be delayed until the window is visible
+ */
+void BrowserApplication::postLaunch()
+{
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
+ if (directory.isEmpty())
+ directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
+ QWebSettings::setIconDatabasePath(directory);
+ QWebSettings::setOfflineStoragePath(directory);
+
+ setWindowIcon(QIcon(QLatin1String(":browser.svg")));
+
+ loadSettings();
+
+ // newMainWindow() needs to be called in main() for this to happen
+ if (m_mainWindows.count() > 0) {
+ QStringList args = QCoreApplication::arguments();
+ if (args.count() > 1)
+ mainWindow()->loadPage(args.last());
+ else
+ mainWindow()->slotHome();
+ }
+ BrowserApplication::historyManager();
+}
+
+void BrowserApplication::loadSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("websettings"));
+
+ QWebSettings *defaultSettings = QWebSettings::globalSettings();
+ QString standardFontFamily = defaultSettings->fontFamily(QWebSettings::StandardFont);
+ int standardFontSize = defaultSettings->fontSize(QWebSettings::DefaultFontSize);
+ QFont standardFont = QFont(standardFontFamily, standardFontSize);
+ standardFont = qvariant_cast<QFont>(settings.value(QLatin1String("standardFont"), standardFont));
+ defaultSettings->setFontFamily(QWebSettings::StandardFont, standardFont.family());
+ defaultSettings->setFontSize(QWebSettings::DefaultFontSize, standardFont.pointSize());
+
+ QString fixedFontFamily = defaultSettings->fontFamily(QWebSettings::FixedFont);
+ int fixedFontSize = defaultSettings->fontSize(QWebSettings::DefaultFixedFontSize);
+ QFont fixedFont = QFont(fixedFontFamily, fixedFontSize);
+ fixedFont = qvariant_cast<QFont>(settings.value(QLatin1String("fixedFont"), fixedFont));
+ defaultSettings->setFontFamily(QWebSettings::FixedFont, fixedFont.family());
+ defaultSettings->setFontSize(QWebSettings::DefaultFixedFontSize, fixedFont.pointSize());
+
+ defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, settings.value(QLatin1String("enableJavascript"), true).toBool());
+ defaultSettings->setAttribute(QWebSettings::PluginsEnabled, settings.value(QLatin1String("enablePlugins"), true).toBool());
+
+ QUrl url = settings.value(QLatin1String("userStyleSheet")).toUrl();
+ defaultSettings->setUserStyleSheetUrl(url);
+
+ defaultSettings->setAttribute(QWebSettings::DnsPrefetchEnabled, true);
+
+ settings.endGroup();
+}
+
+QList<BrowserMainWindow*> BrowserApplication::mainWindows()
+{
+ clean();
+ QList<BrowserMainWindow*> list;
+ for (int i = 0; i < m_mainWindows.count(); ++i)
+ list.append(m_mainWindows.at(i));
+ return list;
+}
+
+void BrowserApplication::clean()
+{
+ // cleanup any deleted main windows first
+ for (int i = m_mainWindows.count() - 1; i >= 0; --i)
+ if (m_mainWindows.at(i).isNull())
+ m_mainWindows.removeAt(i);
+}
+
+void BrowserApplication::saveSession()
+{
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled))
+ return;
+
+ clean();
+
+ QSettings settings;
+ settings.beginGroup(QLatin1String("sessions"));
+
+ QByteArray data;
+ QBuffer buffer(&data);
+ QDataStream stream(&buffer);
+ buffer.open(QIODevice::ReadWrite);
+
+ stream << m_mainWindows.count();
+ for (int i = 0; i < m_mainWindows.count(); ++i)
+ stream << m_mainWindows.at(i)->saveState();
+ settings.setValue(QLatin1String("lastSession"), data);
+ settings.endGroup();
+}
+
+bool BrowserApplication::canRestoreSession() const
+{
+ return !m_lastSession.isEmpty();
+}
+
+void BrowserApplication::restoreLastSession()
+{
+ QList<QByteArray> windows;
+ QBuffer buffer(&m_lastSession);
+ QDataStream stream(&buffer);
+ buffer.open(QIODevice::ReadOnly);
+ int windowCount;
+ stream >> windowCount;
+ for (int i = 0; i < windowCount; ++i) {
+ QByteArray windowState;
+ stream >> windowState;
+ windows.append(windowState);
+ }
+ for (int i = 0; i < windows.count(); ++i) {
+ BrowserMainWindow *newWindow = 0;
+ if (m_mainWindows.count() == 1
+ && mainWindow()->tabWidget()->count() == 1
+ && mainWindow()->currentTab()->url() == QUrl()) {
+ newWindow = mainWindow();
+ } else {
+ newWindow = newMainWindow();
+ }
+ newWindow->restoreState(windows.at(i));
+ }
+}
+
+bool BrowserApplication::isTheOnlyBrowser() const
+{
+ return (m_localServer != 0);
+}
+
+void BrowserApplication::installTranslator(const QString &name)
+{
+ QTranslator *translator = new QTranslator(this);
+ translator->load(name, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
+ QApplication::installTranslator(translator);
+}
+
+#if defined(Q_WS_MAC)
+bool BrowserApplication::event(QEvent* event)
+{
+ switch (event->type()) {
+ case QEvent::ApplicationActivate: {
+ clean();
+ if (!m_mainWindows.isEmpty()) {
+ BrowserMainWindow *mw = mainWindow();
+ if (mw && !mw->isMinimized()) {
+ mainWindow()->show();
+ }
+ return true;
+ }
+ }
+ case QEvent::FileOpen:
+ if (!m_mainWindows.isEmpty()) {
+ mainWindow()->loadPage(static_cast<QFileOpenEvent *>(event)->file());
+ return true;
+ }
+ default:
+ break;
+ }
+ return QApplication::event(event);
+}
+#endif
+
+void BrowserApplication::openUrl(const QUrl &url)
+{
+ mainWindow()->loadPage(url.toString());
+}
+
+BrowserMainWindow *BrowserApplication::newMainWindow()
+{
+ BrowserMainWindow *browser = new BrowserMainWindow();
+ m_mainWindows.prepend(browser);
+ browser->show();
+ return browser;
+}
+
+BrowserMainWindow *BrowserApplication::mainWindow()
+{
+ clean();
+ if (m_mainWindows.isEmpty())
+ newMainWindow();
+ return m_mainWindows[0];
+}
+
+void BrowserApplication::newLocalSocketConnection()
+{
+ QLocalSocket *socket = m_localServer->nextPendingConnection();
+ if (!socket)
+ return;
+ socket->waitForReadyRead(1000);
+ QTextStream stream(socket);
+ QString url;
+ stream >> url;
+ if (!url.isEmpty()) {
+ QSettings settings;
+ settings.beginGroup(QLatin1String("general"));
+ int openLinksIn = settings.value(QLatin1String("openLinksIn"), 0).toInt();
+ settings.endGroup();
+ if (openLinksIn == 1)
+ newMainWindow();
+ else
+ mainWindow()->tabWidget()->newTab();
+ openUrl(url);
+ }
+ delete socket;
+ mainWindow()->raise();
+ mainWindow()->activateWindow();
+}
+
+CookieJar *BrowserApplication::cookieJar()
+{
+ return (CookieJar*)networkAccessManager()->cookieJar();
+}
+
+DownloadManager *BrowserApplication::downloadManager()
+{
+ if (!s_downloadManager) {
+ s_downloadManager = new DownloadManager();
+ }
+ return s_downloadManager;
+}
+
+NetworkAccessManager *BrowserApplication::networkAccessManager()
+{
+ if (!s_networkAccessManager) {
+ s_networkAccessManager = new NetworkAccessManager();
+ s_networkAccessManager->setCookieJar(new CookieJar);
+ }
+ return s_networkAccessManager;
+}
+
+HistoryManager *BrowserApplication::historyManager()
+{
+ if (!s_historyManager) {
+ s_historyManager = new HistoryManager();
+ QWebHistoryInterface::setDefaultInterface(s_historyManager);
+ }
+ return s_historyManager;
+}
+
+BookmarksManager *BrowserApplication::bookmarksManager()
+{
+ if (!s_bookmarksManager) {
+ s_bookmarksManager = new BookmarksManager;
+ }
+ return s_bookmarksManager;
+}
+
+QIcon BrowserApplication::icon(const QUrl &url) const
+{
+ QIcon icon = QWebSettings::iconForUrl(url);
+ if (!icon.isNull())
+ return icon.pixmap(16, 16);
+ if (m_defaultIcon.isNull())
+ m_defaultIcon = QIcon(QLatin1String(":defaulticon.png"));
+ return m_defaultIcon.pixmap(16, 16);
+}
+
diff --git a/examples/webkitwidgets/browser/browserapplication.h b/examples/webkitwidgets/browser/browserapplication.h
new file mode 100644
index 0000000..d322607
--- /dev/null
+++ b/examples/webkitwidgets/browser/browserapplication.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BROWSERAPPLICATION_H
+#define BROWSERAPPLICATION_H
+
+#include <QtWidgets/QApplication>
+
+#include <QtCore/QUrl>
+#include <QtCore/QPointer>
+
+#include <QtGui/QIcon>
+
+QT_BEGIN_NAMESPACE
+class QLocalServer;
+QT_END_NAMESPACE
+
+class BookmarksManager;
+class BrowserMainWindow;
+class CookieJar;
+class DownloadManager;
+class HistoryManager;
+class NetworkAccessManager;
+class BrowserApplication : public QApplication
+{
+ Q_OBJECT
+
+public:
+ BrowserApplication(int &argc, char **argv);
+ ~BrowserApplication();
+ static BrowserApplication *instance();
+ void loadSettings();
+
+ bool isTheOnlyBrowser() const;
+ BrowserMainWindow *mainWindow();
+ QList<BrowserMainWindow*> mainWindows();
+ QIcon icon(const QUrl &url) const;
+
+ void saveSession();
+ bool canRestoreSession() const;
+
+ static HistoryManager *historyManager();
+ static CookieJar *cookieJar();
+ static DownloadManager *downloadManager();
+ static NetworkAccessManager *networkAccessManager();
+ static BookmarksManager *bookmarksManager();
+
+#if defined(Q_WS_MAC)
+ bool event(QEvent *event);
+#endif
+
+public slots:
+ BrowserMainWindow *newMainWindow();
+ void restoreLastSession();
+#if defined(Q_WS_MAC)
+ void lastWindowClosed();
+ void quitBrowser();
+#endif
+
+private slots:
+ void postLaunch();
+ void openUrl(const QUrl &url);
+ void newLocalSocketConnection();
+
+private:
+ void clean();
+ void installTranslator(const QString &name);
+
+ static HistoryManager *s_historyManager;
+ static DownloadManager *s_downloadManager;
+ static NetworkAccessManager *s_networkAccessManager;
+ static BookmarksManager *s_bookmarksManager;
+
+ QList<QPointer<BrowserMainWindow> > m_mainWindows;
+ QLocalServer *m_localServer;
+ QByteArray m_lastSession;
+ mutable QIcon m_defaultIcon;
+};
+
+#endif // BROWSERAPPLICATION_H
+
diff --git a/examples/webkitwidgets/browser/browsermainwindow.cpp b/examples/webkitwidgets/browser/browsermainwindow.cpp
new file mode 100644
index 0000000..9561a3d
--- /dev/null
+++ b/examples/webkitwidgets/browser/browsermainwindow.cpp
@@ -0,0 +1,949 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browsermainwindow.h"
+
+#include "autosaver.h"
+#include "bookmarks.h"
+#include "browserapplication.h"
+#include "chasewidget.h"
+#include "downloadmanager.h"
+#include "history.h"
+#include "settings.h"
+#include "tabwidget.h"
+#include "toolbarsearch.h"
+#include "ui_passworddialog.h"
+#include "webview.h"
+
+#include <QtCore/QSettings>
+
+#include <QtWidgets/QDesktopWidget>
+#include <QtWidgets/QFileDialog>
+#include <QtWidgets/QPlainTextEdit>
+#include <QtPrintSupport/QPrintDialog>
+#include <QtPrintSupport/QPrintPreviewDialog>
+#include <QtPrintSupport/QPrinter>
+#include <QtWidgets/QMenuBar>
+#include <QtWidgets/QMessageBox>
+#include <QtWidgets/QStatusBar>
+#include <QtWidgets/QToolBar>
+#include <QtWidgets/QInputDialog>
+
+#include <QWebFrame>
+#include <QWebHistory>
+
+#include <QtCore/QDebug>
+
+BrowserMainWindow::BrowserMainWindow(QWidget *parent, Qt::WindowFlags flags)
+ : QMainWindow(parent, flags)
+ , m_tabWidget(new TabWidget(this))
+ , m_autoSaver(new AutoSaver(this))
+ , m_historyBack(0)
+ , m_historyForward(0)
+ , m_stop(0)
+ , m_reload(0)
+{
+ setToolButtonStyle(Qt::ToolButtonFollowStyle);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ statusBar()->setSizeGripEnabled(true);
+ setupMenu();
+ setupToolBar();
+
+ QWidget *centralWidget = new QWidget(this);
+ BookmarksModel *boomarksModel = BrowserApplication::bookmarksManager()->bookmarksModel();
+ m_bookmarksToolbar = new BookmarksToolBar(boomarksModel, this);
+ connect(m_bookmarksToolbar, SIGNAL(openUrl(QUrl)),
+ m_tabWidget, SLOT(loadUrlInCurrentTab(QUrl)));
+ connect(m_bookmarksToolbar->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(updateBookmarksToolbarActionText(bool)));
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setSpacing(0);
+ layout->setMargin(0);
+#if defined(Q_WS_MAC)
+ layout->addWidget(m_bookmarksToolbar);
+ layout->addWidget(new QWidget); // <- OS X tab widget style bug
+#else
+ addToolBarBreak();
+ addToolBar(m_bookmarksToolbar);
+#endif
+ layout->addWidget(m_tabWidget);
+ centralWidget->setLayout(layout);
+ setCentralWidget(centralWidget);
+
+ connect(m_tabWidget, SIGNAL(loadPage(QString)),
+ this, SLOT(loadPage(QString)));
+ connect(m_tabWidget, SIGNAL(setCurrentTitle(QString)),
+ this, SLOT(slotUpdateWindowTitle(QString)));
+ connect(m_tabWidget, SIGNAL(showStatusBarMessage(QString)),
+ statusBar(), SLOT(showMessage(QString)));
+ connect(m_tabWidget, SIGNAL(linkHovered(QString)),
+ statusBar(), SLOT(showMessage(QString)));
+ connect(m_tabWidget, SIGNAL(loadProgress(int)),
+ this, SLOT(slotLoadProgress(int)));
+ connect(m_tabWidget, SIGNAL(tabsChanged()),
+ m_autoSaver, SLOT(changeOccurred()));
+ connect(m_tabWidget, SIGNAL(geometryChangeRequested(QRect)),
+ this, SLOT(geometryChangeRequested(QRect)));
+ connect(m_tabWidget, SIGNAL(printRequested(QWebFrame*)),
+ this, SLOT(printRequested(QWebFrame*)));
+ connect(m_tabWidget, SIGNAL(menuBarVisibilityChangeRequested(bool)),
+ menuBar(), SLOT(setVisible(bool)));
+ connect(m_tabWidget, SIGNAL(statusBarVisibilityChangeRequested(bool)),
+ statusBar(), SLOT(setVisible(bool)));
+ connect(m_tabWidget, SIGNAL(toolBarVisibilityChangeRequested(bool)),
+ m_navigationBar, SLOT(setVisible(bool)));
+ connect(m_tabWidget, SIGNAL(toolBarVisibilityChangeRequested(bool)),
+ m_bookmarksToolbar, SLOT(setVisible(bool)));
+#if defined(Q_WS_MAC)
+ connect(m_tabWidget, SIGNAL(lastTabClosed()),
+ this, SLOT(close()));
+#else
+ connect(m_tabWidget, SIGNAL(lastTabClosed()),
+ m_tabWidget, SLOT(newTab()));
+#endif
+
+ slotUpdateWindowTitle();
+ loadDefaultState();
+ m_tabWidget->newTab();
+
+ int size = m_tabWidget->lineEditStack()->sizeHint().height();
+ m_navigationBar->setIconSize(QSize(size, size));
+
+}
+
+BrowserMainWindow::~BrowserMainWindow()
+{
+ m_autoSaver->changeOccurred();
+ m_autoSaver->saveIfNeccessary();
+}
+
+void BrowserMainWindow::loadDefaultState()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("BrowserMainWindow"));
+ QByteArray data = settings.value(QLatin1String("defaultState")).toByteArray();
+ restoreState(data);
+ settings.endGroup();
+}
+
+QSize BrowserMainWindow::sizeHint() const
+{
+ QRect desktopRect = QApplication::desktop()->screenGeometry();
+ QSize size = desktopRect.size() * qreal(0.9);
+ return size;
+}
+
+void BrowserMainWindow::save()
+{
+ BrowserApplication::instance()->saveSession();
+
+ QSettings settings;
+ settings.beginGroup(QLatin1String("BrowserMainWindow"));
+ QByteArray data = saveState(false);
+ settings.setValue(QLatin1String("defaultState"), data);
+ settings.endGroup();
+}
+
+static const qint32 BrowserMainWindowMagic = 0xba;
+
+QByteArray BrowserMainWindow::saveState(bool withTabs) const
+{
+ int version = 2;
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+
+ stream << qint32(BrowserMainWindowMagic);
+ stream << qint32(version);
+
+ stream << size();
+ stream << !m_navigationBar->isHidden();
+ stream << !m_bookmarksToolbar->isHidden();
+ stream << !statusBar()->isHidden();
+ if (withTabs)
+ stream << tabWidget()->saveState();
+ else
+ stream << QByteArray();
+ return data;
+}
+
+bool BrowserMainWindow::restoreState(const QByteArray &state)
+{
+ int version = 2;
+ QByteArray sd = state;
+ QDataStream stream(&sd, QIODevice::ReadOnly);
+ if (stream.atEnd())
+ return false;
+
+ qint32 marker;
+ qint32 v;
+ stream >> marker;
+ stream >> v;
+ if (marker != BrowserMainWindowMagic || v != version)
+ return false;
+
+ QSize size;
+ bool showToolbar;
+ bool showBookmarksBar;
+ bool showStatusbar;
+ QByteArray tabState;
+
+ stream >> size;
+ stream >> showToolbar;
+ stream >> showBookmarksBar;
+ stream >> showStatusbar;
+ stream >> tabState;
+
+ resize(size);
+
+ m_navigationBar->setVisible(showToolbar);
+ updateToolbarActionText(showToolbar);
+
+ m_bookmarksToolbar->setVisible(showBookmarksBar);
+ updateBookmarksToolbarActionText(showBookmarksBar);
+
+ statusBar()->setVisible(showStatusbar);
+ updateStatusbarActionText(showStatusbar);
+
+ if (!tabWidget()->restoreState(tabState))
+ return false;
+
+ return true;
+}
+
+void BrowserMainWindow::setupMenu()
+{
+ new QShortcut(QKeySequence(Qt::Key_F6), this, SLOT(slotSwapFocus()));
+
+ // File
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
+
+ fileMenu->addAction(tr("&New Window"), this, SLOT(slotFileNew()), QKeySequence::New);
+ fileMenu->addAction(m_tabWidget->newTabAction());
+ fileMenu->addAction(tr("&Open File..."), this, SLOT(slotFileOpen()), QKeySequence::Open);
+ fileMenu->addAction(tr("Open &Location..."), this,
+ SLOT(slotSelectLineEdit()), QKeySequence(Qt::ControlModifier + Qt::Key_L));
+ fileMenu->addSeparator();
+ fileMenu->addAction(m_tabWidget->closeTabAction());
+ fileMenu->addSeparator();
+ fileMenu->addAction(tr("&Save As..."), this,
+ SLOT(slotFileSaveAs()), QKeySequence(QKeySequence::Save));
+ fileMenu->addSeparator();
+ BookmarksManager *bookmarksManager = BrowserApplication::bookmarksManager();
+ fileMenu->addAction(tr("&Import Bookmarks..."), bookmarksManager, SLOT(importBookmarks()));
+ fileMenu->addAction(tr("&Export Bookmarks..."), bookmarksManager, SLOT(exportBookmarks()));
+ fileMenu->addSeparator();
+ fileMenu->addAction(tr("P&rint Preview..."), this, SLOT(slotFilePrintPreview()));
+ fileMenu->addAction(tr("&Print..."), this, SLOT(slotFilePrint()), QKeySequence::Print);
+ fileMenu->addSeparator();
+ QAction *action = fileMenu->addAction(tr("Private &Browsing..."), this, SLOT(slotPrivateBrowsing()));
+ action->setCheckable(true);
+ fileMenu->addSeparator();
+
+#if defined(Q_WS_MAC)
+ fileMenu->addAction(tr("&Quit"), BrowserApplication::instance(), SLOT(quitBrowser()), QKeySequence(Qt::CTRL | Qt::Key_Q));
+#else
+ fileMenu->addAction(tr("&Quit"), this, SLOT(close()), QKeySequence(Qt::CTRL | Qt::Key_Q));
+#endif
+
+ // Edit
+ QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
+ QAction *m_undo = editMenu->addAction(tr("&Undo"));
+ m_undo->setShortcuts(QKeySequence::Undo);
+ m_tabWidget->addWebAction(m_undo, QWebPage::Undo);
+ QAction *m_redo = editMenu->addAction(tr("&Redo"));
+ m_redo->setShortcuts(QKeySequence::Redo);
+ m_tabWidget->addWebAction(m_redo, QWebPage::Redo);
+ editMenu->addSeparator();
+ QAction *m_cut = editMenu->addAction(tr("Cu&t"));
+ m_cut->setShortcuts(QKeySequence::Cut);
+ m_tabWidget->addWebAction(m_cut, QWebPage::Cut);
+ QAction *m_copy = editMenu->addAction(tr("&Copy"));
+ m_copy->setShortcuts(QKeySequence::Copy);
+ m_tabWidget->addWebAction(m_copy, QWebPage::Copy);
+ QAction *m_paste = editMenu->addAction(tr("&Paste"));
+ m_paste->setShortcuts(QKeySequence::Paste);
+ m_tabWidget->addWebAction(m_paste, QWebPage::Paste);
+ editMenu->addSeparator();
+
+ QAction *m_find = editMenu->addAction(tr("&Find"));
+ m_find->setShortcuts(QKeySequence::Find);
+ connect(m_find, SIGNAL(triggered()), this, SLOT(slotEditFind()));
+ new QShortcut(QKeySequence(Qt::Key_Slash), this, SLOT(slotEditFind()));
+
+ QAction *m_findNext = editMenu->addAction(tr("&Find Next"));
+ m_findNext->setShortcuts(QKeySequence::FindNext);
+ connect(m_findNext, SIGNAL(triggered()), this, SLOT(slotEditFindNext()));
+
+ QAction *m_findPrevious = editMenu->addAction(tr("&Find Previous"));
+ m_findPrevious->setShortcuts(QKeySequence::FindPrevious);
+ connect(m_findPrevious, SIGNAL(triggered()), this, SLOT(slotEditFindPrevious()));
+
+ editMenu->addSeparator();
+ editMenu->addAction(tr("&Preferences"), this, SLOT(slotPreferences()), tr("Ctrl+,"));
+
+ // View
+ QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
+
+ m_viewBookmarkBar = new QAction(this);
+ updateBookmarksToolbarActionText(true);
+ m_viewBookmarkBar->setShortcut(tr("Shift+Ctrl+B"));
+ connect(m_viewBookmarkBar, SIGNAL(triggered()), this, SLOT(slotViewBookmarksBar()));
+ viewMenu->addAction(m_viewBookmarkBar);
+
+ m_viewToolbar = new QAction(this);
+ updateToolbarActionText(true);
+ m_viewToolbar->setShortcut(tr("Ctrl+|"));
+ connect(m_viewToolbar, SIGNAL(triggered()), this, SLOT(slotViewToolbar()));
+ viewMenu->addAction(m_viewToolbar);
+
+ m_viewStatusbar = new QAction(this);
+ updateStatusbarActionText(true);
+ m_viewStatusbar->setShortcut(tr("Ctrl+/"));
+ connect(m_viewStatusbar, SIGNAL(triggered()), this, SLOT(slotViewStatusbar()));
+ viewMenu->addAction(m_viewStatusbar);
+
+ viewMenu->addSeparator();
+
+ m_stop = viewMenu->addAction(tr("&Stop"));
+ QList<QKeySequence> shortcuts;
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Period));
+ shortcuts.append(Qt::Key_Escape);
+ m_stop->setShortcuts(shortcuts);
+ m_tabWidget->addWebAction(m_stop, QWebPage::Stop);
+
+ m_reload = viewMenu->addAction(tr("Reload Page"));
+ m_reload->setShortcuts(QKeySequence::Refresh);
+ m_tabWidget->addWebAction(m_reload, QWebPage::Reload);
+
+ viewMenu->addAction(tr("Zoom &In"), this, SLOT(slotViewZoomIn()), QKeySequence(Qt::CTRL | Qt::Key_Plus));
+ viewMenu->addAction(tr("Zoom &Out"), this, SLOT(slotViewZoomOut()), QKeySequence(Qt::CTRL | Qt::Key_Minus));
+ viewMenu->addAction(tr("Reset &Zoom"), this, SLOT(slotViewResetZoom()), QKeySequence(Qt::CTRL | Qt::Key_0));
+ QAction *zoomTextOnlyAction = viewMenu->addAction(tr("Zoom &Text Only"));
+ connect(zoomTextOnlyAction, SIGNAL(toggled(bool)), this, SLOT(slotViewZoomTextOnly(bool)));
+ zoomTextOnlyAction->setCheckable(true);
+ zoomTextOnlyAction->setChecked(false);
+
+ viewMenu->addSeparator();
+ viewMenu->addAction(tr("Page S&ource"), this, SLOT(slotViewPageSource()), tr("Ctrl+Alt+U"));
+ QAction *a = viewMenu->addAction(tr("&Full Screen"), this, SLOT(slotViewFullScreen(bool)), Qt::Key_F11);
+ a->setCheckable(true);
+
+ // History
+ HistoryMenu *historyMenu = new HistoryMenu(this);
+ connect(historyMenu, SIGNAL(openUrl(QUrl)),
+ m_tabWidget, SLOT(loadUrlInCurrentTab(QUrl)));
+ connect(historyMenu, SIGNAL(hovered(QString)), this,
+ SLOT(slotUpdateStatusbar(QString)));
+ historyMenu->setTitle(tr("Hi&story"));
+ menuBar()->addMenu(historyMenu);
+ QList<QAction*> historyActions;
+
+ m_historyBack = new QAction(tr("Back"), this);
+ m_tabWidget->addWebAction(m_historyBack, QWebPage::Back);
+ m_historyBack->setShortcuts(QKeySequence::Back);
+ m_historyBack->setIconVisibleInMenu(false);
+
+ m_historyForward = new QAction(tr("Forward"), this);
+ m_tabWidget->addWebAction(m_historyForward, QWebPage::Forward);
+ m_historyForward->setShortcuts(QKeySequence::Forward);
+ m_historyForward->setIconVisibleInMenu(false);
+
+ QAction *m_historyHome = new QAction(tr("Home"), this);
+ connect(m_historyHome, SIGNAL(triggered()), this, SLOT(slotHome()));
+ m_historyHome->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_H));
+
+ m_restoreLastSession = new QAction(tr("Restore Last Session"), this);
+ connect(m_restoreLastSession, SIGNAL(triggered()), BrowserApplication::instance(), SLOT(restoreLastSession()));
+ m_restoreLastSession->setEnabled(BrowserApplication::instance()->canRestoreSession());
+
+ historyActions.append(m_historyBack);
+ historyActions.append(m_historyForward);
+ historyActions.append(m_historyHome);
+ historyActions.append(m_tabWidget->recentlyClosedTabsAction());
+ historyActions.append(m_restoreLastSession);
+ historyMenu->setInitialActions(historyActions);
+
+ // Bookmarks
+ BookmarksMenu *bookmarksMenu = new BookmarksMenu(this);
+ connect(bookmarksMenu, SIGNAL(openUrl(QUrl)),
+ m_tabWidget, SLOT(loadUrlInCurrentTab(QUrl)));
+ connect(bookmarksMenu, SIGNAL(hovered(QString)),
+ this, SLOT(slotUpdateStatusbar(QString)));
+ bookmarksMenu->setTitle(tr("&Bookmarks"));
+ menuBar()->addMenu(bookmarksMenu);
+
+ QList<QAction*> bookmarksActions;
+
+ QAction *showAllBookmarksAction = new QAction(tr("Show All Bookmarks"), this);
+ connect(showAllBookmarksAction, SIGNAL(triggered()), this, SLOT(slotShowBookmarksDialog()));
+ m_addBookmark = new QAction(QIcon(QLatin1String(":addbookmark.png")), tr("Add Bookmark..."), this);
+ m_addBookmark->setIconVisibleInMenu(false);
+
+ connect(m_addBookmark, SIGNAL(triggered()), this, SLOT(slotAddBookmark()));
+ m_addBookmark->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_D));
+
+ bookmarksActions.append(showAllBookmarksAction);
+ bookmarksActions.append(m_addBookmark);
+ bookmarksMenu->setInitialActions(bookmarksActions);
+
+ // Window
+ m_windowMenu = menuBar()->addMenu(tr("&Window"));
+ connect(m_windowMenu, SIGNAL(aboutToShow()),
+ this, SLOT(slotAboutToShowWindowMenu()));
+ slotAboutToShowWindowMenu();
+
+ QMenu *toolsMenu = menuBar()->addMenu(tr("&Tools"));
+ toolsMenu->addAction(tr("Web &Search"), this, SLOT(slotWebSearch()), QKeySequence(tr("Ctrl+K", "Web Search")));
+ a = toolsMenu->addAction(tr("Enable Web &Inspector"), this, SLOT(slotToggleInspector(bool)));
+ a->setCheckable(true);
+
+ QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
+ helpMenu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
+ helpMenu->addAction(tr("About &Demo Browser"), this, SLOT(slotAboutApplication()));
+}
+
+void BrowserMainWindow::setupToolBar()
+{
+ setUnifiedTitleAndToolBarOnMac(true);
+ m_navigationBar = addToolBar(tr("Navigation"));
+ connect(m_navigationBar->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(updateToolbarActionText(bool)));
+
+ m_historyBack->setIcon(style()->standardIcon(QStyle::SP_ArrowBack, 0, this));
+ m_historyBackMenu = new QMenu(this);
+ m_historyBack->setMenu(m_historyBackMenu);
+ connect(m_historyBackMenu, SIGNAL(aboutToShow()),
+ this, SLOT(slotAboutToShowBackMenu()));
+ connect(m_historyBackMenu, SIGNAL(triggered(QAction*)),
+ this, SLOT(slotOpenActionUrl(QAction*)));
+ m_navigationBar->addAction(m_historyBack);
+
+ m_historyForward->setIcon(style()->standardIcon(QStyle::SP_ArrowForward, 0, this));
+ m_historyForwardMenu = new QMenu(this);
+ connect(m_historyForwardMenu, SIGNAL(aboutToShow()),
+ this, SLOT(slotAboutToShowForwardMenu()));
+ connect(m_historyForwardMenu, SIGNAL(triggered(QAction*)),
+ this, SLOT(slotOpenActionUrl(QAction*)));
+ m_historyForward->setMenu(m_historyForwardMenu);
+ m_navigationBar->addAction(m_historyForward);
+
+ m_stopReload = new QAction(this);
+ m_reloadIcon = style()->standardIcon(QStyle::SP_BrowserReload);
+ m_stopReload->setIcon(m_reloadIcon);
+
+ m_navigationBar->addAction(m_stopReload);
+
+ m_navigationBar->addWidget(m_tabWidget->lineEditStack());
+
+ m_toolbarSearch = new ToolbarSearch(m_navigationBar);
+ m_navigationBar->addWidget(m_toolbarSearch);
+ connect(m_toolbarSearch, SIGNAL(search(QUrl)), SLOT(loadUrl(QUrl)));
+
+ m_chaseWidget = new ChaseWidget(this);
+ m_navigationBar->addWidget(m_chaseWidget);
+}
+
+void BrowserMainWindow::slotShowBookmarksDialog()
+{
+ BookmarksDialog *dialog = new BookmarksDialog(this);
+ connect(dialog, SIGNAL(openUrl(QUrl)),
+ m_tabWidget, SLOT(loadUrlInCurrentTab(QUrl)));
+ dialog->show();
+}
+
+void BrowserMainWindow::slotAddBookmark()
+{
+ WebView *webView = currentTab();
+ QString url = webView->url().toString();
+ QString title = webView->title();
+ AddBookmarkDialog dialog(url, title);
+ dialog.exec();
+}
+
+void BrowserMainWindow::slotViewToolbar()
+{
+ if (m_navigationBar->isVisible()) {
+ updateToolbarActionText(false);
+ m_navigationBar->close();
+ } else {
+ updateToolbarActionText(true);
+ m_navigationBar->show();
+ }
+ m_autoSaver->changeOccurred();
+}
+
+void BrowserMainWindow::slotViewBookmarksBar()
+{
+ if (m_bookmarksToolbar->isVisible()) {
+ updateBookmarksToolbarActionText(false);
+ m_bookmarksToolbar->close();
+ } else {
+ updateBookmarksToolbarActionText(true);
+ m_bookmarksToolbar->show();
+ }
+ m_autoSaver->changeOccurred();
+}
+
+void BrowserMainWindow::updateStatusbarActionText(bool visible)
+{
+ m_viewStatusbar->setText(!visible ? tr("Show Status Bar") : tr("Hide Status Bar"));
+}
+
+void BrowserMainWindow::updateToolbarActionText(bool visible)
+{
+ m_viewToolbar->setText(!visible ? tr("Show Toolbar") : tr("Hide Toolbar"));
+}
+
+void BrowserMainWindow::updateBookmarksToolbarActionText(bool visible)
+{
+ m_viewBookmarkBar->setText(!visible ? tr("Show Bookmarks bar") : tr("Hide Bookmarks bar"));
+}
+
+void BrowserMainWindow::slotViewStatusbar()
+{
+ if (statusBar()->isVisible()) {
+ updateStatusbarActionText(false);
+ statusBar()->close();
+ } else {
+ updateStatusbarActionText(true);
+ statusBar()->show();
+ }
+ m_autoSaver->changeOccurred();
+}
+
+void BrowserMainWindow::loadUrl(const QUrl &url)
+{
+ if (!currentTab() || !url.isValid())
+ return;
+
+ m_tabWidget->currentLineEdit()->setText(QString::fromUtf8(url.toEncoded()));
+ m_tabWidget->loadUrlInCurrentTab(url);
+}
+
+void BrowserMainWindow::slotDownloadManager()
+{
+ BrowserApplication::downloadManager()->show();
+}
+
+void BrowserMainWindow::slotSelectLineEdit()
+{
+ m_tabWidget->currentLineEdit()->selectAll();
+ m_tabWidget->currentLineEdit()->setFocus();
+}
+
+void BrowserMainWindow::slotFileSaveAs()
+{
+ BrowserApplication::downloadManager()->download(currentTab()->url(), true);
+}
+
+void BrowserMainWindow::slotPreferences()
+{
+ SettingsDialog *s = new SettingsDialog(this);
+ s->show();
+}
+
+void BrowserMainWindow::slotUpdateStatusbar(const QString &string)
+{
+ statusBar()->showMessage(string, 2000);
+}
+
+void BrowserMainWindow::slotUpdateWindowTitle(const QString &title)
+{
+ if (title.isEmpty()) {
+ setWindowTitle(tr("Qt Demo Browser"));
+ } else {
+#if defined(Q_WS_MAC)
+ setWindowTitle(title);
+#else
+ setWindowTitle(tr("%1 - Qt Demo Browser", "Page title and Browser name").arg(title));
+#endif
+ }
+}
+
+void BrowserMainWindow::slotAboutApplication()
+{
+ QMessageBox::about(this, tr("About"), tr(
+ "Version %1"
+ "<p>This demo demonstrates Qt's "
+ "webkit facilities in action, providing an example "
+ "browser for you to experiment with.<p>"
+ "<p>QtWebKit is based on the Open Source WebKit Project developed at <a href=\"http://webkit.org/\">http://webkit.org/</a>."
+ ).arg(QCoreApplication::applicationVersion()));
+}
+
+void BrowserMainWindow::slotFileNew()
+{
+ BrowserApplication::instance()->newMainWindow();
+ BrowserMainWindow *mw = BrowserApplication::instance()->mainWindow();
+ mw->slotHome();
+}
+
+void BrowserMainWindow::slotFileOpen()
+{
+ QString file = QFileDialog::getOpenFileName(this, tr("Open Web Resource"), QString(),
+ tr("Web Resources (*.html *.htm *.svg *.png *.gif *.svgz);;All files (*.*)"));
+
+ if (file.isEmpty())
+ return;
+
+ loadPage(file);
+}
+
+void BrowserMainWindow::slotFilePrintPreview()
+{
+#ifndef QT_NO_PRINTER
+ if (!currentTab())
+ return;
+ QPrintPreviewDialog *dialog = new QPrintPreviewDialog(this);
+ connect(dialog, SIGNAL(paintRequested(QPrinter*)),
+ currentTab(), SLOT(print(QPrinter*)));
+ dialog->exec();
+#endif
+}
+
+void BrowserMainWindow::slotFilePrint()
+{
+ if (!currentTab())
+ return;
+ printRequested(currentTab()->page()->mainFrame());
+}
+
+void BrowserMainWindow::printRequested(QWebFrame *frame)
+{
+#ifndef QT_NO_PRINTER
+ QPrinter printer;
+ QPrintDialog *dialog = new QPrintDialog(&printer, this);
+ dialog->setWindowTitle(tr("Print Document"));
+ if (dialog->exec() != QDialog::Accepted)
+ return;
+ frame->print(&printer);
+#endif
+}
+
+void BrowserMainWindow::slotPrivateBrowsing()
+{
+ QWebSettings *settings = QWebSettings::globalSettings();
+ bool pb = settings->testAttribute(QWebSettings::PrivateBrowsingEnabled);
+ if (!pb) {
+ QString title = tr("Are you sure you want to turn on private browsing?");
+ QString text = tr("<b>%1</b><br><br>When private browsing in turned on,"
+ " webpages are not added to the history,"
+ " items are automatically removed from the Downloads window," \
+ " new cookies are not stored, current cookies can't be accessed," \
+ " site icons wont be stored, session wont be saved, " \
+ " and searches are not added to the pop-up menu in the Google search box." \
+ " Until you close the window, you can still click the Back and Forward buttons" \
+ " to return to the webpages you have opened.").arg(title);
+
+ QMessageBox::StandardButton button = QMessageBox::question(this, QString(), text,
+ QMessageBox::Ok | QMessageBox::Cancel,
+ QMessageBox::Ok);
+ if (button == QMessageBox::Ok) {
+ settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, true);
+ }
+ } else {
+ settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false);
+
+ QList<BrowserMainWindow*> windows = BrowserApplication::instance()->mainWindows();
+ for (int i = 0; i < windows.count(); ++i) {
+ BrowserMainWindow *window = windows.at(i);
+ window->m_lastSearch = QString::null;
+ window->tabWidget()->clear();
+ }
+ }
+}
+
+void BrowserMainWindow::closeEvent(QCloseEvent *event)
+{
+ if (m_tabWidget->count() > 1) {
+ int ret = QMessageBox::warning(this, QString(),
+ tr("Are you sure you want to close the window?"
+ " There are %1 tabs open").arg(m_tabWidget->count()),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No);
+ if (ret == QMessageBox::No) {
+ event->ignore();
+ return;
+ }
+ }
+ event->accept();
+ deleteLater();
+}
+
+void BrowserMainWindow::slotEditFind()
+{
+ if (!currentTab())
+ return;
+ bool ok;
+ QString search = QInputDialog::getText(this, tr("Find"),
+ tr("Text:"), QLineEdit::Normal,
+ m_lastSearch, &ok);
+ if (ok && !search.isEmpty()) {
+ m_lastSearch = search;
+ if (!currentTab()->findText(m_lastSearch))
+ slotUpdateStatusbar(tr("\"%1\" not found.").arg(m_lastSearch));
+ }
+}
+
+void BrowserMainWindow::slotEditFindNext()
+{
+ if (!currentTab() && !m_lastSearch.isEmpty())
+ return;
+ currentTab()->findText(m_lastSearch);
+}
+
+void BrowserMainWindow::slotEditFindPrevious()
+{
+ if (!currentTab() && !m_lastSearch.isEmpty())
+ return;
+ currentTab()->findText(m_lastSearch, QWebPage::FindBackward);
+}
+
+void BrowserMainWindow::slotViewZoomIn()
+{
+ if (!currentTab())
+ return;
+ currentTab()->setZoomFactor(currentTab()->zoomFactor() + 0.1);
+}
+
+void BrowserMainWindow::slotViewZoomOut()
+{
+ if (!currentTab())
+ return;
+ currentTab()->setZoomFactor(currentTab()->zoomFactor() - 0.1);
+}
+
+void BrowserMainWindow::slotViewResetZoom()
+{
+ if (!currentTab())
+ return;
+ currentTab()->setZoomFactor(1.0);
+}
+
+void BrowserMainWindow::slotViewZoomTextOnly(bool enable)
+{
+ if (!currentTab())
+ return;
+ currentTab()->page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, enable);
+}
+
+void BrowserMainWindow::slotViewFullScreen(bool makeFullScreen)
+{
+ if (makeFullScreen) {
+ showFullScreen();
+ } else {
+ if (isMinimized())
+ showMinimized();
+ else if (isMaximized())
+ showMaximized();
+ else showNormal();
+ }
+}
+
+void BrowserMainWindow::slotViewPageSource()
+{
+ if (!currentTab())
+ return;
+
+ QString markup = currentTab()->page()->mainFrame()->toHtml();
+ QPlainTextEdit *view = new QPlainTextEdit(markup);
+ view->setWindowTitle(tr("Page Source of %1").arg(currentTab()->title()));
+ view->setMinimumWidth(640);
+ view->setAttribute(Qt::WA_DeleteOnClose);
+ view->show();
+}
+
+void BrowserMainWindow::slotHome()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("MainWindow"));
+ QString home = settings.value(QLatin1String("home"), QLatin1String("http://qt-project.org/")).toString();
+ loadPage(home);
+}
+
+void BrowserMainWindow::slotWebSearch()
+{
+ m_toolbarSearch->lineEdit()->selectAll();
+ m_toolbarSearch->lineEdit()->setFocus();
+}
+
+void BrowserMainWindow::slotToggleInspector(bool enable)
+{
+ QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, enable);
+ if (enable) {
+ int result = QMessageBox::question(this, tr("Web Inspector"),
+ tr("The web inspector will only work correctly for pages that were loaded after enabling.\n"
+ "Do you want to reload all pages?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (result == QMessageBox::Yes) {
+ m_tabWidget->reloadAllTabs();
+ }
+ }
+}
+
+void BrowserMainWindow::slotSwapFocus()
+{
+ if (currentTab()->hasFocus())
+ m_tabWidget->currentLineEdit()->setFocus();
+ else
+ currentTab()->setFocus();
+}
+
+void BrowserMainWindow::loadPage(const QString &page)
+{
+ QUrl url = QUrl::fromUserInput(page);
+ loadUrl(url);
+}
+
+TabWidget *BrowserMainWindow::tabWidget() const
+{
+ return m_tabWidget;
+}
+
+WebView *BrowserMainWindow::currentTab() const
+{
+ return m_tabWidget->currentWebView();
+}
+
+void BrowserMainWindow::slotLoadProgress(int progress)
+{
+ if (progress < 100 && progress > 0) {
+ m_chaseWidget->setAnimated(true);
+ disconnect(m_stopReload, SIGNAL(triggered()), m_reload, SLOT(trigger()));
+ if (m_stopIcon.isNull())
+ m_stopIcon = style()->standardIcon(QStyle::SP_BrowserStop);
+ m_stopReload->setIcon(m_stopIcon);
+ connect(m_stopReload, SIGNAL(triggered()), m_stop, SLOT(trigger()));
+ m_stopReload->setToolTip(tr("Stop loading the current page"));
+ } else {
+ m_chaseWidget->setAnimated(false);
+ disconnect(m_stopReload, SIGNAL(triggered()), m_stop, SLOT(trigger()));
+ m_stopReload->setIcon(m_reloadIcon);
+ connect(m_stopReload, SIGNAL(triggered()), m_reload, SLOT(trigger()));
+ m_stopReload->setToolTip(tr("Reload the current page"));
+ }
+}
+
+void BrowserMainWindow::slotAboutToShowBackMenu()
+{
+ m_historyBackMenu->clear();
+ if (!currentTab())
+ return;
+ QWebHistory *history = currentTab()->history();
+ int historyCount = history->count();
+ for (int i = history->backItems(historyCount).count() - 1; i >= 0; --i) {
+ QWebHistoryItem item = history->backItems(history->count()).at(i);
+ QAction *action = new QAction(this);
+ action->setData(-1*(historyCount-i-1));
+ QIcon icon = BrowserApplication::instance()->icon(item.url());
+ action->setIcon(icon);
+ action->setText(item.title());
+ m_historyBackMenu->addAction(action);
+ }
+}
+
+void BrowserMainWindow::slotAboutToShowForwardMenu()
+{
+ m_historyForwardMenu->clear();
+ if (!currentTab())
+ return;
+ QWebHistory *history = currentTab()->history();
+ int historyCount = history->count();
+ for (int i = 0; i < history->forwardItems(history->count()).count(); ++i) {
+ QWebHistoryItem item = history->forwardItems(historyCount).at(i);
+ QAction *action = new QAction(this);
+ action->setData(historyCount-i);
+ QIcon icon = BrowserApplication::instance()->icon(item.url());
+ action->setIcon(icon);
+ action->setText(item.title());
+ m_historyForwardMenu->addAction(action);
+ }
+}
+
+void BrowserMainWindow::slotAboutToShowWindowMenu()
+{
+ m_windowMenu->clear();
+ m_windowMenu->addAction(m_tabWidget->nextTabAction());
+ m_windowMenu->addAction(m_tabWidget->previousTabAction());
+ m_windowMenu->addSeparator();
+ m_windowMenu->addAction(tr("Downloads"), this, SLOT(slotDownloadManager()), QKeySequence(tr("Alt+Ctrl+L", "Download Manager")));
+
+ m_windowMenu->addSeparator();
+ QList<BrowserMainWindow*> windows = BrowserApplication::instance()->mainWindows();
+ for (int i = 0; i < windows.count(); ++i) {
+ BrowserMainWindow *window = windows.at(i);
+ QAction *action = m_windowMenu->addAction(window->windowTitle(), this, SLOT(slotShowWindow()));
+ action->setData(i);
+ action->setCheckable(true);
+ if (window == this)
+ action->setChecked(true);
+ }
+}
+
+void BrowserMainWindow::slotShowWindow()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ QVariant v = action->data();
+ if (v.canConvert<int>()) {
+ int offset = qvariant_cast<int>(v);
+ QList<BrowserMainWindow*> windows = BrowserApplication::instance()->mainWindows();
+ windows.at(offset)->activateWindow();
+ windows.at(offset)->currentTab()->setFocus();
+ }
+ }
+}
+
+void BrowserMainWindow::slotOpenActionUrl(QAction *action)
+{
+ int offset = action->data().toInt();
+ QWebHistory *history = currentTab()->history();
+ if (offset < 0)
+ history->goToItem(history->backItems(-1*offset).first()); // back
+ else if (offset > 0)
+ history->goToItem(history->forwardItems(history->count() - offset + 1).back()); // forward
+ }
+
+void BrowserMainWindow::geometryChangeRequested(const QRect &geometry)
+{
+ setGeometry(geometry);
+}
+
diff --git a/examples/webkitwidgets/browser/browsermainwindow.h b/examples/webkitwidgets/browser/browsermainwindow.h
new file mode 100644
index 0000000..8a93a14
--- /dev/null
+++ b/examples/webkitwidgets/browser/browsermainwindow.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BROWSERMAINWINDOW_H
+#define BROWSERMAINWINDOW_H
+
+#include <QtWidgets/QMainWindow>
+#include <QtGui/QIcon>
+#include <QtCore/QUrl>
+
+class AutoSaver;
+class BookmarksToolBar;
+class ChaseWidget;
+class QWebFrame;
+class TabWidget;
+class ToolbarSearch;
+class WebView;
+
+/*!
+ The MainWindow of the Browser Application.
+
+ Handles the tab widget and all the actions
+ */
+class BrowserMainWindow : public QMainWindow {
+ Q_OBJECT
+
+public:
+ BrowserMainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~BrowserMainWindow();
+ QSize sizeHint() const;
+
+public:
+ TabWidget *tabWidget() const;
+ WebView *currentTab() const;
+ QByteArray saveState(bool withTabs = true) const;
+ bool restoreState(const QByteArray &state);
+
+public slots:
+ void loadPage(const QString &url);
+ void slotHome();
+
+protected:
+ void closeEvent(QCloseEvent *event);
+
+private slots:
+ void save();
+
+ void slotLoadProgress(int);
+ void slotUpdateStatusbar(const QString &string);
+ void slotUpdateWindowTitle(const QString &title = QString());
+
+ void loadUrl(const QUrl &url);
+ void slotPreferences();
+
+ void slotFileNew();
+ void slotFileOpen();
+ void slotFilePrintPreview();
+ void slotFilePrint();
+ void slotPrivateBrowsing();
+ void slotFileSaveAs();
+ void slotEditFind();
+ void slotEditFindNext();
+ void slotEditFindPrevious();
+ void slotShowBookmarksDialog();
+ void slotAddBookmark();
+ void slotViewZoomIn();
+ void slotViewZoomOut();
+ void slotViewResetZoom();
+ void slotViewZoomTextOnly(bool enable);
+ void slotViewToolbar();
+ void slotViewBookmarksBar();
+ void slotViewStatusbar();
+ void slotViewPageSource();
+ void slotViewFullScreen(bool enable);
+
+ void slotWebSearch();
+ void slotToggleInspector(bool enable);
+ void slotAboutApplication();
+ void slotDownloadManager();
+ void slotSelectLineEdit();
+
+ void slotAboutToShowBackMenu();
+ void slotAboutToShowForwardMenu();
+ void slotAboutToShowWindowMenu();
+ void slotOpenActionUrl(QAction *action);
+ void slotShowWindow();
+ void slotSwapFocus();
+
+ void printRequested(QWebFrame *frame);
+ void geometryChangeRequested(const QRect &geometry);
+ void updateToolbarActionText(bool visible);
+ void updateBookmarksToolbarActionText(bool visible);
+
+private:
+ void loadDefaultState();
+ void setupMenu();
+ void setupToolBar();
+ void updateStatusbarActionText(bool visible);
+
+private:
+ QToolBar *m_navigationBar;
+ ToolbarSearch *m_toolbarSearch;
+ BookmarksToolBar *m_bookmarksToolbar;
+ ChaseWidget *m_chaseWidget;
+ TabWidget *m_tabWidget;
+ AutoSaver *m_autoSaver;
+
+ QAction *m_historyBack;
+ QMenu *m_historyBackMenu;
+ QAction *m_historyForward;
+ QMenu *m_historyForwardMenu;
+ QMenu *m_windowMenu;
+
+ QAction *m_stop;
+ QAction *m_reload;
+ QAction *m_stopReload;
+ QAction *m_viewToolbar;
+ QAction *m_viewBookmarkBar;
+ QAction *m_viewStatusbar;
+ QAction *m_restoreLastSession;
+ QAction *m_addBookmark;
+
+ QIcon m_reloadIcon;
+ QIcon m_stopIcon;
+
+ QString m_lastSearch;
+};
+
+#endif // BROWSERMAINWINDOW_H
+
diff --git a/examples/webkitwidgets/browser/chasewidget.cpp b/examples/webkitwidgets/browser/chasewidget.cpp
new file mode 100644
index 0000000..7ab98ee
--- /dev/null
+++ b/examples/webkitwidgets/browser/chasewidget.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "chasewidget.h"
+
+#include <QtCore/QPoint>
+
+#include <QtWidgets/QApplication>
+#include <QtGui/QHideEvent>
+#include <QtGui/QPainter>
+#include <QtGui/QPaintEvent>
+#include <QtGui/QShowEvent>
+
+ChaseWidget::ChaseWidget(QWidget *parent, QPixmap pixmap, bool pixmapEnabled)
+ : QWidget(parent)
+ , m_segment(0)
+ , m_delay(100)
+ , m_step(40)
+ , m_timerId(-1)
+ , m_animated(false)
+ , m_pixmap(pixmap)
+ , m_pixmapEnabled(pixmapEnabled)
+{
+}
+
+void ChaseWidget::setAnimated(bool value)
+{
+ if (m_animated == value)
+ return;
+ m_animated = value;
+ if (m_timerId != -1) {
+ killTimer(m_timerId);
+ m_timerId = -1;
+ }
+ if (m_animated) {
+ m_segment = 0;
+ m_timerId = startTimer(m_delay);
+ }
+ update();
+}
+
+void ChaseWidget::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainter p(this);
+ if (m_pixmapEnabled && !m_pixmap.isNull()) {
+ p.drawPixmap(0, 0, m_pixmap);
+ return;
+ }
+
+ const int extent = qMin(width() - 8, height() - 8);
+ const int displ = extent / 4;
+ const int ext = extent / 4 - 1;
+
+ p.setRenderHint(QPainter::Antialiasing, true);
+
+ if(m_animated)
+ p.setPen(Qt::gray);
+ else
+ p.setPen(QPen(palette().dark().color()));
+
+ p.translate(width() / 2, height() / 2); // center
+
+ for (int segment = 0; segment < segmentCount(); ++segment) {
+ p.rotate(QApplication::isRightToLeft() ? m_step : -m_step);
+ if(m_animated)
+ p.setBrush(colorForSegment(segment));
+ else
+ p.setBrush(palette().background());
+ p.drawEllipse(QRect(displ, -ext / 2, ext, ext));
+ }
+}
+
+QSize ChaseWidget::sizeHint() const
+{
+ return QSize(32, 32);
+}
+
+void ChaseWidget::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == m_timerId) {
+ ++m_segment;
+ update();
+ }
+ QWidget::timerEvent(event);
+}
+
+QColor ChaseWidget::colorForSegment(int seg) const
+{
+ int index = ((seg + m_segment) % segmentCount());
+ int comp = qMax(0, 255 - (index * (255 / segmentCount())));
+ return QColor(comp, comp, comp, 255);
+}
+
+int ChaseWidget::segmentCount() const
+{
+ return 360 / m_step;
+}
+
+void ChaseWidget::setPixmapEnabled(bool enable)
+{
+ m_pixmapEnabled = enable;
+}
+
diff --git a/examples/webkitwidgets/browser/chasewidget.h b/examples/webkitwidgets/browser/chasewidget.h
new file mode 100644
index 0000000..ba98c3b
--- /dev/null
+++ b/examples/webkitwidgets/browser/chasewidget.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CHASEWIDGET_H
+#define CHASEWIDGET_H
+
+#include <QtWidgets/QWidget>
+
+#include <QtCore/QSize>
+#include <QtGui/QColor>
+#include <QtGui/QPixmap>
+
+QT_BEGIN_NAMESPACE
+class QHideEvent;
+class QShowEvent;
+class QPaintEvent;
+class QTimerEvent;
+QT_END_NAMESPACE
+
+class ChaseWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ ChaseWidget(QWidget *parent = 0, QPixmap pixmap = QPixmap(), bool pixmapEnabled = false);
+
+ void setAnimated(bool value);
+ void setPixmapEnabled(bool enable);
+ QSize sizeHint() const;
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void timerEvent(QTimerEvent *event);
+
+private:
+ int segmentCount() const;
+ QColor colorForSegment(int segment) const;
+
+ int m_segment;
+ int m_delay;
+ int m_step;
+ int m_timerId;
+ bool m_animated;
+ QPixmap m_pixmap;
+ bool m_pixmapEnabled;
+};
+
+#endif
diff --git a/examples/webkitwidgets/browser/cookiejar.cpp b/examples/webkitwidgets/browser/cookiejar.cpp
new file mode 100644
index 0000000..d2d72ef
--- /dev/null
+++ b/examples/webkitwidgets/browser/cookiejar.cpp
@@ -0,0 +1,738 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "cookiejar.h"
+
+#include "autosaver.h"
+
+#include <QtCore/QDateTime>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QMetaEnum>
+#include <QtCore/QSettings>
+#include <QtCore/QUrl>
+
+#include <QtWidgets/QCompleter>
+#include <QtGui/QDesktopServices>
+#include <QtGui/QFont>
+#include <QtGui/QFontMetrics>
+#include <QtWidgets/QHeaderView>
+#include <QtGui/QKeyEvent>
+#include <QtCore/QSortFilterProxyModel>
+#include <QtNetwork/QNetworkCookie>
+
+#include <QWebSettings>
+
+#include <QtCore/QDebug>
+
+static const unsigned int JAR_VERSION = 23;
+
+QT_BEGIN_NAMESPACE
+QDataStream &operator<<(QDataStream &stream, const QList<QNetworkCookie> &list)
+{
+ stream << JAR_VERSION;
+ stream << quint32(list.size());
+ for (int i = 0; i < list.size(); ++i)
+ stream << list.at(i).toRawForm();
+ return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
+{
+ list.clear();
+
+ quint32 version;
+ stream >> version;
+
+ if (version != JAR_VERSION)
+ return stream;
+
+ quint32 count;
+ stream >> count;
+ for(quint32 i = 0; i < count; ++i)
+ {
+ QByteArray value;
+ stream >> value;
+ QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(value);
+ if (newCookies.count() == 0 && value.length() != 0) {
+ qWarning() << "CookieJar: Unable to parse saved cookie:" << value;
+ }
+ for (int j = 0; j < newCookies.count(); ++j)
+ list.append(newCookies.at(j));
+ if (stream.atEnd())
+ break;
+ }
+ return stream;
+}
+QT_END_NAMESPACE
+
+CookieJar::CookieJar(QObject *parent)
+ : QNetworkCookieJar(parent)
+ , m_loaded(false)
+ , m_saveTimer(new AutoSaver(this))
+ , m_acceptCookies(AcceptOnlyFromSitesNavigatedTo)
+{
+}
+
+CookieJar::~CookieJar()
+{
+ if (m_keepCookies == KeepUntilExit)
+ clear();
+ m_saveTimer->saveIfNeccessary();
+}
+
+void CookieJar::clear()
+{
+ setAllCookies(QList<QNetworkCookie>());
+ m_saveTimer->changeOccurred();
+ emit cookiesChanged();
+}
+
+void CookieJar::load()
+{
+ if (m_loaded)
+ return;
+ // load cookies and exceptions
+ qRegisterMetaTypeStreamOperators<QList<QNetworkCookie> >("QList<QNetworkCookie>");
+ QSettings cookieSettings(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/cookies.ini"), QSettings::IniFormat);
+ setAllCookies(qvariant_cast<QList<QNetworkCookie> >(cookieSettings.value(QLatin1String("cookies"))));
+ cookieSettings.beginGroup(QLatin1String("Exceptions"));
+ m_exceptions_block = cookieSettings.value(QLatin1String("block")).toStringList();
+ m_exceptions_allow = cookieSettings.value(QLatin1String("allow")).toStringList();
+ m_exceptions_allowForSession = cookieSettings.value(QLatin1String("allowForSession")).toStringList();
+ qSort(m_exceptions_block.begin(), m_exceptions_block.end());
+ qSort(m_exceptions_allow.begin(), m_exceptions_allow.end());
+ qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end());
+
+ loadSettings();
+}
+
+void CookieJar::loadSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("cookies"));
+ QByteArray value = settings.value(QLatin1String("acceptCookies"),
+ QLatin1String("AcceptOnlyFromSitesNavigatedTo")).toByteArray();
+ QMetaEnum acceptPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AcceptPolicy"));
+ m_acceptCookies = acceptPolicyEnum.keyToValue(value) == -1 ?
+ AcceptOnlyFromSitesNavigatedTo :
+ static_cast<AcceptPolicy>(acceptPolicyEnum.keyToValue(value));
+
+ value = settings.value(QLatin1String("keepCookiesUntil"), QLatin1String("KeepUntilExpire")).toByteArray();
+ QMetaEnum keepPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("KeepPolicy"));
+ m_keepCookies = keepPolicyEnum.keyToValue(value) == -1 ?
+ KeepUntilExpire :
+ static_cast<KeepPolicy>(keepPolicyEnum.keyToValue(value));
+
+ if (m_keepCookies == KeepUntilExit)
+ setAllCookies(QList<QNetworkCookie>());
+
+ m_loaded = true;
+ emit cookiesChanged();
+}
+
+void CookieJar::save()
+{
+ if (!m_loaded)
+ return;
+ purgeOldCookies();
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
+ if (directory.isEmpty())
+ directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
+ if (!QFile::exists(directory)) {
+ QDir dir;
+ dir.mkpath(directory);
+ }
+ QSettings cookieSettings(directory + QLatin1String("/cookies.ini"), QSettings::IniFormat);
+ QList<QNetworkCookie> cookies = allCookies();
+ for (int i = cookies.count() - 1; i >= 0; --i) {
+ if (cookies.at(i).isSessionCookie())
+ cookies.removeAt(i);
+ }
+ cookieSettings.setValue(QLatin1String("cookies"), QVariant::fromValue<QList<QNetworkCookie> >(cookies));
+ cookieSettings.beginGroup(QLatin1String("Exceptions"));
+ cookieSettings.setValue(QLatin1String("block"), m_exceptions_block);
+ cookieSettings.setValue(QLatin1String("allow"), m_exceptions_allow);
+ cookieSettings.setValue(QLatin1String("allowForSession"), m_exceptions_allowForSession);
+
+ // save cookie settings
+ QSettings settings;
+ settings.beginGroup(QLatin1String("cookies"));
+ QMetaEnum acceptPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("AcceptPolicy"));
+ settings.setValue(QLatin1String("acceptCookies"), QLatin1String(acceptPolicyEnum.valueToKey(m_acceptCookies)));
+
+ QMetaEnum keepPolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("KeepPolicy"));
+ settings.setValue(QLatin1String("keepCookiesUntil"), QLatin1String(keepPolicyEnum.valueToKey(m_keepCookies)));
+}
+
+void CookieJar::purgeOldCookies()
+{
+ QList<QNetworkCookie> cookies = allCookies();
+ if (cookies.isEmpty())
+ return;
+ int oldCount = cookies.count();
+ QDateTime now = QDateTime::currentDateTime();
+ for (int i = cookies.count() - 1; i >= 0; --i) {
+ if (!cookies.at(i).isSessionCookie() && cookies.at(i).expirationDate() < now)
+ cookies.removeAt(i);
+ }
+ if (oldCount == cookies.count())
+ return;
+ setAllCookies(cookies);
+ emit cookiesChanged();
+}
+
+QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const
+{
+ CookieJar *that = const_cast<CookieJar*>(this);
+ if (!m_loaded)
+ that->load();
+
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) {
+ QList<QNetworkCookie> noCookies;
+ return noCookies;
+ }
+
+ return QNetworkCookieJar::cookiesForUrl(url);
+}
+
+bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url)
+{
+ if (!m_loaded)
+ load();
+
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled))
+ return false;
+
+ QString host = url.host();
+ bool eBlock = qBinaryFind(m_exceptions_block.begin(), m_exceptions_block.end(), host) != m_exceptions_block.end();
+ bool eAllow = qBinaryFind(m_exceptions_allow.begin(), m_exceptions_allow.end(), host) != m_exceptions_allow.end();
+ bool eAllowSession = qBinaryFind(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end(), host) != m_exceptions_allowForSession.end();
+
+ bool addedCookies = false;
+ // pass exceptions
+ bool acceptInitially = (m_acceptCookies != AcceptNever);
+ if ((acceptInitially && !eBlock)
+ || (!acceptInitially && (eAllow || eAllowSession))) {
+ // pass url domain == cookie domain
+ QDateTime soon = QDateTime::currentDateTime();
+ soon = soon.addDays(90);
+ foreach(QNetworkCookie cookie, cookieList) {
+ QList<QNetworkCookie> lst;
+ if (m_keepCookies == KeepUntilTimeLimit
+ && !cookie.isSessionCookie()
+ && cookie.expirationDate() > soon) {
+ cookie.setExpirationDate(soon);
+ }
+ lst += cookie;
+ if (QNetworkCookieJar::setCookiesFromUrl(lst, url)) {
+ addedCookies = true;
+ } else {
+ // finally force it in if wanted
+ if (m_acceptCookies == AcceptAlways) {
+ QList<QNetworkCookie> cookies = allCookies();
+ cookies += cookie;
+ setAllCookies(cookies);
+ addedCookies = true;
+ }
+#if 0
+ else
+ qWarning() << "setCookiesFromUrl failed" << url << cookieList.value(0).toRawForm();
+#endif
+ }
+ }
+ }
+
+ if (addedCookies) {
+ m_saveTimer->changeOccurred();
+ emit cookiesChanged();
+ }
+ return addedCookies;
+}
+
+CookieJar::AcceptPolicy CookieJar::acceptPolicy() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_acceptCookies;
+}
+
+void CookieJar::setAcceptPolicy(AcceptPolicy policy)
+{
+ if (!m_loaded)
+ load();
+ if (policy == m_acceptCookies)
+ return;
+ m_acceptCookies = policy;
+ m_saveTimer->changeOccurred();
+}
+
+CookieJar::KeepPolicy CookieJar::keepPolicy() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_keepCookies;
+}
+
+void CookieJar::setKeepPolicy(KeepPolicy policy)
+{
+ if (!m_loaded)
+ load();
+ if (policy == m_keepCookies)
+ return;
+ m_keepCookies = policy;
+ m_saveTimer->changeOccurred();
+}
+
+QStringList CookieJar::blockedCookies() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_exceptions_block;
+}
+
+QStringList CookieJar::allowedCookies() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_exceptions_allow;
+}
+
+QStringList CookieJar::allowForSessionCookies() const
+{
+ if (!m_loaded)
+ (const_cast<CookieJar*>(this))->load();
+ return m_exceptions_allowForSession;
+}
+
+void CookieJar::setBlockedCookies(const QStringList &list)
+{
+ if (!m_loaded)
+ load();
+ m_exceptions_block = list;
+ qSort(m_exceptions_block.begin(), m_exceptions_block.end());
+ m_saveTimer->changeOccurred();
+}
+
+void CookieJar::setAllowedCookies(const QStringList &list)
+{
+ if (!m_loaded)
+ load();
+ m_exceptions_allow = list;
+ qSort(m_exceptions_allow.begin(), m_exceptions_allow.end());
+ m_saveTimer->changeOccurred();
+}
+
+void CookieJar::setAllowForSessionCookies(const QStringList &list)
+{
+ if (!m_loaded)
+ load();
+ m_exceptions_allowForSession = list;
+ qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end());
+ m_saveTimer->changeOccurred();
+}
+
+CookieModel::CookieModel(CookieJar *cookieJar, QObject *parent)
+ : QAbstractTableModel(parent)
+ , m_cookieJar(cookieJar)
+{
+ connect(m_cookieJar, SIGNAL(cookiesChanged()), this, SLOT(cookiesChanged()));
+ m_cookieJar->load();
+}
+
+QVariant CookieModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::SizeHintRole) {
+ QFont font;
+ font.setPointSize(10);
+ QFontMetrics fm(font);
+ int height = fm.height() + fm.height()/3;
+ int width = fm.width(headerData(section, orientation, Qt::DisplayRole).toString());
+ return QSize(width, height);
+ }
+
+ if (orientation == Qt::Horizontal) {
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ switch (section) {
+ case 0:
+ return tr("Website");
+ case 1:
+ return tr("Name");
+ case 2:
+ return tr("Path");
+ case 3:
+ return tr("Secure");
+ case 4:
+ return tr("Expires");
+ case 5:
+ return tr("Contents");
+ default:
+ return QVariant();
+ }
+ }
+ return QAbstractTableModel::headerData(section, orientation, role);
+}
+
+QVariant CookieModel::data(const QModelIndex &index, int role) const
+{
+ QList<QNetworkCookie> lst;
+ if (m_cookieJar)
+ lst = m_cookieJar->allCookies();
+ if (index.row() < 0 || index.row() >= lst.size())
+ return QVariant();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ case Qt::EditRole: {
+ QNetworkCookie cookie = lst.at(index.row());
+ switch (index.column()) {
+ case 0:
+ return cookie.domain();
+ case 1:
+ return cookie.name();
+ case 2:
+ return cookie.path();
+ case 3:
+ return cookie.isSecure();
+ case 4:
+ return cookie.expirationDate();
+ case 5:
+ return cookie.value();
+ }
+ }
+ case Qt::FontRole:{
+ QFont font;
+ font.setPointSize(10);
+ return font;
+ }
+ }
+
+ return QVariant();
+}
+
+int CookieModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 6;
+}
+
+int CookieModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid() || !m_cookieJar) ? 0 : m_cookieJar->allCookies().count();
+}
+
+bool CookieModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid() || !m_cookieJar)
+ return false;
+ int lastRow = row + count - 1;
+ beginRemoveRows(parent, row, lastRow);
+ QList<QNetworkCookie> lst = m_cookieJar->allCookies();
+ for (int i = lastRow; i >= row; --i) {
+ lst.removeAt(i);
+ }
+ m_cookieJar->setAllCookies(lst);
+ endRemoveRows();
+ return true;
+}
+
+void CookieModel::cookiesChanged()
+{
+ beginResetModel();
+ endResetModel();
+}
+
+CookiesDialog::CookiesDialog(CookieJar *cookieJar, QWidget *parent) : QDialog(parent)
+{
+ setupUi(this);
+ setWindowFlags(Qt::Sheet);
+ CookieModel *model = new CookieModel(cookieJar, this);
+ m_proxyModel = new QSortFilterProxyModel(this);
+ connect(search, SIGNAL(textChanged(QString)),
+ m_proxyModel, SLOT(setFilterFixedString(QString)));
+ connect(removeButton, SIGNAL(clicked()), cookiesTable, SLOT(removeOne()));
+ connect(removeAllButton, SIGNAL(clicked()), cookiesTable, SLOT(removeAll()));
+ m_proxyModel->setSourceModel(model);
+ cookiesTable->verticalHeader()->hide();
+ cookiesTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ cookiesTable->setModel(m_proxyModel);
+ cookiesTable->setAlternatingRowColors(true);
+ cookiesTable->setTextElideMode(Qt::ElideMiddle);
+ cookiesTable->setShowGrid(false);
+ cookiesTable->setSortingEnabled(true);
+ QFont f = font();
+ f.setPointSize(10);
+ QFontMetrics fm(f);
+ int height = fm.height() + fm.height()/3;
+ cookiesTable->verticalHeader()->setDefaultSectionSize(height);
+ cookiesTable->verticalHeader()->setMinimumSectionSize(-1);
+ for (int i = 0; i < model->columnCount(); ++i){
+ int header = cookiesTable->horizontalHeader()->sectionSizeHint(i);
+ switch (i) {
+ case 0:
+ header = fm.width(QLatin1String("averagehost.domain.com"));
+ break;
+ case 1:
+ header = fm.width(QLatin1String("_session_id"));
+ break;
+ case 4:
+ header = fm.width(QDateTime::currentDateTime().toString(Qt::LocalDate));
+ break;
+ }
+ int buffer = fm.width(QLatin1String("xx"));
+ header += buffer;
+ cookiesTable->horizontalHeader()->resizeSection(i, header);
+ }
+ cookiesTable->horizontalHeader()->setStretchLastSection(true);
+}
+
+
+
+CookieExceptionsModel::CookieExceptionsModel(CookieJar *cookiejar, QObject *parent)
+ : QAbstractTableModel(parent)
+ , m_cookieJar(cookiejar)
+{
+ m_allowedCookies = m_cookieJar->allowedCookies();
+ m_blockedCookies = m_cookieJar->blockedCookies();
+ m_sessionCookies = m_cookieJar->allowForSessionCookies();
+}
+
+QVariant CookieExceptionsModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::SizeHintRole) {
+ QFont font;
+ font.setPointSize(10);
+ QFontMetrics fm(font);
+ int height = fm.height() + fm.height()/3;
+ int width = fm.width(headerData(section, orientation, Qt::DisplayRole).toString());
+ return QSize(width, height);
+ }
+
+ if (orientation == Qt::Horizontal
+ && role == Qt::DisplayRole) {
+ switch (section) {
+ case 0:
+ return tr("Website");
+ case 1:
+ return tr("Status");
+ }
+ }
+ return QAbstractTableModel::headerData(section, orientation, role);
+}
+
+QVariant CookieExceptionsModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() < 0 || index.row() >= rowCount())
+ return QVariant();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ case Qt::EditRole: {
+ int row = index.row();
+ if (row < m_allowedCookies.count()) {
+ switch (index.column()) {
+ case 0:
+ return m_allowedCookies.at(row);
+ case 1:
+ return tr("Allow");
+ }
+ }
+ row = row - m_allowedCookies.count();
+ if (row < m_blockedCookies.count()) {
+ switch (index.column()) {
+ case 0:
+ return m_blockedCookies.at(row);
+ case 1:
+ return tr("Block");
+ }
+ }
+ row = row - m_blockedCookies.count();
+ if (row < m_sessionCookies.count()) {
+ switch (index.column()) {
+ case 0:
+ return m_sessionCookies.at(row);
+ case 1:
+ return tr("Allow For Session");
+ }
+ }
+ }
+ case Qt::FontRole:{
+ QFont font;
+ font.setPointSize(10);
+ return font;
+ }
+ }
+ return QVariant();
+}
+
+int CookieExceptionsModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 2;
+}
+
+int CookieExceptionsModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid() || !m_cookieJar) ? 0 : m_allowedCookies.count() + m_blockedCookies.count() + m_sessionCookies.count();
+}
+
+bool CookieExceptionsModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid() || !m_cookieJar)
+ return false;
+
+ int lastRow = row + count - 1;
+ beginRemoveRows(parent, row, lastRow);
+ for (int i = lastRow; i >= row; --i) {
+ if (i < m_allowedCookies.count()) {
+ m_allowedCookies.removeAt(row);
+ continue;
+ }
+ i = i - m_allowedCookies.count();
+ if (i < m_blockedCookies.count()) {
+ m_blockedCookies.removeAt(row);
+ continue;
+ }
+ i = i - m_blockedCookies.count();
+ if (i < m_sessionCookies.count()) {
+ m_sessionCookies.removeAt(row);
+ continue;
+ }
+ }
+ m_cookieJar->setAllowedCookies(m_allowedCookies);
+ m_cookieJar->setBlockedCookies(m_blockedCookies);
+ m_cookieJar->setAllowForSessionCookies(m_sessionCookies);
+ endRemoveRows();
+ return true;
+}
+
+CookiesExceptionsDialog::CookiesExceptionsDialog(CookieJar *cookieJar, QWidget *parent)
+ : QDialog(parent)
+ , m_cookieJar(cookieJar)
+{
+ setupUi(this);
+ setWindowFlags(Qt::Sheet);
+ connect(removeButton, SIGNAL(clicked()), exceptionTable, SLOT(removeOne()));
+ connect(removeAllButton, SIGNAL(clicked()), exceptionTable, SLOT(removeAll()));
+ exceptionTable->verticalHeader()->hide();
+ exceptionTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ exceptionTable->setAlternatingRowColors(true);
+ exceptionTable->setTextElideMode(Qt::ElideMiddle);
+ exceptionTable->setShowGrid(false);
+ exceptionTable->setSortingEnabled(true);
+ m_exceptionsModel = new CookieExceptionsModel(cookieJar, this);
+ m_proxyModel = new QSortFilterProxyModel(this);
+ m_proxyModel->setSourceModel(m_exceptionsModel);
+ connect(search, SIGNAL(textChanged(QString)),
+ m_proxyModel, SLOT(setFilterFixedString(QString)));
+ exceptionTable->setModel(m_proxyModel);
+
+ CookieModel *cookieModel = new CookieModel(cookieJar, this);
+ domainLineEdit->setCompleter(new QCompleter(cookieModel, domainLineEdit));
+
+ connect(domainLineEdit, SIGNAL(textChanged(QString)),
+ this, SLOT(textChanged(QString)));
+ connect(blockButton, SIGNAL(clicked()), this, SLOT(block()));
+ connect(allowButton, SIGNAL(clicked()), this, SLOT(allow()));
+ connect(allowForSessionButton, SIGNAL(clicked()), this, SLOT(allowForSession()));
+
+ QFont f = font();
+ f.setPointSize(10);
+ QFontMetrics fm(f);
+ int height = fm.height() + fm.height()/3;
+ exceptionTable->verticalHeader()->setDefaultSectionSize(height);
+ exceptionTable->verticalHeader()->setMinimumSectionSize(-1);
+ for (int i = 0; i < m_exceptionsModel->columnCount(); ++i){
+ int header = exceptionTable->horizontalHeader()->sectionSizeHint(i);
+ switch (i) {
+ case 0:
+ header = fm.width(QLatin1String("averagebiglonghost.domain.com"));
+ break;
+ case 1:
+ header = fm.width(QLatin1String("Allow For Session"));
+ break;
+ }
+ int buffer = fm.width(QLatin1String("xx"));
+ header += buffer;
+ exceptionTable->horizontalHeader()->resizeSection(i, header);
+ }
+}
+
+void CookiesExceptionsDialog::textChanged(const QString &text)
+{
+ bool enabled = !text.isEmpty();
+ blockButton->setEnabled(enabled);
+ allowButton->setEnabled(enabled);
+ allowForSessionButton->setEnabled(enabled);
+}
+
+void CookiesExceptionsDialog::block()
+{
+ if (domainLineEdit->text().isEmpty())
+ return;
+ m_exceptionsModel->m_blockedCookies.append(domainLineEdit->text());
+ m_cookieJar->setBlockedCookies(m_exceptionsModel->m_blockedCookies);
+ m_exceptionsModel->beginResetModel();
+ m_exceptionsModel->endResetModel();
+}
+
+void CookiesExceptionsDialog::allow()
+{
+ if (domainLineEdit->text().isEmpty())
+ return;
+ m_exceptionsModel->m_allowedCookies.append(domainLineEdit->text());
+ m_cookieJar->setAllowedCookies(m_exceptionsModel->m_allowedCookies);
+ m_exceptionsModel->beginResetModel();
+ m_exceptionsModel->endResetModel();
+}
+
+void CookiesExceptionsDialog::allowForSession()
+{
+ if (domainLineEdit->text().isEmpty())
+ return;
+ m_exceptionsModel->m_sessionCookies.append(domainLineEdit->text());
+ m_cookieJar->setAllowForSessionCookies(m_exceptionsModel->m_sessionCookies);
+ m_exceptionsModel->beginResetModel();
+ m_exceptionsModel->endResetModel();
+}
+
diff --git a/examples/webkitwidgets/browser/cookiejar.h b/examples/webkitwidgets/browser/cookiejar.h
new file mode 100644
index 0000000..3029c38
--- /dev/null
+++ b/examples/webkitwidgets/browser/cookiejar.h
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COOKIEJAR_H
+#define COOKIEJAR_H
+
+#include <QtNetwork/QNetworkCookieJar>
+
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QStringList>
+
+#include <QtWidgets/QDialog>
+#include <QtWidgets/QTableView>
+
+QT_BEGIN_NAMESPACE
+class QSortFilterProxyModel;
+class QKeyEvent;
+QT_END_NAMESPACE
+
+class AutoSaver;
+
+class CookieJar : public QNetworkCookieJar
+{
+ friend class CookieModel;
+ Q_OBJECT
+ Q_PROPERTY(AcceptPolicy acceptPolicy READ acceptPolicy WRITE setAcceptPolicy)
+ Q_PROPERTY(KeepPolicy keepPolicy READ keepPolicy WRITE setKeepPolicy)
+ Q_PROPERTY(QStringList blockedCookies READ blockedCookies WRITE setBlockedCookies)
+ Q_PROPERTY(QStringList allowedCookies READ allowedCookies WRITE setAllowedCookies)
+ Q_PROPERTY(QStringList allowForSessionCookies READ allowForSessionCookies WRITE setAllowForSessionCookies)
+ Q_ENUMS(KeepPolicy)
+ Q_ENUMS(AcceptPolicy)
+
+signals:
+ void cookiesChanged();
+
+public:
+ enum AcceptPolicy {
+ AcceptAlways,
+ AcceptNever,
+ AcceptOnlyFromSitesNavigatedTo
+ };
+
+ enum KeepPolicy {
+ KeepUntilExpire,
+ KeepUntilExit,
+ KeepUntilTimeLimit
+ };
+
+ CookieJar(QObject *parent = 0);
+ ~CookieJar();
+
+ QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const;
+ bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url);
+
+ AcceptPolicy acceptPolicy() const;
+ void setAcceptPolicy(AcceptPolicy policy);
+
+ KeepPolicy keepPolicy() const;
+ void setKeepPolicy(KeepPolicy policy);
+
+ QStringList blockedCookies() const;
+ QStringList allowedCookies() const;
+ QStringList allowForSessionCookies() const;
+
+ void setBlockedCookies(const QStringList &list);
+ void setAllowedCookies(const QStringList &list);
+ void setAllowForSessionCookies(const QStringList &list);
+
+public slots:
+ void clear();
+ void loadSettings();
+
+private slots:
+ void save();
+
+private:
+ void purgeOldCookies();
+ void load();
+ bool m_loaded;
+ AutoSaver *m_saveTimer;
+
+ AcceptPolicy m_acceptCookies;
+ KeepPolicy m_keepCookies;
+
+ QStringList m_exceptions_block;
+ QStringList m_exceptions_allow;
+ QStringList m_exceptions_allowForSession;
+};
+
+class CookieModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ CookieModel(CookieJar *jar, QObject *parent = 0);
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+private slots:
+ void cookiesChanged();
+
+private:
+ CookieJar *m_cookieJar;
+};
+
+#include "ui_cookies.h"
+#include "ui_cookiesexceptions.h"
+
+class CookiesDialog : public QDialog, public Ui_CookiesDialog
+{
+ Q_OBJECT
+
+public:
+ CookiesDialog(CookieJar *cookieJar, QWidget *parent = 0);
+
+private:
+ QSortFilterProxyModel *m_proxyModel;
+};
+
+class CookieExceptionsModel : public QAbstractTableModel
+{
+ Q_OBJECT
+ friend class CookiesExceptionsDialog;
+
+public:
+ CookieExceptionsModel(CookieJar *cookieJar, QObject *parent = 0);
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+private:
+ CookieJar *m_cookieJar;
+
+ // Domains we allow, Domains we block, Domains we allow for this session
+ QStringList m_allowedCookies;
+ QStringList m_blockedCookies;
+ QStringList m_sessionCookies;
+};
+
+class CookiesExceptionsDialog : public QDialog, public Ui_CookiesExceptionsDialog
+{
+ Q_OBJECT
+
+public:
+ CookiesExceptionsDialog(CookieJar *cookieJar, QWidget *parent = 0);
+
+private slots:
+ void block();
+ void allow();
+ void allowForSession();
+ void textChanged(const QString &text);
+
+private:
+ CookieExceptionsModel *m_exceptionsModel;
+ QSortFilterProxyModel *m_proxyModel;
+ CookieJar *m_cookieJar;
+};
+
+#endif // COOKIEJAR_H
+
diff --git a/examples/webkitwidgets/browser/cookies.ui b/examples/webkitwidgets/browser/cookies.ui
new file mode 100644
index 0000000..c4bccc5
--- /dev/null
+++ b/examples/webkitwidgets/browser/cookies.ui
@@ -0,0 +1,106 @@
+<ui version="4.0" >
+ <class>CookiesDialog</class>
+ <widget class="QDialog" name="CookiesDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>550</width>
+ <height>370</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Cookies</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>252</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1" >
+ <widget class="SearchLineEdit" name="search" />
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="EditTableView" name="cookiesTable" />
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeAllButton" >
+ <property name="text" >
+ <string>Remove &amp;All Cookies</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SearchLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>searchlineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>EditTableView</class>
+ <extends>QTableView</extends>
+ <header>edittableview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>CookiesDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>472</x>
+ <y>329</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>461</x>
+ <y>356</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webkitwidgets/browser/cookiesexceptions.ui b/examples/webkitwidgets/browser/cookiesexceptions.ui
new file mode 100644
index 0000000..3d9ef62
--- /dev/null
+++ b/examples/webkitwidgets/browser/cookiesexceptions.ui
@@ -0,0 +1,184 @@
+<ui version="4.0" >
+ <class>CookiesExceptionsDialog</class>
+ <widget class="QDialog" name="CookiesExceptionsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>466</width>
+ <height>446</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Cookie Exceptions</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QGroupBox" name="newExceptionGroupBox" >
+ <property name="title" >
+ <string>New Exception</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Domain:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="domainLineEdit" />
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>81</width>
+ <height>25</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="blockButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Block</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="allowForSessionButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Allow For Session</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="allowButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Allow</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="ExceptionsGroupBox" >
+ <property name="title" >
+ <string>Exceptions</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" colspan="3" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>252</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="3" >
+ <widget class="SearchLineEdit" name="search" />
+ </item>
+ <item row="1" column="0" colspan="4" >
+ <widget class="EditTableView" name="exceptionTable" />
+ </item>
+ <item row="2" column="0" >
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QPushButton" name="removeAllButton" >
+ <property name="text" >
+ <string>Remove &amp;All</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SearchLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>searchlineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>EditTableView</class>
+ <extends>QTableView</extends>
+ <header>edittableview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>CookiesExceptionsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>381</x>
+ <y>428</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>336</x>
+ <y>443</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webkitwidgets/browser/data/addtab.png b/examples/webkitwidgets/browser/data/addtab.png
new file mode 100644
index 0000000..20928fb
--- /dev/null
+++ b/examples/webkitwidgets/browser/data/addtab.png
Binary files differ
diff --git a/examples/webkitwidgets/browser/data/browser.svg b/examples/webkitwidgets/browser/data/browser.svg
new file mode 100644
index 0000000..9908aed
--- /dev/null
+++ b/examples/webkitwidgets/browser/data/browser.svg
@@ -0,0 +1,411 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48px"
+ height="48px"
+ id="svg2160"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ inkscape:export-filename="c:\icons\qtbrowser48.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:docbase="C:\icons"
+ sodipodi:docname="browser.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs2162"><linearGradient
+ id="linearGradient3808">
+ <stop
+ id="stop3810"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.54263568;" />
+ <stop
+ id="stop3812"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+</linearGradient>
+<inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective63" />
+<linearGradient
+ id="linearGradient3326">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.3137255;"
+ offset="0"
+ id="stop3328" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3330" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3318">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.3137255;"
+ offset="0"
+ id="stop3320" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3322" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3302">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.3137255;"
+ offset="0"
+ id="stop3304" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3306" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3267">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3269" />
+ <stop
+ id="stop3275"
+ offset="0.79661018"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3271" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3745">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.19587629;"
+ offset="0"
+ id="stop3747" />
+ <stop
+ style="stop-color:#7cb2ff;stop-opacity:0.07216495;"
+ offset="1"
+ id="stop3749" />
+</linearGradient>
+<linearGradient
+ inkscape:collect="always"
+ id="linearGradient3561">
+ <stop
+ style="stop-color:#b1d0ff;stop-opacity:1;"
+ offset="0"
+ id="stop3563" />
+ <stop
+ style="stop-color:#b1d0ff;stop-opacity:0;"
+ offset="1"
+ id="stop3565" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3181">
+ <stop
+ style="stop-color:#4f7a33;stop-opacity:1;"
+ offset="0"
+ id="stop3183" />
+ <stop
+ style="stop-color:#204712;stop-opacity:1;"
+ offset="1"
+ id="stop3185" />
+</linearGradient>
+<linearGradient
+ id="linearGradient3143">
+ <stop
+ style="stop-color:#c1dbff;stop-opacity:1;"
+ offset="0"
+ id="stop3145" />
+ <stop
+ style="stop-color:#004e92;stop-opacity:1;"
+ offset="1"
+ id="stop3147" />
+</linearGradient>
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3143"
+ id="radialGradient3149"
+ cx="9.1428566"
+ cy="15.142858"
+ fx="9.1428566"
+ fy="15.142858"
+ r="20.121096"
+ gradientUnits="userSpaceOnUse" />
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3181"
+ id="radialGradient3187"
+ cx="10.739879"
+ cy="18.250999"
+ fx="10.739879"
+ fy="18.250999"
+ r="7.4191086"
+ gradientTransform="matrix(1.0504709,0,0,1.5077925,-0.3797113,-9.2677171)"
+ gradientUnits="userSpaceOnUse" />
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3181"
+ id="radialGradient3195"
+ cx="14.947268"
+ cy="35.920116"
+ fx="14.947268"
+ fy="35.920116"
+ r="6.0472684"
+ gradientTransform="matrix(1,0,0,0.7248478,0,9.8834985)"
+ gradientUnits="userSpaceOnUse" />
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3181"
+ id="radialGradient3203"
+ cx="34.227203"
+ cy="24.681196"
+ fx="34.227203"
+ fy="24.681196"
+ r="6.7517419"
+ gradientTransform="matrix(0.9941509,-0.1079997,0.2962199,2.7267411,-7.1108629,-38.921508)"
+ gradientUnits="userSpaceOnUse" />
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3561"
+ id="radialGradient3567"
+ cx="22.714285"
+ cy="23.571428"
+ fx="22.714285"
+ fy="23.571428"
+ r="19.828572"
+ gradientUnits="userSpaceOnUse" />
+<linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3745"
+ id="linearGradient3751"
+ x1="0.84126461"
+ y1="13.678415"
+ x2="31.397495"
+ y2="13.678415"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8791332,0.7829527,-0.6285195,1.0951445,14.147627,-10.49311)" />
+<filter
+ inkscape:collect="always"
+ id="filter4176">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.27747502"
+ id="feGaussianBlur4178" />
+</filter>
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3267"
+ id="radialGradient3273"
+ cx="22.714285"
+ cy="23.571428"
+ fx="22.714285"
+ fy="23.571428"
+ r="19.428572"
+ gradientUnits="userSpaceOnUse" />
+<inkscape:perspective
+ id="perspective136"
+ inkscape:persp3d-origin="138.6795 : 92.479329 : 1"
+ inkscape:vp_z="277.35901 : 138.71899 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 138.71899 : 1"
+ sodipodi:type="inkscape:persp3d" />
+
+
+
+
+
+
+
+
+
+
+<linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3808"
+ id="linearGradient3806"
+ x1="32.829472"
+ y1="32.055603"
+ x2="34.522324"
+ y2="-1.0290829"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8832227,0,0,1,-8.0103007,9.1923882)" />
+</defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="5.6568542"
+ inkscape:cx="30.924085"
+ inkscape:cy="24.59691"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1299"
+ inkscape:window-height="883"
+ inkscape:window-x="373"
+ inkscape:window-y="89"
+ showguides="false" />
+ <metadata
+ id="metadata2165">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Qt Browser</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jens Bache-Wiig</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:rights>
+ <cc:Agent>
+ <dc:title>Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).</dc:title>
+ </cc:Agent>
+ </dc:rights>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.78108437;fill:url(#radialGradient3273);fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3407"
+ sodipodi:cx="22.714285"
+ sodipodi:cy="23.571428"
+ sodipodi:rx="19.428572"
+ sodipodi:ry="19.428572"
+ d="M 42.142857,23.571428 A 19.428572,19.428572 0 1 1 3.2857132,23.571428 A 19.428572,19.428572 0 1 1 42.142857,23.571428 z"
+ transform="matrix(1.0818892,0,0,1.0409446,-2.4313375,0.4303723)" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#radialGradient3149);fill-opacity:1;stroke:none;stroke-width:0.80000000000000004;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path2170"
+ sodipodi:cx="22.714285"
+ sodipodi:cy="23.571428"
+ sodipodi:rx="19.428572"
+ sodipodi:ry="19.428572"
+ d="M 42.142857 23.571428 A 19.428572 19.428572 0 1 1 3.2857132,23.571428 A 19.428572 19.428572 0 1 1 42.142857 23.571428 z" />
+ <path
+ d="M 26.602136,8.2160843 C 26.322653,8.1637524 26.048884,8.1512446 25.78375,8.1745351 L 25.783243,8.1743913 C 25.783243,8.1743913 23.973525,8.3138471 23.891496,8.3211793 C 22.239361,8.4705552 20.985434,10.008307 20.985434,12.131916 L 20.985434,37.174579 L 22.83515,39.126673 L 41.425135,33.998394 C 42.704203,33.746799 43.714709,33.629384 43.714709,31.78483 L 43.714709,11.392226 L 26.602136,8.2160843 z"
+ id="path2998"
+ style="fill:url(#linearGradient3806);fill-opacity:1"
+ sodipodi:nodetypes="cccsccccccc" />
+ <path
+ style="fill:url(#radialGradient3203);fill-opacity:1;fill-rule:evenodd;stroke:#1d3215;stroke-width:0.51392877000000003;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 37.535517,11.721122 C 32.782916,8.7478602 30.602351,6.3542385 32.09957,13.4346 C 32.320572,14.27055 33.291276,13.739232 33.291276,14.862228 C 33.291276,16.155819 32.607502,17.380765 31.797574,18.146663 C 30.959323,18.939344 31.011357,20.258984 31.797574,21.002459 C 33.06234,22.198469 33.942515,22.715936 35.572536,22.715936 C 36.6448,22.715936 37.003629,23.274262 37.23352,24.143834 C 37.362263,24.630808 38.410486,25.085663 38.894503,25.428942 C 38.938905,25.460433 38.139512,26.551348 38.139512,27.999158 C 38.139512,29.113512 38.405167,29.358325 38.743505,29.998215 C 38.949111,30.387072 36.418877,30.283794 36.025532,30.283794 C 35.005751,30.283794 34.181701,30.712163 33.15656,30.712163 C 32.264543,30.712163 31.099578,30.3566 31.344578,31.283323 C 31.763542,32.868074 32.552566,33.932342 32.552566,35.709806 C 32.552566,36.862272 31.047367,37.598377 30.287588,38.137232 C 29.30273,38.835721 29.133207,39.307154 28.475606,40.136289 C 28.132145,40.569341 26.990548,41.409612 28.475606,40.707448 C 29.476144,40.234375 31.192063,39.423774 32.09957,38.565601 C 33.257846,37.470293 34.527421,37.269266 35.723534,36.138176 C 36.659137,35.253436 37.512933,34.691155 38.29051,33.710749 C 39.024031,32.785889 39.498498,31.90347 39.498498,30.712163 C 39.498498,29.682482 39.308098,28.750366 39.951493,28.141948 C 40.902684,24.235856 42.225874,19.789742 39.751646,16.005086 C 38.569376,15.014407 37.717516,13.109859 37.535517,11.721122 z "
+ id="path3151"
+ sodipodi:nodetypes="ccsssssssssssssssssssccc" />
+ <path
+ style="fill:url(#radialGradient3187);fill-opacity:1;fill-rule:evenodd;stroke:#063a0a;stroke-width:0.51231807;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 14.777083,7.8630009 C 14.047432,8.4403746 12.751987,10.898939 13.27641,12.146301 C 13.709874,13.177316 14.920827,13.613143 15.827553,13.859622 C 16.568703,14.061091 17.049015,14.457271 17.478293,15.001835 C 17.832696,15.451415 17.971105,16.346745 18.078563,16.857932 C 18.298637,17.904845 18.947911,17.058563 17.62836,18.000145 C 17.234352,18.281296 14.875696,18.000145 14.476948,18.000145 C 11.976825,18.384083 14.297504,19.464893 14.92715,20.712903 C 15.204987,21.770261 15.377352,22.405336 15.377352,23.711213 C 15.377352,24.875672 15.377352,24.78389 15.377352,25.99564 C 15.377352,27.194757 15.044241,27.28063 13.876679,27.28063 C 13.023055,27.28063 12.647321,26.423969 11.625669,26.423969 C 10.400599,26.423969 11.303539,27.667106 11.475602,27.994513 C 12.006402,29.004538 11.662121,29.599737 10.875334,28.851174 C 9.855722,27.881096 8.8280305,26.760556 8.0240557,25.99564 C 2.8789379,25.807372 4.5677903,23.466499 3.9722395,18.999582 C 5.041259,16.526382 4.7558935,17.248897 7.2737194,12.574632 C 10.149914,9.5491592 13.589212,5.9532919 14.777083,7.8630009 z"
+ id="path3159"
+ sodipodi:nodetypes="csssssccsssssscccc" />
+ <path
+ style="fill:url(#radialGradient3195);fill-opacity:1;fill-rule:evenodd;stroke:#163c0c;stroke-width:0.59999999999999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 10.265966,34.571429 C 9.245427,35.081699 8.6225774,36.042538 9.980252,36.857143 C 10.637564,37.25153 11.478587,37.606311 12.265966,38 C 13.258976,38.496505 14.481138,39.018522 15.408823,39.714286 C 16.227572,40.328348 15.587589,39.928184 16.123109,38.857143 C 16.827927,37.447507 18.14516,38.79674 18.837395,39.142857 C 20.044787,39.746554 20.46001,38.652394 20.694537,37.714286 C 20.459863,35.791335 18.579948,34.625723 17.123109,33.285715 C 16.704922,32.588736 15.507117,31.689713 14.837395,31.857143 C 13.49505,33.304042 12.350312,33.960279 10.265966,34.571429 z "
+ id="path3161"
+ sodipodi:nodetypes="cssssscccc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;fill-opacity:1;stroke:url(#radialGradient3567);stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.6502732"
+ id="path3557"
+ sodipodi:cx="22.714285"
+ sodipodi:cy="23.571428"
+ sodipodi:rx="19.428572"
+ sodipodi:ry="19.428572"
+ d="M 42.142857 23.571428 A 19.428572 19.428572 0 1 1 3.2857132,23.571428 A 19.428572 19.428572 0 1 1 42.142857 23.571428 z"
+ transform="matrix(0.95317,0,0,0.95317,0.9922816,1.1752786)" />
+ <path
+ style="fill:url(#linearGradient3751);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 39.916926,27.786316 C 44.588637,26.790847 38.225604,13.201712 32.946381,8.5000566 C 18.135275,-0.40265528 10.844456,5.6490056 3.6645529,16.333771 C 5.7478288,18.189127 14.704728,33.158645 39.916926,27.786316 z"
+ id="path3578"
+ sodipodi:nodetypes="cccs" />
+ <path
+ d="M 45.902562,20.610592 C 46.007701,20.610592 46.120332,20.603354 46.240455,20.590275 L 45.609873,20.590275 C 45.697743,20.603608 45.798946,20.610592 45.902562,20.610592 z"
+ id="path3012"
+ style="fill:#0a6333" />
+ <path
+ sodipodi:type="arc"
+ style="fill:none;fill-opacity:1;stroke:#273e5e;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3818"
+ sodipodi:cx="22.714285"
+ sodipodi:cy="23.571428"
+ sodipodi:rx="19.428572"
+ sodipodi:ry="19.428572"
+ d="M 42.142857,23.571428 A 19.428572,19.428572 0 1 1 3.2857132,23.571428 A 19.428572,19.428572 0 1 1 42.142857,23.571428 z"
+ transform="matrix(0.9754581,0,0,0.9754581,0.3821951,0.7002631)" />
+ <g
+ transform="matrix(0.1269799,0,0,0.1269799,23.283534,9.5774104)"
+ id="g236">
+ <path
+ style="fill:#024c1c"
+ id="path238"
+ d="M 44.233,0.368 C 42.032,0.004 39.876,-0.083 37.788,0.079 L 37.784,0.078 C 37.784,0.078 23.532,1.048 22.886,1.099 C 9.875,2.138 0,12.834 0,27.605 L 0,201.792 L 14.567,215.37 L 160.968,190.766 C 171.041,189.016 178.999,177.133 178.999,164.303 L 178.999,22.46 L 44.233,0.368 z" />
+
+ <path
+ style="fill:#66b036"
+ id="path240"
+ d="M 179,164.304 C 179,177.134 171.042,189.017 160.969,190.767 L 14.567,215.37 L 14.567,26.683 C 14.567,9.52 28.263,-2.264 44.231,0.368 L 179,22.462 L 179,164.304 z" />
+
+ <g
+ id="g242">
+ <path
+ style="fill:#ffffff"
+ id="path244"
+ d="M 133.897,47.137 L 145.72,48.411 L 145.72,69.158 L 159.025,70.099 L 159.025,83.113 L 145.72,82.502 L 145.72,130.066 C 145.72,134.207 146.176,136.869 147.093,138.064 C 147.919,139.158 149.195,139.697 150.907,139.697 C 151.069,139.697 151.24,139.695 151.414,139.683 C 154.031,139.533 156.878,138.728 159.98,137.314 L 159.98,149.275 C 154.707,151.591 149.532,152.966 144.452,153.398 C 143.716,153.457 143.005,153.486 142.317,153.486 C 137.716,153.486 134.199,152.152 131.797,149.451 C 128.998,146.318 127.598,141.285 127.598,134.387 L 127.598,81.661 L 121.209,81.368 L 121.209,67.424 L 129,67.985 L 133.897,47.137 z" />
+
+ </g>
+
+ <polygon
+ style="fill:#0a6333"
+ id="polygon246"
+ points="159.027,83.112 145.722,82.501 145.722,82.785 152.854,83.112 159.027,83.112 " />
+
+ <path
+ style="fill:#024c1c"
+ id="path248"
+ d="M 148.488,139.21 C 149.168,139.548 149.96,139.696 150.908,139.696 C 151.07,139.696 151.241,139.694 151.415,139.682 C 154.032,139.532 156.879,138.727 159.981,137.313 L 153.806,137.313 C 151.938,138.169 150.178,138.808 148.488,139.21 z" />
+
+ <path
+ style="fill:#024c1c"
+ id="path250"
+ d="M 133.897,47.137 L 127.723,47.137 L 122.93,67.549 L 129,67.985 L 133.897,47.137 z M 131.799,149.45 C 129,146.317 127.6,141.284 127.6,134.386 L 127.6,81.661 L 121.211,81.368 L 121.211,67.424 L 115.03,67.424 L 115.03,70.539 C 115.926,73.897 116.63,77.539 117.149,81.465 L 121.426,81.661 L 121.426,134.386 C 121.426,141.284 122.827,146.318 125.625,149.45 C 128.029,152.151 131.541,153.485 136.141,153.485 L 142.318,153.485 C 137.718,153.485 134.2,152.151 131.799,149.45 z" />
+
+ <path
+ style="fill:#0a6333"
+ id="path252"
+ d="M 102.954,170.419 C 103.782,170.419 104.669,170.362 105.615,170.259 L 100.649,170.259 C 101.341,170.364 102.138,170.419 102.954,170.419 z" />
+
+ <path
+ style="fill:#ffffff"
+ id="path254"
+ d="M 112.036,139.78 C 107.81,149.749 101.365,156.27 92.542,159.288 C 93.43,163.856 94.778,166.929 96.567,168.55 C 97.955,169.796 100.094,170.419 102.958,170.419 C 103.782,170.419 104.671,170.362 105.615,170.259 L 105.615,183.736 L 99.497,184.539 C 97.692,184.771 95.98,184.889 94.361,184.889 C 89.001,184.889 84.665,183.59 81.402,180.961 C 77.085,177.496 73.899,170.805 71.857,160.908 C 62.48,158.91 55.166,152.945 50.103,142.937 C 44.965,132.769 42.349,117.895 42.349,98.441 C 42.349,77.466 45.927,61.985 52.971,52.169 C 58.912,43.885 67.202,39.812 77.634,39.812 C 79.306,39.812 81.033,39.916 82.809,40.124 C 95.081,41.539 103.977,47.329 109.77,57.362 C 115.453,67.177 118.243,81.244 118.243,99.721 C 118.242,116.643 116.186,129.954 112.036,139.78 z M 93.582,135.933 C 95.996,129.724 97.189,117.54 97.189,99.37 C 97.189,83.054 96.007,71.837 93.608,65.682 C 91.21,59.496 87.622,56.153 82.808,55.731 C 82.441,55.7 82.075,55.681 81.724,55.681 C 77.264,55.681 73.84,58.283 71.447,63.508 C 68.863,69.201 67.555,81.003 67.555,98.866 C 67.555,116.129 68.826,128.379 71.388,135.569 C 73.804,142.419 77.423,145.813 82.174,145.813 C 82.384,145.813 82.593,145.805 82.809,145.79 C 87.566,145.489 91.148,142.202 93.582,135.933" />
+
+ <path
+ style="fill:#024c1c"
+ id="path256"
+ d="M 84.708,183.003 C 84.59,182.95 84.477,182.896 84.361,182.839 C 84.349,182.835 84.336,182.829 84.323,182.821 C 84.218,182.77 84.115,182.716 84.011,182.663 C 83.991,182.653 83.971,182.642 83.948,182.63 C 83.854,182.579 83.761,182.528 83.667,182.476 C 83.636,182.46 83.609,182.443 83.579,182.427 C 83.494,182.38 83.412,182.331 83.328,182.284 C 83.286,182.263 83.25,182.239 83.209,182.214 C 83.137,182.171 83.062,182.128 82.994,182.083 C 82.943,182.054 82.897,182.024 82.848,181.993 C 82.785,181.954 82.726,181.915 82.663,181.876 C 82.606,181.837 82.552,181.798 82.492,181.759 C 82.442,181.726 82.392,181.693 82.342,181.659 C 82.272,181.612 82.206,181.563 82.141,181.518 C 82.101,181.489 82.061,181.463 82.021,181.432 C 81.943,181.377 81.866,181.319 81.79,181.26 C 81.764,181.239 81.735,181.221 81.708,181.199 C 81.607,181.121 81.505,181.039 81.402,180.959 C 77.085,177.494 73.899,170.803 71.857,160.906 C 62.48,158.908 55.166,152.943 50.103,142.935 C 44.965,132.767 42.349,117.893 42.349,98.439 C 42.349,77.464 45.927,61.983 52.971,52.167 C 58.912,43.883 67.202,39.81 77.634,39.81 C 77.67,39.81 71.114,39.806 71.114,39.806 L 71.114,39.81 C 60.694,39.818 52.411,43.89 46.476,52.167 C 39.434,61.984 35.855,77.465 35.855,98.439 C 35.855,117.892 38.469,132.767 43.609,142.935 C 48.671,152.943 55.983,158.908 65.361,160.906 C 67.403,170.802 70.588,177.494 74.904,180.959 C 78.168,183.588 82.507,184.887 87.867,184.887 C 87.967,184.887 88.07,184.887 88.17,184.885 L 93.861,184.885 C 90.361,184.828 87.306,184.203 84.716,183.006 C 84.712,183.007 84.708,183.007 84.708,183.003 z M 87.113,65.681 C 89.511,71.837 90.69,83.054 90.69,99.369 C 90.69,117.539 89.502,129.723 87.083,135.932 C 85.142,140.942 82.439,144.047 79.013,145.248 C 79.999,145.621 81.058,145.81 82.173,145.81 C 82.383,145.81 82.592,145.802 82.808,145.787 C 87.567,145.488 91.149,142.201 93.582,135.932 C 95.996,129.723 97.189,117.539 97.189,99.369 C 97.189,83.053 96.007,71.836 93.608,65.681 C 91.21,59.495 87.622,56.152 82.808,55.73 C 82.441,55.699 82.075,55.68 81.724,55.68 C 80.601,55.68 79.549,55.845 78.556,56.173 L 78.556,56.175 L 78.556,56.175 C 82.254,57.322 85.104,60.5 87.113,65.681 z" />
+
+</g>
+ </g>
+</svg>
diff --git a/examples/webkitwidgets/browser/data/closetab.png b/examples/webkitwidgets/browser/data/closetab.png
new file mode 100644
index 0000000..ab9d669
--- /dev/null
+++ b/examples/webkitwidgets/browser/data/closetab.png
Binary files differ
diff --git a/examples/webkitwidgets/browser/data/data.qrc b/examples/webkitwidgets/browser/data/data.qrc
new file mode 100644
index 0000000..c7d0294
--- /dev/null
+++ b/examples/webkitwidgets/browser/data/data.qrc
@@ -0,0 +1,11 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>addtab.png</file>
+ <file>closetab.png</file>
+ <file>history.png</file>
+ <file>browser.svg</file>
+ <file>defaultbookmarks.xbel</file>
+ <file>loading.gif</file>
+ <file>defaulticon.png</file>
+</qresource>
+</RCC>
diff --git a/examples/webkitwidgets/browser/data/defaultbookmarks.xbel b/examples/webkitwidgets/browser/data/defaultbookmarks.xbel
new file mode 100644
index 0000000..7a95e36
--- /dev/null
+++ b/examples/webkitwidgets/browser/data/defaultbookmarks.xbel
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE xbel>
+<xbel version="1.0">
+ <folder folded="yes">
+ <title>Bookmarks Bar</title>
+ <bookmark href="http://qt-project.org/">
+ <title>Qt Home Page</title>
+ </bookmark>
+ <bookmark href="http://webkit.org/">
+ <title>WebKit.org</title>
+ </bookmark>
+ <bookmark href="http://qt-project.org/doc/">
+ <title>Qt Documentation</title>
+ </bookmark>
+ <bookmark href="http://qt-project.org/quarterly/">
+ <title>Qt Quarterly</title>
+ </bookmark>
+ <bookmark href="http://planet.qt-project.org/">
+ <title>Qt Blog</title>
+ </bookmark>
+ <bookmark href="http://www.qtcentre.org/">
+ <title>Qt Centre</title>
+ </bookmark>
+ <bookmark href="http://qt-apps.org/">
+ <title>Qt-Apps.org</title>
+ </bookmark>
+ <bookmark href="http://qt-project.org/wiki/OnlineCommunities/">
+ <title>Online Communities</title>
+ </bookmark>
+ <bookmark href="http://xkcd.com/">
+ <title>xkcd</title>
+ </bookmark>
+ <bookmark href="http://twitter.com/qtproject">
+ <title>Twitter</title>
+ </bookmark>
+ </folder>
+ <folder folded="yes">
+ <title>Bookmarks Menu</title>
+ <bookmark href="http://reddit.com/">
+ <title>reddit.com: what's new online!</title>
+ </bookmark>
+ </folder>
+</xbel>
diff --git a/examples/webkitwidgets/browser/data/defaulticon.png b/examples/webkitwidgets/browser/data/defaulticon.png
new file mode 100644
index 0000000..01a0920
--- /dev/null
+++ b/examples/webkitwidgets/browser/data/defaulticon.png
Binary files differ
diff --git a/examples/webkitwidgets/browser/data/history.png b/examples/webkitwidgets/browser/data/history.png
new file mode 100644
index 0000000..552a1cb
--- /dev/null
+++ b/examples/webkitwidgets/browser/data/history.png
Binary files differ
diff --git a/examples/webkitwidgets/browser/data/loading.gif b/examples/webkitwidgets/browser/data/loading.gif
new file mode 100644
index 0000000..c1545eb
--- /dev/null
+++ b/examples/webkitwidgets/browser/data/loading.gif
Binary files differ
diff --git a/examples/webkitwidgets/browser/downloaditem.ui b/examples/webkitwidgets/browser/downloaditem.ui
new file mode 100644
index 0000000..4a0a0fd
--- /dev/null
+++ b/examples/webkitwidgets/browser/downloaditem.ui
@@ -0,0 +1,134 @@
+<ui version="4.0" >
+ <class>DownloadItem</class>
+ <widget class="QWidget" name="DownloadItem" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>423</width>
+ <height>110</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="fileIcon" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Minimum" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Ico</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <widget class="SqueezeLabel" native="1" name="fileNameLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" stdset="0" >
+ <string>Filename</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="progressBar" >
+ <property name="value" >
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="SqueezeLabel" native="1" name="downloadInfoLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" stdset="0" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>17</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="tryAgainButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Try Again</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="stopButton" >
+ <property name="text" >
+ <string>Stop</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="openButton" >
+ <property name="text" >
+ <string>Open</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>17</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SqueezeLabel</class>
+ <extends>QWidget</extends>
+ <header>squeezelabel.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/webkitwidgets/browser/downloadmanager.cpp b/examples/webkitwidgets/browser/downloadmanager.cpp
new file mode 100644
index 0000000..93c9cc4
--- /dev/null
+++ b/examples/webkitwidgets/browser/downloadmanager.cpp
@@ -0,0 +1,579 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "downloadmanager.h"
+
+#include "autosaver.h"
+#include "browserapplication.h"
+#include "networkaccessmanager.h"
+
+#include <math.h>
+
+#include <QtCore/QMetaEnum>
+#include <QtCore/QSettings>
+
+#include <QtGui/QDesktopServices>
+#include <QtWidgets/QFileDialog>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QFileIconProvider>
+
+#include <QtCore/QDebug>
+
+#include <QWebSettings>
+
+/*!
+ DownloadItem is a widget that is displayed in the download manager list.
+ It moves the data from the QNetworkReply into the QFile as well
+ as update the information/progressbar and report errors.
+ */
+DownloadItem::DownloadItem(QNetworkReply *reply, bool requestFileName, QWidget *parent)
+ : QWidget(parent)
+ , m_reply(reply)
+ , m_requestFileName(requestFileName)
+ , m_bytesReceived(0)
+{
+ setupUi(this);
+ QPalette p = downloadInfoLabel->palette();
+ p.setColor(QPalette::Text, Qt::darkGray);
+ downloadInfoLabel->setPalette(p);
+ progressBar->setMaximum(0);
+ tryAgainButton->hide();
+ connect(stopButton, SIGNAL(clicked()), this, SLOT(stop()));
+ connect(openButton, SIGNAL(clicked()), this, SLOT(open()));
+ connect(tryAgainButton, SIGNAL(clicked()), this, SLOT(tryAgain()));
+
+ init();
+}
+
+void DownloadItem::init()
+{
+ if (!m_reply)
+ return;
+
+ // attach to the m_reply
+ m_url = m_reply->url();
+ m_reply->setParent(this);
+ connect(m_reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
+ connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(error(QNetworkReply::NetworkError)));
+ connect(m_reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(downloadProgress(qint64,qint64)));
+ connect(m_reply, SIGNAL(metaDataChanged()),
+ this, SLOT(metaDataChanged()));
+ connect(m_reply, SIGNAL(finished()),
+ this, SLOT(finished()));
+
+ // reset info
+ downloadInfoLabel->clear();
+ progressBar->setValue(0);
+ getFileName();
+
+ // start timer for the download estimation
+ m_downloadTime.start();
+
+ if (m_reply->error() != QNetworkReply::NoError) {
+ error(m_reply->error());
+ finished();
+ }
+}
+
+void DownloadItem::getFileName()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("downloadmanager"));
+ QString defaultLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
+ QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString();
+ if (!downloadDirectory.isEmpty())
+ downloadDirectory += QLatin1Char('/');
+
+ QString defaultFileName = saveFileName(downloadDirectory);
+ QString fileName = defaultFileName;
+ if (m_requestFileName) {
+ fileName = QFileDialog::getSaveFileName(this, tr("Save File"), defaultFileName);
+ if (fileName.isEmpty()) {
+ m_reply->close();
+ fileNameLabel->setText(tr("Download canceled: %1").arg(QFileInfo(defaultFileName).fileName()));
+ return;
+ }
+ }
+ m_output.setFileName(fileName);
+ fileNameLabel->setText(QFileInfo(m_output.fileName()).fileName());
+ if (m_requestFileName)
+ downloadReadyRead();
+}
+
+QString DownloadItem::saveFileName(const QString &directory) const
+{
+ // Move this function into QNetworkReply to also get file name sent from the server
+ QString path = m_url.path();
+ QFileInfo info(path);
+ QString baseName = info.completeBaseName();
+ QString endName = info.suffix();
+
+ if (baseName.isEmpty()) {
+ baseName = QLatin1String("unnamed_download");
+ qDebug() << "DownloadManager:: downloading unknown file:" << m_url;
+ }
+ QString name = directory + baseName + QLatin1Char('.') + endName;
+ if (QFile::exists(name)) {
+ // already exists, don't overwrite
+ int i = 1;
+ do {
+ name = directory + baseName + QLatin1Char('-') + QString::number(i++) + QLatin1Char('.') + endName;
+ } while (QFile::exists(name));
+ }
+ return name;
+}
+
+
+void DownloadItem::stop()
+{
+ setUpdatesEnabled(false);
+ stopButton->setEnabled(false);
+ stopButton->hide();
+ tryAgainButton->setEnabled(true);
+ tryAgainButton->show();
+ setUpdatesEnabled(true);
+ m_reply->abort();
+}
+
+void DownloadItem::open()
+{
+ QFileInfo info(m_output);
+ QUrl url = QUrl::fromLocalFile(info.absolutePath());
+ QDesktopServices::openUrl(url);
+}
+
+void DownloadItem::tryAgain()
+{
+ if (!tryAgainButton->isEnabled())
+ return;
+
+ tryAgainButton->setEnabled(false);
+ tryAgainButton->setVisible(false);
+ stopButton->setEnabled(true);
+ stopButton->setVisible(true);
+ progressBar->setVisible(true);
+
+ QNetworkReply *r = BrowserApplication::networkAccessManager()->get(QNetworkRequest(m_url));
+ if (m_reply)
+ m_reply->deleteLater();
+ if (m_output.exists())
+ m_output.remove();
+ m_reply = r;
+ init();
+ emit statusChanged();
+}
+
+void DownloadItem::downloadReadyRead()
+{
+ if (m_requestFileName && m_output.fileName().isEmpty())
+ return;
+ if (!m_output.isOpen()) {
+ // in case someone else has already put a file there
+ if (!m_requestFileName)
+ getFileName();
+ if (!m_output.open(QIODevice::WriteOnly)) {
+ downloadInfoLabel->setText(tr("Error opening save file: %1")
+ .arg(m_output.errorString()));
+ stopButton->click();
+ emit statusChanged();
+ return;
+ }
+ emit statusChanged();
+ }
+ if (-1 == m_output.write(m_reply->readAll())) {
+ downloadInfoLabel->setText(tr("Error saving: %1")
+ .arg(m_output.errorString()));
+ stopButton->click();
+ }
+}
+
+void DownloadItem::error(QNetworkReply::NetworkError)
+{
+ qDebug() << "DownloadItem::error" << m_reply->errorString() << m_url;
+ downloadInfoLabel->setText(tr("Network Error: %1").arg(m_reply->errorString()));
+ tryAgainButton->setEnabled(true);
+ tryAgainButton->setVisible(true);
+}
+
+void DownloadItem::metaDataChanged()
+{
+ qDebug() << "DownloadItem::metaDataChanged: not handled.";
+}
+
+void DownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ m_bytesReceived = bytesReceived;
+ if (bytesTotal == -1) {
+ progressBar->setValue(0);
+ progressBar->setMaximum(0);
+ } else {
+ progressBar->setValue(bytesReceived);
+ progressBar->setMaximum(bytesTotal);
+ }
+ updateInfoLabel();
+}
+
+void DownloadItem::updateInfoLabel()
+{
+ if (m_reply->error() == QNetworkReply::NoError)
+ return;
+
+ qint64 bytesTotal = progressBar->maximum();
+ bool running = !downloadedSuccessfully();
+
+ // update info label
+ double speed = m_bytesReceived * 1000.0 / m_downloadTime.elapsed();
+ double timeRemaining = ((double)(bytesTotal - m_bytesReceived)) / speed;
+ QString timeRemainingString = tr("seconds");
+ if (timeRemaining > 60) {
+ timeRemaining = timeRemaining / 60;
+ timeRemainingString = tr("minutes");
+ }
+ timeRemaining = floor(timeRemaining);
+
+ // When downloading the eta should never be 0
+ if (timeRemaining == 0)
+ timeRemaining = 1;
+
+ QString info;
+ if (running) {
+ QString remaining;
+ if (bytesTotal != 0)
+ remaining = tr("- %4 %5 remaining")
+ .arg(timeRemaining)
+ .arg(timeRemainingString);
+ info = tr("%1 of %2 (%3/sec) %4")
+ .arg(dataString(m_bytesReceived))
+ .arg(bytesTotal == 0 ? tr("?") : dataString(bytesTotal))
+ .arg(dataString((int)speed))
+ .arg(remaining);
+ } else {
+ if (m_bytesReceived == bytesTotal)
+ info = dataString(m_output.size());
+ else
+ info = tr("%1 of %2 - Stopped")
+ .arg(dataString(m_bytesReceived))
+ .arg(dataString(bytesTotal));
+ }
+ downloadInfoLabel->setText(info);
+}
+
+QString DownloadItem::dataString(int size) const
+{
+ QString unit;
+ if (size < 1024) {
+ unit = tr("bytes");
+ } else if (size < 1024*1024) {
+ size /= 1024;
+ unit = tr("kB");
+ } else {
+ size /= 1024*1024;
+ unit = tr("MB");
+ }
+ return QString(QLatin1String("%1 %2")).arg(size).arg(unit);
+}
+
+bool DownloadItem::downloading() const
+{
+ return (progressBar->isVisible());
+}
+
+bool DownloadItem::downloadedSuccessfully() const
+{
+ return (stopButton->isHidden() && tryAgainButton->isHidden());
+}
+
+void DownloadItem::finished()
+{
+ progressBar->hide();
+ stopButton->setEnabled(false);
+ stopButton->hide();
+ m_output.close();
+ updateInfoLabel();
+ emit statusChanged();
+}
+
+/*!
+ DownloadManager is a Dialog that contains a list of DownloadItems
+
+ It is a basic download manager. It only downloads the file, doesn't do BitTorrent,
+ extract zipped files or anything fancy.
+ */
+DownloadManager::DownloadManager(QWidget *parent)
+ : QDialog(parent)
+ , m_autoSaver(new AutoSaver(this))
+ , m_manager(BrowserApplication::networkAccessManager())
+ , m_iconProvider(0)
+ , m_removePolicy(Never)
+{
+ setupUi(this);
+ downloadsView->setShowGrid(false);
+ downloadsView->verticalHeader()->hide();
+ downloadsView->horizontalHeader()->hide();
+ downloadsView->setAlternatingRowColors(true);
+ downloadsView->horizontalHeader()->setStretchLastSection(true);
+ m_model = new DownloadModel(this);
+ downloadsView->setModel(m_model);
+ connect(cleanupButton, SIGNAL(clicked()), this, SLOT(cleanup()));
+ load();
+}
+
+DownloadManager::~DownloadManager()
+{
+ m_autoSaver->changeOccurred();
+ m_autoSaver->saveIfNeccessary();
+ if (m_iconProvider)
+ delete m_iconProvider;
+}
+
+int DownloadManager::activeDownloads() const
+{
+ int count = 0;
+ for (int i = 0; i < m_downloads.count(); ++i) {
+ if (m_downloads.at(i)->stopButton->isEnabled())
+ ++count;
+ }
+ return count;
+}
+
+void DownloadManager::download(const QNetworkRequest &request, bool requestFileName)
+{
+ if (request.url().isEmpty())
+ return;
+ handleUnsupportedContent(m_manager->get(request), requestFileName);
+}
+
+void DownloadManager::handleUnsupportedContent(QNetworkReply *reply, bool requestFileName)
+{
+ if (!reply || reply->url().isEmpty())
+ return;
+ QVariant header = reply->header(QNetworkRequest::ContentLengthHeader);
+ bool ok;
+ int size = header.toInt(&ok);
+ if (ok && size == 0)
+ return;
+
+ qDebug() << "DownloadManager::handleUnsupportedContent" << reply->url() << "requestFileName" << requestFileName;
+ DownloadItem *item = new DownloadItem(reply, requestFileName, this);
+ addItem(item);
+}
+
+void DownloadManager::addItem(DownloadItem *item)
+{
+ connect(item, SIGNAL(statusChanged()), this, SLOT(updateRow()));
+ int row = m_downloads.count();
+ m_model->beginInsertRows(QModelIndex(), row, row);
+ m_downloads.append(item);
+ m_model->endInsertRows();
+ updateItemCount();
+ if (row == 0)
+ show();
+ downloadsView->setIndexWidget(m_model->index(row, 0), item);
+ QIcon icon = style()->standardIcon(QStyle::SP_FileIcon);
+ item->fileIcon->setPixmap(icon.pixmap(48, 48));
+ downloadsView->setRowHeight(row, item->sizeHint().height());
+}
+
+void DownloadManager::updateRow()
+{
+ DownloadItem *item = qobject_cast<DownloadItem*>(sender());
+ int row = m_downloads.indexOf(item);
+ if (-1 == row)
+ return;
+ if (!m_iconProvider)
+ m_iconProvider = new QFileIconProvider();
+ QIcon icon = m_iconProvider->icon(item->m_output.fileName());
+ if (icon.isNull())
+ icon = style()->standardIcon(QStyle::SP_FileIcon);
+ item->fileIcon->setPixmap(icon.pixmap(48, 48));
+ downloadsView->setRowHeight(row, item->minimumSizeHint().height());
+
+ bool remove = false;
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (!item->downloading()
+ && globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled))
+ remove = true;
+
+ if (item->downloadedSuccessfully()
+ && removePolicy() == DownloadManager::SuccessFullDownload) {
+ remove = true;
+ }
+ if (remove)
+ m_model->removeRow(row);
+
+ cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0);
+}
+
+DownloadManager::RemovePolicy DownloadManager::removePolicy() const
+{
+ return m_removePolicy;
+}
+
+void DownloadManager::setRemovePolicy(RemovePolicy policy)
+{
+ if (policy == m_removePolicy)
+ return;
+ m_removePolicy = policy;
+ m_autoSaver->changeOccurred();
+}
+
+void DownloadManager::save() const
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("downloadmanager"));
+ QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy"));
+ settings.setValue(QLatin1String("removeDownloadsPolicy"), QLatin1String(removePolicyEnum.valueToKey(m_removePolicy)));
+ settings.setValue(QLatin1String("size"), size());
+ if (m_removePolicy == Exit)
+ return;
+
+ for (int i = 0; i < m_downloads.count(); ++i) {
+ QString key = QString(QLatin1String("download_%1_")).arg(i);
+ settings.setValue(key + QLatin1String("url"), m_downloads[i]->m_url);
+ settings.setValue(key + QLatin1String("location"), QFileInfo(m_downloads[i]->m_output).filePath());
+ settings.setValue(key + QLatin1String("done"), m_downloads[i]->downloadedSuccessfully());
+ }
+ int i = m_downloads.count();
+ QString key = QString(QLatin1String("download_%1_")).arg(i);
+ while (settings.contains(key + QLatin1String("url"))) {
+ settings.remove(key + QLatin1String("url"));
+ settings.remove(key + QLatin1String("location"));
+ settings.remove(key + QLatin1String("done"));
+ key = QString(QLatin1String("download_%1_")).arg(++i);
+ }
+}
+
+void DownloadManager::load()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("downloadmanager"));
+ QSize size = settings.value(QLatin1String("size")).toSize();
+ if (size.isValid())
+ resize(size);
+ QByteArray value = settings.value(QLatin1String("removeDownloadsPolicy"), QLatin1String("Never")).toByteArray();
+ QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy"));
+ m_removePolicy = removePolicyEnum.keyToValue(value) == -1 ?
+ Never :
+ static_cast<RemovePolicy>(removePolicyEnum.keyToValue(value));
+
+ int i = 0;
+ QString key = QString(QLatin1String("download_%1_")).arg(i);
+ while (settings.contains(key + QLatin1String("url"))) {
+ QUrl url = settings.value(key + QLatin1String("url")).toUrl();
+ QString fileName = settings.value(key + QLatin1String("location")).toString();
+ bool done = settings.value(key + QLatin1String("done"), true).toBool();
+ if (!url.isEmpty() && !fileName.isEmpty()) {
+ DownloadItem *item = new DownloadItem(0, this);
+ item->m_output.setFileName(fileName);
+ item->fileNameLabel->setText(QFileInfo(item->m_output.fileName()).fileName());
+ item->m_url = url;
+ item->stopButton->setVisible(false);
+ item->stopButton->setEnabled(false);
+ item->tryAgainButton->setVisible(!done);
+ item->tryAgainButton->setEnabled(!done);
+ item->progressBar->setVisible(!done);
+ addItem(item);
+ }
+ key = QString(QLatin1String("download_%1_")).arg(++i);
+ }
+ cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0);
+}
+
+void DownloadManager::cleanup()
+{
+ if (m_downloads.isEmpty())
+ return;
+ m_model->removeRows(0, m_downloads.count());
+ updateItemCount();
+ if (m_downloads.isEmpty() && m_iconProvider) {
+ delete m_iconProvider;
+ m_iconProvider = 0;
+ }
+ m_autoSaver->changeOccurred();
+}
+
+void DownloadManager::updateItemCount()
+{
+ int count = m_downloads.count();
+ itemCount->setText(count == 1 ? tr("1 Download") : tr("%1 Downloads").arg(count));
+}
+
+DownloadModel::DownloadModel(DownloadManager *downloadManager, QObject *parent)
+ : QAbstractListModel(parent)
+ , m_downloadManager(downloadManager)
+{
+}
+
+QVariant DownloadModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() < 0 || index.row() >= rowCount(index.parent()))
+ return QVariant();
+ if (role == Qt::ToolTipRole)
+ if (!m_downloadManager->m_downloads.at(index.row())->downloadedSuccessfully())
+ return m_downloadManager->m_downloads.at(index.row())->downloadInfoLabel->text();
+ return QVariant();
+}
+
+int DownloadModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : m_downloadManager->m_downloads.count();
+}
+
+bool DownloadModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid())
+ return false;
+
+ int lastRow = row + count - 1;
+ for (int i = lastRow; i >= row; --i) {
+ if (m_downloadManager->m_downloads.at(i)->downloadedSuccessfully()
+ || m_downloadManager->m_downloads.at(i)->tryAgainButton->isEnabled()) {
+ beginRemoveRows(parent, i, i);
+ m_downloadManager->m_downloads.takeAt(i)->deleteLater();
+ endRemoveRows();
+ }
+ }
+ m_downloadManager->m_autoSaver->changeOccurred();
+ return true;
+}
+
diff --git a/examples/webkitwidgets/browser/downloadmanager.h b/examples/webkitwidgets/browser/downloadmanager.h
new file mode 100644
index 0000000..5decb3a
--- /dev/null
+++ b/examples/webkitwidgets/browser/downloadmanager.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DOWNLOADMANAGER_H
+#define DOWNLOADMANAGER_H
+
+#include "ui_downloads.h"
+#include "ui_downloaditem.h"
+
+#include <QtNetwork/QNetworkReply>
+
+#include <QtCore/QFile>
+#include <QtCore/QTime>
+
+class DownloadItem : public QWidget, public Ui_DownloadItem
+{
+ Q_OBJECT
+
+signals:
+ void statusChanged();
+
+public:
+ DownloadItem(QNetworkReply *reply = 0, bool requestFileName = false, QWidget *parent = 0);
+ bool downloading() const;
+ bool downloadedSuccessfully() const;
+
+ QUrl m_url;
+
+ QFile m_output;
+ QNetworkReply *m_reply;
+
+private slots:
+ void stop();
+ void tryAgain();
+ void open();
+
+ void downloadReadyRead();
+ void error(QNetworkReply::NetworkError code);
+ void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ void metaDataChanged();
+ void finished();
+
+private:
+ void getFileName();
+ void init();
+ void updateInfoLabel();
+ QString dataString(int size) const;
+
+ QString saveFileName(const QString &directory) const;
+
+ bool m_requestFileName;
+ qint64 m_bytesReceived;
+ QTime m_downloadTime;
+};
+
+class AutoSaver;
+class DownloadModel;
+QT_BEGIN_NAMESPACE
+class QFileIconProvider;
+QT_END_NAMESPACE
+
+class DownloadManager : public QDialog, public Ui_DownloadDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(RemovePolicy removePolicy READ removePolicy WRITE setRemovePolicy)
+ Q_ENUMS(RemovePolicy)
+
+public:
+ enum RemovePolicy {
+ Never,
+ Exit,
+ SuccessFullDownload
+ };
+
+ DownloadManager(QWidget *parent = 0);
+ ~DownloadManager();
+ int activeDownloads() const;
+
+ RemovePolicy removePolicy() const;
+ void setRemovePolicy(RemovePolicy policy);
+
+public slots:
+ void download(const QNetworkRequest &request, bool requestFileName = false);
+ inline void download(const QUrl &url, bool requestFileName = false)
+ { download(QNetworkRequest(url), requestFileName); }
+ void handleUnsupportedContent(QNetworkReply *reply, bool requestFileName = false);
+ void cleanup();
+
+private slots:
+ void save() const;
+ void updateRow();
+
+private:
+ void addItem(DownloadItem *item);
+ void updateItemCount();
+ void load();
+
+ AutoSaver *m_autoSaver;
+ DownloadModel *m_model;
+ QNetworkAccessManager *m_manager;
+ QFileIconProvider *m_iconProvider;
+ QList<DownloadItem*> m_downloads;
+ RemovePolicy m_removePolicy;
+ friend class DownloadModel;
+};
+
+class DownloadModel : public QAbstractListModel
+{
+ friend class DownloadManager;
+ Q_OBJECT
+
+public:
+ DownloadModel(DownloadManager *downloadManager, QObject *parent = 0);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+private:
+ DownloadManager *m_downloadManager;
+
+};
+
+#endif // DOWNLOADMANAGER_H
+
diff --git a/examples/webkitwidgets/browser/downloads.ui b/examples/webkitwidgets/browser/downloads.ui
new file mode 100644
index 0000000..a2e2569
--- /dev/null
+++ b/examples/webkitwidgets/browser/downloads.ui
@@ -0,0 +1,83 @@
+<ui version="4.0" >
+ <class>DownloadDialog</class>
+ <widget class="QDialog" name="DownloadDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>332</width>
+ <height>252</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Downloads</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <item row="0" column="0" colspan="3" >
+ <widget class="EditTableView" name="downloadsView" />
+ </item>
+ <item row="1" column="0" >
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QPushButton" name="cleanupButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Clean up</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>58</width>
+ <height>24</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="itemCount" >
+ <property name="text" >
+ <string>0 Items</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <spacer name="horizontalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>148</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>EditTableView</class>
+ <extends>QTableView</extends>
+ <header>edittableview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/webkitwidgets/browser/edittableview.cpp b/examples/webkitwidgets/browser/edittableview.cpp
new file mode 100644
index 0000000..5415967
--- /dev/null
+++ b/examples/webkitwidgets/browser/edittableview.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "edittableview.h"
+#include <QtGui/QKeyEvent>
+
+EditTableView::EditTableView(QWidget *parent)
+ : QTableView(parent)
+{
+}
+
+void EditTableView::keyPressEvent(QKeyEvent *event)
+{
+ if ((event->key() == Qt::Key_Delete
+ || event->key() == Qt::Key_Backspace)
+ && model()) {
+ removeOne();
+ } else {
+ QAbstractItemView::keyPressEvent(event);
+ }
+}
+
+void EditTableView::removeOne()
+{
+ if (!model() || !selectionModel())
+ return;
+ int row = currentIndex().row();
+ model()->removeRow(row, rootIndex());
+ QModelIndex idx = model()->index(row, 0, rootIndex());
+ if (!idx.isValid())
+ idx = model()->index(row - 1, 0, rootIndex());
+ selectionModel()->select(idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+}
+
+void EditTableView::removeAll()
+{
+ if (model())
+ model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex());
+}
+
diff --git a/examples/webkitwidgets/browser/edittableview.h b/examples/webkitwidgets/browser/edittableview.h
new file mode 100644
index 0000000..fa465ea
--- /dev/null
+++ b/examples/webkitwidgets/browser/edittableview.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EDITTABLEVIEW_H
+#define EDITTABLEVIEW_H
+
+#include <QtWidgets/QTableView>
+
+class EditTableView : public QTableView
+{
+ Q_OBJECT
+
+public:
+ EditTableView(QWidget *parent = 0);
+ void keyPressEvent(QKeyEvent *event);
+
+public slots:
+ void removeOne();
+ void removeAll();
+};
+
+#endif // EDITTABLEVIEW_H
+
diff --git a/examples/webkitwidgets/browser/edittreeview.cpp b/examples/webkitwidgets/browser/edittreeview.cpp
new file mode 100644
index 0000000..dfe27ad
--- /dev/null
+++ b/examples/webkitwidgets/browser/edittreeview.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "edittreeview.h"
+
+#include <QtGui/QKeyEvent>
+
+EditTreeView::EditTreeView(QWidget *parent)
+ : QTreeView(parent)
+{
+}
+
+void EditTreeView::keyPressEvent(QKeyEvent *event)
+{
+ if ((event->key() == Qt::Key_Delete
+ || event->key() == Qt::Key_Backspace)
+ && model()) {
+ removeOne();
+ } else {
+ QAbstractItemView::keyPressEvent(event);
+ }
+}
+
+void EditTreeView::removeOne()
+{
+ if (!model())
+ return;
+ QModelIndex ci = currentIndex();
+ int row = ci.row();
+ model()->removeRow(row, ci.parent());
+}
+
+void EditTreeView::removeAll()
+{
+ if (!model())
+ return;
+ model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex());
+}
+
diff --git a/examples/webkitwidgets/browser/edittreeview.h b/examples/webkitwidgets/browser/edittreeview.h
new file mode 100644
index 0000000..166aaad
--- /dev/null
+++ b/examples/webkitwidgets/browser/edittreeview.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EDITTREEVIEW_H
+#define EDITTREEVIEW_H
+
+#include <QtWidgets/QTreeView>
+
+class EditTreeView : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ EditTreeView(QWidget *parent = 0);
+ void keyPressEvent(QKeyEvent *event);
+
+public slots:
+ void removeOne();
+ void removeAll();
+};
+
+#endif // EDITTREEVIEW_H
+
diff --git a/examples/webkitwidgets/browser/history.cpp b/examples/webkitwidgets/browser/history.cpp
new file mode 100644
index 0000000..11a42f2
--- /dev/null
+++ b/examples/webkitwidgets/browser/history.cpp
@@ -0,0 +1,1292 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "history.h"
+
+#include "autosaver.h"
+#include "browserapplication.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QSettings>
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QTextStream>
+
+#include <QtCore/QtAlgorithms>
+
+#include <QtGui/QClipboard>
+#include <QtGui/QDesktopServices>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QStyle>
+
+#include <QWebHistoryInterface>
+#include <QWebSettings>
+
+#include <QtCore/QDebug>
+
+static const unsigned int HISTORY_VERSION = 23;
+
+HistoryManager::HistoryManager(QObject *parent)
+ : QWebHistoryInterface(parent)
+ , m_saveTimer(new AutoSaver(this))
+ , m_historyLimit(30)
+ , m_historyModel(0)
+ , m_historyFilterModel(0)
+ , m_historyTreeModel(0)
+{
+ m_expiredTimer.setSingleShot(true);
+ connect(&m_expiredTimer, SIGNAL(timeout()),
+ this, SLOT(checkForExpired()));
+ connect(this, SIGNAL(entryAdded(HistoryItem)),
+ m_saveTimer, SLOT(changeOccurred()));
+ connect(this, SIGNAL(entryRemoved(HistoryItem)),
+ m_saveTimer, SLOT(changeOccurred()));
+ load();
+
+ m_historyModel = new HistoryModel(this, this);
+ m_historyFilterModel = new HistoryFilterModel(m_historyModel, this);
+ m_historyTreeModel = new HistoryTreeModel(m_historyFilterModel, this);
+
+ // QWebHistoryInterface will delete the history manager
+ QWebHistoryInterface::setDefaultInterface(this);
+}
+
+HistoryManager::~HistoryManager()
+{
+ m_saveTimer->saveIfNeccessary();
+}
+
+QList<HistoryItem> HistoryManager::history() const
+{
+ return m_history;
+}
+
+bool HistoryManager::historyContains(const QString &url) const
+{
+ return m_historyFilterModel->historyContains(url);
+}
+
+void HistoryManager::addHistoryEntry(const QString &url)
+{
+ QUrl cleanUrl(url);
+ cleanUrl.setPassword(QString());
+ cleanUrl.setHost(cleanUrl.host().toLower());
+ HistoryItem item(cleanUrl.toString(), QDateTime::currentDateTime());
+ addHistoryItem(item);
+}
+
+void HistoryManager::setHistory(const QList<HistoryItem> &history, bool loadedAndSorted)
+{
+ m_history = history;
+
+ // verify that it is sorted by date
+ if (!loadedAndSorted)
+ qSort(m_history.begin(), m_history.end());
+
+ checkForExpired();
+
+ if (loadedAndSorted) {
+ m_lastSavedUrl = m_history.value(0).url;
+ } else {
+ m_lastSavedUrl = QString();
+ m_saveTimer->changeOccurred();
+ }
+ emit historyReset();
+}
+
+HistoryModel *HistoryManager::historyModel() const
+{
+ return m_historyModel;
+}
+
+HistoryFilterModel *HistoryManager::historyFilterModel() const
+{
+ return m_historyFilterModel;
+}
+
+HistoryTreeModel *HistoryManager::historyTreeModel() const
+{
+ return m_historyTreeModel;
+}
+
+void HistoryManager::checkForExpired()
+{
+ if (m_historyLimit < 0 || m_history.isEmpty())
+ return;
+
+ QDateTime now = QDateTime::currentDateTime();
+ int nextTimeout = 0;
+
+ while (!m_history.isEmpty()) {
+ QDateTime checkForExpired = m_history.last().dateTime;
+ checkForExpired.setDate(checkForExpired.date().addDays(m_historyLimit));
+ if (now.daysTo(checkForExpired) > 7) {
+ // check at most in a week to prevent int overflows on the timer
+ nextTimeout = 7 * 86400;
+ } else {
+ nextTimeout = now.secsTo(checkForExpired);
+ }
+ if (nextTimeout > 0)
+ break;
+ HistoryItem item = m_history.takeLast();
+ // remove from saved file also
+ m_lastSavedUrl = QString();
+ emit entryRemoved(item);
+ }
+
+ if (nextTimeout > 0)
+ m_expiredTimer.start(nextTimeout * 1000);
+}
+
+void HistoryManager::addHistoryItem(const HistoryItem &item)
+{
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled))
+ return;
+
+ m_history.prepend(item);
+ emit entryAdded(item);
+ if (m_history.count() == 1)
+ checkForExpired();
+}
+
+void HistoryManager::updateHistoryItem(const QUrl &url, const QString &title)
+{
+ for (int i = 0; i < m_history.count(); ++i) {
+ if (url == m_history.at(i).url) {
+ m_history[i].title = title;
+ m_saveTimer->changeOccurred();
+ if (m_lastSavedUrl.isEmpty())
+ m_lastSavedUrl = m_history.at(i).url;
+ emit entryUpdated(i);
+ break;
+ }
+ }
+}
+
+int HistoryManager::historyLimit() const
+{
+ return m_historyLimit;
+}
+
+void HistoryManager::setHistoryLimit(int limit)
+{
+ if (m_historyLimit == limit)
+ return;
+ m_historyLimit = limit;
+ checkForExpired();
+ m_saveTimer->changeOccurred();
+}
+
+void HistoryManager::clear()
+{
+ m_history.clear();
+ m_lastSavedUrl = QString();
+ m_saveTimer->changeOccurred();
+ m_saveTimer->saveIfNeccessary();
+ historyReset();
+}
+
+void HistoryManager::loadSettings()
+{
+ // load settings
+ QSettings settings;
+ settings.beginGroup(QLatin1String("history"));
+ m_historyLimit = settings.value(QLatin1String("historyLimit"), 30).toInt();
+}
+
+void HistoryManager::load()
+{
+ loadSettings();
+
+ QFile historyFile(QStandardPaths::writableLocation(QStandardPaths::DataLocation)
+ + QLatin1String("/history"));
+ if (!historyFile.exists())
+ return;
+ if (!historyFile.open(QFile::ReadOnly)) {
+ qWarning() << "Unable to open history file" << historyFile.fileName();
+ return;
+ }
+
+ QList<HistoryItem> list;
+ QDataStream in(&historyFile);
+ // Double check that the history file is sorted as it is read in
+ bool needToSort = false;
+ HistoryItem lastInsertedItem;
+ QByteArray data;
+ QDataStream stream;
+ QBuffer buffer;
+ stream.setDevice(&buffer);
+ while (!historyFile.atEnd()) {
+ in >> data;
+ buffer.close();
+ buffer.setBuffer(&data);
+ buffer.open(QIODevice::ReadOnly);
+ quint32 ver;
+ stream >> ver;
+ if (ver != HISTORY_VERSION)
+ continue;
+ HistoryItem item;
+ stream >> item.url;
+ stream >> item.dateTime;
+ stream >> item.title;
+
+ if (!item.dateTime.isValid())
+ continue;
+
+ if (item == lastInsertedItem) {
+ if (lastInsertedItem.title.isEmpty() && !list.isEmpty())
+ list[0].title = item.title;
+ continue;
+ }
+
+ if (!needToSort && !list.isEmpty() && lastInsertedItem < item)
+ needToSort = true;
+
+ list.prepend(item);
+ lastInsertedItem = item;
+ }
+ if (needToSort)
+ qSort(list.begin(), list.end());
+
+ setHistory(list, true);
+
+ // If we had to sort re-write the whole history sorted
+ if (needToSort) {
+ m_lastSavedUrl = QString();
+ m_saveTimer->changeOccurred();
+ }
+}
+
+void HistoryManager::save()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("history"));
+ settings.setValue(QLatin1String("historyLimit"), m_historyLimit);
+
+ bool saveAll = m_lastSavedUrl.isEmpty();
+ int first = m_history.count() - 1;
+ if (!saveAll) {
+ // find the first one to save
+ for (int i = 0; i < m_history.count(); ++i) {
+ if (m_history.at(i).url == m_lastSavedUrl) {
+ first = i - 1;
+ break;
+ }
+ }
+ }
+ if (first == m_history.count() - 1)
+ saveAll = true;
+
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
+ if (directory.isEmpty())
+ directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
+ if (!QFile::exists(directory)) {
+ QDir dir;
+ dir.mkpath(directory);
+ }
+
+ QFile historyFile(directory + QLatin1String("/history"));
+ // When saving everything use a temporary file to prevent possible data loss.
+ QTemporaryFile tempFile;
+ tempFile.setAutoRemove(false);
+ bool open = false;
+ if (saveAll) {
+ open = tempFile.open();
+ } else {
+ open = historyFile.open(QFile::Append);
+ }
+
+ if (!open) {
+ qWarning() << "Unable to open history file for saving"
+ << (saveAll ? tempFile.fileName() : historyFile.fileName());
+ return;
+ }
+
+ QDataStream out(saveAll ? &tempFile : &historyFile);
+ for (int i = first; i >= 0; --i) {
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+ HistoryItem item = m_history.at(i);
+ stream << HISTORY_VERSION << item.url << item.dateTime << item.title;
+ out << data;
+ }
+ tempFile.close();
+
+ if (saveAll) {
+ if (historyFile.exists() && !historyFile.remove())
+ qWarning() << "History: error removing old history." << historyFile.errorString();
+ if (!tempFile.rename(historyFile.fileName()))
+ qWarning() << "History: error moving new history over old." << tempFile.errorString() << historyFile.fileName();
+ }
+ m_lastSavedUrl = m_history.value(0).url;
+}
+
+HistoryModel::HistoryModel(HistoryManager *history, QObject *parent)
+ : QAbstractTableModel(parent)
+ , m_history(history)
+{
+ Q_ASSERT(m_history);
+ connect(m_history, SIGNAL(historyReset()),
+ this, SLOT(historyReset()));
+ connect(m_history, SIGNAL(entryRemoved(HistoryItem)),
+ this, SLOT(historyReset()));
+
+ connect(m_history, SIGNAL(entryAdded(HistoryItem)),
+ this, SLOT(entryAdded()));
+ connect(m_history, SIGNAL(entryUpdated(int)),
+ this, SLOT(entryUpdated(int)));
+}
+
+void HistoryModel::historyReset()
+{
+ beginResetModel();
+ endResetModel();
+}
+
+void HistoryModel::entryAdded()
+{
+ beginInsertRows(QModelIndex(), 0, 0);
+ endInsertRows();
+}
+
+void HistoryModel::entryUpdated(int offset)
+{
+ QModelIndex idx = index(offset, 0);
+ emit dataChanged(idx, idx);
+}
+
+QVariant HistoryModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal
+ && role == Qt::DisplayRole) {
+ switch (section) {
+ case 0: return tr("Title");
+ case 1: return tr("Address");
+ }
+ }
+ return QAbstractTableModel::headerData(section, orientation, role);
+}
+
+QVariant HistoryModel::data(const QModelIndex &index, int role) const
+{
+ QList<HistoryItem> lst = m_history->history();
+ if (index.row() < 0 || index.row() >= lst.size())
+ return QVariant();
+
+ const HistoryItem &item = lst.at(index.row());
+ switch (role) {
+ case DateTimeRole:
+ return item.dateTime;
+ case DateRole:
+ return item.dateTime.date();
+ case UrlRole:
+ return QUrl(item.url);
+ case UrlStringRole:
+ return item.url;
+ case Qt::DisplayRole:
+ case Qt::EditRole: {
+ switch (index.column()) {
+ case 0:
+ // when there is no title try to generate one from the url
+ if (item.title.isEmpty()) {
+ QString page = QFileInfo(QUrl(item.url).path()).fileName();
+ if (!page.isEmpty())
+ return page;
+ return item.url;
+ }
+ return item.title;
+ case 1:
+ return item.url;
+ }
+ }
+ case Qt::DecorationRole:
+ if (index.column() == 0) {
+ return BrowserApplication::instance()->icon(item.url);
+ }
+ }
+ return QVariant();
+}
+
+int HistoryModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 2;
+}
+
+int HistoryModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : m_history->history().count();
+}
+
+bool HistoryModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid())
+ return false;
+ int lastRow = row + count - 1;
+ beginRemoveRows(parent, row, lastRow);
+ QList<HistoryItem> lst = m_history->history();
+ for (int i = lastRow; i >= row; --i)
+ lst.removeAt(i);
+ disconnect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset()));
+ m_history->setHistory(lst);
+ connect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset()));
+ endRemoveRows();
+ return true;
+}
+
+#define MOVEDROWS 15
+
+/*
+ Maps the first bunch of items of the source model to the root
+*/
+HistoryMenuModel::HistoryMenuModel(HistoryTreeModel *sourceModel, QObject *parent)
+ : QAbstractProxyModel(parent)
+ , m_treeModel(sourceModel)
+{
+ setSourceModel(sourceModel);
+}
+
+int HistoryMenuModel::bumpedRows() const
+{
+ QModelIndex first = m_treeModel->index(0, 0);
+ if (!first.isValid())
+ return 0;
+ return qMin(m_treeModel->rowCount(first), MOVEDROWS);
+}
+
+int HistoryMenuModel::columnCount(const QModelIndex &parent) const
+{
+ return m_treeModel->columnCount(mapToSource(parent));
+}
+
+int HistoryMenuModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.column() > 0)
+ return 0;
+
+ if (!parent.isValid()) {
+ int folders = sourceModel()->rowCount();
+ int bumpedItems = bumpedRows();
+ if (bumpedItems <= MOVEDROWS
+ && bumpedItems == sourceModel()->rowCount(sourceModel()->index(0, 0)))
+ --folders;
+ return bumpedItems + folders;
+ }
+
+ if (parent.internalId() == -1) {
+ if (parent.row() < bumpedRows())
+ return 0;
+ }
+
+ QModelIndex idx = mapToSource(parent);
+ int defaultCount = sourceModel()->rowCount(idx);
+ if (idx == sourceModel()->index(0, 0))
+ return defaultCount - bumpedRows();
+ return defaultCount;
+}
+
+QModelIndex HistoryMenuModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ // currently not used or autotested
+ Q_ASSERT(false);
+ int sr = m_treeModel->mapToSource(sourceIndex).row();
+ return createIndex(sourceIndex.row(), sourceIndex.column(), sr);
+}
+
+QModelIndex HistoryMenuModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ if (!proxyIndex.isValid())
+ return QModelIndex();
+
+ if (proxyIndex.internalId() == -1) {
+ int bumpedItems = bumpedRows();
+ if (proxyIndex.row() < bumpedItems)
+ return m_treeModel->index(proxyIndex.row(), proxyIndex.column(), m_treeModel->index(0, 0));
+ if (bumpedItems <= MOVEDROWS && bumpedItems == sourceModel()->rowCount(m_treeModel->index(0, 0)))
+ --bumpedItems;
+ return m_treeModel->index(proxyIndex.row() - bumpedItems, proxyIndex.column());
+ }
+
+ QModelIndex historyIndex = m_treeModel->sourceModel()->index(proxyIndex.internalId(), proxyIndex.column());
+ QModelIndex treeIndex = m_treeModel->mapFromSource(historyIndex);
+ return treeIndex;
+}
+
+QModelIndex HistoryMenuModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0
+ || column < 0 || column >= columnCount(parent)
+ || parent.column() > 0)
+ return QModelIndex();
+ if (!parent.isValid())
+ return createIndex(row, column, -1);
+
+ QModelIndex treeIndexParent = mapToSource(parent);
+
+ int bumpedItems = 0;
+ if (treeIndexParent == m_treeModel->index(0, 0))
+ bumpedItems = bumpedRows();
+ QModelIndex treeIndex = m_treeModel->index(row + bumpedItems, column, treeIndexParent);
+ QModelIndex historyIndex = m_treeModel->mapToSource(treeIndex);
+ int historyRow = historyIndex.row();
+ if (historyRow == -1)
+ historyRow = treeIndex.row();
+ return createIndex(row, column, historyRow);
+}
+
+QModelIndex HistoryMenuModel::parent(const QModelIndex &index) const
+{
+ int offset = index.internalId();
+ if (offset == -1 || !index.isValid())
+ return QModelIndex();
+
+ QModelIndex historyIndex = m_treeModel->sourceModel()->index(index.internalId(), 0);
+ QModelIndex treeIndex = m_treeModel->mapFromSource(historyIndex);
+ QModelIndex treeIndexParent = treeIndex.parent();
+
+ int sr = m_treeModel->mapToSource(treeIndexParent).row();
+ int bumpedItems = bumpedRows();
+ if (bumpedItems <= MOVEDROWS && bumpedItems == sourceModel()->rowCount(sourceModel()->index(0, 0)))
+ --bumpedItems;
+ return createIndex(bumpedItems + treeIndexParent.row(), treeIndexParent.column(), sr);
+}
+
+
+HistoryMenu::HistoryMenu(QWidget *parent)
+ : ModelMenu(parent)
+ , m_history(0)
+{
+ connect(this, SIGNAL(activated(QModelIndex)),
+ this, SLOT(activated(QModelIndex)));
+ setHoverRole(HistoryModel::UrlStringRole);
+}
+
+void HistoryMenu::activated(const QModelIndex &index)
+{
+ emit openUrl(index.data(HistoryModel::UrlRole).toUrl());
+}
+
+bool HistoryMenu::prePopulated()
+{
+ if (!m_history) {
+ m_history = BrowserApplication::historyManager();
+ m_historyMenuModel = new HistoryMenuModel(m_history->historyTreeModel(), this);
+ setModel(m_historyMenuModel);
+ }
+ // initial actions
+ for (int i = 0; i < m_initialActions.count(); ++i)
+ addAction(m_initialActions.at(i));
+ if (!m_initialActions.isEmpty())
+ addSeparator();
+ setFirstSeparator(m_historyMenuModel->bumpedRows());
+
+ return false;
+}
+
+void HistoryMenu::postPopulated()
+{
+ if (m_history->history().count() > 0)
+ addSeparator();
+
+ QAction *showAllAction = new QAction(tr("Show All History"), this);
+ connect(showAllAction, SIGNAL(triggered()), this, SLOT(showHistoryDialog()));
+ addAction(showAllAction);
+
+ QAction *clearAction = new QAction(tr("Clear History"), this);
+ connect(clearAction, SIGNAL(triggered()), m_history, SLOT(clear()));
+ addAction(clearAction);
+}
+
+void HistoryMenu::showHistoryDialog()
+{
+ HistoryDialog *dialog = new HistoryDialog(this);
+ connect(dialog, SIGNAL(openUrl(QUrl)),
+ this, SIGNAL(openUrl(QUrl)));
+ dialog->show();
+}
+
+void HistoryMenu::setInitialActions(QList<QAction*> actions)
+{
+ m_initialActions = actions;
+ for (int i = 0; i < m_initialActions.count(); ++i)
+ addAction(m_initialActions.at(i));
+}
+
+TreeProxyModel::TreeProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
+{
+ setSortRole(HistoryModel::DateTimeRole);
+ setFilterCaseSensitivity(Qt::CaseInsensitive);
+}
+
+bool TreeProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ if (!source_parent.isValid())
+ return true;
+ return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
+}
+
+HistoryDialog::HistoryDialog(QWidget *parent, HistoryManager *setHistory) : QDialog(parent)
+{
+ HistoryManager *history = setHistory;
+ if (!history)
+ history = BrowserApplication::historyManager();
+ setupUi(this);
+ tree->setUniformRowHeights(true);
+ tree->setSelectionBehavior(QAbstractItemView::SelectRows);
+ tree->setTextElideMode(Qt::ElideMiddle);
+ QAbstractItemModel *model = history->historyTreeModel();
+ TreeProxyModel *proxyModel = new TreeProxyModel(this);
+ connect(search, SIGNAL(textChanged(QString)),
+ proxyModel, SLOT(setFilterFixedString(QString)));
+ connect(removeButton, SIGNAL(clicked()), tree, SLOT(removeOne()));
+ connect(removeAllButton, SIGNAL(clicked()), history, SLOT(clear()));
+ proxyModel->setSourceModel(model);
+ tree->setModel(proxyModel);
+ tree->setExpanded(proxyModel->index(0, 0), true);
+ tree->setAlternatingRowColors(true);
+ QFontMetrics fm(font());
+ int header = fm.width(QLatin1Char('m')) * 40;
+ tree->header()->resizeSection(0, header);
+ tree->header()->setStretchLastSection(true);
+ connect(tree, SIGNAL(activated(QModelIndex)),
+ this, SLOT(open()));
+ tree->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(tree, SIGNAL(customContextMenuRequested(QPoint)),
+ this, SLOT(customContextMenuRequested(QPoint)));
+}
+
+void HistoryDialog::customContextMenuRequested(const QPoint &pos)
+{
+ QMenu menu;
+ QModelIndex index = tree->indexAt(pos);
+ index = index.sibling(index.row(), 0);
+ if (index.isValid() && !tree->model()->hasChildren(index)) {
+ menu.addAction(tr("Open"), this, SLOT(open()));
+ menu.addSeparator();
+ menu.addAction(tr("Copy"), this, SLOT(copy()));
+ }
+ menu.addAction(tr("Delete"), tree, SLOT(removeOne()));
+ menu.exec(QCursor::pos());
+}
+
+void HistoryDialog::open()
+{
+ QModelIndex index = tree->currentIndex();
+ if (!index.parent().isValid())
+ return;
+ emit openUrl(index.data(HistoryModel::UrlRole).toUrl());
+}
+
+void HistoryDialog::copy()
+{
+ QModelIndex index = tree->currentIndex();
+ if (!index.parent().isValid())
+ return;
+ QString url = index.data(HistoryModel::UrlStringRole).toString();
+
+ QClipboard *clipboard = QApplication::clipboard();
+ clipboard->setText(url);
+}
+
+HistoryFilterModel::HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent)
+ : QAbstractProxyModel(parent),
+ m_loaded(false)
+{
+ setSourceModel(sourceModel);
+}
+
+int HistoryFilterModel::historyLocation(const QString &url) const
+{
+ load();
+ if (!m_historyHash.contains(url))
+ return 0;
+ return sourceModel()->rowCount() - m_historyHash.value(url);
+}
+
+QVariant HistoryFilterModel::data(const QModelIndex &index, int role) const
+{
+ return QAbstractProxyModel::data(index, role);
+}
+
+void HistoryFilterModel::setSourceModel(QAbstractItemModel *newSourceModel)
+{
+ if (sourceModel()) {
+ disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(dataChanged(QModelIndex,QModelIndex)));
+ disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
+ disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
+ }
+
+ QAbstractProxyModel::setSourceModel(newSourceModel);
+
+ if (sourceModel()) {
+ m_loaded = false;
+ connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
+ connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
+ connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
+ }
+}
+
+void HistoryFilterModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+ emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight));
+}
+
+QVariant HistoryFilterModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ return sourceModel()->headerData(section, orientation, role);
+}
+
+void HistoryFilterModel::sourceReset()
+{
+ m_loaded = false;
+ beginResetModel();
+ endResetModel();
+}
+
+int HistoryFilterModel::rowCount(const QModelIndex &parent) const
+{
+ load();
+ if (parent.isValid())
+ return 0;
+ return m_historyHash.count();
+}
+
+int HistoryFilterModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 2;
+}
+
+QModelIndex HistoryFilterModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ load();
+ int sourceRow = sourceModel()->rowCount() - proxyIndex.internalId();
+ return sourceModel()->index(sourceRow, proxyIndex.column());
+}
+
+QModelIndex HistoryFilterModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ load();
+ QString url = sourceIndex.data(HistoryModel::UrlStringRole).toString();
+ if (!m_historyHash.contains(url))
+ return QModelIndex();
+
+ // This can be done in a binary search, but we can't use qBinary find
+ // because it can't take: qBinaryFind(m_sourceRow.end(), m_sourceRow.begin(), v);
+ // so if this is a performance bottlneck then convert to binary search, until then
+ // the cleaner/easier to read code wins the day.
+ int realRow = -1;
+ int sourceModelRow = sourceModel()->rowCount() - sourceIndex.row();
+
+ for (int i = 0; i < m_sourceRow.count(); ++i) {
+ if (m_sourceRow.at(i) == sourceModelRow) {
+ realRow = i;
+ break;
+ }
+ }
+ if (realRow == -1)
+ return QModelIndex();
+
+ return createIndex(realRow, sourceIndex.column(), sourceModel()->rowCount() - sourceIndex.row());
+}
+
+QModelIndex HistoryFilterModel::index(int row, int column, const QModelIndex &parent) const
+{
+ load();
+ if (row < 0 || row >= rowCount(parent)
+ || column < 0 || column >= columnCount(parent))
+ return QModelIndex();
+
+ return createIndex(row, column, m_sourceRow[row]);
+}
+
+QModelIndex HistoryFilterModel::parent(const QModelIndex &) const
+{
+ return QModelIndex();
+}
+
+void HistoryFilterModel::load() const
+{
+ if (m_loaded)
+ return;
+ m_sourceRow.clear();
+ m_historyHash.clear();
+ m_historyHash.reserve(sourceModel()->rowCount());
+ for (int i = 0; i < sourceModel()->rowCount(); ++i) {
+ QModelIndex idx = sourceModel()->index(i, 0);
+ QString url = idx.data(HistoryModel::UrlStringRole).toString();
+ if (!m_historyHash.contains(url)) {
+ m_sourceRow.append(sourceModel()->rowCount() - i);
+ m_historyHash[url] = sourceModel()->rowCount() - i;
+ }
+ }
+ m_loaded = true;
+}
+
+void HistoryFilterModel::sourceRowsInserted(const QModelIndex &parent, int start, int end)
+{
+ Q_ASSERT(start == end && start == 0);
+ Q_UNUSED(end);
+ if (!m_loaded)
+ return;
+ QModelIndex idx = sourceModel()->index(start, 0, parent);
+ QString url = idx.data(HistoryModel::UrlStringRole).toString();
+ if (m_historyHash.contains(url)) {
+ int sourceRow = sourceModel()->rowCount() - m_historyHash[url];
+ int realRow = mapFromSource(sourceModel()->index(sourceRow, 0)).row();
+ beginRemoveRows(QModelIndex(), realRow, realRow);
+ m_sourceRow.removeAt(realRow);
+ m_historyHash.remove(url);
+ endRemoveRows();
+ }
+ beginInsertRows(QModelIndex(), 0, 0);
+ m_historyHash.insert(url, sourceModel()->rowCount() - start);
+ m_sourceRow.insert(0, sourceModel()->rowCount());
+ endInsertRows();
+}
+
+void HistoryFilterModel::sourceRowsRemoved(const QModelIndex &, int start, int end)
+{
+ Q_UNUSED(start);
+ Q_UNUSED(end);
+ sourceReset();
+}
+
+/*
+ Removing a continuous block of rows will remove filtered rows too as this is
+ the users intention.
+*/
+bool HistoryFilterModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (row < 0 || count <= 0 || row + count > rowCount(parent) || parent.isValid())
+ return false;
+ int lastRow = row + count - 1;
+ disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
+ beginRemoveRows(parent, row, lastRow);
+ int oldCount = rowCount();
+ int start = sourceModel()->rowCount() - m_sourceRow.value(row);
+ int end = sourceModel()->rowCount() - m_sourceRow.value(lastRow);
+ sourceModel()->removeRows(start, end - start + 1);
+ endRemoveRows();
+ connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
+ m_loaded = false;
+ if (oldCount - count != rowCount()) {
+ beginResetModel();
+ endResetModel();
+ }
+ return true;
+}
+
+HistoryCompletionModel::HistoryCompletionModel(QObject *parent)
+ : QAbstractProxyModel(parent)
+{
+}
+
+QVariant HistoryCompletionModel::data(const QModelIndex &index, int role) const
+{
+ if (sourceModel()
+ && (role == Qt::EditRole || role == Qt::DisplayRole)
+ && index.isValid()) {
+ QModelIndex idx = mapToSource(index);
+ idx = idx.sibling(idx.row(), 1);
+ QString urlString = idx.data(HistoryModel::UrlStringRole).toString();
+ if (index.row() % 2) {
+ QUrl url = urlString;
+ QString s = url.toString(QUrl::RemoveScheme
+ | QUrl::RemoveUserInfo
+ | QUrl::StripTrailingSlash);
+ return s.mid(2); // strip // from the front
+ }
+ return urlString;
+ }
+ return QAbstractProxyModel::data(index, role);
+}
+
+int HistoryCompletionModel::rowCount(const QModelIndex &parent) const
+{
+ return (parent.isValid() || !sourceModel()) ? 0 : sourceModel()->rowCount(parent) * 2;
+}
+
+int HistoryCompletionModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.isValid()) ? 0 : 1;
+}
+
+QModelIndex HistoryCompletionModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ int row = sourceIndex.row() * 2;
+ return index(row, sourceIndex.column());
+}
+
+QModelIndex HistoryCompletionModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ if (!sourceModel())
+ return QModelIndex();
+ int row = proxyIndex.row() / 2;
+ return sourceModel()->index(row, proxyIndex.column());
+}
+
+QModelIndex HistoryCompletionModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0 || row >= rowCount(parent)
+ || column < 0 || column >= columnCount(parent))
+ return QModelIndex();
+ return createIndex(row, column);
+}
+
+QModelIndex HistoryCompletionModel::parent(const QModelIndex &) const
+{
+ return QModelIndex();
+}
+
+void HistoryCompletionModel::setSourceModel(QAbstractItemModel *newSourceModel)
+{
+ if (sourceModel()) {
+ disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceReset()));
+ }
+
+ QAbstractProxyModel::setSourceModel(newSourceModel);
+
+ if (newSourceModel) {
+ connect(newSourceModel, SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceReset()));
+ }
+
+ beginResetModel();
+ endResetModel();
+}
+
+void HistoryCompletionModel::sourceReset()
+{
+ beginResetModel();
+ endResetModel();
+}
+
+HistoryTreeModel::HistoryTreeModel(QAbstractItemModel *sourceModel, QObject *parent)
+ : QAbstractProxyModel(parent)
+{
+ setSourceModel(sourceModel);
+}
+
+QVariant HistoryTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ return sourceModel()->headerData(section, orientation, role);
+}
+
+QVariant HistoryTreeModel::data(const QModelIndex &index, int role) const
+{
+ if ((role == Qt::EditRole || role == Qt::DisplayRole)) {
+ int start = index.internalId();
+ if (start == 0) {
+ int offset = sourceDateRow(index.row());
+ if (index.column() == 0) {
+ QModelIndex idx = sourceModel()->index(offset, 0);
+ QDate date = idx.data(HistoryModel::DateRole).toDate();
+ if (date == QDate::currentDate())
+ return tr("Earlier Today");
+ return date.toString(QLatin1String("dddd, MMMM d, yyyy"));
+ }
+ if (index.column() == 1) {
+ return tr("%1 items").arg(rowCount(index.sibling(index.row(), 0)));
+ }
+ }
+ }
+ if (role == Qt::DecorationRole && index.column() == 0 && !index.parent().isValid())
+ return QIcon(QLatin1String(":history.png"));
+ if (role == HistoryModel::DateRole && index.column() == 0 && index.internalId() == 0) {
+ int offset = sourceDateRow(index.row());
+ QModelIndex idx = sourceModel()->index(offset, 0);
+ return idx.data(HistoryModel::DateRole);
+ }
+
+ return QAbstractProxyModel::data(index, role);
+}
+
+int HistoryTreeModel::columnCount(const QModelIndex &parent) const
+{
+ return sourceModel()->columnCount(mapToSource(parent));
+}
+
+int HistoryTreeModel::rowCount(const QModelIndex &parent) const
+{
+ if ( parent.internalId() != 0
+ || parent.column() > 0
+ || !sourceModel())
+ return 0;
+
+ // row count OF dates
+ if (!parent.isValid()) {
+ if (!m_sourceRowCache.isEmpty())
+ return m_sourceRowCache.count();
+ QDate currentDate;
+ int rows = 0;
+ int totalRows = sourceModel()->rowCount();
+
+ for (int i = 0; i < totalRows; ++i) {
+ QDate rowDate = sourceModel()->index(i, 0).data(HistoryModel::DateRole).toDate();
+ if (rowDate != currentDate) {
+ m_sourceRowCache.append(i);
+ currentDate = rowDate;
+ ++rows;
+ }
+ }
+ Q_ASSERT(m_sourceRowCache.count() == rows);
+ return rows;
+ }
+
+ // row count FOR a date
+ int start = sourceDateRow(parent.row());
+ int end = sourceDateRow(parent.row() + 1);
+ return (end - start);
+}
+
+// Translate the top level date row into the offset where that date starts
+int HistoryTreeModel::sourceDateRow(int row) const
+{
+ if (row <= 0)
+ return 0;
+
+ if (m_sourceRowCache.isEmpty())
+ rowCount(QModelIndex());
+
+ if (row >= m_sourceRowCache.count()) {
+ if (!sourceModel())
+ return 0;
+ return sourceModel()->rowCount();
+ }
+ return m_sourceRowCache.at(row);
+}
+
+QModelIndex HistoryTreeModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ int offset = proxyIndex.internalId();
+ if (offset == 0)
+ return QModelIndex();
+ int startDateRow = sourceDateRow(offset - 1);
+ return sourceModel()->index(startDateRow + proxyIndex.row(), proxyIndex.column());
+}
+
+QModelIndex HistoryTreeModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (row < 0
+ || column < 0 || column >= columnCount(parent)
+ || parent.column() > 0)
+ return QModelIndex();
+
+ if (!parent.isValid())
+ return createIndex(row, column);
+ return createIndex(row, column, parent.row() + 1);
+}
+
+QModelIndex HistoryTreeModel::parent(const QModelIndex &index) const
+{
+ int offset = index.internalId();
+ if (offset == 0 || !index.isValid())
+ return QModelIndex();
+ return createIndex(offset - 1, 0);
+}
+
+bool HistoryTreeModel::hasChildren(const QModelIndex &parent) const
+{
+ QModelIndex grandparent = parent.parent();
+ if (!grandparent.isValid())
+ return true;
+ return false;
+}
+
+Qt::ItemFlags HistoryTreeModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
+}
+
+bool HistoryTreeModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (row < 0 || count <= 0 || row + count > rowCount(parent))
+ return false;
+
+ if (parent.isValid()) {
+ // removing pages
+ int offset = sourceDateRow(parent.row());
+ return sourceModel()->removeRows(offset + row, count);
+ } else {
+ // removing whole dates
+ for (int i = row + count - 1; i >= row; --i) {
+ QModelIndex dateParent = index(i, 0);
+ int offset = sourceDateRow(dateParent.row());
+ if (!sourceModel()->removeRows(offset, rowCount(dateParent)))
+ return false;
+ }
+ }
+ return true;
+}
+
+void HistoryTreeModel::setSourceModel(QAbstractItemModel *newSourceModel)
+{
+ if (sourceModel()) {
+ disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(sourceReset()));
+ disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
+ disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
+ }
+
+ QAbstractProxyModel::setSourceModel(newSourceModel);
+
+ if (newSourceModel) {
+ connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(sourceReset()));
+ connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
+ connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
+ }
+
+ beginResetModel();
+ endResetModel();
+}
+
+void HistoryTreeModel::sourceReset()
+{
+ beginResetModel();
+ m_sourceRowCache.clear();
+ endResetModel();
+}
+
+void HistoryTreeModel::sourceRowsInserted(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent); // Avoid warnings when compiling release
+ Q_ASSERT(!parent.isValid());
+ if (start != 0 || start != end) {
+ beginResetModel();
+ m_sourceRowCache.clear();
+ endResetModel();
+ return;
+ }
+
+ m_sourceRowCache.clear();
+ QModelIndex treeIndex = mapFromSource(sourceModel()->index(start, 0));
+ QModelIndex treeParent = treeIndex.parent();
+ if (rowCount(treeParent) == 1) {
+ beginInsertRows(QModelIndex(), 0, 0);
+ endInsertRows();
+ } else {
+ beginInsertRows(treeParent, treeIndex.row(), treeIndex.row());
+ endInsertRows();
+ }
+}
+
+QModelIndex HistoryTreeModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ if (!sourceIndex.isValid())
+ return QModelIndex();
+
+ if (m_sourceRowCache.isEmpty())
+ rowCount(QModelIndex());
+
+ QList<int>::iterator it;
+ it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), sourceIndex.row());
+ if (*it != sourceIndex.row())
+ --it;
+ int dateRow = qMax(0, it - m_sourceRowCache.begin());
+ int row = sourceIndex.row() - m_sourceRowCache.at(dateRow);
+ return createIndex(row, sourceIndex.column(), dateRow + 1);
+}
+
+void HistoryTreeModel::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent); // Avoid warnings when compiling release
+ Q_ASSERT(!parent.isValid());
+ if (m_sourceRowCache.isEmpty())
+ return;
+ for (int i = end; i >= start;) {
+ QList<int>::iterator it;
+ it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), i);
+ // playing it safe
+ if (it == m_sourceRowCache.end()) {
+ beginResetModel();
+ m_sourceRowCache.clear();
+ endResetModel();
+ return;
+ }
+
+ if (*it != i)
+ --it;
+ int row = qMax(0, it - m_sourceRowCache.begin());
+ int offset = m_sourceRowCache[row];
+ QModelIndex dateParent = index(row, 0);
+ // If we can remove all the rows in the date do that and skip over them
+ int rc = rowCount(dateParent);
+ if (i - rc + 1 == offset && start <= i - rc + 1) {
+ beginRemoveRows(QModelIndex(), row, row);
+ m_sourceRowCache.removeAt(row);
+ i -= rc + 1;
+ } else {
+ beginRemoveRows(dateParent, i - offset, i - offset);
+ ++row;
+ --i;
+ }
+ for (int j = row; j < m_sourceRowCache.count(); ++j)
+ --m_sourceRowCache[j];
+ endRemoveRows();
+ }
+}
+
diff --git a/examples/webkitwidgets/browser/history.h b/examples/webkitwidgets/browser/history.h
new file mode 100644
index 0000000..0add405
--- /dev/null
+++ b/examples/webkitwidgets/browser/history.h
@@ -0,0 +1,350 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HISTORY_H
+#define HISTORY_H
+
+#include "modelmenu.h"
+
+#include <QtCore/QDateTime>
+#include <QtCore/QHash>
+#include <QtCore/QObject>
+#include <QtCore/QTimer>
+#include <QtCore/QUrl>
+
+#include <QtCore/QSortFilterProxyModel>
+
+#include <QWebHistoryInterface>
+
+class HistoryItem
+{
+public:
+ HistoryItem() {}
+ HistoryItem(const QString &u,
+ const QDateTime &d = QDateTime(), const QString &t = QString())
+ : title(t), url(u), dateTime(d) {}
+
+ inline bool operator==(const HistoryItem &other) const
+ { return other.title == title
+ && other.url == url && other.dateTime == dateTime; }
+
+ // history is sorted in reverse
+ inline bool operator <(const HistoryItem &other) const
+ { return dateTime > other.dateTime; }
+
+ QString title;
+ QString url;
+ QDateTime dateTime;
+};
+
+class AutoSaver;
+class HistoryModel;
+class HistoryFilterModel;
+class HistoryTreeModel;
+class HistoryManager : public QWebHistoryInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(int historyLimit READ historyLimit WRITE setHistoryLimit)
+
+signals:
+ void historyReset();
+ void entryAdded(const HistoryItem &item);
+ void entryRemoved(const HistoryItem &item);
+ void entryUpdated(int offset);
+
+public:
+ HistoryManager(QObject *parent = 0);
+ ~HistoryManager();
+
+ bool historyContains(const QString &url) const;
+ void addHistoryEntry(const QString &url);
+
+ void updateHistoryItem(const QUrl &url, const QString &title);
+
+ int historyLimit() const;
+ void setHistoryLimit(int limit);
+
+ QList<HistoryItem> history() const;
+ void setHistory(const QList<HistoryItem> &history, bool loadedAndSorted = false);
+
+ // History manager keeps around these models for use by the completer and other classes
+ HistoryModel *historyModel() const;
+ HistoryFilterModel *historyFilterModel() const;
+ HistoryTreeModel *historyTreeModel() const;
+
+public slots:
+ void clear();
+ void loadSettings();
+
+private slots:
+ void save();
+ void checkForExpired();
+
+protected:
+ void addHistoryItem(const HistoryItem &item);
+
+private:
+ void load();
+
+ AutoSaver *m_saveTimer;
+ int m_historyLimit;
+ QTimer m_expiredTimer;
+ QList<HistoryItem> m_history;
+ QString m_lastSavedUrl;
+
+ HistoryModel *m_historyModel;
+ HistoryFilterModel *m_historyFilterModel;
+ HistoryTreeModel *m_historyTreeModel;
+};
+
+class HistoryModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public slots:
+ void historyReset();
+ void entryAdded();
+ void entryUpdated(int offset);
+
+public:
+ enum Roles {
+ DateRole = Qt::UserRole + 1,
+ DateTimeRole = Qt::UserRole + 2,
+ UrlRole = Qt::UserRole + 3,
+ UrlStringRole = Qt::UserRole + 4
+ };
+
+ HistoryModel(HistoryManager *history, QObject *parent = 0);
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+
+private:
+ HistoryManager *m_history;
+};
+
+/*!
+ Proxy model that will remove any duplicate entries.
+ Both m_sourceRow and m_historyHash store their offsets not from
+ the front of the list, but as offsets from the back.
+ */
+class HistoryFilterModel : public QAbstractProxyModel
+{
+ Q_OBJECT
+
+public:
+ HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent = 0);
+
+ inline bool historyContains(const QString &url) const
+ { load(); return m_historyHash.contains(url); }
+ int historyLocation(const QString &url) const;
+
+ QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
+ QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
+ void setSourceModel(QAbstractItemModel *sourceModel);
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex& index= QModelIndex()) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+private slots:
+ void sourceReset();
+ void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void sourceRowsInserted(const QModelIndex &parent, int start, int end);
+ void sourceRowsRemoved(const QModelIndex &, int, int);
+
+private:
+ void load() const;
+
+ mutable QList<int> m_sourceRow;
+ mutable QHash<QString, int> m_historyHash;
+ mutable bool m_loaded;
+};
+
+/*
+ The history menu
+ - Removes the first twenty entries and puts them as children of the top level.
+ - If there are less then twenty entries then the first folder is also removed.
+
+ The mapping is done by knowing that HistoryTreeModel is over a table
+ We store that row offset in our index's private data.
+*/
+class HistoryMenuModel : public QAbstractProxyModel
+{
+ Q_OBJECT
+
+public:
+ HistoryMenuModel(HistoryTreeModel *sourceModel, QObject *parent = 0);
+ int columnCount(const QModelIndex &parent) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex mapFromSource(const QModelIndex & sourceIndex) const;
+ QModelIndex mapToSource(const QModelIndex & proxyIndex) const;
+ QModelIndex index(int, int, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index = QModelIndex()) const;
+
+ int bumpedRows() const;
+
+private:
+ HistoryTreeModel *m_treeModel;
+};
+
+// Menu that is dynamically populated from the history
+class HistoryMenu : public ModelMenu
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ HistoryMenu(QWidget *parent = 0);
+ void setInitialActions(QList<QAction*> actions);
+
+protected:
+ bool prePopulated();
+ void postPopulated();
+
+private slots:
+ void activated(const QModelIndex &index);
+ void showHistoryDialog();
+
+private:
+ HistoryManager *m_history;
+ HistoryMenuModel *m_historyMenuModel;
+ QList<QAction*> m_initialActions;
+};
+
+// proxy model for the history model that
+// exposes each url http://www.foo.com and it url starting at the host www.foo.com
+class HistoryCompletionModel : public QAbstractProxyModel
+{
+ Q_OBJECT
+
+public:
+ HistoryCompletionModel(QObject *parent = 0);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
+ QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
+ QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex& index= QModelIndex()) const;
+ void setSourceModel(QAbstractItemModel *sourceModel);
+
+private slots:
+ void sourceReset();
+
+};
+
+// proxy model for the history model that converts the list
+// into a tree, one top level node per day.
+// Used in the HistoryDialog.
+class HistoryTreeModel : public QAbstractProxyModel
+{
+ Q_OBJECT
+
+public:
+ HistoryTreeModel(QAbstractItemModel *sourceModel, QObject *parent = 0);
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int columnCount(const QModelIndex &parent) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
+ QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index= QModelIndex()) const;
+ bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+
+ void setSourceModel(QAbstractItemModel *sourceModel);
+
+private slots:
+ void sourceReset();
+ void sourceRowsInserted(const QModelIndex &parent, int start, int end);
+ void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
+
+private:
+ int sourceDateRow(int row) const;
+ mutable QList<int> m_sourceRowCache;
+
+};
+
+// A modified QSortFilterProxyModel that always accepts the root nodes in the tree
+// so filtering is only done on the children.
+// Used in the HistoryDialog
+class TreeProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ TreeProxyModel(QObject *parent = 0);
+
+protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+};
+
+#include "ui_history.h"
+
+class HistoryDialog : public QDialog, public Ui_HistoryDialog
+{
+ Q_OBJECT
+
+signals:
+ void openUrl(const QUrl &url);
+
+public:
+ HistoryDialog(QWidget *parent = 0, HistoryManager *history = 0);
+
+private slots:
+ void customContextMenuRequested(const QPoint &pos);
+ void open();
+ void copy();
+
+};
+
+#endif // HISTORY_H
+
diff --git a/examples/webkitwidgets/browser/history.ui b/examples/webkitwidgets/browser/history.ui
new file mode 100644
index 0000000..0944940
--- /dev/null
+++ b/examples/webkitwidgets/browser/history.ui
@@ -0,0 +1,106 @@
+<ui version="4.0" >
+ <class>HistoryDialog</class>
+ <widget class="QDialog" name="HistoryDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>758</width>
+ <height>450</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>History</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>252</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1" >
+ <widget class="SearchLineEdit" name="search" />
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="EditTreeView" name="tree" />
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QPushButton" name="removeButton" >
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeAllButton" >
+ <property name="text" >
+ <string>Remove &amp;All</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>SearchLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>searchlineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>EditTreeView</class>
+ <extends>QTreeView</extends>
+ <header>edittreeview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>HistoryDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>472</x>
+ <y>329</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>461</x>
+ <y>356</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webkitwidgets/browser/htmls/htmls.qrc b/examples/webkitwidgets/browser/htmls/htmls.qrc
new file mode 100644
index 0000000..03b256c
--- /dev/null
+++ b/examples/webkitwidgets/browser/htmls/htmls.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>notfound.html</file>
+</qresource>
+</RCC>
diff --git a/examples/webkitwidgets/browser/htmls/notfound.html b/examples/webkitwidgets/browser/htmls/notfound.html
new file mode 100644
index 0000000..e89845a
--- /dev/null
+++ b/examples/webkitwidgets/browser/htmls/notfound.html
@@ -0,0 +1,63 @@
+<html>
+<head>
+<title>%1</title>
+<style>
+body {
+ padding: 3em 0em;
+ background: #eeeeee;
+}
+hr {
+ color: lightgray;
+ width: 100%;
+}
+img {
+ float: left;
+ opacity: .8;
+}
+#box {
+ background: white;
+ border: 1px solid lightgray;
+ width: 600px;
+ padding: 60px;
+ margin: auto;
+}
+h1 {
+ font-size: 130%;
+ font-weight: bold;
+ border-bottom: 1px solid lightgray;
+ margin-left: 48px;
+}
+h2 {
+ font-size: 100%;
+ font-weight: normal;
+ border-bottom: 1px solid lightgray;
+ margin-left: 48px;
+}
+ul {
+ font-size: 80%;
+ padding-left: 48px;
+ margin: 0;
+}
+#reloadButton {
+ padding-left: 48px;
+}
+</style>
+</head>
+<body>
+ <div id="box">
+ <img src="data:image/png;base64,IMAGE_BINARY_DATA_HERE" width="32" height="32"/>
+ <h1>%2</h1>
+ <h2>When connecting to: %3.</h2>
+ <ul>
+ <li>Check the address for errors such as <b>ww</b>.example.com
+ instead of <b>www</b>.example.com</li>
+ <li>If the address is correct, try checking the network
+ connection.</li>
+ <li>If your computer or network is protected by a firewall or
+ proxy, make sure that the browser demo is permitted to access
+ the network.</li>
+ </ul>
+ <br/><br/>
+ </div>
+</body>
+</html>
diff --git a/examples/webkitwidgets/browser/main.cpp b/examples/webkitwidgets/browser/main.cpp
new file mode 100644
index 0000000..1480c66
--- /dev/null
+++ b/examples/webkitwidgets/browser/main.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browserapplication.h"
+
+int main(int argc, char **argv)
+{
+ Q_INIT_RESOURCE(data);
+ BrowserApplication application(argc, argv);
+ if (!application.isTheOnlyBrowser())
+ return 0;
+ application.newMainWindow();
+ return application.exec();
+}
+
diff --git a/examples/webkitwidgets/browser/modelmenu.cpp b/examples/webkitwidgets/browser/modelmenu.cpp
new file mode 100644
index 0000000..8226fb8
--- /dev/null
+++ b/examples/webkitwidgets/browser/modelmenu.cpp
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "modelmenu.h"
+
+#include <QtCore/QAbstractItemModel>
+#include <qdebug.h>
+
+ModelMenu::ModelMenu(QWidget * parent)
+ : QMenu(parent)
+ , m_maxRows(7)
+ , m_firstSeparator(-1)
+ , m_maxWidth(-1)
+ , m_hoverRole(0)
+ , m_separatorRole(0)
+ , m_model(0)
+{
+ connect(this, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
+}
+
+bool ModelMenu::prePopulated()
+{
+ return false;
+}
+
+void ModelMenu::postPopulated()
+{
+}
+
+void ModelMenu::setModel(QAbstractItemModel *model)
+{
+ m_model = model;
+}
+
+QAbstractItemModel *ModelMenu::model() const
+{
+ return m_model;
+}
+
+void ModelMenu::setMaxRows(int max)
+{
+ m_maxRows = max;
+}
+
+int ModelMenu::maxRows() const
+{
+ return m_maxRows;
+}
+
+void ModelMenu::setFirstSeparator(int offset)
+{
+ m_firstSeparator = offset;
+}
+
+int ModelMenu::firstSeparator() const
+{
+ return m_firstSeparator;
+}
+
+void ModelMenu::setRootIndex(const QModelIndex &index)
+{
+ m_root = index;
+}
+
+QModelIndex ModelMenu::rootIndex() const
+{
+ return m_root;
+}
+
+void ModelMenu::setHoverRole(int role)
+{
+ m_hoverRole = role;
+}
+
+int ModelMenu::hoverRole() const
+{
+ return m_hoverRole;
+}
+
+void ModelMenu::setSeparatorRole(int role)
+{
+ m_separatorRole = role;
+}
+
+int ModelMenu::separatorRole() const
+{
+ return m_separatorRole;
+}
+
+Q_DECLARE_METATYPE(QModelIndex)
+void ModelMenu::aboutToShow()
+{
+ if (QMenu *menu = qobject_cast<QMenu*>(sender())) {
+ QVariant v = menu->menuAction()->data();
+ if (v.canConvert<QModelIndex>()) {
+ QModelIndex idx = qvariant_cast<QModelIndex>(v);
+ createMenu(idx, -1, menu, menu);
+ disconnect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
+ return;
+ }
+ }
+
+ clear();
+ if (prePopulated())
+ addSeparator();
+ int max = m_maxRows;
+ if (max != -1)
+ max += m_firstSeparator;
+ createMenu(m_root, max, this, this);
+ postPopulated();
+}
+
+void ModelMenu::createMenu(const QModelIndex &parent, int max, QMenu *parentMenu, QMenu *menu)
+{
+ if (!menu) {
+ QString title = parent.data().toString();
+ menu = new QMenu(title, this);
+ QIcon icon = qvariant_cast<QIcon>(parent.data(Qt::DecorationRole));
+ menu->setIcon(icon);
+ parentMenu->addMenu(menu);
+ QVariant v;
+ v.setValue(parent);
+ menu->menuAction()->setData(v);
+ connect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShow()));
+ return;
+ }
+
+ int end = m_model->rowCount(parent);
+ if (max != -1)
+ end = qMin(max, end);
+
+ connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(triggered(QAction*)));
+ connect(menu, SIGNAL(hovered(QAction*)), this, SLOT(hovered(QAction*)));
+
+ for (int i = 0; i < end; ++i) {
+ QModelIndex idx = m_model->index(i, 0, parent);
+ if (m_model->hasChildren(idx)) {
+ createMenu(idx, -1, menu);
+ } else {
+ if (m_separatorRole != 0
+ && idx.data(m_separatorRole).toBool())
+ addSeparator();
+ else
+ menu->addAction(makeAction(idx));
+ }
+ if (menu == this && i == m_firstSeparator - 1)
+ addSeparator();
+ }
+}
+
+QAction *ModelMenu::makeAction(const QModelIndex &index)
+{
+ QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
+ QAction *action = makeAction(icon, index.data().toString(), this);
+ QVariant v;
+ v.setValue(index);
+ action->setData(v);
+ return action;
+}
+
+QAction *ModelMenu::makeAction(const QIcon &icon, const QString &text, QObject *parent)
+{
+ QFontMetrics fm(font());
+ if (-1 == m_maxWidth)
+ m_maxWidth = fm.width(QLatin1Char('m')) * 30;
+ QString smallText = fm.elidedText(text, Qt::ElideMiddle, m_maxWidth);
+ return new QAction(icon, smallText, parent);
+}
+
+void ModelMenu::triggered(QAction *action)
+{
+ QVariant v = action->data();
+ if (v.canConvert<QModelIndex>()) {
+ QModelIndex idx = qvariant_cast<QModelIndex>(v);
+ emit activated(idx);
+ }
+}
+
+void ModelMenu::hovered(QAction *action)
+{
+ QVariant v = action->data();
+ if (v.canConvert<QModelIndex>()) {
+ QModelIndex idx = qvariant_cast<QModelIndex>(v);
+ QString hoveredString = idx.data(m_hoverRole).toString();
+ if (!hoveredString.isEmpty())
+ emit hovered(hoveredString);
+ }
+}
+
diff --git a/examples/webkitwidgets/browser/modelmenu.h b/examples/webkitwidgets/browser/modelmenu.h
new file mode 100644
index 0000000..e28861d
--- /dev/null
+++ b/examples/webkitwidgets/browser/modelmenu.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MODELMENU_H
+#define MODELMENU_H
+
+#include <QtWidgets/QMenu>
+#include <QtCore/QAbstractItemModel>
+
+// A QMenu that is dynamically populated from a QAbstractItemModel
+class ModelMenu : public QMenu
+{
+ Q_OBJECT
+
+signals:
+ void activated(const QModelIndex &index);
+ void hovered(const QString &text);
+
+public:
+ ModelMenu(QWidget *parent = 0);
+
+ void setModel(QAbstractItemModel *model);
+ QAbstractItemModel *model() const;
+
+ void setMaxRows(int max);
+ int maxRows() const;
+
+ void setFirstSeparator(int offset);
+ int firstSeparator() const;
+
+ void setRootIndex(const QModelIndex &index);
+ QModelIndex rootIndex() const;
+
+ void setHoverRole(int role);
+ int hoverRole() const;
+
+ void setSeparatorRole(int role);
+ int separatorRole() const;
+
+ QAction *makeAction(const QIcon &icon, const QString &text, QObject *parent);
+
+protected:
+ // add any actions before the tree, return true if any actions are added.
+ virtual bool prePopulated();
+ // add any actions after the tree
+ virtual void postPopulated();
+ // put all of the children of parent into menu up to max
+ void createMenu(const QModelIndex &parent, int max, QMenu *parentMenu = 0, QMenu *menu = 0);
+
+private slots:
+ void aboutToShow();
+ void triggered(QAction *action);
+ void hovered(QAction *action);
+
+private:
+ QAction *makeAction(const QModelIndex &index);
+ int m_maxRows;
+ int m_firstSeparator;
+ int m_maxWidth;
+ int m_hoverRole;
+ int m_separatorRole;
+ QAbstractItemModel *m_model;
+ QPersistentModelIndex m_root;
+};
+
+#endif // MODELMENU_H
+
diff --git a/examples/webkitwidgets/browser/networkaccessmanager.cpp b/examples/webkitwidgets/browser/networkaccessmanager.cpp
new file mode 100644
index 0000000..b4d635f
--- /dev/null
+++ b/examples/webkitwidgets/browser/networkaccessmanager.cpp
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "networkaccessmanager.h"
+
+#include "browserapplication.h"
+#include "browsermainwindow.h"
+#include "ui_passworddialog.h"
+#include "ui_proxy.h"
+
+#include <QtCore/QSettings>
+
+#include <QtGui/QDesktopServices>
+#include <QtWidgets/QDialog>
+#include <QtWidgets/QMessageBox>
+#include <QtWidgets/QStyle>
+#include <QtGui/QTextDocument>
+
+#include <QtNetwork/QAuthenticator>
+#include <QtNetwork/QNetworkDiskCache>
+#include <QtNetwork/QNetworkProxy>
+#include <QtNetwork/QNetworkRequest>
+#include <QtNetwork/QNetworkReply>
+#include <QtNetwork/QSslError>
+
+NetworkAccessManager::NetworkAccessManager(QObject *parent)
+ : QNetworkAccessManager(parent),
+ requestFinishedCount(0), requestFinishedFromCacheCount(0), requestFinishedPipelinedCount(0),
+ requestFinishedSecureCount(0), requestFinishedDownloadBufferCount(0)
+{
+ connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
+ SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
+ connect(this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
+ connect(this, SIGNAL(finished(QNetworkReply*)),
+ SLOT(requestFinished(QNetworkReply*)));
+#ifndef QT_NO_OPENSSL
+ connect(this, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
+ SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
+#endif
+ loadSettings();
+
+ QNetworkDiskCache *diskCache = new QNetworkDiskCache(this);
+ QString location = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+ diskCache->setCacheDirectory(location);
+ setCache(diskCache);
+}
+
+QNetworkReply* NetworkAccessManager::createRequest(Operation op, const QNetworkRequest & req, QIODevice * outgoingData)
+{
+ QNetworkRequest request = req; // copy so we can modify
+ // this is a temporary hack until we properly use the pipelining flags from QtWebkit
+ // pipeline everything! :)
+ request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+ return QNetworkAccessManager::createRequest(op, request, outgoingData);
+}
+
+void NetworkAccessManager::requestFinished(QNetworkReply *reply)
+{
+ requestFinishedCount++;
+
+ if (reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool() == true)
+ requestFinishedFromCacheCount++;
+
+ if (reply->attribute(QNetworkRequest::HttpPipeliningWasUsedAttribute).toBool() == true)
+ requestFinishedPipelinedCount++;
+
+ if (reply->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool() == true)
+ requestFinishedSecureCount++;
+
+ if (reply->attribute(QNetworkRequest::DownloadBufferAttribute).isValid() == true)
+ requestFinishedDownloadBufferCount++;
+
+ if (requestFinishedCount % 10)
+ return;
+
+ double pctCached = (double(requestFinishedFromCacheCount) * 100.0/ double(requestFinishedCount));
+ double pctPipelined = (double(requestFinishedPipelinedCount) * 100.0/ double(requestFinishedCount));
+ double pctSecure = (double(requestFinishedSecureCount) * 100.0/ double(requestFinishedCount));
+ double pctDownloadBuffer = (double(requestFinishedDownloadBufferCount) * 100.0/ double(requestFinishedCount));
+
+#ifdef QT_DEBUG
+ qDebug("STATS [%lli requests total] [%3.2f%% from cache] [%3.2f%% pipelined] [%3.2f%% SSL/TLS] [%3.2f%% Zerocopy]", requestFinishedCount, pctCached, pctPipelined, pctSecure, pctDownloadBuffer);
+#endif
+}
+
+void NetworkAccessManager::loadSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("proxy"));
+ QNetworkProxy proxy;
+ if (settings.value(QLatin1String("enabled"), false).toBool()) {
+ if (settings.value(QLatin1String("type"), 0).toInt() == 0)
+ proxy = QNetworkProxy::Socks5Proxy;
+ else
+ proxy = QNetworkProxy::HttpProxy;
+ proxy.setHostName(settings.value(QLatin1String("hostName")).toString());
+ proxy.setPort(settings.value(QLatin1String("port"), 1080).toInt());
+ proxy.setUser(settings.value(QLatin1String("userName")).toString());
+ proxy.setPassword(settings.value(QLatin1String("password")).toString());
+ }
+ setProxy(proxy);
+}
+
+void NetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *auth)
+{
+ BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
+
+ QDialog dialog(mainWindow);
+ dialog.setWindowFlags(Qt::Sheet);
+
+ Ui::PasswordDialog passwordDialog;
+ passwordDialog.setupUi(&dialog);
+
+ passwordDialog.iconLabel->setText(QString());
+ passwordDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32));
+
+ QString introMessage = tr("<qt>Enter username and password for \"%1\" at %2</qt>");
+ introMessage = introMessage.arg(reply->url().toString().toHtmlEscaped()).arg(reply->url().toString().toHtmlEscaped());
+ passwordDialog.introLabel->setText(introMessage);
+ passwordDialog.introLabel->setWordWrap(true);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ auth->setUser(passwordDialog.userNameLineEdit->text());
+ auth->setPassword(passwordDialog.passwordLineEdit->text());
+ }
+}
+
+void NetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth)
+{
+ BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
+
+ QDialog dialog(mainWindow);
+ dialog.setWindowFlags(Qt::Sheet);
+
+ Ui::ProxyDialog proxyDialog;
+ proxyDialog.setupUi(&dialog);
+
+ proxyDialog.iconLabel->setText(QString());
+ proxyDialog.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32));
+
+ QString introMessage = tr("<qt>Connect to proxy \"%1\" using:</qt>");
+ introMessage = introMessage.arg(proxy.hostName().toHtmlEscaped());
+ proxyDialog.introLabel->setText(introMessage);
+ proxyDialog.introLabel->setWordWrap(true);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ auth->setUser(proxyDialog.userNameLineEdit->text());
+ auth->setPassword(proxyDialog.passwordLineEdit->text());
+ }
+}
+
+#ifndef QT_NO_OPENSSL
+void NetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &error)
+{
+ // check if SSL certificate has been trusted already
+ QString replyHost = reply->url().host() + QString(":%1").arg(reply->url().port());
+ if(! sslTrustedHostList.contains(replyHost)) {
+ BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
+
+ QStringList errorStrings;
+ for (int i = 0; i < error.count(); ++i)
+ errorStrings += error.at(i).errorString();
+ QString errors = errorStrings.join(QLatin1String("\n"));
+ int ret = QMessageBox::warning(mainWindow, QCoreApplication::applicationName(),
+ tr("SSL Errors:\n\n%1\n\n%2\n\n"
+ "Do you want to ignore these errors for this host?").arg(reply->url().toString()).arg(errors),
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No);
+ if (ret == QMessageBox::Yes) {
+ reply->ignoreSslErrors();
+ sslTrustedHostList.append(replyHost);
+ }
+ }
+}
+#endif
diff --git a/examples/webkitwidgets/browser/networkaccessmanager.h b/examples/webkitwidgets/browser/networkaccessmanager.h
new file mode 100644
index 0000000..9dde549
--- /dev/null
+++ b/examples/webkitwidgets/browser/networkaccessmanager.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NETWORKACCESSMANAGER_H
+#define NETWORKACCESSMANAGER_H
+
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkRequest>
+
+class NetworkAccessManager : public QNetworkAccessManager
+{
+ Q_OBJECT
+
+public:
+ NetworkAccessManager(QObject *parent = 0);
+
+ virtual QNetworkReply* createRequest ( Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0 );
+
+private:
+ QList<QString> sslTrustedHostList;
+ qint64 requestFinishedCount;
+ qint64 requestFinishedFromCacheCount;
+ qint64 requestFinishedPipelinedCount;
+ qint64 requestFinishedSecureCount;
+ qint64 requestFinishedDownloadBufferCount;
+
+public slots:
+ void loadSettings();
+ void requestFinished(QNetworkReply *reply);
+
+private slots:
+ void authenticationRequired(QNetworkReply *reply, QAuthenticator *auth);
+ void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth);
+#ifndef QT_NO_OPENSSL
+ void sslErrors(QNetworkReply *reply, const QList<QSslError> &error);
+#endif
+};
+
+#endif // NETWORKACCESSMANAGER_H
diff --git a/examples/webkitwidgets/browser/passworddialog.ui b/examples/webkitwidgets/browser/passworddialog.ui
new file mode 100644
index 0000000..7c16658
--- /dev/null
+++ b/examples/webkitwidgets/browser/passworddialog.ui
@@ -0,0 +1,111 @@
+<ui version="4.0" >
+ <class>PasswordDialog</class>
+ <widget class="QDialog" name="PasswordDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>399</width>
+ <height>148</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Authentication Required</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="iconLabel" >
+ <property name="text" >
+ <string>DUMMY ICON</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="introLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>INTRO TEXT DUMMY</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Username:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="userNameLineEdit" />
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="lblPassword" >
+ <property name="text" >
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="passwordLineEdit" >
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>PasswordDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>PasswordDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webkitwidgets/browser/proxy.ui b/examples/webkitwidgets/browser/proxy.ui
new file mode 100644
index 0000000..62a8be6
--- /dev/null
+++ b/examples/webkitwidgets/browser/proxy.ui
@@ -0,0 +1,104 @@
+<ui version="4.0" >
+ <class>ProxyDialog</class>
+ <widget class="QDialog" name="ProxyDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>369</width>
+ <height>144</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Proxy Authentication</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="iconLabel" >
+ <property name="text" >
+ <string>ICON</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QLabel" name="introLabel" >
+ <property name="text" >
+ <string>Connect to proxy</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QLabel" name="usernameLabel" >
+ <property name="text" >
+ <string>Username:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QLineEdit" name="userNameLineEdit" />
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <widget class="QLabel" name="passwordLabel" >
+ <property name="text" >
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QLineEdit" name="passwordLineEdit" >
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="3" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProxyDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ProxyDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webkitwidgets/browser/searchlineedit.cpp b/examples/webkitwidgets/browser/searchlineedit.cpp
new file mode 100644
index 0000000..06f14a4
--- /dev/null
+++ b/examples/webkitwidgets/browser/searchlineedit.cpp
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "searchlineedit.h"
+
+#include <QtGui/QPainter>
+#include <QtGui/QMouseEvent>
+#include <QtWidgets/QMenu>
+#include <QtWidgets/QStyle>
+#include <QtWidgets/QStyleOptionFrameV2>
+
+ClearButton::ClearButton(QWidget *parent)
+ : QAbstractButton(parent)
+{
+#ifndef QT_NO_CURSOR
+ setCursor(Qt::ArrowCursor);
+#endif // QT_NO_CURSOR
+ setToolTip(tr("Clear"));
+ setVisible(false);
+ setFocusPolicy(Qt::NoFocus);
+}
+
+void ClearButton::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainter painter(this);
+ int height = this->height();
+
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ QColor color = palette().color(QPalette::Mid);
+ painter.setBrush(isDown()
+ ? palette().color(QPalette::Dark)
+ : palette().color(QPalette::Mid));
+ painter.setPen(painter.brush().color());
+ int size = width();
+ int offset = size / 5;
+ int radius = size - offset * 2;
+ painter.drawEllipse(offset, offset, radius, radius);
+
+ painter.setPen(palette().color(QPalette::Base));
+ int border = offset * 2;
+ painter.drawLine(border, border, width() - border, height - border);
+ painter.drawLine(border, height - border, width() - border, border);
+}
+
+void ClearButton::textChanged(const QString &text)
+{
+ setVisible(!text.isEmpty());
+}
+
+/*
+ Search icon on the left hand side of the search widget
+ When a menu is set a down arrow appears
+ */
+class SearchButton : public QAbstractButton {
+public:
+ SearchButton(QWidget *parent = 0);
+ void paintEvent(QPaintEvent *event);
+ QMenu *m_menu;
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+};
+
+SearchButton::SearchButton(QWidget *parent)
+ : QAbstractButton(parent),
+ m_menu(0)
+{
+ setObjectName(QLatin1String("SearchButton"));
+#ifndef QT_NO_CURSOR
+ setCursor(Qt::ArrowCursor);
+#endif //QT_NO_CURSOR
+ setFocusPolicy(Qt::NoFocus);
+}
+
+void SearchButton::mousePressEvent(QMouseEvent *event)
+{
+ if (m_menu && event->button() == Qt::LeftButton) {
+ QWidget *p = parentWidget();
+ if (p) {
+ QPoint r = p->mapToGlobal(QPoint(0, p->height()));
+ m_menu->exec(QPoint(r.x() + height() / 2, r.y()));
+ }
+ event->accept();
+ }
+ QAbstractButton::mousePressEvent(event);
+}
+
+void SearchButton::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainterPath myPath;
+
+ int radius = (height() / 5) * 2;
+ QRect circle(height() / 3 - 1, height() / 4, radius, radius);
+ myPath.addEllipse(circle);
+
+ myPath.arcMoveTo(circle, 300);
+ QPointF c = myPath.currentPosition();
+ int diff = height() / 7;
+ myPath.lineTo(qMin(width() - 2, (int)c.x() + diff), c.y() + diff);
+
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.setPen(QPen(Qt::darkGray, 2));
+ painter.drawPath(myPath);
+
+ if (m_menu) {
+ QPainterPath dropPath;
+ dropPath.arcMoveTo(circle, 320);
+ QPointF c = dropPath.currentPosition();
+ c = QPointF(c.x() + 3.5, c.y() + 0.5);
+ dropPath.moveTo(c);
+ dropPath.lineTo(c.x() + 4, c.y());
+ dropPath.lineTo(c.x() + 2, c.y() + 2);
+ dropPath.closeSubpath();
+ painter.setPen(Qt::darkGray);
+ painter.setBrush(Qt::darkGray);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ painter.drawPath(dropPath);
+ }
+ painter.end();
+}
+
+/*
+ SearchLineEdit is an enhanced QLineEdit
+ - A Search icon on the left with optional menu
+ - When there is no text and doesn't have focus an "inactive text" is displayed
+ - When there is text a clear button is displayed on the right hand side
+ */
+SearchLineEdit::SearchLineEdit(QWidget *parent) : ExLineEdit(parent),
+ m_searchButton(new SearchButton(this))
+{
+ connect(lineEdit(), SIGNAL(textChanged(QString)),
+ this, SIGNAL(textChanged(QString)));
+ setLeftWidget(m_searchButton);
+ m_inactiveText = tr("Search");
+
+ QSizePolicy policy = sizePolicy();
+ setSizePolicy(QSizePolicy::Preferred, policy.verticalPolicy());
+}
+
+void SearchLineEdit::paintEvent(QPaintEvent *event)
+{
+ if (lineEdit()->text().isEmpty() && !hasFocus() && !m_inactiveText.isEmpty()) {
+ ExLineEdit::paintEvent(event);
+ QStyleOptionFrameV2 panel;
+ initStyleOption(&panel);
+ QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
+ QFontMetrics fm = fontMetrics();
+ int horizontalMargin = lineEdit()->x();
+ QRect lineRect(horizontalMargin + r.x(), r.y() + (r.height() - fm.height() + 1) / 2,
+ r.width() - 2 * horizontalMargin, fm.height());
+ QPainter painter(this);
+ painter.setPen(palette().brush(QPalette::Disabled, QPalette::Text).color());
+ painter.drawText(lineRect, Qt::AlignLeft|Qt::AlignVCenter, m_inactiveText);
+ } else {
+ ExLineEdit::paintEvent(event);
+ }
+}
+
+void SearchLineEdit::resizeEvent(QResizeEvent *event)
+{
+ updateGeometries();
+ ExLineEdit::resizeEvent(event);
+}
+
+void SearchLineEdit::updateGeometries()
+{
+ int menuHeight = height();
+ int menuWidth = menuHeight + 1;
+ if (!m_searchButton->m_menu)
+ menuWidth = (menuHeight / 5) * 4;
+ m_searchButton->resize(QSize(menuWidth, menuHeight));
+}
+
+QString SearchLineEdit::inactiveText() const
+{
+ return m_inactiveText;
+}
+
+void SearchLineEdit::setInactiveText(const QString &text)
+{
+ m_inactiveText = text;
+}
+
+void SearchLineEdit::setMenu(QMenu *menu)
+{
+ if (m_searchButton->m_menu)
+ m_searchButton->m_menu->deleteLater();
+ m_searchButton->m_menu = menu;
+ updateGeometries();
+}
+
+QMenu *SearchLineEdit::menu() const
+{
+ if (!m_searchButton->m_menu) {
+ m_searchButton->m_menu = new QMenu(m_searchButton);
+ if (isVisible())
+ (const_cast<SearchLineEdit*>(this))->updateGeometries();
+ }
+ return m_searchButton->m_menu;
+}
+
diff --git a/examples/webkitwidgets/browser/searchlineedit.h b/examples/webkitwidgets/browser/searchlineedit.h
new file mode 100644
index 0000000..5e50bb1
--- /dev/null
+++ b/examples/webkitwidgets/browser/searchlineedit.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SEARCHLINEEDIT_H
+#define SEARCHLINEEDIT_H
+
+#include "urllineedit.h"
+
+#include <QtWidgets/QLineEdit>
+#include <QtWidgets/QAbstractButton>
+
+QT_BEGIN_NAMESPACE
+class QMenu;
+QT_END_NAMESPACE
+
+class SearchButton;
+
+/*
+ Clear button on the right hand side of the search widget.
+ Hidden by default
+ "A circle with an X in it"
+ */
+class ClearButton : public QAbstractButton
+{
+ Q_OBJECT
+
+public:
+ ClearButton(QWidget *parent = 0);
+ void paintEvent(QPaintEvent *event);
+
+public slots:
+ void textChanged(const QString &text);
+};
+
+
+class SearchLineEdit : public ExLineEdit
+{
+ Q_OBJECT
+ Q_PROPERTY(QString inactiveText READ inactiveText WRITE setInactiveText)
+
+signals:
+ void textChanged(const QString &text);
+
+public:
+ SearchLineEdit(QWidget *parent = 0);
+
+ QString inactiveText() const;
+ void setInactiveText(const QString &text);
+
+ QMenu *menu() const;
+ void setMenu(QMenu *menu);
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+ void paintEvent(QPaintEvent *event);
+
+private:
+ void updateGeometries();
+
+ SearchButton *m_searchButton;
+ QString m_inactiveText;
+};
+
+#endif // SEARCHLINEEDIT_H
+
diff --git a/examples/webkitwidgets/browser/settings.cpp b/examples/webkitwidgets/browser/settings.cpp
new file mode 100644
index 0000000..501c890
--- /dev/null
+++ b/examples/webkitwidgets/browser/settings.cpp
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "settings.h"
+
+#include "browserapplication.h"
+#include "browsermainwindow.h"
+#include "cookiejar.h"
+#include "history.h"
+#include "networkaccessmanager.h"
+#include "webview.h"
+
+#include <QtCore/QSettings>
+#include <QtWidgets/QtWidgets>
+#include <QtWebKitWidgets>
+
+SettingsDialog::SettingsDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ setupUi(this);
+ connect(exceptionsButton, SIGNAL(clicked()), this, SLOT(showExceptions()));
+ connect(setHomeToCurrentPageButton, SIGNAL(clicked()), this, SLOT(setHomeToCurrentPage()));
+ connect(cookiesButton, SIGNAL(clicked()), this, SLOT(showCookies()));
+ connect(standardFontButton, SIGNAL(clicked()), this, SLOT(chooseFont()));
+ connect(fixedFontButton, SIGNAL(clicked()), this, SLOT(chooseFixedFont()));
+
+ loadDefaults();
+ loadFromSettings();
+}
+
+void SettingsDialog::loadDefaults()
+{
+ QWebSettings *defaultSettings = QWebSettings::globalSettings();
+ QString standardFontFamily = defaultSettings->fontFamily(QWebSettings::StandardFont);
+ int standardFontSize = defaultSettings->fontSize(QWebSettings::DefaultFontSize);
+ standardFont = QFont(standardFontFamily, standardFontSize);
+ standardLabel->setText(QString(QLatin1String("%1 %2")).arg(standardFont.family()).arg(standardFont.pointSize()));
+
+ QString fixedFontFamily = defaultSettings->fontFamily(QWebSettings::FixedFont);
+ int fixedFontSize = defaultSettings->fontSize(QWebSettings::DefaultFixedFontSize);
+ fixedFont = QFont(fixedFontFamily, fixedFontSize);
+ fixedLabel->setText(QString(QLatin1String("%1 %2")).arg(fixedFont.family()).arg(fixedFont.pointSize()));
+
+ downloadsLocation->setText(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
+
+ enableJavascript->setChecked(defaultSettings->testAttribute(QWebSettings::JavascriptEnabled));
+ enablePlugins->setChecked(defaultSettings->testAttribute(QWebSettings::PluginsEnabled));
+}
+
+void SettingsDialog::loadFromSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("MainWindow"));
+ QString defaultHome = QLatin1String("http://qt-project.org/");
+ homeLineEdit->setText(settings.value(QLatin1String("home"), defaultHome).toString());
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("history"));
+ int historyExpire = settings.value(QLatin1String("historyExpire")).toInt();
+ int idx = 0;
+ switch (historyExpire) {
+ case 1: idx = 0; break;
+ case 7: idx = 1; break;
+ case 14: idx = 2; break;
+ case 30: idx = 3; break;
+ case 365: idx = 4; break;
+ case -1: idx = 5; break;
+ default:
+ idx = 5;
+ }
+ expireHistory->setCurrentIndex(idx);
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("downloadmanager"));
+ QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), downloadsLocation->text()).toString();
+ downloadsLocation->setText(downloadDirectory);
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("general"));
+ openLinksIn->setCurrentIndex(settings.value(QLatin1String("openLinksIn"), openLinksIn->currentIndex()).toInt());
+
+ settings.endGroup();
+
+ // Appearance
+ settings.beginGroup(QLatin1String("websettings"));
+ fixedFont = qvariant_cast<QFont>(settings.value(QLatin1String("fixedFont"), fixedFont));
+ standardFont = qvariant_cast<QFont>(settings.value(QLatin1String("standardFont"), standardFont));
+
+ standardLabel->setText(QString(QLatin1String("%1 %2")).arg(standardFont.family()).arg(standardFont.pointSize()));
+ fixedLabel->setText(QString(QLatin1String("%1 %2")).arg(fixedFont.family()).arg(fixedFont.pointSize()));
+
+ enableJavascript->setChecked(settings.value(QLatin1String("enableJavascript"), enableJavascript->isChecked()).toBool());
+ enablePlugins->setChecked(settings.value(QLatin1String("enablePlugins"), enablePlugins->isChecked()).toBool());
+ userStyleSheet->setText(settings.value(QLatin1String("userStyleSheet")).toUrl().toString());
+ settings.endGroup();
+
+ // Privacy
+ settings.beginGroup(QLatin1String("cookies"));
+
+ CookieJar *jar = BrowserApplication::cookieJar();
+ QByteArray value = settings.value(QLatin1String("acceptCookies"), QLatin1String("AcceptOnlyFromSitesNavigatedTo")).toByteArray();
+ QMetaEnum acceptPolicyEnum = jar->staticMetaObject.enumerator(jar->staticMetaObject.indexOfEnumerator("AcceptPolicy"));
+ CookieJar::AcceptPolicy acceptCookies = acceptPolicyEnum.keyToValue(value) == -1 ?
+ CookieJar::AcceptOnlyFromSitesNavigatedTo :
+ static_cast<CookieJar::AcceptPolicy>(acceptPolicyEnum.keyToValue(value));
+ switch(acceptCookies) {
+ case CookieJar::AcceptAlways:
+ acceptCombo->setCurrentIndex(0);
+ break;
+ case CookieJar::AcceptNever:
+ acceptCombo->setCurrentIndex(1);
+ break;
+ case CookieJar::AcceptOnlyFromSitesNavigatedTo:
+ acceptCombo->setCurrentIndex(2);
+ break;
+ }
+
+ value = settings.value(QLatin1String("keepCookiesUntil"), QLatin1String("Expire")).toByteArray();
+ QMetaEnum keepPolicyEnum = jar->staticMetaObject.enumerator(jar->staticMetaObject.indexOfEnumerator("KeepPolicy"));
+ CookieJar::KeepPolicy keepCookies = keepPolicyEnum.keyToValue(value) == -1 ?
+ CookieJar::KeepUntilExpire :
+ static_cast<CookieJar::KeepPolicy>(keepPolicyEnum.keyToValue(value));
+ switch(keepCookies) {
+ case CookieJar::KeepUntilExpire:
+ keepUntilCombo->setCurrentIndex(0);
+ break;
+ case CookieJar::KeepUntilExit:
+ keepUntilCombo->setCurrentIndex(1);
+ break;
+ case CookieJar::KeepUntilTimeLimit:
+ keepUntilCombo->setCurrentIndex(2);
+ break;
+ }
+ settings.endGroup();
+
+
+ // Proxy
+ settings.beginGroup(QLatin1String("proxy"));
+ proxySupport->setChecked(settings.value(QLatin1String("enabled"), false).toBool());
+ proxyType->setCurrentIndex(settings.value(QLatin1String("type"), 0).toInt());
+ proxyHostName->setText(settings.value(QLatin1String("hostName")).toString());
+ proxyPort->setValue(settings.value(QLatin1String("port"), 1080).toInt());
+ proxyUserName->setText(settings.value(QLatin1String("userName")).toString());
+ proxyPassword->setText(settings.value(QLatin1String("password")).toString());
+ settings.endGroup();
+}
+
+void SettingsDialog::saveToSettings()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("MainWindow"));
+ settings.setValue(QLatin1String("home"), homeLineEdit->text());
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("general"));
+ settings.setValue(QLatin1String("openLinksIn"), openLinksIn->currentIndex());
+ settings.endGroup();
+
+ settings.beginGroup(QLatin1String("history"));
+ int historyExpire = expireHistory->currentIndex();
+ int idx = -1;
+ switch (historyExpire) {
+ case 0: idx = 1; break;
+ case 1: idx = 7; break;
+ case 2: idx = 14; break;
+ case 3: idx = 30; break;
+ case 4: idx = 365; break;
+ case 5: idx = -1; break;
+ }
+ settings.setValue(QLatin1String("historyExpire"), idx);
+ settings.endGroup();
+
+ // Appearance
+ settings.beginGroup(QLatin1String("websettings"));
+ settings.setValue(QLatin1String("fixedFont"), fixedFont);
+ settings.setValue(QLatin1String("standardFont"), standardFont);
+ settings.setValue(QLatin1String("enableJavascript"), enableJavascript->isChecked());
+ settings.setValue(QLatin1String("enablePlugins"), enablePlugins->isChecked());
+ QString userStyleSheetString = userStyleSheet->text();
+ if (QFile::exists(userStyleSheetString))
+ settings.setValue(QLatin1String("userStyleSheet"), QUrl::fromLocalFile(userStyleSheetString));
+ else
+ settings.setValue(QLatin1String("userStyleSheet"), QUrl(userStyleSheetString));
+ settings.endGroup();
+
+ //Privacy
+ settings.beginGroup(QLatin1String("cookies"));
+
+ CookieJar::KeepPolicy keepCookies;
+ switch(acceptCombo->currentIndex()) {
+ default:
+ case 0:
+ keepCookies = CookieJar::KeepUntilExpire;
+ break;
+ case 1:
+ keepCookies = CookieJar::KeepUntilExit;
+ break;
+ case 2:
+ keepCookies = CookieJar::KeepUntilTimeLimit;
+ break;
+ }
+ CookieJar *jar = BrowserApplication::cookieJar();
+ QMetaEnum acceptPolicyEnum = jar->staticMetaObject.enumerator(jar->staticMetaObject.indexOfEnumerator("AcceptPolicy"));
+ settings.setValue(QLatin1String("acceptCookies"), QLatin1String(acceptPolicyEnum.valueToKey(keepCookies)));
+
+ CookieJar::KeepPolicy keepPolicy;
+ switch(keepUntilCombo->currentIndex()) {
+ default:
+ case 0:
+ keepPolicy = CookieJar::KeepUntilExpire;
+ break;
+ case 1:
+ keepPolicy = CookieJar::KeepUntilExit;
+ break;
+ case 2:
+ keepPolicy = CookieJar::KeepUntilTimeLimit;
+ break;
+ }
+
+ QMetaEnum keepPolicyEnum = jar->staticMetaObject.enumerator(jar->staticMetaObject.indexOfEnumerator("KeepPolicy"));
+ settings.setValue(QLatin1String("keepCookiesUntil"), QLatin1String(keepPolicyEnum.valueToKey(keepPolicy)));
+
+ settings.endGroup();
+
+ // proxy
+ settings.beginGroup(QLatin1String("proxy"));
+ settings.setValue(QLatin1String("enabled"), proxySupport->isChecked());
+ settings.setValue(QLatin1String("type"), proxyType->currentIndex());
+ settings.setValue(QLatin1String("hostName"), proxyHostName->text());
+ settings.setValue(QLatin1String("port"), proxyPort->text());
+ settings.setValue(QLatin1String("userName"), proxyUserName->text());
+ settings.setValue(QLatin1String("password"), proxyPassword->text());
+ settings.endGroup();
+
+ BrowserApplication::instance()->loadSettings();
+ BrowserApplication::networkAccessManager()->loadSettings();
+ BrowserApplication::cookieJar()->loadSettings();
+ BrowserApplication::historyManager()->loadSettings();
+}
+
+void SettingsDialog::accept()
+{
+ saveToSettings();
+ QDialog::accept();
+}
+
+void SettingsDialog::showCookies()
+{
+ CookiesDialog *dialog = new CookiesDialog(BrowserApplication::cookieJar(), this);
+ dialog->exec();
+}
+
+void SettingsDialog::showExceptions()
+{
+ CookiesExceptionsDialog *dialog = new CookiesExceptionsDialog(BrowserApplication::cookieJar(), this);
+ dialog->exec();
+}
+
+void SettingsDialog::chooseFont()
+{
+ bool ok;
+ QFont font = QFontDialog::getFont(&ok, standardFont, this);
+ if ( ok ) {
+ standardFont = font;
+ standardLabel->setText(QString(QLatin1String("%1 %2")).arg(font.family()).arg(font.pointSize()));
+ }
+}
+
+void SettingsDialog::chooseFixedFont()
+{
+ bool ok;
+ QFont font = QFontDialog::getFont(&ok, fixedFont, this);
+ if ( ok ) {
+ fixedFont = font;
+ fixedLabel->setText(QString(QLatin1String("%1 %2")).arg(font.family()).arg(font.pointSize()));
+ }
+}
+
+void SettingsDialog::setHomeToCurrentPage()
+{
+ BrowserMainWindow *mw = static_cast<BrowserMainWindow*>(parent());
+ WebView *webView = mw->currentTab();
+ if (webView)
+ homeLineEdit->setText(webView->url().toString());
+}
+
diff --git a/examples/webkitwidgets/browser/settings.h b/examples/webkitwidgets/browser/settings.h
new file mode 100644
index 0000000..93719fe
--- /dev/null
+++ b/examples/webkitwidgets/browser/settings.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include <QtWidgets/QDialog>
+#include "ui_settings.h"
+
+class SettingsDialog : public QDialog, public Ui_Settings
+{
+ Q_OBJECT
+
+public:
+ SettingsDialog(QWidget *parent = 0);
+ void accept();
+
+private slots:
+ void loadDefaults();
+ void loadFromSettings();
+ void saveToSettings();
+
+ void setHomeToCurrentPage();
+ void showCookies();
+ void showExceptions();
+
+ void chooseFont();
+ void chooseFixedFont();
+
+private:
+ QFont standardFont;
+ QFont fixedFont;
+};
+
+#endif // SETTINGS_H
+
diff --git a/examples/webkitwidgets/browser/settings.ui b/examples/webkitwidgets/browser/settings.ui
new file mode 100644
index 0000000..3491ce0
--- /dev/null
+++ b/examples/webkitwidgets/browser/settings.ui
@@ -0,0 +1,614 @@
+<ui version="4.0" >
+ <class>Settings</class>
+ <widget class="QDialog" name="Settings" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>657</width>
+ <height>322</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Settings</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="2" column="0" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QTabWidget" name="tabWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>General</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_4" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Home:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QLineEdit" name="homeLineEdit" />
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="setHomeToCurrentPageButton" >
+ <property name="text" >
+ <string>Set to current page</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <spacer name="horizontalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>280</width>
+ <height>18</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_4" >
+ <property name="text" >
+ <string>Remove history items:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" colspan="2" >
+ <widget class="QComboBox" name="expireHistory" >
+ <item>
+ <property name="text" >
+ <string>After one day</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>After one week</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>After two weeks</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>After one month</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>After one year</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Manually</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_7" >
+ <property name="text" >
+ <string>Save downloads to:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2" >
+ <widget class="QLineEdit" name="downloadsLocation" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_8" >
+ <property name="text" >
+ <string>Open links from applications:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" colspan="2" >
+ <widget class="QComboBox" name="openLinksIn" >
+ <item>
+ <property name="text" >
+ <string>In a tab in the current window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>In a new window</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>391</width>
+ <height>262</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_3" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Appearance</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_3" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>Standard font:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="standardLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="text" >
+ <string>Times 16</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QPushButton" name="standardFontButton" >
+ <property name="text" >
+ <string>Select...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_6" >
+ <property name="text" >
+ <string>Fixed-width font:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="fixedLabel" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="text" >
+ <string>Courier 13</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="fixedFontButton" >
+ <property name="text" >
+ <string>Select...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>93</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_2" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Privacy</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3" >
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Web Content</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <widget class="QCheckBox" name="enablePlugins" >
+ <property name="text" >
+ <string>Enable Plugins</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="enableJavascript" >
+ <property name="text" >
+ <string>Enable Javascript</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="cookiesGroupBox" >
+ <property name="title" >
+ <string>Cookies</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Accept Cookies:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="acceptCombo" >
+ <item>
+ <property name="text" >
+ <string>Always</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Never</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Only from sites you navigate to</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QPushButton" name="exceptionsButton" >
+ <property name="text" >
+ <string>Exceptions...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Keep until:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="keepUntilCombo" >
+ <item>
+ <property name="text" >
+ <string>They expire</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>I exit the application</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>At most 90 days</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="cookiesButton" >
+ <property name="text" >
+ <string>Cookies...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>371</width>
+ <height>177</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_4" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>627</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Proxy</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QGroupBox" name="proxySupport" >
+ <property name="title" >
+ <string>Enable proxy</string>
+ </property>
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_6" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_9" >
+ <property name="text" >
+ <string>Type:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <widget class="QComboBox" name="proxyType" >
+ <item>
+ <property name="text" >
+ <string>Socks5</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Http</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_10" >
+ <property name="text" >
+ <string>Host:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2" >
+ <widget class="QLineEdit" name="proxyHostName" />
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_11" >
+ <property name="text" >
+ <string>Port:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QSpinBox" name="proxyPort" >
+ <property name="maximum" >
+ <number>10000</number>
+ </property>
+ <property name="value" >
+ <number>1080</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <spacer name="horizontalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>293</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_12" >
+ <property name="text" >
+ <string>User Name:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2" >
+ <widget class="QLineEdit" name="proxyUserName" />
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="label_13" >
+ <property name="text" >
+ <string>Password:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" colspan="2" >
+ <widget class="QLineEdit" name="proxyPassword" >
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <spacer name="verticalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>8</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_5" >
+ <attribute name="title" >
+ <string>Advanced</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_2" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_14" >
+ <property name="text" >
+ <string>Style Sheet:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="userStyleSheet" />
+ </item>
+ <item row="1" column="1" >
+ <spacer name="verticalSpacer_3" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>176</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Settings</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Settings</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webkitwidgets/browser/squeezelabel.cpp b/examples/webkitwidgets/browser/squeezelabel.cpp
new file mode 100644
index 0000000..ff133eb
--- /dev/null
+++ b/examples/webkitwidgets/browser/squeezelabel.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "squeezelabel.h"
+
+SqueezeLabel::SqueezeLabel(QWidget *parent) : QLabel(parent)
+{
+}
+
+void SqueezeLabel::paintEvent(QPaintEvent *event)
+{
+ QFontMetrics fm = fontMetrics();
+ if (fm.width(text()) > contentsRect().width()) {
+ QString elided = fm.elidedText(text(), Qt::ElideMiddle, width());
+ QString oldText = text();
+ setText(elided);
+ QLabel::paintEvent(event);
+ setText(oldText);
+ } else {
+ QLabel::paintEvent(event);
+ }
+}
+
diff --git a/examples/webkitwidgets/browser/squeezelabel.h b/examples/webkitwidgets/browser/squeezelabel.h
new file mode 100644
index 0000000..f3407c2
--- /dev/null
+++ b/examples/webkitwidgets/browser/squeezelabel.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SQUEEZELABEL_H
+#define SQUEEZELABEL_H
+
+#include <QtWidgets/QLabel>
+
+class SqueezeLabel : public QLabel
+{
+ Q_OBJECT
+
+public:
+ SqueezeLabel(QWidget *parent = 0);
+
+protected:
+ void paintEvent(QPaintEvent *event);
+
+};
+
+#endif // SQUEEZELABEL_H
+
diff --git a/examples/webkitwidgets/browser/tabwidget.cpp b/examples/webkitwidgets/browser/tabwidget.cpp
new file mode 100644
index 0000000..b706959
--- /dev/null
+++ b/examples/webkitwidgets/browser/tabwidget.cpp
@@ -0,0 +1,835 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "tabwidget.h"
+
+#include "browserapplication.h"
+#include "browsermainwindow.h"
+#include "history.h"
+#include "urllineedit.h"
+#include "webview.h"
+
+#include <QtCore/QMimeData>
+#include <QtGui/QClipboard>
+#include <QtWidgets/QCompleter>
+#include <QtWidgets/QListView>
+#include <QtWidgets/QMenu>
+#include <QtWidgets/QMessageBox>
+#include <QtGui/QDrag>
+#include <QtGui/QMouseEvent>
+#include <QtWidgets/QStackedWidget>
+#include <QtWidgets/QStyle>
+#include <QtWidgets/QToolButton>
+
+#include <QtCore/QDebug>
+
+TabBar::TabBar(QWidget *parent)
+ : QTabBar(parent)
+{
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ setAcceptDrops(true);
+ connect(this, SIGNAL(customContextMenuRequested(QPoint)),
+ this, SLOT(contextMenuRequested(QPoint)));
+
+ QString ctrl = QLatin1String("Ctrl+%1");
+ for (int i = 1; i <= 10; ++i) {
+ int key = i;
+ if (key == 10)
+ key = 0;
+ QShortcut *shortCut = new QShortcut(ctrl.arg(key), this);
+ m_tabShortcuts.append(shortCut);
+ connect(shortCut, SIGNAL(activated()), this, SLOT(selectTabAction()));
+ }
+ setTabsClosable(true);
+ connect(this, SIGNAL(tabCloseRequested(int)),
+ this, SIGNAL(closeTab(int)));
+ setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab);
+ setMovable(true);
+}
+
+void TabBar::selectTabAction()
+{
+ if (QShortcut *shortCut = qobject_cast<QShortcut*>(sender())) {
+ int index = m_tabShortcuts.indexOf(shortCut);
+ if (index == 0)
+ index = 10;
+ setCurrentIndex(index);
+ }
+}
+
+void TabBar::contextMenuRequested(const QPoint &position)
+{
+ QMenu menu;
+ menu.addAction(tr("New &Tab"), this, SIGNAL(newTab()), QKeySequence::AddTab);
+ int index = tabAt(position);
+ if (-1 != index) {
+ QAction *action = menu.addAction(tr("Clone Tab"),
+ this, SLOT(cloneTab()));
+ action->setData(index);
+
+ menu.addSeparator();
+
+ action = menu.addAction(tr("&Close Tab"),
+ this, SLOT(closeTab()), QKeySequence::Close);
+ action->setData(index);
+
+ action = menu.addAction(tr("Close &Other Tabs"),
+ this, SLOT(closeOtherTabs()));
+ action->setData(index);
+
+ menu.addSeparator();
+
+ action = menu.addAction(tr("Reload Tab"),
+ this, SLOT(reloadTab()), QKeySequence::Refresh);
+ action->setData(index);
+ } else {
+ menu.addSeparator();
+ }
+ menu.addAction(tr("Reload All Tabs"), this, SIGNAL(reloadAllTabs()));
+ menu.exec(QCursor::pos());
+}
+
+void TabBar::cloneTab()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ int index = action->data().toInt();
+ emit cloneTab(index);
+ }
+}
+
+void TabBar::closeTab()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ int index = action->data().toInt();
+ emit closeTab(index);
+ }
+}
+
+void TabBar::closeOtherTabs()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ int index = action->data().toInt();
+ emit closeOtherTabs(index);
+ }
+}
+
+void TabBar::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ m_dragStartPos = event->pos();
+ QTabBar::mousePressEvent(event);
+}
+
+void TabBar::mouseMoveEvent(QMouseEvent *event)
+{
+ if (event->buttons() == Qt::LeftButton) {
+ int diffX = event->pos().x() - m_dragStartPos.x();
+ int diffY = event->pos().y() - m_dragStartPos.y();
+ if ((event->pos() - m_dragStartPos).manhattanLength() > QApplication::startDragDistance()
+ && diffX < 3 && diffX > -3
+ && diffY < -10) {
+ QDrag *drag = new QDrag(this);
+ QMimeData *mimeData = new QMimeData;
+ QList<QUrl> urls;
+ int index = tabAt(event->pos());
+ QUrl url = tabData(index).toUrl();
+ urls.append(url);
+ mimeData->setUrls(urls);
+ mimeData->setText(tabText(index));
+ mimeData->setData(QLatin1String("action"), "tab-reordering");
+ drag->setMimeData(mimeData);
+ drag->exec();
+ }
+ }
+ QTabBar::mouseMoveEvent(event);
+}
+
+// When index is -1 index chooses the current tab
+void TabWidget::reloadTab(int index)
+{
+ if (index < 0)
+ index = currentIndex();
+ if (index < 0 || index >= count())
+ return;
+
+ QWidget *widget = this->widget(index);
+ if (WebView *tab = qobject_cast<WebView*>(widget))
+ tab->reload();
+}
+
+void TabBar::reloadTab()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ int index = action->data().toInt();
+ emit reloadTab(index);
+ }
+}
+
+TabWidget::TabWidget(QWidget *parent)
+ : QTabWidget(parent)
+ , m_recentlyClosedTabsAction(0)
+ , m_newTabAction(0)
+ , m_closeTabAction(0)
+ , m_nextTabAction(0)
+ , m_previousTabAction(0)
+ , m_recentlyClosedTabsMenu(0)
+ , m_lineEditCompleter(0)
+ , m_lineEdits(0)
+ , m_tabBar(new TabBar(this))
+{
+ setElideMode(Qt::ElideRight);
+
+ connect(m_tabBar, SIGNAL(newTab()), this, SLOT(newTab()));
+ connect(m_tabBar, SIGNAL(closeTab(int)), this, SLOT(closeTab(int)));
+ connect(m_tabBar, SIGNAL(cloneTab(int)), this, SLOT(cloneTab(int)));
+ connect(m_tabBar, SIGNAL(closeOtherTabs(int)), this, SLOT(closeOtherTabs(int)));
+ connect(m_tabBar, SIGNAL(reloadTab(int)), this, SLOT(reloadTab(int)));
+ connect(m_tabBar, SIGNAL(reloadAllTabs()), this, SLOT(reloadAllTabs()));
+ connect(m_tabBar, SIGNAL(tabMoved(int,int)), this, SLOT(moveTab(int,int)));
+ setTabBar(m_tabBar);
+ setDocumentMode(true);
+
+ // Actions
+ m_newTabAction = new QAction(QIcon(QLatin1String(":addtab.png")), tr("New &Tab"), this);
+ m_newTabAction->setShortcuts(QKeySequence::AddTab);
+ m_newTabAction->setIconVisibleInMenu(false);
+ connect(m_newTabAction, SIGNAL(triggered()), this, SLOT(newTab()));
+
+ m_closeTabAction = new QAction(QIcon(QLatin1String(":closetab.png")), tr("&Close Tab"), this);
+ m_closeTabAction->setShortcuts(QKeySequence::Close);
+ m_closeTabAction->setIconVisibleInMenu(false);
+ connect(m_closeTabAction, SIGNAL(triggered()), this, SLOT(closeTab()));
+
+ m_nextTabAction = new QAction(tr("Show Next Tab"), this);
+ QList<QKeySequence> shortcuts;
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceRight));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageDown));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketRight));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Less));
+ m_nextTabAction->setShortcuts(shortcuts);
+ connect(m_nextTabAction, SIGNAL(triggered()), this, SLOT(nextTab()));
+
+ m_previousTabAction = new QAction(tr("Show Previous Tab"), this);
+ shortcuts.clear();
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceLeft));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageUp));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketLeft));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Greater));
+ m_previousTabAction->setShortcuts(shortcuts);
+ connect(m_previousTabAction, SIGNAL(triggered()), this, SLOT(previousTab()));
+
+ m_recentlyClosedTabsMenu = new QMenu(this);
+ connect(m_recentlyClosedTabsMenu, SIGNAL(aboutToShow()),
+ this, SLOT(aboutToShowRecentTabsMenu()));
+ connect(m_recentlyClosedTabsMenu, SIGNAL(triggered(QAction*)),
+ this, SLOT(aboutToShowRecentTriggeredAction(QAction*)));
+ m_recentlyClosedTabsAction = new QAction(tr("Recently Closed Tabs"), this);
+ m_recentlyClosedTabsAction->setMenu(m_recentlyClosedTabsMenu);
+ m_recentlyClosedTabsAction->setEnabled(false);
+
+ connect(this, SIGNAL(currentChanged(int)),
+ this, SLOT(currentChanged(int)));
+
+ m_lineEdits = new QStackedWidget(this);
+}
+
+void TabWidget::clear()
+{
+ // clear the recently closed tabs
+ m_recentlyClosedTabs.clear();
+ // clear the line edit history
+ for (int i = 0; i < m_lineEdits->count(); ++i) {
+ QLineEdit *qLineEdit = lineEdit(i);
+ qLineEdit->setText(qLineEdit->text());
+ }
+}
+
+void TabWidget::moveTab(int fromIndex, int toIndex)
+{
+ QWidget *lineEdit = m_lineEdits->widget(fromIndex);
+ m_lineEdits->removeWidget(lineEdit);
+ m_lineEdits->insertWidget(toIndex, lineEdit);
+}
+
+void TabWidget::addWebAction(QAction *action, QWebPage::WebAction webAction)
+{
+ if (!action)
+ return;
+ m_actions.append(new WebActionMapper(action, webAction, this));
+}
+
+void TabWidget::currentChanged(int index)
+{
+ WebView *webView = this->webView(index);
+ if (!webView)
+ return;
+
+ Q_ASSERT(m_lineEdits->count() == count());
+
+ WebView *oldWebView = this->webView(m_lineEdits->currentIndex());
+ if (oldWebView) {
+ disconnect(oldWebView, SIGNAL(statusBarMessage(QString)),
+ this, SIGNAL(showStatusBarMessage(QString)));
+ disconnect(oldWebView->page(), SIGNAL(linkHovered(QString,QString,QString)),
+ this, SIGNAL(linkHovered(QString)));
+ disconnect(oldWebView, SIGNAL(loadProgress(int)),
+ this, SIGNAL(loadProgress(int)));
+ }
+
+ connect(webView, SIGNAL(statusBarMessage(QString)),
+ this, SIGNAL(showStatusBarMessage(QString)));
+ connect(webView->page(), SIGNAL(linkHovered(QString,QString,QString)),
+ this, SIGNAL(linkHovered(QString)));
+ connect(webView, SIGNAL(loadProgress(int)),
+ this, SIGNAL(loadProgress(int)));
+
+ for (int i = 0; i < m_actions.count(); ++i) {
+ WebActionMapper *mapper = m_actions[i];
+ mapper->updateCurrent(webView->page());
+ }
+ emit setCurrentTitle(webView->title());
+ m_lineEdits->setCurrentIndex(index);
+ emit loadProgress(webView->progress());
+ emit showStatusBarMessage(webView->lastStatusBarText());
+ if (webView->url().isEmpty())
+ m_lineEdits->currentWidget()->setFocus();
+ else
+ webView->setFocus();
+}
+
+QAction *TabWidget::newTabAction() const
+{
+ return m_newTabAction;
+}
+
+QAction *TabWidget::closeTabAction() const
+{
+ return m_closeTabAction;
+}
+
+QAction *TabWidget::recentlyClosedTabsAction() const
+{
+ return m_recentlyClosedTabsAction;
+}
+
+QAction *TabWidget::nextTabAction() const
+{
+ return m_nextTabAction;
+}
+
+QAction *TabWidget::previousTabAction() const
+{
+ return m_previousTabAction;
+}
+
+QWidget *TabWidget::lineEditStack() const
+{
+ return m_lineEdits;
+}
+
+QLineEdit *TabWidget::currentLineEdit() const
+{
+ return lineEdit(m_lineEdits->currentIndex());
+}
+
+WebView *TabWidget::currentWebView() const
+{
+ return webView(currentIndex());
+}
+
+QLineEdit *TabWidget::lineEdit(int index) const
+{
+ UrlLineEdit *urlLineEdit = qobject_cast<UrlLineEdit*>(m_lineEdits->widget(index));
+ if (urlLineEdit)
+ return urlLineEdit->lineEdit();
+ return 0;
+}
+
+WebView *TabWidget::webView(int index) const
+{
+ QWidget *widget = this->widget(index);
+ if (WebView *webView = qobject_cast<WebView*>(widget)) {
+ return webView;
+ } else {
+ // optimization to delay creating the first webview
+ if (count() == 1) {
+ TabWidget *that = const_cast<TabWidget*>(this);
+ that->setUpdatesEnabled(false);
+ that->newTab();
+ that->closeTab(0);
+ that->setUpdatesEnabled(true);
+ return currentWebView();
+ }
+ }
+ return 0;
+}
+
+int TabWidget::webViewIndex(WebView *webView) const
+{
+ int index = indexOf(webView);
+ return index;
+}
+
+WebView *TabWidget::newTab(bool makeCurrent)
+{
+ // line edit
+ UrlLineEdit *urlLineEdit = new UrlLineEdit;
+ QLineEdit *lineEdit = urlLineEdit->lineEdit();
+ if (!m_lineEditCompleter && count() > 0) {
+ HistoryCompletionModel *completionModel = new HistoryCompletionModel(this);
+ completionModel->setSourceModel(BrowserApplication::historyManager()->historyFilterModel());
+ m_lineEditCompleter = new QCompleter(completionModel, this);
+ // Should this be in Qt by default?
+ QAbstractItemView *popup = m_lineEditCompleter->popup();
+ QListView *listView = qobject_cast<QListView*>(popup);
+ if (listView)
+ listView->setUniformItemSizes(true);
+ }
+ lineEdit->setCompleter(m_lineEditCompleter);
+ connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(lineEditReturnPressed()));
+ m_lineEdits->addWidget(urlLineEdit);
+ m_lineEdits->setSizePolicy(lineEdit->sizePolicy());
+
+ // optimization to delay creating the more expensive WebView, history, etc
+ if (count() == 0) {
+ QWidget *emptyWidget = new QWidget;
+ QPalette p = emptyWidget->palette();
+ p.setColor(QPalette::Window, palette().color(QPalette::Base));
+ emptyWidget->setPalette(p);
+ emptyWidget->setAutoFillBackground(true);
+ disconnect(this, SIGNAL(currentChanged(int)),
+ this, SLOT(currentChanged(int)));
+ addTab(emptyWidget, tr("(Untitled)"));
+ connect(this, SIGNAL(currentChanged(int)),
+ this, SLOT(currentChanged(int)));
+ return 0;
+ }
+
+ // webview
+ WebView *webView = new WebView;
+ urlLineEdit->setWebView(webView);
+ connect(webView, SIGNAL(loadStarted()),
+ this, SLOT(webViewLoadStarted()));
+ connect(webView, SIGNAL(loadFinished(bool)),
+ this, SLOT(webViewIconChanged()));
+ connect(webView, SIGNAL(iconChanged()),
+ this, SLOT(webViewIconChanged()));
+ connect(webView, SIGNAL(titleChanged(QString)),
+ this, SLOT(webViewTitleChanged(QString)));
+ connect(webView, SIGNAL(urlChanged(QUrl)),
+ this, SLOT(webViewUrlChanged(QUrl)));
+ connect(webView->page(), SIGNAL(windowCloseRequested()),
+ this, SLOT(windowCloseRequested()));
+ connect(webView->page(), SIGNAL(geometryChangeRequested(QRect)),
+ this, SIGNAL(geometryChangeRequested(QRect)));
+ connect(webView->page(), SIGNAL(printRequested(QWebFrame*)),
+ this, SIGNAL(printRequested(QWebFrame*)));
+ connect(webView->page(), SIGNAL(menuBarVisibilityChangeRequested(bool)),
+ this, SIGNAL(menuBarVisibilityChangeRequested(bool)));
+ connect(webView->page(), SIGNAL(statusBarVisibilityChangeRequested(bool)),
+ this, SIGNAL(statusBarVisibilityChangeRequested(bool)));
+ connect(webView->page(), SIGNAL(toolBarVisibilityChangeRequested(bool)),
+ this, SIGNAL(toolBarVisibilityChangeRequested(bool)));
+ addTab(webView, tr("(Untitled)"));
+ if (makeCurrent)
+ setCurrentWidget(webView);
+
+ // webview actions
+ for (int i = 0; i < m_actions.count(); ++i) {
+ WebActionMapper *mapper = m_actions[i];
+ mapper->addChild(webView->page()->action(mapper->webAction()));
+ }
+
+ if (count() == 1)
+ currentChanged(currentIndex());
+ emit tabsChanged();
+ return webView;
+}
+
+void TabWidget::reloadAllTabs()
+{
+ for (int i = 0; i < count(); ++i) {
+ QWidget *tabWidget = widget(i);
+ if (WebView *tab = qobject_cast<WebView*>(tabWidget)) {
+ tab->reload();
+ }
+ }
+}
+
+void TabWidget::lineEditReturnPressed()
+{
+ if (QLineEdit *lineEdit = qobject_cast<QLineEdit*>(sender())) {
+ emit loadPage(lineEdit->text());
+ if (m_lineEdits->currentWidget() == lineEdit)
+ currentWebView()->setFocus();
+ }
+}
+
+void TabWidget::windowCloseRequested()
+{
+ WebPage *webPage = qobject_cast<WebPage*>(sender());
+ WebView *webView = qobject_cast<WebView*>(webPage->view());
+ int index = webViewIndex(webView);
+ if (index >= 0) {
+ if (count() == 1)
+ webView->webPage()->mainWindow()->close();
+ else
+ closeTab(index);
+ }
+}
+
+void TabWidget::closeOtherTabs(int index)
+{
+ if (-1 == index)
+ return;
+ for (int i = count() - 1; i > index; --i)
+ closeTab(i);
+ for (int i = index - 1; i >= 0; --i)
+ closeTab(i);
+}
+
+// When index is -1 index chooses the current tab
+void TabWidget::cloneTab(int index)
+{
+ if (index < 0)
+ index = currentIndex();
+ if (index < 0 || index >= count())
+ return;
+ WebView *tab = newTab(false);
+ tab->setUrl(webView(index)->url());
+}
+
+// When index is -1 index chooses the current tab
+void TabWidget::closeTab(int index)
+{
+ if (index < 0)
+ index = currentIndex();
+ if (index < 0 || index >= count())
+ return;
+
+ bool hasFocus = false;
+ if (WebView *tab = webView(index)) {
+ if (tab->isModified()) {
+ QMessageBox closeConfirmation(tab);
+ closeConfirmation.setWindowFlags(Qt::Sheet);
+ closeConfirmation.setWindowTitle(tr("Do you really want to close this page?"));
+ closeConfirmation.setInformativeText(tr("You have modified this page and when closing it you would lose the modification.\n"
+ "Do you really want to close this page?\n"));
+ closeConfirmation.setIcon(QMessageBox::Question);
+ closeConfirmation.addButton(QMessageBox::Yes);
+ closeConfirmation.addButton(QMessageBox::No);
+ closeConfirmation.setEscapeButton(QMessageBox::No);
+ if (closeConfirmation.exec() == QMessageBox::No)
+ return;
+ }
+ hasFocus = tab->hasFocus();
+
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (!globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) {
+ m_recentlyClosedTabsAction->setEnabled(true);
+ m_recentlyClosedTabs.prepend(tab->url());
+ if (m_recentlyClosedTabs.size() >= TabWidget::m_recentlyClosedTabsSize)
+ m_recentlyClosedTabs.removeLast();
+ }
+ }
+ QWidget *lineEdit = m_lineEdits->widget(index);
+ m_lineEdits->removeWidget(lineEdit);
+ lineEdit->deleteLater();
+ QWidget *webView = widget(index);
+ removeTab(index);
+ webView->deleteLater();
+ emit tabsChanged();
+ if (hasFocus && count() > 0)
+ currentWebView()->setFocus();
+ if (count() == 0)
+ emit lastTabClosed();
+}
+
+void TabWidget::webViewLoadStarted()
+{
+ WebView *webView = qobject_cast<WebView*>(sender());
+ int index = webViewIndex(webView);
+ if (-1 != index) {
+ QIcon icon(QLatin1String(":loading.gif"));
+ setTabIcon(index, icon);
+ }
+}
+
+void TabWidget::webViewIconChanged()
+{
+ WebView *webView = qobject_cast<WebView*>(sender());
+ int index = webViewIndex(webView);
+ if (-1 != index) {
+ QIcon icon = BrowserApplication::instance()->icon(webView->url());
+ setTabIcon(index, icon);
+ }
+}
+
+void TabWidget::webViewTitleChanged(const QString &title)
+{
+ WebView *webView = qobject_cast<WebView*>(sender());
+ int index = webViewIndex(webView);
+ if (-1 != index) {
+ setTabText(index, title);
+ }
+ if (currentIndex() == index)
+ emit setCurrentTitle(title);
+ BrowserApplication::historyManager()->updateHistoryItem(webView->url(), title);
+}
+
+void TabWidget::webViewUrlChanged(const QUrl &url)
+{
+ WebView *webView = qobject_cast<WebView*>(sender());
+ int index = webViewIndex(webView);
+ if (-1 != index) {
+ m_tabBar->setTabData(index, url);
+ }
+ emit tabsChanged();
+}
+
+void TabWidget::aboutToShowRecentTabsMenu()
+{
+ m_recentlyClosedTabsMenu->clear();
+ for (int i = 0; i < m_recentlyClosedTabs.count(); ++i) {
+ QAction *action = new QAction(m_recentlyClosedTabsMenu);
+ action->setData(m_recentlyClosedTabs.at(i));
+ QIcon icon = BrowserApplication::instance()->icon(m_recentlyClosedTabs.at(i));
+ action->setIcon(icon);
+ action->setText(m_recentlyClosedTabs.at(i).toString());
+ m_recentlyClosedTabsMenu->addAction(action);
+ }
+}
+
+void TabWidget::aboutToShowRecentTriggeredAction(QAction *action)
+{
+ QUrl url = action->data().toUrl();
+ loadUrlInCurrentTab(url);
+}
+
+void TabWidget::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ if (!childAt(event->pos())
+ // Remove the line below when QTabWidget does not have a one pixel frame
+ && event->pos().y() < (tabBar()->y() + tabBar()->height())) {
+ newTab();
+ return;
+ }
+ QTabWidget::mouseDoubleClickEvent(event);
+}
+
+void TabWidget::contextMenuEvent(QContextMenuEvent *event)
+{
+ if (!childAt(event->pos())) {
+ m_tabBar->contextMenuRequested(event->pos());
+ return;
+ }
+ QTabWidget::contextMenuEvent(event);
+}
+
+void TabWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::MidButton && !childAt(event->pos())
+ // Remove the line below when QTabWidget does not have a one pixel frame
+ && event->pos().y() < (tabBar()->y() + tabBar()->height())) {
+ QUrl url(QApplication::clipboard()->text(QClipboard::Selection));
+ if (!url.isEmpty() && url.isValid() && !url.scheme().isEmpty()) {
+ WebView *webView = newTab();
+ webView->setUrl(url);
+ }
+ }
+}
+
+void TabWidget::loadUrlInCurrentTab(const QUrl &url)
+{
+ WebView *webView = currentWebView();
+ if (webView) {
+ webView->loadUrl(url);
+ webView->setFocus();
+ }
+}
+
+void TabWidget::nextTab()
+{
+ int next = currentIndex() + 1;
+ if (next == count())
+ next = 0;
+ setCurrentIndex(next);
+}
+
+void TabWidget::previousTab()
+{
+ int next = currentIndex() - 1;
+ if (next < 0)
+ next = count() - 1;
+ setCurrentIndex(next);
+}
+
+static const qint32 TabWidgetMagic = 0xaa;
+
+QByteArray TabWidget::saveState() const
+{
+ int version = 1;
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+
+ stream << qint32(TabWidgetMagic);
+ stream << qint32(version);
+
+ QStringList tabs;
+ for (int i = 0; i < count(); ++i) {
+ if (WebView *tab = qobject_cast<WebView*>(widget(i))) {
+ tabs.append(tab->url().toString());
+ } else {
+ tabs.append(QString::null);
+ }
+ }
+ stream << tabs;
+ stream << currentIndex();
+ return data;
+}
+
+bool TabWidget::restoreState(const QByteArray &state)
+{
+ int version = 1;
+ QByteArray sd = state;
+ QDataStream stream(&sd, QIODevice::ReadOnly);
+ if (stream.atEnd())
+ return false;
+
+ qint32 marker;
+ qint32 v;
+ stream >> marker;
+ stream >> v;
+ if (marker != TabWidgetMagic || v != version)
+ return false;
+
+ QStringList openTabs;
+ stream >> openTabs;
+
+ for (int i = 0; i < openTabs.count(); ++i) {
+ if (i != 0)
+ newTab();
+ loadPage(openTabs.at(i));
+ }
+
+ int currentTab;
+ stream >> currentTab;
+ setCurrentIndex(currentTab);
+
+ return true;
+}
+
+WebActionMapper::WebActionMapper(QAction *root, QWebPage::WebAction webAction, QObject *parent)
+ : QObject(parent)
+ , m_currentParent(0)
+ , m_root(root)
+ , m_webAction(webAction)
+{
+ if (!m_root)
+ return;
+ connect(m_root, SIGNAL(triggered()), this, SLOT(rootTriggered()));
+ connect(root, SIGNAL(destroyed(QObject*)), this, SLOT(rootDestroyed()));
+ root->setEnabled(false);
+}
+
+void WebActionMapper::rootDestroyed()
+{
+ m_root = 0;
+}
+
+void WebActionMapper::currentDestroyed()
+{
+ updateCurrent(0);
+}
+
+void WebActionMapper::addChild(QAction *action)
+{
+ if (!action)
+ return;
+ connect(action, SIGNAL(changed()), this, SLOT(childChanged()));
+}
+
+QWebPage::WebAction WebActionMapper::webAction() const
+{
+ return m_webAction;
+}
+
+void WebActionMapper::rootTriggered()
+{
+ if (m_currentParent) {
+ QAction *gotoAction = m_currentParent->action(m_webAction);
+ gotoAction->trigger();
+ }
+}
+
+void WebActionMapper::childChanged()
+{
+ if (QAction *source = qobject_cast<QAction*>(sender())) {
+ if (m_root
+ && m_currentParent
+ && source->parent() == m_currentParent) {
+ m_root->setChecked(source->isChecked());
+ m_root->setEnabled(source->isEnabled());
+ }
+ }
+}
+
+void WebActionMapper::updateCurrent(QWebPage *currentParent)
+{
+ if (m_currentParent)
+ disconnect(m_currentParent, SIGNAL(destroyed(QObject*)),
+ this, SLOT(currentDestroyed()));
+
+ m_currentParent = currentParent;
+ if (!m_root)
+ return;
+ if (!m_currentParent) {
+ m_root->setEnabled(false);
+ m_root->setChecked(false);
+ return;
+ }
+ QAction *source = m_currentParent->action(m_webAction);
+ m_root->setChecked(source->isChecked());
+ m_root->setEnabled(source->isEnabled());
+ connect(m_currentParent, SIGNAL(destroyed(QObject*)),
+ this, SLOT(currentDestroyed()));
+}
+
diff --git a/examples/webkitwidgets/browser/tabwidget.h b/examples/webkitwidgets/browser/tabwidget.h
new file mode 100644
index 0000000..29b518b
--- /dev/null
+++ b/examples/webkitwidgets/browser/tabwidget.h
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TABWIDGET_H
+#define TABWIDGET_H
+
+#include <QtWidgets/QTabBar>
+
+#include <QtWidgets/QShortcut>
+/*
+ Tab bar with a few more features such as a context menu and shortcuts
+ */
+class TabBar : public QTabBar
+{
+ Q_OBJECT
+
+signals:
+ void newTab();
+ void cloneTab(int index);
+ void closeTab(int index);
+ void closeOtherTabs(int index);
+ void reloadTab(int index);
+ void reloadAllTabs();
+ void tabMoveRequested(int fromIndex, int toIndex);
+
+public:
+ TabBar(QWidget *parent = 0);
+
+protected:
+ void mousePressEvent(QMouseEvent* event);
+ void mouseMoveEvent(QMouseEvent* event);
+
+private slots:
+ void selectTabAction();
+ void cloneTab();
+ void closeTab();
+ void closeOtherTabs();
+ void reloadTab();
+ void contextMenuRequested(const QPoint &position);
+
+private:
+ QList<QShortcut*> m_tabShortcuts;
+ friend class TabWidget;
+
+ QPoint m_dragStartPos;
+ int m_dragCurrentIndex;
+};
+
+#include <QWebPage>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+class WebView;
+/*!
+ A proxy object that connects a single browser action
+ to one child webpage action at a time.
+
+ Example usage: used to keep the main window stop action in sync with
+ the current tabs webview's stop action.
+ */
+class WebActionMapper : public QObject
+{
+ Q_OBJECT
+
+public:
+ WebActionMapper(QAction *root, QWebPage::WebAction webAction, QObject *parent);
+ QWebPage::WebAction webAction() const;
+ void addChild(QAction *action);
+ void updateCurrent(QWebPage *currentParent);
+
+private slots:
+ void rootTriggered();
+ void childChanged();
+ void rootDestroyed();
+ void currentDestroyed();
+
+private:
+ QWebPage *m_currentParent;
+ QAction *m_root;
+ QWebPage::WebAction m_webAction;
+};
+
+#include <QtCore/QUrl>
+#include <QtWidgets/QTabWidget>
+QT_BEGIN_NAMESPACE
+class QCompleter;
+class QLineEdit;
+class QMenu;
+class QStackedWidget;
+QT_END_NAMESPACE
+/*!
+ TabWidget that contains WebViews and a stack widget of associated line edits.
+
+ Connects up the current tab's signals to this class's signal and uses WebActionMapper
+ to proxy the actions.
+ */
+class TabWidget : public QTabWidget
+{
+ Q_OBJECT
+
+signals:
+ // tab widget signals
+ void loadPage(const QString &url);
+ void tabsChanged();
+ void lastTabClosed();
+
+ // current tab signals
+ void setCurrentTitle(const QString &url);
+ void showStatusBarMessage(const QString &message);
+ void linkHovered(const QString &link);
+ void loadProgress(int progress);
+ void geometryChangeRequested(const QRect &geometry);
+ void menuBarVisibilityChangeRequested(bool visible);
+ void statusBarVisibilityChangeRequested(bool visible);
+ void toolBarVisibilityChangeRequested(bool visible);
+ void printRequested(QWebFrame *frame);
+
+public:
+ TabWidget(QWidget *parent = 0);
+ void clear();
+ void addWebAction(QAction *action, QWebPage::WebAction webAction);
+
+ QAction *newTabAction() const;
+ QAction *closeTabAction() const;
+ QAction *recentlyClosedTabsAction() const;
+ QAction *nextTabAction() const;
+ QAction *previousTabAction() const;
+
+ QWidget *lineEditStack() const;
+ QLineEdit *currentLineEdit() const;
+ WebView *currentWebView() const;
+ WebView *webView(int index) const;
+ QLineEdit *lineEdit(int index) const;
+ int webViewIndex(WebView *webView) const;
+
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+
+protected:
+ void mouseDoubleClickEvent(QMouseEvent *event);
+ void contextMenuEvent(QContextMenuEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+
+public slots:
+ void loadUrlInCurrentTab(const QUrl &url);
+ WebView *newTab(bool makeCurrent = true);
+ void cloneTab(int index = -1);
+ void closeTab(int index = -1);
+ void closeOtherTabs(int index);
+ void reloadTab(int index = -1);
+ void reloadAllTabs();
+ void nextTab();
+ void previousTab();
+
+private slots:
+ void currentChanged(int index);
+ void aboutToShowRecentTabsMenu();
+ void aboutToShowRecentTriggeredAction(QAction *action);
+ void webViewLoadStarted();
+ void webViewIconChanged();
+ void webViewTitleChanged(const QString &title);
+ void webViewUrlChanged(const QUrl &url);
+ void lineEditReturnPressed();
+ void windowCloseRequested();
+ void moveTab(int fromIndex, int toIndex);
+
+private:
+ QAction *m_recentlyClosedTabsAction;
+ QAction *m_newTabAction;
+ QAction *m_closeTabAction;
+ QAction *m_nextTabAction;
+ QAction *m_previousTabAction;
+
+ QMenu *m_recentlyClosedTabsMenu;
+ static const int m_recentlyClosedTabsSize = 10;
+ QList<QUrl> m_recentlyClosedTabs;
+ QList<WebActionMapper*> m_actions;
+
+ QCompleter *m_lineEditCompleter;
+ QStackedWidget *m_lineEdits;
+ TabBar *m_tabBar;
+};
+
+#endif // TABWIDGET_H
+
diff --git a/examples/webkitwidgets/browser/toolbarsearch.cpp b/examples/webkitwidgets/browser/toolbarsearch.cpp
new file mode 100644
index 0000000..33bc51c
--- /dev/null
+++ b/examples/webkitwidgets/browser/toolbarsearch.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "toolbarsearch.h"
+#include "autosaver.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QUrl>
+#include <QtCore/QUrlQuery>
+
+#include <QtWidgets/QCompleter>
+#include <QtWidgets/QMenu>
+#include <QtCore/QStringListModel>
+
+#include <QWebSettings>
+
+/*
+ ToolbarSearch is a very basic search widget that also contains a small history.
+ Searches are turned into urls that use Google to perform search
+ */
+ToolbarSearch::ToolbarSearch(QWidget *parent)
+ : SearchLineEdit(parent)
+ , m_autosaver(new AutoSaver(this))
+ , m_maxSavedSearches(10)
+ , m_stringListModel(new QStringListModel(this))
+{
+ QMenu *m = menu();
+ connect(m, SIGNAL(aboutToShow()), this, SLOT(aboutToShowMenu()));
+ connect(m, SIGNAL(triggered(QAction*)), this, SLOT(triggeredMenuAction(QAction*)));
+
+ QCompleter *completer = new QCompleter(m_stringListModel, this);
+ completer->setCompletionMode(QCompleter::InlineCompletion);
+ lineEdit()->setCompleter(completer);
+
+ connect(lineEdit(), SIGNAL(returnPressed()), SLOT(searchNow()));
+ setInactiveText(tr("Google"));
+ load();
+}
+
+ToolbarSearch::~ToolbarSearch()
+{
+ m_autosaver->saveIfNeccessary();
+}
+
+void ToolbarSearch::save()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("toolbarsearch"));
+ settings.setValue(QLatin1String("recentSearches"), m_stringListModel->stringList());
+ settings.setValue(QLatin1String("maximumSaved"), m_maxSavedSearches);
+ settings.endGroup();
+}
+
+void ToolbarSearch::load()
+{
+ QSettings settings;
+ settings.beginGroup(QLatin1String("toolbarsearch"));
+ QStringList list = settings.value(QLatin1String("recentSearches")).toStringList();
+ m_maxSavedSearches = settings.value(QLatin1String("maximumSaved"), m_maxSavedSearches).toInt();
+ m_stringListModel->setStringList(list);
+ settings.endGroup();
+}
+
+void ToolbarSearch::searchNow()
+{
+ QString searchText = lineEdit()->text();
+ QStringList newList = m_stringListModel->stringList();
+ if (newList.contains(searchText))
+ newList.removeAt(newList.indexOf(searchText));
+ newList.prepend(searchText);
+ if (newList.size() >= m_maxSavedSearches)
+ newList.removeLast();
+
+ QWebSettings *globalSettings = QWebSettings::globalSettings();
+ if (!globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) {
+ m_stringListModel->setStringList(newList);
+ m_autosaver->changeOccurred();
+ }
+
+ QUrl url(QLatin1String("http://www.google.com/search"));
+ QUrlQuery urlQuery;
+ urlQuery.addQueryItem(QLatin1String("q"), searchText);
+ urlQuery.addQueryItem(QLatin1String("ie"), QLatin1String("UTF-8"));
+ urlQuery.addQueryItem(QLatin1String("oe"), QLatin1String("UTF-8"));
+ urlQuery.addQueryItem(QLatin1String("client"), QLatin1String("qtdemobrowser"));
+ url.setQuery(urlQuery);
+ emit search(url);
+}
+
+void ToolbarSearch::aboutToShowMenu()
+{
+ lineEdit()->selectAll();
+ QMenu *m = menu();
+ m->clear();
+ QStringList list = m_stringListModel->stringList();
+ if (list.isEmpty()) {
+ m->addAction(tr("No Recent Searches"));
+ return;
+ }
+
+ QAction *recent = m->addAction(tr("Recent Searches"));
+ recent->setEnabled(false);
+ for (int i = 0; i < list.count(); ++i) {
+ QString text = list.at(i);
+ m->addAction(text)->setData(text);
+ }
+ m->addSeparator();
+ m->addAction(tr("Clear Recent Searches"), this, SLOT(clear()));
+}
+
+void ToolbarSearch::triggeredMenuAction(QAction *action)
+{
+ QVariant v = action->data();
+ if (v.canConvert<QString>()) {
+ QString text = v.toString();
+ lineEdit()->setText(text);
+ searchNow();
+ }
+}
+
+void ToolbarSearch::clear()
+{
+ m_stringListModel->setStringList(QStringList());
+ m_autosaver->changeOccurred();;
+}
+
diff --git a/examples/webkitwidgets/browser/toolbarsearch.h b/examples/webkitwidgets/browser/toolbarsearch.h
new file mode 100644
index 0000000..bbf2973
--- /dev/null
+++ b/examples/webkitwidgets/browser/toolbarsearch.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TOOLBARSEARCH_H
+#define TOOLBARSEARCH_H
+
+#include "searchlineedit.h"
+
+QT_BEGIN_NAMESPACE
+class QUrl;
+class QAction;
+class QStringListModel;
+QT_END_NAMESPACE
+
+class AutoSaver;
+
+class ToolbarSearch : public SearchLineEdit
+{
+ Q_OBJECT
+
+signals:
+ void search(const QUrl &url);
+
+public:
+ ToolbarSearch(QWidget *parent = 0);
+ ~ToolbarSearch();
+
+public slots:
+ void clear();
+ void searchNow();
+
+private slots:
+ void save();
+ void aboutToShowMenu();
+ void triggeredMenuAction(QAction *action);
+
+private:
+ void load();
+
+ AutoSaver *m_autosaver;
+ int m_maxSavedSearches;
+ QStringListModel *m_stringListModel;
+};
+
+#endif // TOOLBARSEARCH_H
+
diff --git a/examples/webkitwidgets/browser/urllineedit.cpp b/examples/webkitwidgets/browser/urllineedit.cpp
new file mode 100644
index 0000000..1fdc73d
--- /dev/null
+++ b/examples/webkitwidgets/browser/urllineedit.cpp
@@ -0,0 +1,342 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "urllineedit.h"
+
+#include "browserapplication.h"
+#include "searchlineedit.h"
+#include "webview.h"
+
+#include <QtCore/QEvent>
+#include <QtCore/QMimeData>
+
+#include <QtWidgets/QApplication>
+#include <QtWidgets/QCompleter>
+#include <QtGui/QFocusEvent>
+#include <QtWidgets/QHBoxLayout>
+#include <QtWidgets/QLabel>
+#include <QtWidgets/QLineEdit>
+#include <QtGui/QDrag>
+#include <QtGui/QPainter>
+#include <QtWidgets/QStyle>
+#include <QtWidgets/QStyleOptionFrameV2>
+
+#include <QtCore/QDebug>
+
+ExLineEdit::ExLineEdit(QWidget *parent)
+ : QWidget(parent)
+ , m_leftWidget(0)
+ , m_lineEdit(new QLineEdit(this))
+ , m_clearButton(0)
+{
+ setFocusPolicy(m_lineEdit->focusPolicy());
+ setAttribute(Qt::WA_InputMethodEnabled);
+ setSizePolicy(m_lineEdit->sizePolicy());
+ setBackgroundRole(m_lineEdit->backgroundRole());
+ setMouseTracking(true);
+ setAcceptDrops(true);
+ setAttribute(Qt::WA_MacShowFocusRect, true);
+ QPalette p = m_lineEdit->palette();
+ setPalette(p);
+
+ // line edit
+ m_lineEdit->setFrame(false);
+ m_lineEdit->setFocusProxy(this);
+ m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
+ QPalette clearPalette = m_lineEdit->palette();
+ clearPalette.setBrush(QPalette::Base, QBrush(Qt::transparent));
+ m_lineEdit->setPalette(clearPalette);
+
+ // clearButton
+ m_clearButton = new ClearButton(this);
+ connect(m_clearButton, SIGNAL(clicked()),
+ m_lineEdit, SLOT(clear()));
+ connect(m_lineEdit, SIGNAL(textChanged(QString)),
+ m_clearButton, SLOT(textChanged(QString)));
+}
+
+void ExLineEdit::setLeftWidget(QWidget *widget)
+{
+ m_leftWidget = widget;
+}
+
+QWidget *ExLineEdit::leftWidget() const
+{
+ return m_leftWidget;
+}
+
+void ExLineEdit::resizeEvent(QResizeEvent *event)
+{
+ Q_ASSERT(m_leftWidget);
+ updateGeometries();
+ QWidget::resizeEvent(event);
+}
+
+void ExLineEdit::updateGeometries()
+{
+ QStyleOptionFrameV2 panel;
+ initStyleOption(&panel);
+ QRect rect = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
+
+ int height = rect.height();
+ int width = rect.width();
+
+ int m_leftWidgetHeight = m_leftWidget->height();
+ m_leftWidget->setGeometry(rect.x() + 2, rect.y() + (height - m_leftWidgetHeight)/2,
+ m_leftWidget->width(), m_leftWidget->height());
+
+ int clearButtonWidth = this->height();
+ m_lineEdit->setGeometry(m_leftWidget->x() + m_leftWidget->width(), 0,
+ width - clearButtonWidth - m_leftWidget->width(), this->height());
+
+ m_clearButton->setGeometry(this->width() - clearButtonWidth, 0,
+ clearButtonWidth, this->height());
+}
+
+void ExLineEdit::initStyleOption(QStyleOptionFrameV2 *option) const
+{
+ option->initFrom(this);
+ option->rect = contentsRect();
+ option->lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, option, this);
+ option->midLineWidth = 0;
+ option->state |= QStyle::State_Sunken;
+ if (m_lineEdit->isReadOnly())
+ option->state |= QStyle::State_ReadOnly;
+#ifdef QT_KEYPAD_NAVIGATION
+ if (hasEditFocus())
+ option->state |= QStyle::State_HasEditFocus;
+#endif
+ option->features = QStyleOptionFrameV2::None;
+}
+
+QSize ExLineEdit::sizeHint() const
+{
+ m_lineEdit->setFrame(true);
+ QSize size = m_lineEdit->sizeHint();
+ m_lineEdit->setFrame(false);
+ return size;
+}
+
+void ExLineEdit::focusInEvent(QFocusEvent *event)
+{
+ m_lineEdit->event(event);
+ QWidget::focusInEvent(event);
+}
+
+void ExLineEdit::focusOutEvent(QFocusEvent *event)
+{
+ m_lineEdit->event(event);
+
+ if (m_lineEdit->completer()) {
+ connect(m_lineEdit->completer(), SIGNAL(activated(QString)),
+ m_lineEdit, SLOT(setText(QString)));
+ connect(m_lineEdit->completer(), SIGNAL(highlighted(QString)),
+ m_lineEdit, SLOT(_q_completionHighlighted(QString)));
+ }
+ QWidget::focusOutEvent(event);
+}
+
+void ExLineEdit::keyPressEvent(QKeyEvent *event)
+{
+ m_lineEdit->event(event);
+}
+
+bool ExLineEdit::event(QEvent *event)
+{
+ if (event->type() == QEvent::ShortcutOverride)
+ return m_lineEdit->event(event);
+ return QWidget::event(event);
+}
+
+void ExLineEdit::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QStyleOptionFrameV2 panel;
+ initStyleOption(&panel);
+ style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p, this);
+}
+
+QVariant ExLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ return m_lineEdit->inputMethodQuery(property);
+}
+
+void ExLineEdit::inputMethodEvent(QInputMethodEvent *e)
+{
+ m_lineEdit->event(e);
+}
+
+
+class UrlIconLabel : public QLabel
+{
+
+public:
+ UrlIconLabel(QWidget *parent);
+
+ WebView *m_webView;
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+
+private:
+ QPoint m_dragStartPos;
+
+};
+
+UrlIconLabel::UrlIconLabel(QWidget *parent)
+ : QLabel(parent)
+ , m_webView(0)
+{
+ setMinimumWidth(16);
+ setMinimumHeight(16);
+}
+
+void UrlIconLabel::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ m_dragStartPos = event->pos();
+ QLabel::mousePressEvent(event);
+}
+
+void UrlIconLabel::mouseMoveEvent(QMouseEvent *event)
+{
+ if (event->buttons() == Qt::LeftButton
+ && (event->pos() - m_dragStartPos).manhattanLength() > QApplication::startDragDistance()
+ && m_webView) {
+ QDrag *drag = new QDrag(this);
+ QMimeData *mimeData = new QMimeData;
+ mimeData->setText(QString::fromUtf8(m_webView->url().toEncoded()));
+ QList<QUrl> urls;
+ urls.append(m_webView->url());
+ mimeData->setUrls(urls);
+ drag->setMimeData(mimeData);
+ drag->exec();
+ }
+}
+
+UrlLineEdit::UrlLineEdit(QWidget *parent)
+ : ExLineEdit(parent)
+ , m_webView(0)
+ , m_iconLabel(0)
+{
+ // icon
+ m_iconLabel = new UrlIconLabel(this);
+ m_iconLabel->resize(16, 16);
+ setLeftWidget(m_iconLabel);
+ m_defaultBaseColor = palette().color(QPalette::Base);
+
+ webViewIconChanged();
+}
+
+void UrlLineEdit::setWebView(WebView *webView)
+{
+ Q_ASSERT(!m_webView);
+ m_webView = webView;
+ m_iconLabel->m_webView = webView;
+ connect(webView, SIGNAL(urlChanged(QUrl)),
+ this, SLOT(webViewUrlChanged(QUrl)));
+ connect(webView, SIGNAL(loadFinished(bool)),
+ this, SLOT(webViewIconChanged()));
+ connect(webView, SIGNAL(iconChanged()),
+ this, SLOT(webViewIconChanged()));
+ connect(webView, SIGNAL(loadProgress(int)),
+ this, SLOT(update()));
+}
+
+void UrlLineEdit::webViewUrlChanged(const QUrl &url)
+{
+ m_lineEdit->setText(QString::fromUtf8(url.toEncoded()));
+ m_lineEdit->setCursorPosition(0);
+}
+
+void UrlLineEdit::webViewIconChanged()
+{
+ QUrl url = (m_webView) ? m_webView->url() : QUrl();
+ QIcon icon = BrowserApplication::instance()->icon(url);
+ QPixmap pixmap(icon.pixmap(16, 16));
+ m_iconLabel->setPixmap(pixmap);
+}
+
+QLinearGradient UrlLineEdit::generateGradient(const QColor &color) const
+{
+ QLinearGradient gradient(0, 0, 0, height());
+ gradient.setColorAt(0, m_defaultBaseColor);
+ gradient.setColorAt(0.15, color.lighter(120));
+ gradient.setColorAt(0.5, color);
+ gradient.setColorAt(0.85, color.lighter(120));
+ gradient.setColorAt(1, m_defaultBaseColor);
+ return gradient;
+}
+
+void UrlLineEdit::focusOutEvent(QFocusEvent *event)
+{
+ if (m_lineEdit->text().isEmpty() && m_webView)
+ m_lineEdit->setText(QString::fromUtf8(m_webView->url().toEncoded()));
+ ExLineEdit::focusOutEvent(event);
+}
+
+void UrlLineEdit::paintEvent(QPaintEvent *event)
+{
+ QPalette p = palette();
+ if (m_webView && m_webView->url().scheme() == QLatin1String("https")) {
+ QColor lightYellow(248, 248, 210);
+ p.setBrush(QPalette::Base, generateGradient(lightYellow));
+ } else {
+ p.setBrush(QPalette::Base, m_defaultBaseColor);
+ }
+ setPalette(p);
+ ExLineEdit::paintEvent(event);
+
+ QPainter painter(this);
+ QStyleOptionFrameV2 panel;
+ initStyleOption(&panel);
+ QRect backgroundRect = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
+ if (m_webView && !hasFocus()) {
+ int progress = m_webView->progress();
+ QColor loadingColor = QColor(116, 192, 250);
+ painter.setBrush(generateGradient(loadingColor));
+ painter.setPen(Qt::transparent);
+ int mid = backgroundRect.width() / 100 * progress;
+ QRect progressRect(backgroundRect.x(), backgroundRect.y(), mid, backgroundRect.height());
+ painter.drawRect(progressRect);
+ }
+}
diff --git a/examples/webkitwidgets/browser/urllineedit.h b/examples/webkitwidgets/browser/urllineedit.h
new file mode 100644
index 0000000..f9716fd
--- /dev/null
+++ b/examples/webkitwidgets/browser/urllineedit.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef URLLINEEDIT_H
+#define URLLINEEDIT_H
+
+#include <QtCore/QUrl>
+#include <QtWidgets/QWidget>
+#include <QtWidgets/QStyleOptionFrame>
+
+QT_BEGIN_NAMESPACE
+class QLineEdit;
+QT_END_NAMESPACE
+
+class ClearButton;
+class ExLineEdit : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ExLineEdit(QWidget *parent = 0);
+
+ inline QLineEdit *lineEdit() const { return m_lineEdit; }
+
+ void setLeftWidget(QWidget *widget);
+ QWidget *leftWidget() const;
+
+ QSize sizeHint() const;
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+protected:
+ void focusInEvent(QFocusEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void paintEvent(QPaintEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ void inputMethodEvent(QInputMethodEvent *e);
+ bool event(QEvent *event);
+
+protected:
+ void updateGeometries();
+ void initStyleOption(QStyleOptionFrameV2 *option) const;
+
+ QWidget *m_leftWidget;
+ QLineEdit *m_lineEdit;
+ ClearButton *m_clearButton;
+};
+
+class UrlIconLabel;
+class WebView;
+class UrlLineEdit : public ExLineEdit
+{
+ Q_OBJECT
+
+public:
+ UrlLineEdit(QWidget *parent = 0);
+ void setWebView(WebView *webView);
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void focusOutEvent(QFocusEvent *event);
+
+private slots:
+ void webViewUrlChanged(const QUrl &url);
+ void webViewIconChanged();
+
+private:
+ QLinearGradient generateGradient(const QColor &color) const;
+ WebView *m_webView;
+ UrlIconLabel *m_iconLabel;
+ QColor m_defaultBaseColor;
+
+};
+
+
+#endif // URLLINEEDIT_H
+
diff --git a/examples/webkitwidgets/browser/webview.cpp b/examples/webkitwidgets/browser/webview.cpp
new file mode 100644
index 0000000..41c6558
--- /dev/null
+++ b/examples/webkitwidgets/browser/webview.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "browserapplication.h"
+#include "browsermainwindow.h"
+#include "cookiejar.h"
+#include "downloadmanager.h"
+#include "networkaccessmanager.h"
+#include "tabwidget.h"
+#include "webview.h"
+
+#include <QtGui/QClipboard>
+#include <QtWidgets/QMenu>
+#include <QtWidgets/QMessageBox>
+#include <QtGui/QMouseEvent>
+
+#include <QWebHitTestResult>
+
+#ifndef QT_NO_UITOOLS
+#include <QtUiTools/QUiLoader>
+#endif //QT_NO_UITOOLS
+
+#include <QtCore/QDebug>
+#include <QtCore/QBuffer>
+
+WebPage::WebPage(QObject *parent)
+ : QWebPage(parent)
+ , m_keyboardModifiers(Qt::NoModifier)
+ , m_pressedButtons(Qt::NoButton)
+ , m_openInNewTab(false)
+{
+ setNetworkAccessManager(BrowserApplication::networkAccessManager());
+ connect(this, SIGNAL(unsupportedContent(QNetworkReply*)),
+ this, SLOT(handleUnsupportedContent(QNetworkReply*)));
+}
+
+BrowserMainWindow *WebPage::mainWindow()
+{
+ QObject *w = this->parent();
+ while (w) {
+ if (BrowserMainWindow *mw = qobject_cast<BrowserMainWindow*>(w))
+ return mw;
+ w = w->parent();
+ }
+ return BrowserApplication::instance()->mainWindow();
+}
+
+bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type)
+{
+ // ctrl open in new tab
+ // ctrl-shift open in new tab and select
+ // ctrl-alt open in new window
+ if (type == QWebPage::NavigationTypeLinkClicked
+ && (m_keyboardModifiers & Qt::ControlModifier
+ || m_pressedButtons == Qt::MidButton)) {
+ bool newWindow = (m_keyboardModifiers & Qt::AltModifier);
+ WebView *webView;
+ if (newWindow) {
+ BrowserApplication::instance()->newMainWindow();
+ BrowserMainWindow *newMainWindow = BrowserApplication::instance()->mainWindow();
+ webView = newMainWindow->currentTab();
+ newMainWindow->raise();
+ newMainWindow->activateWindow();
+ webView->setFocus();
+ } else {
+ bool selectNewTab = (m_keyboardModifiers & Qt::ShiftModifier);
+ webView = mainWindow()->tabWidget()->newTab(selectNewTab);
+ }
+ webView->load(request);
+ m_keyboardModifiers = Qt::NoModifier;
+ m_pressedButtons = Qt::NoButton;
+ return false;
+ }
+ if (frame == mainFrame()) {
+ m_loadingUrl = request.url();
+ emit loadingUrl(m_loadingUrl);
+ }
+ return QWebPage::acceptNavigationRequest(frame, request, type);
+}
+
+QWebPage *WebPage::createWindow(QWebPage::WebWindowType type)
+{
+ Q_UNUSED(type);
+ if (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton)
+ m_openInNewTab = true;
+ if (m_openInNewTab) {
+ m_openInNewTab = false;
+ return mainWindow()->tabWidget()->newTab()->page();
+ }
+ BrowserApplication::instance()->newMainWindow();
+ BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow();
+ return mainWindow->currentTab()->page();
+}
+
+#if !defined(QT_NO_UITOOLS)
+QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
+{
+ Q_UNUSED(url);
+ Q_UNUSED(paramNames);
+ Q_UNUSED(paramValues);
+ QUiLoader loader;
+ return loader.createWidget(classId, view());
+}
+#endif // !defined(QT_NO_UITOOLS)
+
+void WebPage::handleUnsupportedContent(QNetworkReply *reply)
+{
+ QString errorString = reply->errorString();
+
+ if (m_loadingUrl != reply->url()) {
+ // sub resource of this page
+ qWarning() << "Resource" << reply->url().toEncoded() << "has unknown Content-Type, will be ignored.";
+ reply->deleteLater();
+ return;
+ }
+
+ if (reply->error() == QNetworkReply::NoError && !reply->header(QNetworkRequest::ContentTypeHeader).isValid()) {
+ errorString = "Unknown Content-Type";
+ }
+
+ QFile file(QLatin1String(":/notfound.html"));
+ bool isOpened = file.open(QIODevice::ReadOnly);
+ Q_ASSERT(isOpened);
+ Q_UNUSED(isOpened)
+
+ QString title = tr("Error loading page: %1").arg(reply->url().toString());
+ QString html = QString(QLatin1String(file.readAll()))
+ .arg(title)
+ .arg(errorString)
+ .arg(reply->url().toString());
+
+ QBuffer imageBuffer;
+ imageBuffer.open(QBuffer::ReadWrite);
+ QIcon icon = view()->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, view());
+ QPixmap pixmap = icon.pixmap(QSize(32,32));
+ if (pixmap.save(&imageBuffer, "PNG")) {
+ html.replace(QLatin1String("IMAGE_BINARY_DATA_HERE"),
+ QString(QLatin1String(imageBuffer.buffer().toBase64())));
+ }
+
+ QList<QWebFrame*> frames;
+ frames.append(mainFrame());
+ while (!frames.isEmpty()) {
+ QWebFrame *frame = frames.takeFirst();
+ if (frame->url() == reply->url()) {
+ frame->setHtml(html, reply->url());
+ return;
+ }
+ QList<QWebFrame *> children = frame->childFrames();
+ foreach(QWebFrame *frame, children)
+ frames.append(frame);
+ }
+ if (m_loadingUrl == reply->url()) {
+ mainFrame()->setHtml(html, reply->url());
+ }
+}
+
+
+WebView::WebView(QWidget* parent)
+ : QWebView(parent)
+ , m_progress(0)
+ , m_page(new WebPage(this))
+{
+ setPage(m_page);
+ connect(page(), SIGNAL(statusBarMessage(QString)),
+ SLOT(setStatusBarText(QString)));
+ connect(this, SIGNAL(loadProgress(int)),
+ this, SLOT(setProgress(int)));
+ connect(this, SIGNAL(loadFinished(bool)),
+ this, SLOT(loadFinished()));
+ connect(page(), SIGNAL(loadingUrl(QUrl)),
+ this, SIGNAL(urlChanged(QUrl)));
+ connect(page(), SIGNAL(downloadRequested(QNetworkRequest)),
+ this, SLOT(downloadRequested(QNetworkRequest)));
+ page()->setForwardUnsupportedContent(true);
+
+}
+
+void WebView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QWebHitTestResult r = page()->mainFrame()->hitTestContent(event->pos());
+ if (!r.linkUrl().isEmpty()) {
+ QMenu menu(this);
+ menu.addAction(pageAction(QWebPage::OpenLinkInNewWindow));
+ menu.addAction(tr("Open in New Tab"), this, SLOT(openLinkInNewTab()));
+ menu.addSeparator();
+ menu.addAction(pageAction(QWebPage::DownloadLinkToDisk));
+ // Add link to bookmarks...
+ menu.addSeparator();
+ menu.addAction(pageAction(QWebPage::CopyLinkToClipboard));
+ if (page()->settings()->testAttribute(QWebSettings::DeveloperExtrasEnabled))
+ menu.addAction(pageAction(QWebPage::InspectElement));
+ menu.exec(mapToGlobal(event->pos()));
+ return;
+ }
+ QWebView::contextMenuEvent(event);
+}
+
+void WebView::wheelEvent(QWheelEvent *event)
+{
+ if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
+ int numDegrees = event->delta() / 8;
+ int numSteps = numDegrees / 15;
+ setTextSizeMultiplier(textSizeMultiplier() + numSteps * 0.1);
+ event->accept();
+ return;
+ }
+ QWebView::wheelEvent(event);
+}
+
+void WebView::openLinkInNewTab()
+{
+ m_page->m_openInNewTab = true;
+ pageAction(QWebPage::OpenLinkInNewWindow)->trigger();
+}
+
+void WebView::setProgress(int progress)
+{
+ m_progress = progress;
+}
+
+void WebView::loadFinished()
+{
+ if (100 != m_progress) {
+ qWarning() << "Received finished signal while progress is still:" << progress()
+ << "Url:" << url();
+ }
+ m_progress = 0;
+}
+
+void WebView::loadUrl(const QUrl &url)
+{
+ m_initialUrl = url;
+ load(url);
+}
+
+QString WebView::lastStatusBarText() const
+{
+ return m_statusBarText;
+}
+
+QUrl WebView::url() const
+{
+ QUrl url = QWebView::url();
+ if (!url.isEmpty())
+ return url;
+
+ return m_initialUrl;
+}
+
+void WebView::mousePressEvent(QMouseEvent *event)
+{
+ m_page->m_pressedButtons = event->buttons();
+ m_page->m_keyboardModifiers = event->modifiers();
+ QWebView::mousePressEvent(event);
+}
+
+void WebView::mouseReleaseEvent(QMouseEvent *event)
+{
+ QWebView::mouseReleaseEvent(event);
+ if (!event->isAccepted() && (m_page->m_pressedButtons & Qt::MidButton)) {
+ QUrl url(QApplication::clipboard()->text(QClipboard::Selection));
+ if (!url.isEmpty() && url.isValid() && !url.scheme().isEmpty()) {
+ setUrl(url);
+ }
+ }
+}
+
+void WebView::setStatusBarText(const QString &string)
+{
+ m_statusBarText = string;
+}
+
+void WebView::downloadRequested(const QNetworkRequest &request)
+{
+ BrowserApplication::downloadManager()->download(request);
+}
+
diff --git a/examples/webkitwidgets/browser/webview.h b/examples/webkitwidgets/browser/webview.h
new file mode 100644
index 0000000..c48d141
--- /dev/null
+++ b/examples/webkitwidgets/browser/webview.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WEBVIEW_H
+#define WEBVIEW_H
+
+#include <QWebView>
+
+QT_BEGIN_NAMESPACE
+class QAuthenticator;
+class QMouseEvent;
+class QNetworkProxy;
+class QNetworkReply;
+class QSslError;
+QT_END_NAMESPACE
+
+class BrowserMainWindow;
+class WebPage : public QWebPage {
+ Q_OBJECT
+
+signals:
+ void loadingUrl(const QUrl &url);
+
+public:
+ WebPage(QObject *parent = 0);
+ BrowserMainWindow *mainWindow();
+
+protected:
+ bool acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type);
+ QWebPage *createWindow(QWebPage::WebWindowType type);
+#if !defined(QT_NO_UITOOLS)
+ QObject *createPlugin(const QString &classId, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues);
+#endif
+
+private slots:
+ void handleUnsupportedContent(QNetworkReply *reply);
+
+private:
+ friend class WebView;
+
+ // set the webview mousepressedevent
+ Qt::KeyboardModifiers m_keyboardModifiers;
+ Qt::MouseButtons m_pressedButtons;
+ bool m_openInNewTab;
+ QUrl m_loadingUrl;
+};
+
+class WebView : public QWebView {
+ Q_OBJECT
+
+public:
+ WebView(QWidget *parent = 0);
+ WebPage *webPage() const { return m_page; }
+
+ void loadUrl(const QUrl &url);
+ QUrl url() const;
+
+ QString lastStatusBarText() const;
+ inline int progress() const { return m_progress; }
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void contextMenuEvent(QContextMenuEvent *event);
+ void wheelEvent(QWheelEvent *event);
+
+private slots:
+ void setProgress(int progress);
+ void loadFinished();
+ void setStatusBarText(const QString &string);
+ void downloadRequested(const QNetworkRequest &request);
+ void openLinkInNewTab();
+
+private:
+ QString m_statusBarText;
+ QUrl m_initialUrl;
+ int m_progress;
+ WebPage *m_page;
+};
+
+#endif
diff --git a/examples/webkitwidgets/browser/xbel.cpp b/examples/webkitwidgets/browser/xbel.cpp
new file mode 100644
index 0000000..e52afe1
--- /dev/null
+++ b/examples/webkitwidgets/browser/xbel.cpp
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "xbel.h"
+
+#include <QtCore/QFile>
+
+BookmarkNode::BookmarkNode(BookmarkNode::Type type, BookmarkNode *parent) :
+ expanded(false)
+ , m_parent(parent)
+ , m_type(type)
+{
+ if (parent)
+ parent->add(this);
+}
+
+BookmarkNode::~BookmarkNode()
+{
+ if (m_parent)
+ m_parent->remove(this);
+ qDeleteAll(m_children);
+ m_parent = 0;
+ m_type = BookmarkNode::Root;
+}
+
+bool BookmarkNode::operator==(const BookmarkNode &other)
+{
+ if (url != other.url
+ || title != other.title
+ || desc != other.desc
+ || expanded != other.expanded
+ || m_type != other.m_type
+ || m_children.count() != other.m_children.count())
+ return false;
+
+ for (int i = 0; i < m_children.count(); ++i)
+ if (!((*(m_children[i])) == (*(other.m_children[i]))))
+ return false;
+ return true;
+}
+
+BookmarkNode::Type BookmarkNode::type() const
+{
+ return m_type;
+}
+
+void BookmarkNode::setType(Type type)
+{
+ m_type = type;
+}
+
+QList<BookmarkNode *> BookmarkNode::children() const
+{
+ return m_children;
+}
+
+BookmarkNode *BookmarkNode::parent() const
+{
+ return m_parent;
+}
+
+void BookmarkNode::add(BookmarkNode *child, int offset)
+{
+ Q_ASSERT(child->m_type != Root);
+ if (child->m_parent)
+ child->m_parent->remove(child);
+ child->m_parent = this;
+ if (-1 == offset)
+ offset = m_children.size();
+ m_children.insert(offset, child);
+}
+
+void BookmarkNode::remove(BookmarkNode *child)
+{
+ child->m_parent = 0;
+ m_children.removeAll(child);
+}
+
+
+XbelReader::XbelReader()
+{
+}
+
+BookmarkNode *XbelReader::read(const QString &fileName)
+{
+ QFile file(fileName);
+ if (!file.exists()) {
+ return new BookmarkNode(BookmarkNode::Root);
+ }
+ file.open(QFile::ReadOnly);
+ return read(&file);
+}
+
+BookmarkNode *XbelReader::read(QIODevice *device)
+{
+ BookmarkNode *root = new BookmarkNode(BookmarkNode::Root);
+ setDevice(device);
+ if (readNextStartElement()) {
+ QString version = attributes().value(QLatin1String("version")).toString();
+ if (name() == QLatin1String("xbel")
+ && (version.isEmpty() || version == QLatin1String("1.0"))) {
+ readXBEL(root);
+ } else {
+ raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
+ }
+ }
+ return root;
+}
+
+void XbelReader::readXBEL(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("xbel"));
+
+ while (readNextStartElement()) {
+ if (name() == QLatin1String("folder"))
+ readFolder(parent);
+ else if (name() == QLatin1String("bookmark"))
+ readBookmarkNode(parent);
+ else if (name() == QLatin1String("separator"))
+ readSeparator(parent);
+ else
+ skipCurrentElement();
+ }
+}
+
+void XbelReader::readFolder(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("folder"));
+
+ BookmarkNode *folder = new BookmarkNode(BookmarkNode::Folder, parent);
+ folder->expanded = (attributes().value(QLatin1String("folded")) == QLatin1String("no"));
+
+ while (readNextStartElement()) {
+ if (name() == QLatin1String("title"))
+ readTitle(folder);
+ else if (name() == QLatin1String("desc"))
+ readDescription(folder);
+ else if (name() == QLatin1String("folder"))
+ readFolder(folder);
+ else if (name() == QLatin1String("bookmark"))
+ readBookmarkNode(folder);
+ else if (name() == QLatin1String("separator"))
+ readSeparator(folder);
+ else
+ skipCurrentElement();
+ }
+}
+
+void XbelReader::readTitle(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("title"));
+ parent->title = readElementText();
+}
+
+void XbelReader::readDescription(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("desc"));
+ parent->desc = readElementText();
+}
+
+void XbelReader::readSeparator(BookmarkNode *parent)
+{
+ new BookmarkNode(BookmarkNode::Separator, parent);
+ // empty elements have a start and end element
+ readNext();
+}
+
+void XbelReader::readBookmarkNode(BookmarkNode *parent)
+{
+ Q_ASSERT(isStartElement() && name() == QLatin1String("bookmark"));
+ BookmarkNode *bookmark = new BookmarkNode(BookmarkNode::Bookmark, parent);
+ bookmark->url = attributes().value(QLatin1String("href")).toString();
+ while (readNextStartElement()) {
+ if (name() == QLatin1String("title"))
+ readTitle(bookmark);
+ else if (name() == QLatin1String("desc"))
+ readDescription(bookmark);
+ else
+ skipCurrentElement();
+ }
+ if (bookmark->title.isEmpty())
+ bookmark->title = QObject::tr("Unknown title");
+}
+
+
+XbelWriter::XbelWriter()
+{
+ setAutoFormatting(true);
+}
+
+bool XbelWriter::write(const QString &fileName, const BookmarkNode *root)
+{
+ QFile file(fileName);
+ if (!root || !file.open(QFile::WriteOnly))
+ return false;
+ return write(&file, root);
+}
+
+bool XbelWriter::write(QIODevice *device, const BookmarkNode *root)
+{
+ setDevice(device);
+
+ writeStartDocument();
+ writeDTD(QLatin1String("<!DOCTYPE xbel>"));
+ writeStartElement(QLatin1String("xbel"));
+ writeAttribute(QLatin1String("version"), QLatin1String("1.0"));
+ if (root->type() == BookmarkNode::Root) {
+ for (int i = 0; i < root->children().count(); ++i)
+ writeItem(root->children().at(i));
+ } else {
+ writeItem(root);
+ }
+
+ writeEndDocument();
+ return true;
+}
+
+void XbelWriter::writeItem(const BookmarkNode *parent)
+{
+ switch (parent->type()) {
+ case BookmarkNode::Folder:
+ writeStartElement(QLatin1String("folder"));
+ writeAttribute(QLatin1String("folded"), parent->expanded ? QLatin1String("no") : QLatin1String("yes"));
+ writeTextElement(QLatin1String("title"), parent->title);
+ for (int i = 0; i < parent->children().count(); ++i)
+ writeItem(parent->children().at(i));
+ writeEndElement();
+ break;
+ case BookmarkNode::Bookmark:
+ writeStartElement(QLatin1String("bookmark"));
+ if (!parent->url.isEmpty())
+ writeAttribute(QLatin1String("href"), parent->url);
+ writeTextElement(QLatin1String("title"), parent->title);
+ if (!parent->desc.isEmpty())
+ writeAttribute(QLatin1String("desc"), parent->desc);
+ writeEndElement();
+ break;
+ case BookmarkNode::Separator:
+ writeEmptyElement(QLatin1String("separator"));
+ break;
+ default:
+ break;
+ }
+}
+
diff --git a/examples/webkitwidgets/browser/xbel.h b/examples/webkitwidgets/browser/xbel.h
new file mode 100644
index 0000000..a919def
--- /dev/null
+++ b/examples/webkitwidgets/browser/xbel.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef XBEL_H
+#define XBEL_H
+
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QDateTime>
+
+class BookmarkNode
+{
+public:
+ enum Type {
+ Root,
+ Folder,
+ Bookmark,
+ Separator
+ };
+
+ BookmarkNode(Type type = Root, BookmarkNode *parent = 0);
+ ~BookmarkNode();
+ bool operator==(const BookmarkNode &other);
+
+ Type type() const;
+ void setType(Type type);
+ QList<BookmarkNode *> children() const;
+ BookmarkNode *parent() const;
+
+ void add(BookmarkNode *child, int offset = -1);
+ void remove(BookmarkNode *child);
+
+ QString url;
+ QString title;
+ QString desc;
+ bool expanded;
+
+private:
+ BookmarkNode *m_parent;
+ Type m_type;
+ QList<BookmarkNode *> m_children;
+
+};
+
+class XbelReader : public QXmlStreamReader
+{
+public:
+ XbelReader();
+ BookmarkNode *read(const QString &fileName);
+ BookmarkNode *read(QIODevice *device);
+
+private:
+ void readXBEL(BookmarkNode *parent);
+ void readTitle(BookmarkNode *parent);
+ void readDescription(BookmarkNode *parent);
+ void readSeparator(BookmarkNode *parent);
+ void readFolder(BookmarkNode *parent);
+ void readBookmarkNode(BookmarkNode *parent);
+};
+
+#include <QtCore/QXmlStreamWriter>
+
+class XbelWriter : public QXmlStreamWriter
+{
+public:
+ XbelWriter();
+ bool write(const QString &fileName, const BookmarkNode *root);
+ bool write(QIODevice *device, const BookmarkNode *root);
+
+private:
+ void writeItem(const BookmarkNode *parent);
+};
+
+#endif // XBEL_H
+
diff --git a/examples/webkitwidgets/domtraversal/doc/images/webkit-domtraversal.png b/examples/webkitwidgets/domtraversal/doc/images/webkit-domtraversal.png
new file mode 100644
index 0000000..8b6f34a
--- /dev/null
+++ b/examples/webkitwidgets/domtraversal/doc/images/webkit-domtraversal.png
Binary files differ
diff --git a/examples/webkitwidgets/domtraversal/doc/src/domtraversal.qdoc b/examples/webkitwidgets/domtraversal/doc/src/domtraversal.qdoc
new file mode 100644
index 0000000..52764f3
--- /dev/null
+++ b/examples/webkitwidgets/domtraversal/doc/src/domtraversal.qdoc
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example domtraversal
+ \title DOM Traversal Example
+
+ \brief The DOM Traversal example shows how to use the QWebElement class to access
+ the structure of a Web page.
+
+ \image webkit-domtraversal.png
+
+ The QWebElement class provides an API that can be used to examine the structure
+ and content of a Web page via a Document Object Model (DOM) interface. It can be
+ used for basic traversal of the document structure, to search for particular
+ elements (see the \l{Simple Selector Example}), and to modify content in-place.
+
+ This example uses a QWebView widget to display the Web page, and a dock widget
+ holds the QTreeWidget that shows the document structure. These widgets are
+ placed in an instance of the \c Window class, which we describe below.
+
+ \section1 Window Class Definition
+
+ The \c Window class is derived from QMainWindow and its user interface is created
+ using \l{Qt Designer}. As a result, the class is also derived from the user
+ interface class created by \l uic:
+
+ \snippet domtraversal/window.h Window class definition
+
+ Two important functions to note are the \c on_webView_loadFinished() slot and
+ the \c examineChildElements() function. The former is automatically called
+ when the QWebView widget finishes loading a page. See the
+ \l{#Further Reading}{Further Reading} section for more information on this
+ mechanism.
+
+ The \c examineChildElements() function is used to traverse the document structure
+ and add items to the QTreeWidget.
+
+ \section1 Window Class Implementation
+
+ In the \c Window class constructor, we call the \l{QWidget::}{setupUi()} function
+ to set up the user interface described in the \c{window.ui} file:
+
+ \snippet domtraversal/window.cpp Window constructor
+
+ When the Web page is loaded, the \c on_webView_loadFinished() slot is called. Here,
+ we clear the tree widget and begin inspection of the document by obtaining the
+ document element from the page's main frame:
+
+ \snippet domtraversal/window.cpp begin document inspection
+
+ At this point, we call the \c examineChildElements() function to traverse the
+ document, starting with the child elements of the document element for which we
+ will create top level items in the tree widget.
+
+ The \c examineChildElements() function accepts a parent element and a parent item.
+ Starting with the first child element, which we obtain with the element's
+ \l{QWebElement::}{firstChild()} function, we examine each child element of the
+ parent item. For each valid (non-null) element, which we check by calling its
+ \l{QWebElement::}{isNull()} function, we create a new QTreeWidgetItem instance with
+ the element name and add it to the parent item.
+
+ \snippet domtraversal/window.cpp traverse document
+
+ We recursively examine the child elements for each element by calling
+ \c examineChildElements() with the current child element and the newly-created item.
+ To obtain the next element at the same level in the document, we call its
+ \l{QWebElement::}{nextSibling()} function.
+
+ This recursive approach to reading the document makes it easy to create a simple
+ representation of the document structure in a tree widget.
+
+ For completeness, we show the \c setUrl() function, which is provided to allow the
+ document URL to be set from the example's \c main() function.
+
+ \snippet domtraversal/window.cpp set URL
+
+ \section1 Starting the Example
+
+ We set up the application, create
+ a \c Window instance, set its URL, and show it:
+
+ \snippet domtraversal/main.cpp main program
+
+ When the application's event loop is run, the Qt home page will load, and the
+ tree widget will be updated to show the document structure. Navigating to another
+ page will cause the tree widget to be updated to show the document structure of
+ the new page.
+
+ \section1 Further Reading
+
+ The QWebElement documentation contains more information about DOM access for the
+ QtWebKit classes.
+
+ In this example, we take advantage of Qt's
+ \l{Using a Designer UI File in Your Application#Automatic Connections}{auto-connection}
+ feature to avoid explicitly connecting signals to slots. The user interface
+ contains a QWebView widget called \c webView whose \l{QWebView::}{loadFinished()}
+ signal is automatically connected to the \c on_webView_loadFinished() slot when
+ we call \l{QWidget::}{setupUi()} in the \c Window constructor.
+*/
diff --git a/examples/webkitwidgets/domtraversal/domtraversal.pro b/examples/webkitwidgets/domtraversal/domtraversal.pro
new file mode 100644
index 0000000..8c53258
--- /dev/null
+++ b/examples/webkitwidgets/domtraversal/domtraversal.pro
@@ -0,0 +1,9 @@
+QT += webkitwidgets network widgets
+FORMS = window.ui
+HEADERS = window.h
+SOURCES = main.cpp \
+ window.cpp
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/domtraversal
+INSTALLS += target
diff --git a/examples/webkitwidgets/domtraversal/main.cpp b/examples/webkitwidgets/domtraversal/main.cpp
new file mode 100644
index 0000000..d105e47
--- /dev/null
+++ b/examples/webkitwidgets/domtraversal/main.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//! [main program]
+#include <QApplication>
+#include "window.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ Window window;
+ window.show();
+ window.setUrl(QUrl("http://qt-project.org/"));
+ return app.exec();
+}
+//! [main program]
diff --git a/examples/webkitwidgets/domtraversal/window.cpp b/examples/webkitwidgets/domtraversal/window.cpp
new file mode 100644
index 0000000..f96b9be
--- /dev/null
+++ b/examples/webkitwidgets/domtraversal/window.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+#include <QtWebKitWidgets>
+
+#include "window.h"
+
+//! [Window constructor]
+Window::Window(QWidget *parent)
+ : QMainWindow(parent)
+{
+ setupUi(this);
+}
+//! [Window constructor]
+
+//! [set URL]
+void Window::setUrl(const QUrl &url)
+{
+ webView->setUrl(url);
+}
+//! [set URL]
+
+//! [begin document inspection]
+void Window::on_webView_loadFinished()
+{
+ treeWidget->clear();
+
+ QWebFrame *frame = webView->page()->mainFrame();
+ QWebElement document = frame->documentElement();
+
+ examineChildElements(document, treeWidget->invisibleRootItem());
+}
+//! [begin document inspection]
+
+//! [traverse document]
+void Window::examineChildElements(const QWebElement &parentElement,
+ QTreeWidgetItem *parentItem)
+{
+ QWebElement element = parentElement.firstChild();
+ while (!element.isNull()) {
+
+ QTreeWidgetItem *item = new QTreeWidgetItem();
+ item->setText(0, element.tagName());
+ parentItem->addChild(item);
+
+ examineChildElements(element, item);
+
+ element = element.nextSibling();
+ }
+}
+//! [traverse document]
diff --git a/examples/webkitwidgets/domtraversal/window.h b/examples/webkitwidgets/domtraversal/window.h
new file mode 100644
index 0000000..f9ce2f7
--- /dev/null
+++ b/examples/webkitwidgets/domtraversal/window.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <QMainWindow>
+#include <QUrl>
+#include <QWebElement>
+
+QT_BEGIN_NAMESPACE
+class QTreeWidgetItem;
+QT_END_NAMESPACE
+
+//! [Window class definition]
+#include "ui_window.h"
+
+class Window : public QMainWindow, private Ui::Window
+{
+ Q_OBJECT
+
+public:
+ Window(QWidget *parent = 0);
+ void setUrl(const QUrl &url);
+
+public slots:
+ void on_webView_loadFinished();
+
+private:
+ void examineChildElements(const QWebElement &parentElement,
+ QTreeWidgetItem *parentItem);
+};
+//! [Window class definition]
+
+#endif
diff --git a/examples/webkitwidgets/domtraversal/window.ui b/examples/webkitwidgets/domtraversal/window.ui
new file mode 100644
index 0000000..e245aa6
--- /dev/null
+++ b/examples/webkitwidgets/domtraversal/window.ui
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Window</class>
+ <widget class="QMainWindow" name="Window">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Web Element DOM Traversal</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="topMargin">
+ <number>4</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QWebView" name="webView">
+ <property name="url">
+ <url>
+ <string>http://qt-project.org/</string>
+ </url>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>27</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ <widget class="QDockWidget" name="dockWidget">
+ <property name="allowedAreas">
+ <set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
+ </property>
+ <property name="windowTitle">
+ <string>Document Structure</string>
+ </property>
+ <attribute name="dockWidgetArea">
+ <number>1</number>
+ </attribute>
+ <widget class="QWidget" name="dockWidgetContents">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="margin">
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QTreeWidget" name="treeWidget">
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QWebView</class>
+ <extends>QWidget</extends>
+ <header>QtWebKitWidgets/QWebView</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/webkitwidgets/embedded/anomaly/README.TXT b/examples/webkitwidgets/embedded/anomaly/README.TXT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/README.TXT
diff --git a/examples/webkitwidgets/embedded/anomaly/anomaly.pro b/examples/webkitwidgets/embedded/anomaly/anomaly.pro
new file mode 100644
index 0000000..ddb20f2
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/anomaly.pro
@@ -0,0 +1,28 @@
+QT += network \
+ webkitwidgets \
+ widgets
+HEADERS += src/BrowserWindow.h \
+ src/BrowserView.h \
+ src/TitleBar.h \
+ src/HomeView.h \
+ src/AddressBar.h \
+ src/BookmarksView.h \
+ src/flickcharm.h \
+ src/ZoomStrip.h \
+ src/ControlStrip.h \
+ src/webview.h
+SOURCES += src/Main.cpp \
+ src/BrowserWindow.cpp \
+ src/BrowserView.cpp \
+ src/TitleBar.cpp \
+ src/HomeView.cpp \
+ src/AddressBar.cpp \
+ src/BookmarksView.cpp \
+ src/flickcharm.cpp \
+ src/ZoomStrip.cpp \
+ src/ControlStrip.cpp \
+ src/webview.cpp
+RESOURCES += src/anomaly.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/embedded/anomaly
+INSTALLS += target
diff --git a/examples/webkitwidgets/embedded/anomaly/src/AddressBar.cpp b/examples/webkitwidgets/embedded/anomaly/src/AddressBar.cpp
new file mode 100644
index 0000000..dfb4043
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/AddressBar.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "AddressBar.h"
+
+#include <QtCore>
+#include <QtWidgets>
+
+AddressBar::AddressBar(QWidget *parent)
+ : QWidget(parent)
+{
+ m_lineEdit = new QLineEdit(parent);
+ m_lineEdit->setPlaceholderText("Enter address or search terms");
+ connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(processAddress()));
+ m_toolButton = new QToolButton(parent);
+ m_toolButton->setText("Go");
+ connect(m_toolButton, SIGNAL(clicked()), SLOT(processAddress()));
+}
+
+QSize AddressBar::sizeHint() const
+{
+ return m_lineEdit->sizeHint();
+}
+
+void AddressBar::processAddress()
+{
+ if (!m_lineEdit->text().isEmpty())
+ emit addressEntered(m_lineEdit->text());
+}
+
+void AddressBar::resizeEvent(QResizeEvent *event)
+{
+ int x, y, w, h;
+
+ m_toolButton->adjustSize();
+ x = width() - m_toolButton->width();
+ y = 0;
+ w = m_toolButton->width();
+ h = height() - 1;
+ m_toolButton->setGeometry(x, y, w, h);
+ m_toolButton->show();
+
+ x = 0;
+ y = 0;
+ w = width() - m_toolButton->width();
+ h = height() - 1;
+ m_lineEdit->setGeometry(x, y, w, h);
+ m_lineEdit->show();
+}
+
+void AddressBar::focusInEvent(QFocusEvent *event)
+{
+ m_lineEdit->setFocus();
+ QWidget::focusInEvent(event);
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/AddressBar.h b/examples/webkitwidgets/embedded/anomaly/src/AddressBar.h
new file mode 100644
index 0000000..ae9010d
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/AddressBar.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ADDRESSBAR_H
+#define ADDRESSBAR_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QLineEdit;
+class QToolButton;
+QT_END_NAMESPACE
+
+class AddressBar : public QWidget
+{
+ Q_OBJECT
+
+public:
+ AddressBar(QWidget *parent = 0);
+ QSize sizeHint() const;
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+ void focusInEvent(QFocusEvent *event);
+
+signals:
+ void addressEntered(const QString &address);
+
+private slots:
+ void processAddress();
+
+private:
+ QLineEdit *m_lineEdit;
+ QToolButton *m_toolButton;
+};
+
+#endif // ADDRESSBAR_H
diff --git a/examples/webkitwidgets/embedded/anomaly/src/BookmarksView.cpp b/examples/webkitwidgets/embedded/anomaly/src/BookmarksView.cpp
new file mode 100644
index 0000000..63e48e2
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/BookmarksView.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "BookmarksView.h"
+
+#include <QtWidgets>
+
+BookmarksView::BookmarksView(QWidget *parent)
+ : QWidget(parent)
+{
+ QListWidget *m_iconView = new QListWidget(this);
+ connect(m_iconView, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(activate(QListWidgetItem*)));
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ setLayout(layout);
+ layout->addWidget(m_iconView);
+
+ m_iconView->addItem("www.google.com");
+ m_iconView->addItem("qt-project.org/doc/qt-5.0");
+ m_iconView->addItem("news.bbc.co.uk/2/mobile/default.stm");
+ m_iconView->addItem("mobile.wikipedia.org");
+ m_iconView->addItem("qt.digia.com");
+ m_iconView->addItem("en.wikipedia.org");
+
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+}
+
+void BookmarksView::activate(QListWidgetItem *item)
+{
+ QUrl url = item->text().prepend("http://");
+ emit urlSelected(url);
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/BookmarksView.h b/examples/webkitwidgets/embedded/anomaly/src/BookmarksView.h
new file mode 100644
index 0000000..4d68a6c
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/BookmarksView.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BOOKMARKSVIEW_H
+#define BOOKMARKSVIEW_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QListWidgetItem;
+class QUrl;
+QT_END_NAMESPACE
+
+class BookmarksView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ BookmarksView(QWidget *parent = 0);
+
+signals:
+ void urlSelected(const QUrl &url);
+
+private slots:
+ void activate(QListWidgetItem *item);
+};
+
+#endif // BOOKMARKSVIEW_H
diff --git a/examples/webkitwidgets/embedded/anomaly/src/BrowserView.cpp b/examples/webkitwidgets/embedded/anomaly/src/BrowserView.cpp
new file mode 100644
index 0000000..46f898d
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/BrowserView.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "BrowserView.h"
+
+#include <QtWidgets>
+#include <QtNetwork>
+#include <QtWebKitWidgets>
+
+#include "ControlStrip.h"
+#include "TitleBar.h"
+#include "flickcharm.h"
+#include "webview.h"
+#include "ZoomStrip.h"
+
+BrowserView::BrowserView(QWidget *parent)
+ : QWidget(parent)
+ , m_titleBar(0)
+ , m_webView(0)
+ , m_progress(0)
+ , m_currentZoom(100)
+{
+ m_titleBar = new TitleBar(this);
+ m_webView = new WebView(this);
+ m_zoomStrip = new ZoomStrip(this);
+ m_controlStrip = new ControlStrip(this);
+
+ m_zoomLevels << 30 << 50 << 67 << 80 << 90;
+ m_zoomLevels << 100;
+ m_zoomLevels << 110 << 120 << 133 << 150 << 170 << 200 << 240 << 300;
+
+ QNetworkConfigurationManager manager;
+ if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) {
+ // Get saved network configuration
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+ settings.beginGroup(QLatin1String("QtNetwork"));
+ const QString id =
+ settings.value(QLatin1String("DefaultNetworkConfiguration")).toString();
+ settings.endGroup();
+
+ // If the saved network configuration is not currently discovered use the system
+ // default
+ QNetworkConfiguration config = manager.configurationFromIdentifier(id);
+ if ((config.state() & QNetworkConfiguration::Discovered) !=
+ QNetworkConfiguration::Discovered) {
+ config = manager.defaultConfiguration();
+ }
+
+ m_webView->page()->networkAccessManager()->setConfiguration(config);
+ }
+
+ QTimer::singleShot(0, this, SLOT(initialize()));
+}
+
+void BrowserView::initialize()
+{
+ connect(m_zoomStrip, SIGNAL(zoomInClicked()), SLOT(zoomIn()));
+ connect(m_zoomStrip, SIGNAL(zoomOutClicked()), SLOT(zoomOut()));
+
+ connect(m_controlStrip, SIGNAL(menuClicked()), SIGNAL(menuButtonClicked()));
+ connect(m_controlStrip, SIGNAL(backClicked()), m_webView, SLOT(back()));
+ connect(m_controlStrip, SIGNAL(forwardClicked()), m_webView, SLOT(forward()));
+ connect(m_controlStrip, SIGNAL(closeClicked()), qApp, SLOT(quit()));
+
+ QPalette pal = m_webView->palette();
+ pal.setBrush(QPalette::Base, Qt::white);
+ m_webView->setPalette(pal);
+
+ FlickCharm *flickCharm = new FlickCharm(this);
+ flickCharm->activateOn(m_webView);
+
+ m_webView->setZoomFactor(static_cast<qreal>(m_currentZoom)/100.0);
+ connect(m_webView, SIGNAL(loadStarted()), SLOT(start()));
+ connect(m_webView, SIGNAL(loadProgress(int)), SLOT(setProgress(int)));
+ connect(m_webView, SIGNAL(loadFinished(bool)), SLOT(finish(bool)));
+ connect(m_webView, SIGNAL(urlChanged(QUrl)), SLOT(updateTitleBar()));
+
+ m_webView->setHtml("about:blank");
+ m_webView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_webView->setFocus();
+}
+
+void BrowserView::start()
+{
+ m_progress = 0;
+ updateTitleBar();
+ //m_titleBar->setText(m_webView->url().toString());
+}
+
+void BrowserView::setProgress(int percent)
+{
+ m_progress = percent;
+ updateTitleBar();
+ //m_titleBar->setText(QString("Loading %1%").arg(percent));
+}
+
+void BrowserView::updateTitleBar()
+{
+ QUrl url = m_webView->url();
+ m_titleBar->setHost(url.host());
+ m_titleBar->setTitle(m_webView->title());
+ m_titleBar->setProgress(m_progress);
+}
+
+void BrowserView::finish(bool ok)
+{
+ m_progress = 0;
+ updateTitleBar();
+
+ // TODO: handle error
+ if (!ok) {
+ //m_titleBar->setText("Loading failed.");
+ }
+}
+
+void BrowserView::zoomIn()
+{
+ int i = m_zoomLevels.indexOf(m_currentZoom);
+ Q_ASSERT(i >= 0);
+ if (i < m_zoomLevels.count() - 1)
+ m_currentZoom = m_zoomLevels[i + 1];
+
+ m_webView->setZoomFactor(static_cast<qreal>(m_currentZoom)/100.0);
+}
+
+void BrowserView::zoomOut()
+{
+ int i = m_zoomLevels.indexOf(m_currentZoom);
+ Q_ASSERT(i >= 0);
+ if (i > 0)
+ m_currentZoom = m_zoomLevels[i - 1];
+
+ m_webView->setZoomFactor(static_cast<qreal>(m_currentZoom)/100.0);
+}
+
+void BrowserView::resizeEvent(QResizeEvent *event)
+{
+ QWidget::resizeEvent(event);
+
+ int h1 = m_titleBar->sizeHint().height();
+ int h2 = m_controlStrip->sizeHint().height();
+
+ m_titleBar->setGeometry(0, 0, width(), h1);
+ m_controlStrip->setGeometry(0, height() - h2, width(), h2);
+ m_webView->setGeometry(0, h1, width(), height() - h1);
+
+ int zw = m_zoomStrip->sizeHint().width();
+ int zh = m_zoomStrip->sizeHint().height();
+ m_zoomStrip->move(width() - zw, (height() - zh) / 2);
+}
+
+void BrowserView::navigate(const QUrl &url)
+{
+ m_webView->load(url);
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/BrowserView.h b/examples/webkitwidgets/embedded/anomaly/src/BrowserView.h
new file mode 100644
index 0000000..51f5897
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/BrowserView.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BROWSERVIEW_H
+#define BROWSERVIEW_H
+
+#include <QWidget>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+class QUrl;
+QT_END_NAMESPACE
+
+class QWebView;
+class TitleBar;
+class ControlStrip;
+class WebView;
+class ZoomStrip;
+
+class BrowserView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ BrowserView(QWidget *parent = 0);
+
+public slots:
+ void navigate(const QUrl &url);
+ void zoomIn();
+ void zoomOut();
+
+private slots:
+ void initialize();
+ void start();
+ void setProgress(int percent);
+ void finish(bool);
+ void updateTitleBar();
+
+signals:
+ void menuButtonClicked();
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+
+private:
+ TitleBar *m_titleBar;
+ WebView *m_webView;
+ ZoomStrip *m_zoomStrip;
+ ControlStrip *m_controlStrip;
+ int m_progress;
+ int m_currentZoom;
+ QVector<int> m_zoomLevels;
+};
+
+#endif // BROWSERVIEW_H
+
diff --git a/examples/webkitwidgets/embedded/anomaly/src/BrowserWindow.cpp b/examples/webkitwidgets/embedded/anomaly/src/BrowserWindow.cpp
new file mode 100644
index 0000000..c380766
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/BrowserWindow.cpp
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "BrowserWindow.h"
+
+#include <QtCore>
+#include <QtWidgets>
+#include <QPropertyAnimation>
+#include <QResizeEvent>
+
+#include "BrowserView.h"
+#include "HomeView.h"
+
+BrowserWindow::BrowserWindow()
+ : m_slidingSurface(new QWidget(this))
+ , m_homeView(new HomeView(m_slidingSurface))
+ , m_browserView(new BrowserView(m_slidingSurface))
+ , m_animation(new QPropertyAnimation(this, "slideValue"))
+{
+ m_slidingSurface->setAutoFillBackground(true);
+
+ m_homeView->resize(size());
+
+ m_browserView->resize(size());
+
+ connect(m_homeView, SIGNAL(addressEntered(QString)), SLOT(gotoAddress(QString)));
+ connect(m_homeView, SIGNAL(urlActivated(QUrl)), SLOT(navigate(QUrl)));
+
+ connect(m_browserView, SIGNAL(menuButtonClicked()), SLOT(showHomeView()));
+
+ m_animation->setDuration(200);
+ connect(m_animation, SIGNAL(finished()), SLOT(animationFinished()));
+
+ setSlideValue(0.0f);
+}
+
+void BrowserWindow::gotoAddress(const QString &address)
+{
+ m_browserView->navigate(QUrl::fromUserInput(address));
+ showBrowserView();
+}
+
+void BrowserWindow::animationFinished()
+{
+ m_animation->setDirection(QAbstractAnimation::Forward);
+}
+
+void BrowserWindow::navigate(const QUrl &url)
+{
+ m_browserView->navigate(url);
+ showBrowserView();
+}
+
+void BrowserWindow::setSlideValue(qreal slideRatio)
+{
+ // we use a ratio to handle resize corectly
+ const int pos = -qRound(slideRatio * width());
+ m_slidingSurface->scroll(pos - m_homeView->x(), 0);
+
+ if (qFuzzyCompare(slideRatio, static_cast<qreal>(1.0f))) {
+ m_browserView->show();
+ m_homeView->hide();
+ } else if (qFuzzyCompare(slideRatio, static_cast<qreal>(0.0f))) {
+ m_homeView->show();
+ m_browserView->hide();
+ } else {
+ m_browserView->show();
+ m_homeView->show();
+ }
+}
+
+qreal BrowserWindow::slideValue() const
+{
+ Q_ASSERT(m_slidingSurface->x() < width());
+ return static_cast<qreal>(qAbs(m_homeView->x())) / width();
+}
+
+void BrowserWindow::showHomeView()
+{
+ m_animation->setStartValue(slideValue());
+ m_animation->setEndValue(0.0f);
+ m_animation->start();
+ m_homeView->setFocus();
+}
+
+void BrowserWindow::showBrowserView()
+{
+ m_animation->setStartValue(slideValue());
+ m_animation->setEndValue(1.0f);
+ m_animation->start();
+
+ m_browserView->setFocus();
+}
+
+void BrowserWindow::keyReleaseEvent(QKeyEvent *event)
+{
+ QWidget::keyReleaseEvent(event);
+
+ if (event->key() == Qt::Key_F3) {
+ if (m_animation->state() == QAbstractAnimation::Running) {
+ const QAbstractAnimation::Direction direction = m_animation->direction() == QAbstractAnimation::Forward
+ ? QAbstractAnimation::Forward
+ : QAbstractAnimation::Backward;
+ m_animation->setDirection(direction);
+ } else if (qFuzzyCompare(slideValue(), static_cast<qreal>(1.0f)))
+ showHomeView();
+ else
+ showBrowserView();
+ event->accept();
+ }
+}
+
+void BrowserWindow::resizeEvent(QResizeEvent *event)
+{
+ const QSize oldSize = event->oldSize();
+ const qreal oldSlidingRatio = static_cast<qreal>(qAbs(m_homeView->x())) / oldSize.width();
+
+ const QSize newSize = event->size();
+ m_slidingSurface->resize(newSize.width() * 2, newSize.height());
+
+ m_homeView->resize(newSize);
+ m_homeView->move(0, 0);
+
+ m_browserView->resize(newSize);
+ m_browserView->move(newSize.width(), 0);
+
+ setSlideValue(oldSlidingRatio);
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/BrowserWindow.h b/examples/webkitwidgets/embedded/anomaly/src/BrowserWindow.h
new file mode 100644
index 0000000..eb97f77
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/BrowserWindow.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BROWSERWINDOW_H
+#define BROWSERWINDOW_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QPropertyAnimation;
+class QUrl;
+QT_END_NAMESPACE
+
+class BrowserView;
+class HomeView;
+
+class BrowserWindow : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal slideValue READ slideValue WRITE setSlideValue)
+
+public:
+ BrowserWindow();
+
+private slots:
+ void navigate(const QUrl &url);
+ void gotoAddress(const QString &address);
+ void animationFinished();
+
+public slots:
+ void showBrowserView();
+ void showHomeView();
+
+protected:
+ void keyReleaseEvent(QKeyEvent *event);
+ void resizeEvent(QResizeEvent *event);
+
+private:
+ void setSlideValue(qreal);
+ qreal slideValue() const;
+
+ QWidget *m_slidingSurface;
+ HomeView *m_homeView;
+ BrowserView *m_browserView;
+ QPropertyAnimation *m_animation;
+};
+
+#endif // BROWSERWINDOW_H
diff --git a/examples/webkitwidgets/embedded/anomaly/src/ControlStrip.cpp b/examples/webkitwidgets/embedded/anomaly/src/ControlStrip.cpp
new file mode 100644
index 0000000..c5f2aee
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/ControlStrip.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ControlStrip.h"
+
+#include <QtCore>
+#include <QtWidgets>
+
+ControlStrip::ControlStrip(QWidget *parent)
+ : QWidget(parent)
+{
+ menuPixmap.load(":/images/edit-find.png");
+ backPixmap.load(":/images/go-previous.png");
+ forwardPixmap.load(":/images/go-next.png");
+ closePixmap.load(":/images/button-close.png");
+}
+
+QSize ControlStrip::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+QSize ControlStrip::minimumSizeHint() const
+{
+ return QSize(320, 48);
+}
+
+void ControlStrip::mousePressEvent(QMouseEvent *event)
+{
+ int h = height();
+ int spacing = qMin(h, (width() - h * 4) / 3);
+ int x = event->pos().x();
+
+ if (x < h) {
+ emit menuClicked();
+ event->accept();
+ return;
+ }
+
+ if (x > width() - h) {
+ emit closeClicked();
+ event->accept();
+ return;
+ }
+
+ if ((x < width() - (h + spacing)) && (x > width() - (h * 2 + spacing))) {
+ emit forwardClicked();
+ event->accept();
+ return;
+ }
+
+ if ((x < width() - (h * 2 + spacing * 2)) && (x > width() - (h * 3 + spacing * 2))) {
+ emit backClicked();
+ event->accept();
+ return;
+ }
+}
+
+void ControlStrip::paintEvent(QPaintEvent *event)
+{
+ int h = height();
+ int spacing = qMin(h, (width() - h * 4) / 3);
+ int s = (height() - menuPixmap.height()) / 2;
+
+ QPainter p(this);
+ p.fillRect(event->rect(), QColor(32, 32, 32, 192));
+ p.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ p.drawPixmap(s, s, menuPixmap);
+ p.drawPixmap(width() - h + s, s, closePixmap);
+ p.drawPixmap(width() - (h * 2 + spacing) + s, s, forwardPixmap);
+ p.drawPixmap(width() - (h * 3 + spacing * 2) + s, s, backPixmap);
+
+ p.end();
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/ControlStrip.h b/examples/webkitwidgets/embedded/anomaly/src/ControlStrip.h
new file mode 100644
index 0000000..8c37036
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/ControlStrip.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CONTROLSTRIP_H
+#define CONTROLSTRIP_H
+
+#include <QWidget>
+
+class ControlStrip : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ControlStrip(QWidget *parent = 0);
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+signals:
+ void menuClicked();
+ void backClicked();
+ void forwardClicked();
+ void closeClicked();
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+
+private:
+ QPixmap menuPixmap;
+ QPixmap backPixmap;
+ QPixmap forwardPixmap;
+ QPixmap closePixmap;
+};
+
+#endif // CONTROLSTRIP_H
diff --git a/examples/webkitwidgets/embedded/anomaly/src/HomeView.cpp b/examples/webkitwidgets/embedded/anomaly/src/HomeView.cpp
new file mode 100644
index 0000000..9bc0fee
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/HomeView.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "HomeView.h"
+
+#include <QtCore>
+#include <QtWidgets>
+
+#include "AddressBar.h"
+#include "BookmarksView.h"
+
+HomeView::HomeView(QWidget *parent)
+ : QWidget(parent)
+ , m_addressBar(0)
+{
+ m_addressBar = new AddressBar(parent);
+ connect(m_addressBar, SIGNAL(addressEntered(QString)), SLOT(gotoAddress(QString)));
+
+ m_bookmarks = new BookmarksView(parent);
+ connect(m_bookmarks, SIGNAL(urlSelected(QUrl)), SIGNAL(urlActivated(QUrl)));
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(4);
+ layout->setSpacing(4);
+ layout->addWidget(m_addressBar);
+ layout->addWidget(m_bookmarks);
+}
+
+void HomeView::gotoAddress(const QString &address)
+{
+ emit addressEntered(address);
+}
+
+void HomeView::focusInEvent(QFocusEvent *event)
+{
+ m_addressBar->setFocus();
+ QWidget::focusInEvent(event);
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/HomeView.h b/examples/webkitwidgets/embedded/anomaly/src/HomeView.h
new file mode 100644
index 0000000..bac25ae
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/HomeView.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HOMEVIEW_H
+#define HOMEVIEW_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QUrl;
+QT_END_NAMESPACE
+
+class AddressBar;
+class BookmarksView;
+
+class HomeView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ HomeView(QWidget *parent);
+
+signals:
+ void urlActivated(const QUrl &url);
+ void addressEntered(const QString &address);
+
+private slots:
+ void gotoAddress(const QString &address);
+
+protected:
+ void focusInEvent(QFocusEvent *event);
+
+private:
+ AddressBar *m_addressBar;
+ BookmarksView *m_bookmarks;
+};
+
+#endif // HOMEVIEW_H
diff --git a/examples/webkitwidgets/embedded/anomaly/src/Main.cpp b/examples/webkitwidgets/embedded/anomaly/src/Main.cpp
new file mode 100644
index 0000000..958738d
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/Main.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QtWidgets>
+#include <QtWebKitWidgets>
+
+#include "BrowserWindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ app.setApplicationName("Anomaly");
+ app.setApplicationVersion("0.0.0");
+
+ BrowserWindow window;
+ window.resize(360, 640);
+ window.show();
+ app.setStyle("windows");
+
+#ifdef QT_KEYPAD_NAVIGATION
+ QApplication::setNavigationMode(Qt::NavigationModeCursorAuto);
+#endif
+ return app.exec();
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/TitleBar.cpp b/examples/webkitwidgets/embedded/anomaly/src/TitleBar.cpp
new file mode 100644
index 0000000..c6a67e8
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/TitleBar.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "TitleBar.h"
+
+#include <QtCore>
+#include <QtWidgets>
+
+TitleBar::TitleBar(QWidget *parent)
+ : QWidget(parent)
+ , m_progress(0)
+{
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+}
+
+void TitleBar::setHost(const QString &host)
+{
+ m_host = host;
+ update();
+}
+
+void TitleBar::setTitle(const QString &title)
+{
+ m_title = title;
+ update();
+}
+
+void TitleBar::setProgress(int percent)
+{
+ m_progress = percent;
+ update();
+}
+
+QSize TitleBar::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+QSize TitleBar::minimumSizeHint() const
+{
+ QFontMetrics fm = fontMetrics();
+ return QSize(100, fm.height());
+}
+
+void TitleBar::paintEvent(QPaintEvent *event)
+{
+ QString title = m_host;
+ if (!m_title.isEmpty())
+ title.append(": ").append(m_title);
+
+ QPalette pal = palette();
+ QPainter p(this);
+ p.fillRect(event->rect(), pal.color(QPalette::Highlight));
+
+ if (m_progress > 0) {
+
+ QRect box = rect();
+ box.setLeft(16);
+ box.setWidth(width() - box.left() - 110);
+
+ p.setPen(pal.color(QPalette::HighlightedText));
+ p.setOpacity(0.8);
+ p.drawText(box, Qt::AlignLeft + Qt::AlignVCenter, title);
+
+ int x = width() - 100 - 5;
+ int y = 1;
+ int h = height() - 4;
+
+ p.setOpacity(1.0);
+ p.setBrush(Qt::NoBrush);
+ p.setPen(pal.color(QPalette::HighlightedText));
+ p.drawRect(x, y, 100, h);
+ p.setPen(Qt::NoPen);
+ p.setBrush(pal.color(QPalette::HighlightedText));
+ p.drawRect(x, y, m_progress, h);
+ } else {
+
+ QRect box = rect();
+ box.setLeft(16);
+ box.setWidth(width() - box.left() - 5);
+ p.setPen(pal.color(QPalette::HighlightedText));
+ p.drawText(box, Qt::AlignLeft + Qt::AlignVCenter, title);
+ }
+
+ p.end();
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/TitleBar.h b/examples/webkitwidgets/embedded/anomaly/src/TitleBar.h
new file mode 100644
index 0000000..9747f97
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/TitleBar.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TITLEBAR_H
+#define TITLEBAR_H
+
+#include <QWidget>
+
+class TitleBar : public QWidget
+{
+ Q_OBJECT
+
+public:
+ TitleBar(QWidget *parent = 0);
+
+ void setHost(const QString &host);
+ void setTitle(const QString &title);
+ void setProgress(int percent);
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+protected:
+ void paintEvent(QPaintEvent *event);
+
+private:
+ QString m_host;
+ QString m_title;
+ int m_progress;
+};
+
+#endif // TITLEBAR_H
diff --git a/examples/webkitwidgets/embedded/anomaly/src/ZoomStrip.cpp b/examples/webkitwidgets/embedded/anomaly/src/ZoomStrip.cpp
new file mode 100644
index 0000000..5b0b15e
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/ZoomStrip.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ZoomStrip.h"
+
+#include <QtCore>
+#include <QtWidgets>
+
+ZoomStrip::ZoomStrip(QWidget *parent)
+ : QWidget(parent)
+{
+ zoomInPixmap.load(":/images/list-add.png");
+ zoomOutPixmap.load(":/images/list-remove.png");
+}
+
+QSize ZoomStrip::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+QSize ZoomStrip::minimumSizeHint() const
+{
+ return QSize(48, 96);
+}
+
+void ZoomStrip::mousePressEvent(QMouseEvent *event)
+{
+ if (event->pos().y() < height() / 2)
+ emit zoomInClicked();
+ else
+ emit zoomOutClicked();
+}
+
+void ZoomStrip::paintEvent(QPaintEvent *event)
+{
+ int w = width();
+ int s = (w - zoomInPixmap.width()) / 2;
+
+ QPainter p(this);
+ p.fillRect(event->rect(), QColor(128, 128, 128, 128));
+ p.drawPixmap(s, s, zoomInPixmap);
+ p.drawPixmap(s, s + w, zoomOutPixmap);
+ p.end();
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/ZoomStrip.h b/examples/webkitwidgets/embedded/anomaly/src/ZoomStrip.h
new file mode 100644
index 0000000..a30b6a3
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/ZoomStrip.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ZOOMSTRIP_H
+#define ZOOMSTRIP_H
+
+#include <QWidget>
+
+class ZoomStrip : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ZoomStrip(QWidget *parent = 0);
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+signals:
+ void zoomInClicked();
+ void zoomOutClicked();
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+
+private:
+ QPixmap zoomInPixmap;
+ QPixmap zoomOutPixmap;
+};
+
+#endif // ZOOMSTRIP_H
diff --git a/examples/webkitwidgets/embedded/anomaly/src/anomaly.qrc b/examples/webkitwidgets/embedded/anomaly/src/anomaly.qrc
new file mode 100644
index 0000000..d8ea630
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/anomaly.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/" >
+ <file>images/go-next.png</file>
+ <file>images/go-previous.png</file>
+ <file>images/edit-find.png</file>
+ <file>images/list-add.png</file>
+ <file>images/list-remove.png</file>
+ <file>images/button-close.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/webkitwidgets/embedded/anomaly/src/flickcharm.cpp b/examples/webkitwidgets/embedded/anomaly/src/flickcharm.cpp
new file mode 100644
index 0000000..4e30ee8
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/flickcharm.cpp
@@ -0,0 +1,402 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "flickcharm.h"
+
+#include <QAbstractScrollArea>
+#include <QApplication>
+#include <QBasicTimer>
+#include <QEvent>
+#include <QHash>
+#include <QList>
+#include <QMouseEvent>
+#include <QScrollBar>
+#include <QTime>
+#include <QWebFrame>
+#include <QWebView>
+
+#include <QDebug>
+
+const int fingerAccuracyThreshold = 3;
+
+struct FlickData {
+ typedef enum {
+ Steady, // Interaction without scrolling
+ ManualScroll, // Scrolling manually with the finger on the screen
+ AutoScroll, // Scrolling automatically
+ AutoScrollAcceleration // Scrolling automatically but a finger is on the screen
+ } State;
+ State state;
+ QWidget *widget;
+ QPoint pressPos;
+ QPoint lastPos;
+ QPoint speed;
+ QTime speedTimer;
+ QList<QEvent*> ignored;
+ QTime accelerationTimer;
+ bool lastPosValid:1;
+ bool waitingAcceleration:1;
+
+ FlickData()
+ : lastPosValid(false)
+ , waitingAcceleration(false)
+ {}
+
+ void resetSpeed()
+ {
+ speed = QPoint();
+ lastPosValid = false;
+ }
+ void updateSpeed(const QPoint &newPosition)
+ {
+ if (lastPosValid) {
+ const int timeElapsed = speedTimer.elapsed();
+ if (timeElapsed) {
+ const QPoint newPixelDiff = (newPosition - lastPos);
+ const QPoint pixelsPerSecond = newPixelDiff * (1000 / timeElapsed);
+ // fingers are inacurates, we ignore small changes to avoid stopping the autoscroll because
+ // of a small horizontal offset when scrolling vertically
+ const int newSpeedY = (qAbs(pixelsPerSecond.y()) > fingerAccuracyThreshold) ? pixelsPerSecond.y() : 0;
+ const int newSpeedX = (qAbs(pixelsPerSecond.x()) > fingerAccuracyThreshold) ? pixelsPerSecond.x() : 0;
+ if (state == AutoScrollAcceleration) {
+ const int max = 4000; // px by seconds
+ const int oldSpeedY = speed.y();
+ const int oldSpeedX = speed.x();
+ if ((oldSpeedY <= 0 && newSpeedY <= 0) || (oldSpeedY >= 0 && newSpeedY >= 0)
+ && (oldSpeedX <= 0 && newSpeedX <= 0) || (oldSpeedX >= 0 && newSpeedX >= 0)) {
+ speed.setY(qBound(-max, (oldSpeedY + (newSpeedY / 4)), max));
+ speed.setX(qBound(-max, (oldSpeedX + (newSpeedX / 4)), max));
+ } else {
+ speed = QPoint();
+ }
+ } else {
+ const int max = 2500; // px by seconds
+ // we average the speed to avoid strange effects with the last delta
+ if (!speed.isNull()) {
+ speed.setX(qBound(-max, (speed.x() / 4) + (newSpeedX * 3 / 4), max));
+ speed.setY(qBound(-max, (speed.y() / 4) + (newSpeedY * 3 / 4), max));
+ } else {
+ speed = QPoint(newSpeedX, newSpeedY);
+ }
+ }
+ }
+ } else {
+ lastPosValid = true;
+ }
+ speedTimer.start();
+ lastPos = newPosition;
+ }
+
+ // scroll by dx, dy
+ // return true if the widget was scrolled
+ bool scrollWidget(const int dx, const int dy)
+ {
+ QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);
+ if (scrollArea) {
+ const int x = scrollArea->horizontalScrollBar()->value();
+ const int y = scrollArea->verticalScrollBar()->value();
+ scrollArea->horizontalScrollBar()->setValue(x - dx);
+ scrollArea->verticalScrollBar()->setValue(y - dy);
+ return (scrollArea->horizontalScrollBar()->value() != x
+ || scrollArea->verticalScrollBar()->value() != y);
+ }
+
+ QWebView *webView = qobject_cast<QWebView*>(widget);
+ if (webView) {
+ QWebFrame *frame = webView->page()->mainFrame();
+ const QPoint position = frame->scrollPosition();
+ frame->setScrollPosition(position - QPoint(dx, dy));
+ return frame->scrollPosition() != position;
+ }
+ return false;
+ }
+
+ bool scrollTo(const QPoint &newPosition)
+ {
+ const QPoint delta = newPosition - lastPos;
+ updateSpeed(newPosition);
+ return scrollWidget(delta.x(), delta.y());
+ }
+};
+
+class FlickCharmPrivate
+{
+public:
+ QHash<QWidget*, FlickData*> flickData;
+ QBasicTimer ticker;
+ QTime timeCounter;
+ void startTicker(QObject *object)
+ {
+ if (!ticker.isActive())
+ ticker.start(15, object);
+ timeCounter.start();
+ }
+};
+
+FlickCharm::FlickCharm(QObject *parent): QObject(parent)
+{
+ d = new FlickCharmPrivate;
+}
+
+FlickCharm::~FlickCharm()
+{
+ delete d;
+}
+
+void FlickCharm::activateOn(QWidget *widget)
+{
+ QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);
+ if (scrollArea) {
+ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ QWidget *viewport = scrollArea->viewport();
+
+ viewport->installEventFilter(this);
+ scrollArea->installEventFilter(this);
+
+ d->flickData.remove(viewport);
+ d->flickData[viewport] = new FlickData;
+ d->flickData[viewport]->widget = widget;
+ d->flickData[viewport]->state = FlickData::Steady;
+
+ return;
+ }
+
+ QWebView *webView = qobject_cast<QWebView*>(widget);
+ if (webView) {
+ QWebFrame *frame = webView->page()->mainFrame();
+ frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
+ frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
+
+ webView->installEventFilter(this);
+
+ d->flickData.remove(webView);
+ d->flickData[webView] = new FlickData;
+ d->flickData[webView]->widget = webView;
+ d->flickData[webView]->state = FlickData::Steady;
+
+ return;
+ }
+
+ qWarning() << "FlickCharm only works on QAbstractScrollArea (and derived classes)";
+ qWarning() << "or QWebView (and derived classes)";
+}
+
+void FlickCharm::deactivateFrom(QWidget *widget)
+{
+ QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);
+ if (scrollArea) {
+ QWidget *viewport = scrollArea->viewport();
+
+ viewport->removeEventFilter(this);
+ scrollArea->removeEventFilter(this);
+
+ delete d->flickData[viewport];
+ d->flickData.remove(viewport);
+
+ return;
+ }
+
+ QWebView *webView = qobject_cast<QWebView*>(widget);
+ if (webView) {
+ webView->removeEventFilter(this);
+
+ delete d->flickData[webView];
+ d->flickData.remove(webView);
+
+ return;
+ }
+}
+
+static QPoint deaccelerate(const QPoint &speed, const int deltatime)
+{
+ const int deltaSpeed = deltatime;
+
+ int x = speed.x();
+ int y = speed.y();
+ x = (x == 0) ? x : (x > 0) ? qMax(0, x - deltaSpeed) : qMin(0, x + deltaSpeed);
+ y = (y == 0) ? y : (y > 0) ? qMax(0, y - deltaSpeed) : qMin(0, y + deltaSpeed);
+ return QPoint(x, y);
+}
+
+bool FlickCharm::eventFilter(QObject *object, QEvent *event)
+{
+ if (!object->isWidgetType())
+ return false;
+
+ const QEvent::Type type = event->type();
+
+ switch (type) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease:
+ break;
+ case QEvent::MouseButtonDblClick: // skip double click
+ return true;
+ default:
+ return false;
+ }
+
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+ if (type == QEvent::MouseMove && mouseEvent->buttons() != Qt::LeftButton)
+ return false;
+
+ if (mouseEvent->modifiers() != Qt::NoModifier)
+ return false;
+
+ QWidget *viewport = qobject_cast<QWidget*>(object);
+ FlickData *data = d->flickData.value(viewport);
+ if (!viewport || !data || data->ignored.removeAll(event))
+ return false;
+
+ const QPoint mousePos = mouseEvent->pos();
+ bool consumed = false;
+ switch (data->state) {
+
+ case FlickData::Steady:
+ if (type == QEvent::MouseButtonPress) {
+ consumed = true;
+ data->pressPos = mousePos;
+ } else if (type == QEvent::MouseButtonRelease) {
+ consumed = true;
+ QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress,
+ data->pressPos, Qt::LeftButton,
+ Qt::LeftButton, Qt::NoModifier);
+ QMouseEvent *event2 = new QMouseEvent(QEvent::MouseButtonRelease,
+ data->pressPos, Qt::LeftButton,
+ Qt::LeftButton, Qt::NoModifier);
+
+ data->ignored << event1;
+ data->ignored << event2;
+ QApplication::postEvent(object, event1);
+ QApplication::postEvent(object, event2);
+ } else if (type == QEvent::MouseMove) {
+ consumed = true;
+ data->scrollTo(mousePos);
+
+ const QPoint delta = mousePos - data->pressPos;
+ if (delta.x() > fingerAccuracyThreshold || delta.y() > fingerAccuracyThreshold)
+ data->state = FlickData::ManualScroll;
+ }
+ break;
+
+ case FlickData::ManualScroll:
+ if (type == QEvent::MouseMove) {
+ consumed = true;
+ data->scrollTo(mousePos);
+ } else if (type == QEvent::MouseButtonRelease) {
+ consumed = true;
+ data->state = FlickData::AutoScroll;
+ data->lastPosValid = false;
+ d->startTicker(this);
+ }
+ break;
+
+ case FlickData::AutoScroll:
+ if (type == QEvent::MouseButtonPress) {
+ consumed = true;
+ data->state = FlickData::AutoScrollAcceleration;
+ data->waitingAcceleration = true;
+ data->accelerationTimer.start();
+ data->updateSpeed(mousePos);
+ data->pressPos = mousePos;
+ } else if (type == QEvent::MouseButtonRelease) {
+ consumed = true;
+ data->state = FlickData::Steady;
+ data->resetSpeed();
+ }
+ break;
+
+ case FlickData::AutoScrollAcceleration:
+ if (type == QEvent::MouseMove) {
+ consumed = true;
+ data->updateSpeed(mousePos);
+ data->accelerationTimer.start();
+ if (data->speed.isNull())
+ data->state = FlickData::ManualScroll;
+ } else if (type == QEvent::MouseButtonRelease) {
+ consumed = true;
+ data->state = FlickData::AutoScroll;
+ data->waitingAcceleration = false;
+ data->lastPosValid = false;
+ }
+ break;
+ default:
+ break;
+ }
+ data->lastPos = mousePos;
+ return true;
+}
+
+void FlickCharm::timerEvent(QTimerEvent *event)
+{
+ int count = 0;
+ QHashIterator<QWidget*, FlickData*> item(d->flickData);
+ while (item.hasNext()) {
+ item.next();
+ FlickData *data = item.value();
+ if (data->state == FlickData::AutoScrollAcceleration
+ && data->waitingAcceleration
+ && data->accelerationTimer.elapsed() > 40) {
+ data->state = FlickData::ManualScroll;
+ data->resetSpeed();
+ }
+ if (data->state == FlickData::AutoScroll || data->state == FlickData::AutoScrollAcceleration) {
+ const int timeElapsed = d->timeCounter.elapsed();
+ const QPoint delta = (data->speed) * timeElapsed / 1000;
+ bool hasScrolled = data->scrollWidget(delta.x(), delta.y());
+
+ if (data->speed.isNull() || !hasScrolled)
+ data->state = FlickData::Steady;
+ else
+ count++;
+ data->speed = deaccelerate(data->speed, timeElapsed);
+ }
+ }
+
+ if (!count)
+ d->ticker.stop();
+ else
+ d->timeCounter.start();
+
+ QObject::timerEvent(event);
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/flickcharm.h b/examples/webkitwidgets/embedded/anomaly/src/flickcharm.h
new file mode 100644
index 0000000..8042ecd
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/flickcharm.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FLICKCHARM_H
+#define FLICKCHARM_H
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+class FlickCharmPrivate;
+
+class FlickCharm: public QObject
+{
+ Q_OBJECT
+public:
+ FlickCharm(QObject *parent = 0);
+ ~FlickCharm();
+ void activateOn(QWidget *widget);
+ void deactivateFrom(QWidget *widget);
+ bool eventFilter(QObject *object, QEvent *event);
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private:
+ FlickCharmPrivate *d;
+};
+
+#endif // FLICKCHARM_H
diff --git a/examples/webkitwidgets/embedded/anomaly/src/images/button-close.png b/examples/webkitwidgets/embedded/anomaly/src/images/button-close.png
new file mode 100644
index 0000000..7a7b048
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/images/button-close.png
Binary files differ
diff --git a/examples/webkitwidgets/embedded/anomaly/src/images/edit-find.png b/examples/webkitwidgets/embedded/anomaly/src/images/edit-find.png
new file mode 100644
index 0000000..b84b1e2
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/images/edit-find.png
Binary files differ
diff --git a/examples/webkitwidgets/embedded/anomaly/src/images/go-next.png b/examples/webkitwidgets/embedded/anomaly/src/images/go-next.png
new file mode 100644
index 0000000..ed89a36
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/images/go-next.png
Binary files differ
diff --git a/examples/webkitwidgets/embedded/anomaly/src/images/go-previous.png b/examples/webkitwidgets/embedded/anomaly/src/images/go-previous.png
new file mode 100644
index 0000000..44e803d
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/images/go-previous.png
Binary files differ
diff --git a/examples/webkitwidgets/embedded/anomaly/src/images/list-add.png b/examples/webkitwidgets/embedded/anomaly/src/images/list-add.png
new file mode 100644
index 0000000..2acdd8f
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/images/list-add.png
Binary files differ
diff --git a/examples/webkitwidgets/embedded/anomaly/src/images/list-remove.png b/examples/webkitwidgets/embedded/anomaly/src/images/list-remove.png
new file mode 100644
index 0000000..c5524f7
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/images/list-remove.png
Binary files differ
diff --git a/examples/webkitwidgets/embedded/anomaly/src/webview.cpp b/examples/webkitwidgets/embedded/anomaly/src/webview.cpp
new file mode 100644
index 0000000..03d9ced
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/webview.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "webview.h"
+
+#include <QPaintEvent>
+#include <QWebFrame>
+
+WebView::WebView(QWidget *parent)
+ : QWebView(parent)
+ , inLoading(false)
+{
+ connect(this, SIGNAL(loadStarted()), this, SLOT(newPageLoading()));
+ connect(this, SIGNAL(loadFinished(bool)), this, SLOT(pageLoaded(bool)));
+ page()->setPreferredContentsSize(QSize(1024, 768));
+}
+
+void WebView::paintEvent(QPaintEvent *event)
+{
+ if (inLoading && loadingTime.elapsed() < 750) {
+ QPainter painter(this);
+ painter.setBrush(Qt::white);
+ painter.setPen(Qt::NoPen);
+ foreach (const QRect &rect, event->region().rects()) {
+ painter.drawRect(rect);
+ }
+ } else {
+ QWebView::paintEvent(event);
+ }
+}
+
+void WebView::newPageLoading()
+{
+ inLoading = true;
+ loadingTime.start();
+}
+
+void WebView::pageLoaded(bool)
+{
+ inLoading = false;
+ update();
+}
diff --git a/examples/webkitwidgets/embedded/anomaly/src/webview.h b/examples/webkitwidgets/embedded/anomaly/src/webview.h
new file mode 100644
index 0000000..d7d4193
--- /dev/null
+++ b/examples/webkitwidgets/embedded/anomaly/src/webview.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WEBVIEW_H
+#define WEBVIEW_H
+
+#include <QWebView>
+#include <QTime>
+
+class WebView : public QWebView
+{
+ Q_OBJECT
+public:
+ WebView(QWidget *parent = 0);
+
+protected:
+ void paintEvent(QPaintEvent *event);
+
+private slots:
+ void newPageLoading();
+ void pageLoaded(bool ok);
+
+private:
+ QTime loadingTime;
+ bool inLoading;
+};
+
+#endif // WEBVIEW_H
diff --git a/examples/webkitwidgets/embedded/embedded.pro b/examples/webkitwidgets/embedded/embedded.pro
new file mode 100644
index 0000000..9c61eec
--- /dev/null
+++ b/examples/webkitwidgets/embedded/embedded.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += anomaly
diff --git a/examples/webkitwidgets/fancybrowser/doc/images/fancybrowser-example.png b/examples/webkitwidgets/fancybrowser/doc/images/fancybrowser-example.png
new file mode 100644
index 0000000..717ac9d
--- /dev/null
+++ b/examples/webkitwidgets/fancybrowser/doc/images/fancybrowser-example.png
Binary files differ
diff --git a/examples/webkitwidgets/fancybrowser/doc/src/fancybrowser.qdoc b/examples/webkitwidgets/fancybrowser/doc/src/fancybrowser.qdoc
new file mode 100644
index 0000000..7734478
--- /dev/null
+++ b/examples/webkitwidgets/fancybrowser/doc/src/fancybrowser.qdoc
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example fancybrowser
+ \title Fancy Browser Example
+
+ \brief The Fancy Browser example shows how to use JQuery with QtWebKit to
+ create a web browser with special effects and content
+ manipulation.
+
+ \image fancybrowser-example.png
+
+ The application makes use of QWebFrame::evaluateJavaScript to
+ evaluate the jQuery JavaScript code. A QMainWindow with a QWebView
+ as central widget builds up the browser itself.
+
+ \section1 MainWindow Class Definition
+
+ The \c MainWindow class inherits QMainWindow. It implements a number of
+ slots to perform actions on both the application and on the web content.
+
+ \snippet fancybrowser/mainwindow.h 1
+
+ We also declare a QString that contains the jQuery, a QWebView
+ that displays the web content, and a QLineEdit that acts as the
+ address bar.
+
+ \section1 MainWindow Class Implementation
+
+ We start by implementing the constructor.
+
+ \snippet fancybrowser/mainwindow.cpp 1
+
+ The first part of the constructor sets the value of \c progress to
+ 0. This value will be used later in the code to visualize the
+ loading of a webpage.
+
+ Next, the jQuery library is loaded using a QFile and reading the file
+ content. The jQuery library is a JavaScript library that provides different
+ functions for manipulating HTML.
+
+ \snippet fancybrowser/mainwindow.cpp 2
+
+ The second part of the constructor creates a QWebView and connects
+ slots to the views signals. Furthermore, we create a QLineEdit as
+ the browsers address bar. We then set the horizontal QSizePolicy
+ to fill the available area in the browser at all times. We add the
+ QLineEdit to a QToolbar together with a set of navigation actions
+ from QWebView::pageAction.
+
+ \snippet fancybrowser/mainwindow.cpp 3
+
+ The third and last part of the constructor implements two QMenus and assigns
+ a set of actions to them. The last line sets the QWebView as the central
+ widget in the QMainWindow.
+
+ \snippet fancybrowser/mainwindow.cpp 4
+
+ When the page is loaded, \c adjustLocation() updates the address
+ bar; \c adjustLocation() is triggered by the \c loadFinished()
+ signal in QWebView. In \c changeLocation() we create a QUrl
+ object, and then use it to load the page into the QWebView. When
+ the new web page has finished loading, \c adjustLocation() will be
+ run once more to update the address bar.
+
+ \snippet fancybrowser/mainwindow.cpp 5
+
+ \c adjustTitle() sets the window title and displays the loading
+ progress. This slot is triggered by the \c titleChanged() signal
+ in QWebView.
+
+ \snippet fancybrowser/mainwindow.cpp 6
+
+ When a web page has loaded, \c finishLoading() is triggered by the
+ \c loadFinished() signal in QWebView. \c finishLoading() then updates the
+ progress in the title bar and calls \c evaluateJavaScript() to evaluate the
+ jQuery library. This evaluates the JavaScript against the current web page.
+ What that means is that the JavaScript can be viewed as part of the content
+ loaded into the QWebView, and therefore needs to be loaded every time a new
+ page is loaded. Once the jQuery library is loaded, we can start executing
+ the different jQuery functions in the browser.
+
+ The rotateImages() function is then called explicitely to make sure
+ that the images of the newly loaded page respect the state of the toggle
+ action.
+
+ \snippet fancybrowser/mainwindow.cpp 7
+
+ The first jQuery-based function, \c highlightAllLinks(), is designed to
+ highlight all links in the current webpage. The JavaScript code looks
+ for web elements named \e {a}, which is the tag for a hyperlink.
+ For each such element, the background color is set to be yellow by
+ using CSS.
+
+ \snippet fancybrowser/mainwindow.cpp 8
+
+ The \c rotateImages() function rotates the images on the current
+ web page. Webkit supports CSS transforms and this JavaScript code
+ looks up all \e {img} elements and rotates the images 180 degrees
+ and then back again.
+
+ \snippet fancybrowser/mainwindow.cpp 9
+
+ The remaining four methods remove different elements from the current web
+ page. \c removeGifImages() removes all GIF images on the page by looking up
+ the \e {src} attribute of all the elements on the web page. Any element with
+ a \e {gif} file as its source is removed. \c removeInlineFrames() removes all
+ \e {iframe} or inline elements. \c removeObjectElements() removes all
+ \e {object} elements, and \c removeEmbeddedElements() removes any elements
+ such as plugins embedded on the page using the \e {embed} tag.
+
+*/
+
diff --git a/examples/webkitwidgets/fancybrowser/fancybrowser.pro b/examples/webkitwidgets/fancybrowser/fancybrowser.pro
new file mode 100644
index 0000000..81938ec
--- /dev/null
+++ b/examples/webkitwidgets/fancybrowser/fancybrowser.pro
@@ -0,0 +1,9 @@
+QT += webkitwidgets network widgets
+HEADERS = mainwindow.h
+SOURCES = main.cpp \
+ mainwindow.cpp
+RESOURCES = jquery.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/fancybrowser
+INSTALLS += target
diff --git a/examples/webkitwidgets/fancybrowser/jquery.min.js b/examples/webkitwidgets/fancybrowser/jquery.min.js
new file mode 100644
index 0000000..b1ae21d
--- /dev/null
+++ b/examples/webkitwidgets/fancybrowser/jquery.min.js
@@ -0,0 +1,19 @@
+/*
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ * Copyright 2009, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML=' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file
diff --git a/examples/webkitwidgets/fancybrowser/jquery.qrc b/examples/webkitwidgets/fancybrowser/jquery.qrc
new file mode 100644
index 0000000..1022d68
--- /dev/null
+++ b/examples/webkitwidgets/fancybrowser/jquery.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/" >
+ <file>jquery.min.js</file>
+ </qresource>
+</RCC>
diff --git a/examples/webkitwidgets/fancybrowser/main.cpp b/examples/webkitwidgets/fancybrowser/main.cpp
new file mode 100644
index 0000000..f671a7d
--- /dev/null
+++ b/examples/webkitwidgets/fancybrowser/main.cpp
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+#include "mainwindow.h"
+
+int main(int argc, char * argv[])
+{
+ QApplication app(argc, argv);
+ QUrl url;
+ if (argc > 1)
+ url = QUrl::fromUserInput(argv[1]);
+ else
+ url = QUrl("http://www.google.com/ncr");
+ MainWindow *browser = new MainWindow(url);
+ browser->show();
+ return app.exec();
+}
diff --git a/examples/webkitwidgets/fancybrowser/mainwindow.cpp b/examples/webkitwidgets/fancybrowser/mainwindow.cpp
new file mode 100644
index 0000000..da6b070
--- /dev/null
+++ b/examples/webkitwidgets/fancybrowser/mainwindow.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+#include <QtNetwork>
+#include <QtWebKitWidgets>
+#include "mainwindow.h"
+
+//! [1]
+
+MainWindow::MainWindow(const QUrl& url)
+{
+ progress = 0;
+
+ QFile file;
+ file.setFileName(":/jquery.min.js");
+ file.open(QIODevice::ReadOnly);
+ jQuery = file.readAll();
+ file.close();
+//! [1]
+
+ QNetworkProxyFactory::setUseSystemConfiguration(true);
+
+//! [2]
+ view = new QWebView(this);
+ view->load(url);
+ connect(view, SIGNAL(loadFinished(bool)), SLOT(adjustLocation()));
+ connect(view, SIGNAL(titleChanged(QString)), SLOT(adjustTitle()));
+ connect(view, SIGNAL(loadProgress(int)), SLOT(setProgress(int)));
+ connect(view, SIGNAL(loadFinished(bool)), SLOT(finishLoading(bool)));
+
+ locationEdit = new QLineEdit(this);
+ locationEdit->setSizePolicy(QSizePolicy::Expanding, locationEdit->sizePolicy().verticalPolicy());
+ connect(locationEdit, SIGNAL(returnPressed()), SLOT(changeLocation()));
+
+ QToolBar *toolBar = addToolBar(tr("Navigation"));
+ toolBar->addAction(view->pageAction(QWebPage::Back));
+ toolBar->addAction(view->pageAction(QWebPage::Forward));
+ toolBar->addAction(view->pageAction(QWebPage::Reload));
+ toolBar->addAction(view->pageAction(QWebPage::Stop));
+ toolBar->addWidget(locationEdit);
+//! [2]
+
+ QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
+ QAction* viewSourceAction = new QAction("Page Source", this);
+ connect(viewSourceAction, SIGNAL(triggered()), SLOT(viewSource()));
+ viewMenu->addAction(viewSourceAction);
+
+//! [3]
+ QMenu *effectMenu = menuBar()->addMenu(tr("&Effect"));
+ effectMenu->addAction("Highlight all links", this, SLOT(highlightAllLinks()));
+
+ rotateAction = new QAction(this);
+ rotateAction->setIcon(style()->standardIcon(QStyle::SP_FileDialogDetailedView));
+ rotateAction->setCheckable(true);
+ rotateAction->setText(tr("Turn images upside down"));
+ connect(rotateAction, SIGNAL(toggled(bool)), this, SLOT(rotateImages(bool)));
+ effectMenu->addAction(rotateAction);
+
+ QMenu *toolsMenu = menuBar()->addMenu(tr("&Tools"));
+ toolsMenu->addAction(tr("Remove GIF images"), this, SLOT(removeGifImages()));
+ toolsMenu->addAction(tr("Remove all inline frames"), this, SLOT(removeInlineFrames()));
+ toolsMenu->addAction(tr("Remove all object elements"), this, SLOT(removeObjectElements()));
+ toolsMenu->addAction(tr("Remove all embedded elements"), this, SLOT(removeEmbeddedElements()));
+
+ setCentralWidget(view);
+ setUnifiedTitleAndToolBarOnMac(true);
+}
+//! [3]
+
+void MainWindow::viewSource()
+{
+ QNetworkAccessManager* accessManager = view->page()->networkAccessManager();
+ QNetworkRequest request(view->url());
+ QNetworkReply* reply = accessManager->get(request);
+ connect(reply, SIGNAL(finished()), this, SLOT(slotSourceDownloaded()));
+}
+
+void MainWindow::slotSourceDownloaded()
+{
+ QNetworkReply* reply = qobject_cast<QNetworkReply*>(const_cast<QObject*>(sender()));
+ QTextEdit* textEdit = new QTextEdit(NULL);
+ textEdit->setAttribute(Qt::WA_DeleteOnClose);
+ textEdit->show();
+ textEdit->setPlainText(reply->readAll());
+ reply->deleteLater();
+}
+
+//! [4]
+void MainWindow::adjustLocation()
+{
+ locationEdit->setText(view->url().toString());
+}
+
+void MainWindow::changeLocation()
+{
+ QUrl url = QUrl::fromUserInput(locationEdit->text());
+ view->load(url);
+ view->setFocus();
+}
+//! [4]
+
+//! [5]
+void MainWindow::adjustTitle()
+{
+ if (progress <= 0 || progress >= 100)
+ setWindowTitle(view->title());
+ else
+ setWindowTitle(QString("%1 (%2%)").arg(view->title()).arg(progress));
+}
+
+void MainWindow::setProgress(int p)
+{
+ progress = p;
+ adjustTitle();
+}
+//! [5]
+
+//! [6]
+void MainWindow::finishLoading(bool)
+{
+ progress = 100;
+ adjustTitle();
+ view->page()->mainFrame()->evaluateJavaScript(jQuery);
+
+ rotateImages(rotateAction->isChecked());
+}
+//! [6]
+
+//! [7]
+void MainWindow::highlightAllLinks()
+{
+ // We append '; undefined' after the jQuery call here to prevent a possible recursion loop and crash caused by
+ // the way the elements returned by the each iterator elements reference each other, which causes problems upon
+ // converting them to QVariants.
+ QString code = "$('a').each( function () { $(this).css('background-color', 'yellow') } ); undefined";
+ view->page()->mainFrame()->evaluateJavaScript(code);
+}
+//! [7]
+
+//! [8]
+void MainWindow::rotateImages(bool invert)
+{
+ QString code;
+
+ // We append '; undefined' after each of the jQuery calls here to prevent a possible recursion loop and crash caused by
+ // the way the elements returned by the each iterator elements reference each other, which causes problems upon
+ // converting them to QVariants.
+ if (invert)
+ code = "$('img').each( function () { $(this).css('-webkit-transition', '-webkit-transform 2s'); $(this).css('-webkit-transform', 'rotate(180deg)') } ); undefined";
+ else
+ code = "$('img').each( function () { $(this).css('-webkit-transition', '-webkit-transform 2s'); $(this).css('-webkit-transform', 'rotate(0deg)') } ); undefined";
+ view->page()->mainFrame()->evaluateJavaScript(code);
+}
+//! [8]
+
+//! [9]
+void MainWindow::removeGifImages()
+{
+ QString code = "$('[src*=gif]').remove()";
+ view->page()->mainFrame()->evaluateJavaScript(code);
+}
+
+void MainWindow::removeInlineFrames()
+{
+ QString code = "$('iframe').remove()";
+ view->page()->mainFrame()->evaluateJavaScript(code);
+}
+
+void MainWindow::removeObjectElements()
+{
+ QString code = "$('object').remove()";
+ view->page()->mainFrame()->evaluateJavaScript(code);
+}
+
+void MainWindow::removeEmbeddedElements()
+{
+ QString code = "$('embed').remove()";
+ view->page()->mainFrame()->evaluateJavaScript(code);
+}
+//! [9]
+
diff --git a/examples/webkitwidgets/fancybrowser/mainwindow.h b/examples/webkitwidgets/fancybrowser/mainwindow.h
new file mode 100644
index 0000000..fabb6a0
--- /dev/null
+++ b/examples/webkitwidgets/fancybrowser/mainwindow.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+
+class QWebView;
+QT_BEGIN_NAMESPACE
+class QLineEdit;
+QT_END_NAMESPACE
+
+//! [1]
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(const QUrl& url);
+
+protected slots:
+
+ void adjustLocation();
+ void changeLocation();
+ void adjustTitle();
+ void setProgress(int p);
+ void finishLoading(bool);
+
+ void viewSource();
+ void slotSourceDownloaded();
+
+ void highlightAllLinks();
+ void rotateImages(bool invert);
+ void removeGifImages();
+ void removeInlineFrames();
+ void removeObjectElements();
+ void removeEmbeddedElements();
+
+private:
+ QString jQuery;
+ QWebView *view;
+ QLineEdit *locationEdit;
+ QAction *rotateAction;
+ int progress;
+//! [1]
+};
diff --git a/examples/webkitwidgets/formextractor/doc/images/formextractor-example.png b/examples/webkitwidgets/formextractor/doc/images/formextractor-example.png
new file mode 100644
index 0000000..155cdaa
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/doc/images/formextractor-example.png
Binary files differ
diff --git a/examples/webkitwidgets/formextractor/doc/src/formextractor.qdoc b/examples/webkitwidgets/formextractor/doc/src/formextractor.qdoc
new file mode 100644
index 0000000..5b27054
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/doc/src/formextractor.qdoc
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example formextractor
+ \title Form Extractor Example
+
+ \brief The Form Extractor example shows how to use QWebFrame with JavaScript to
+ extract form data.
+
+ \image formextractor-example.png
+
+*/
diff --git a/examples/webkitwidgets/formextractor/form.html b/examples/webkitwidgets/formextractor/form.html
new file mode 100755
index 0000000..6b0bbde
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/form.html
@@ -0,0 +1,46 @@
+<html><body>
+<h1>
+The Green People Book Club
+</h1>
+
+<p>
+Welcome to The Green People Book Club. Please register to obtain a membership with us.
+</p>
+ <form onsubmit="formExtractor.submit()">
+ <table>
+ <tbody><tr>
+ <td>
+ First name:
+ </td>
+ <td>
+ <input type="text" id="firstname">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Last name:
+ </td>
+ <td>
+ <input type="text" id="lastname">
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Gender:
+ </td>
+ <td>
+ <input type="radio" name="gender" id="genderMale" value="Male"> Male
+ <input type="radio" name="gender" id="genderFemale" value="Female"> Female
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <input type="checkbox" id="updates" value="receive">
+ Check here if you would like to receive regular updates from us:
+ </td>
+ </tr>
+ </tbody></table>
+ <input type="submit" value="Submit">
+ </form>
+
+</body></html>
diff --git a/examples/webkitwidgets/formextractor/formextractor.cpp b/examples/webkitwidgets/formextractor/formextractor.cpp
new file mode 100644
index 0000000..28f6abf
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/formextractor.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "formextractor.h"
+
+#include <QWebElement>
+
+FormExtractor::FormExtractor(QWidget *parent, Qt::WindowFlags flags)
+ : QWidget(parent, flags)
+{
+ ui.setupUi(this);
+ ui.webView->setUrl(QUrl("qrc:/form.html"));
+ connect(ui.webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
+ this, SLOT(populateJavaScriptWindowObject()));
+ resize(300, 300);
+}
+
+FormExtractor::~FormExtractor()
+{
+}
+
+void FormExtractor::submit()
+{
+ QWebFrame *frame = ui.webView->page()->mainFrame();
+
+ QWebElement firstName = frame->findFirstElement("#firstname");
+ QWebElement lastName = frame->findFirstElement("#lastname");
+ QWebElement maleGender = frame->findFirstElement("#genderMale");
+ QWebElement femaleGender = frame->findFirstElement("#genderFemale");
+ QWebElement updates = frame->findFirstElement("#updates");
+
+ ui.firstNameEdit->setText(firstName.evaluateJavaScript("this.value").toString());
+ ui.lastNameEdit->setText(lastName.evaluateJavaScript("this.value").toString());
+
+ if (maleGender.evaluateJavaScript("this.checked").toBool())
+ ui.genderEdit->setText(maleGender.evaluateJavaScript("this.value").toString());
+ else if (femaleGender.evaluateJavaScript("this.checked").toBool())
+ ui.genderEdit->setText(femaleGender.evaluateJavaScript("this.value").toString());
+
+ if (updates.evaluateJavaScript("this.checked").toBool())
+ ui.updatesEdit->setText("Yes");
+ else
+ ui.updatesEdit->setText("No");
+}
+
+void FormExtractor::populateJavaScriptWindowObject()
+{
+ ui.webView->page()->mainFrame()->addToJavaScriptWindowObject("formExtractor", this);
+}
diff --git a/examples/webkitwidgets/formextractor/formextractor.h b/examples/webkitwidgets/formextractor/formextractor.h
new file mode 100644
index 0000000..ff62f8c
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/formextractor.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FORMEXTRACTOR_H
+#define FORMEXTRACTOR_H
+
+#include <QtWidgets/QWidget>
+#include <QWebFrame>
+#include "ui_formextractor.h"
+
+class FormExtractor : public QWidget
+{
+ Q_OBJECT
+
+public:
+ FormExtractor(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~FormExtractor();
+
+public slots:
+ void submit();
+ void populateJavaScriptWindowObject();
+
+private:
+ Ui::Form ui;
+};
+
+#endif // FORMEXTRACTOR_H
diff --git a/examples/webkitwidgets/formextractor/formextractor.pro b/examples/webkitwidgets/formextractor/formextractor.pro
new file mode 100644
index 0000000..050ac89
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/formextractor.pro
@@ -0,0 +1,14 @@
+QT += webkitwidgets network widgets
+TARGET = formextractor
+TEMPLATE = app
+SOURCES += main.cpp \
+ formextractor.cpp \
+ mainwindow.cpp
+HEADERS += formextractor.h \
+ mainwindow.h
+FORMS += formextractor.ui
+RESOURCES += formextractor.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/formextractor
+INSTALLS += target
diff --git a/examples/webkitwidgets/formextractor/formextractor.qrc b/examples/webkitwidgets/formextractor/formextractor.qrc
new file mode 100644
index 0000000..e35f4b2
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/formextractor.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+ <qresource>
+ <file>form.html</file>
+ </qresource>
+ </RCC> \ No newline at end of file
diff --git a/examples/webkitwidgets/formextractor/formextractor.ui b/examples/webkitwidgets/formextractor/formextractor.ui
new file mode 100644
index 0000000..5c4afec
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/formextractor.ui
@@ -0,0 +1,159 @@
+<ui version="4.0" >
+ <class>Form</class>
+ <widget class="QWidget" name="Form" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>680</width>
+ <height>218</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QGroupBox" name="webFormGroupBox" >
+ <property name="title" >
+ <string>Web Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QWebView" name="webView" >
+ <property name="minimumSize" >
+ <size>
+ <width>200</width>
+ <height>150</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>400</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="url" >
+ <url>
+ <string>about:blank</string>
+ </url>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>28</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="dataGroupBox" >
+ <property name="title" >
+ <string>Extracted Data</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3" >
+ <item>
+ <layout class="QFormLayout" name="formLayout" >
+ <property name="fieldGrowthPolicy" >
+ <enum>QFormLayout::FieldsStayAtSizeHint</enum>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="firstNameLabel" >
+ <property name="text" >
+ <string>First Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="firstNameEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="lastNameLabel" >
+ <property name="text" >
+ <string>Last Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="lastNameEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="genderLabel" >
+ <property name="text" >
+ <string>Gender</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="genderEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="updatesLabel" >
+ <property name="text" >
+ <string>Receive Updates</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="updatesEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>24</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QWebView</class>
+ <extends>QWidget</extends>
+ <header>QtWebKit/QWebView</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/webkitwidgets/formextractor/main.cpp b/examples/webkitwidgets/formextractor/main.cpp
new file mode 100644
index 0000000..8dae190
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/main.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets/QApplication>
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ Q_INIT_RESOURCE(formextractor);
+ QApplication app(argc, argv);
+ MainWindow mainWindow;
+ mainWindow.setWindowTitle("Form Extractor");
+ mainWindow.show();
+ return app.exec();
+}
diff --git a/examples/webkitwidgets/formextractor/mainwindow.cpp b/examples/webkitwidgets/formextractor/mainwindow.cpp
new file mode 100644
index 0000000..9e52ce8
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/mainwindow.cpp
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+#include "mainwindow.h"
+
+MainWindow::MainWindow()
+{
+ createActions();
+ createMenus();
+ centralWidget = new FormExtractor(this);
+ setCentralWidget(centralWidget);
+ setUnifiedTitleAndToolBarOnMac(true);
+}
+
+void MainWindow::createActions()
+{
+ exitAct = new QAction(tr("E&xit"), this);
+ exitAct->setStatusTip(tr("Exit the application"));
+ exitAct->setShortcuts(QKeySequence::Quit);
+ connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
+
+ aboutAct = new QAction(tr("&About"), this);
+ aboutAct->setStatusTip(tr("Show the application's About box"));
+ connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
+
+ aboutQtAct = new QAction(tr("About &Qt"), this);
+ aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
+ connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
+}
+
+void MainWindow::createMenus()
+{
+ fileMenu = menuBar()->addMenu(tr("&File"));
+ fileMenu->addAction(exitAct);
+
+ menuBar()->addSeparator();
+
+ helpMenu = menuBar()->addMenu(tr("&Help"));
+ helpMenu->addAction(aboutAct);
+ helpMenu->addAction(aboutQtAct);
+}
+
+void MainWindow::about()
+{
+ QMessageBox::about(this, tr("About Form Extractor"),
+ tr("The <b>Form Extractor</b> example demonstrates how to "
+ "extract data from a web form using QtWebKit."));
+
+}
diff --git a/examples/webkitwidgets/formextractor/mainwindow.h b/examples/webkitwidgets/formextractor/mainwindow.h
new file mode 100644
index 0000000..cd4e8a6
--- /dev/null
+++ b/examples/webkitwidgets/formextractor/mainwindow.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include "formextractor.h"
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QMenu;
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+private slots:
+ void about();
+
+private:
+ FormExtractor *centralWidget;
+ QMenu *fileMenu;
+ QMenu *helpMenu;
+ QAction *exitAct;
+ QAction *aboutAct;
+ QAction *aboutQtAct;
+
+ void createActions();
+ void createMenus();
+};
+
+#endif // MAINWINDOW_H
diff --git a/examples/webkitwidgets/framecapture/framecapture.cpp b/examples/webkitwidgets/framecapture/framecapture.cpp
new file mode 100644
index 0000000..0b3441c
--- /dev/null
+++ b/examples/webkitwidgets/framecapture/framecapture.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "framecapture.h"
+
+#include <iostream>
+
+FrameCapture::FrameCapture(): QObject(), m_percent(0)
+{
+ connect(&m_page, SIGNAL(loadProgress(int)), this, SLOT(printProgress(int)));
+ connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(saveResult(bool)));
+}
+
+void FrameCapture::load(const QUrl &url, const QString &outputFileName)
+{
+ std::cout << "Loading " << qPrintable(url.toString()) << std::endl;
+ m_percent = 0;
+ int index = outputFileName.lastIndexOf('.');
+ m_fileName = (index == -1) ? outputFileName + ".png" : outputFileName;
+ m_page.mainFrame()->load(url);
+ m_page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
+ m_page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
+ m_page.setViewportSize(QSize(1024, 768));
+}
+
+void FrameCapture::printProgress(int percent)
+{
+ if (m_percent >= percent)
+ return;
+
+ while (m_percent++ < percent)
+ std::cout << "#" << std::flush;
+}
+
+void FrameCapture::saveResult(bool ok)
+{
+ std::cout << std::endl;
+
+ // crude error-checking
+ if (!ok) {
+ std::cerr << "Failed loading " << qPrintable(m_page.mainFrame()->url().toString()) << std::endl;
+ emit finished();
+ return;
+ }
+
+ // save each frame in different image files
+ saveFrame(m_page.mainFrame());
+
+ emit finished();
+}
+
+void FrameCapture::saveFrame(QWebFrame *frame)
+{
+ static int frameCounter = 0;
+
+ QString fileName(m_fileName);
+ if (frameCounter) {
+ int index = m_fileName.lastIndexOf('.');
+ fileName = fileName.insert(index, "_frame" + QString::number(frameCounter));
+ }
+
+ QImage image(frame->contentsSize(), QImage::Format_ARGB32_Premultiplied);
+ image.fill(Qt::transparent);
+
+ QPainter painter(&image);
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.setRenderHint(QPainter::TextAntialiasing, true);
+ painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
+ frame->documentElement().render(&painter);
+ painter.end();
+
+ image.save(fileName);
+
+ ++frameCounter;
+ foreach(QWebFrame *childFrame, frame->childFrames())
+ saveFrame(childFrame);
+}
+
diff --git a/examples/webkitwidgets/framecapture/framecapture.h b/examples/webkitwidgets/framecapture/framecapture.h
new file mode 100644
index 0000000..6f49ffb
--- /dev/null
+++ b/examples/webkitwidgets/framecapture/framecapture.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FRAMECAPTURE_H
+#define FRAMECAPTURE_H
+
+#include <QtWebKitWidgets>
+
+class FrameCapture : public QObject
+{
+ Q_OBJECT
+
+public:
+ FrameCapture();
+ void load(const QUrl &url, const QString &outputFileName);
+
+signals:
+ void finished();
+
+private slots:
+ void printProgress(int percent);
+ void saveResult(bool ok);
+
+private:
+ QWebPage m_page;
+ QString m_fileName;
+ int m_percent;
+
+ void saveFrame(QWebFrame *frame);
+};
+
+#endif
diff --git a/examples/webkitwidgets/framecapture/framecapture.pro b/examples/webkitwidgets/framecapture/framecapture.pro
new file mode 100644
index 0000000..bdd1b4e
--- /dev/null
+++ b/examples/webkitwidgets/framecapture/framecapture.pro
@@ -0,0 +1,9 @@
+QT += webkitwidgets network widgets
+
+HEADERS = framecapture.h
+SOURCES = main.cpp \
+ framecapture.cpp
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/framecapture
+INSTALLS += target
diff --git a/examples/webkitwidgets/framecapture/main.cpp b/examples/webkitwidgets/framecapture/main.cpp
new file mode 100644
index 0000000..e900313
--- /dev/null
+++ b/examples/webkitwidgets/framecapture/main.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "framecapture.h"
+
+#include <iostream>
+#include <QtWidgets>
+
+int main(int argc, char * argv[])
+{
+ if (argc != 3) {
+ std::cout << "Capture a web page and save its internal frames in different images" << std::endl << std::endl;
+ std::cout << " framecapture <url> <outputfile>" << std::endl;
+ std::cout << std::endl;
+ std::cout << "Notes:" << std::endl;
+ std::cout << " 'url' is the URL of the web page to be captured" << std::endl;
+ std::cout << " 'outputfile' is the prefix of the image files to be generated" << std::endl;
+ std::cout << std::endl;
+ std::cout << "Example: " << std::endl;
+ std::cout << " framecapture qt-project.org trolltech.png" << std::endl;
+ std::cout << std::endl;
+ std::cout << "Result:" << std::endl;
+ std::cout << " trolltech.png (full page)" << std::endl;
+ std::cout << " trolltech_frame1.png (...) trolltech_frameN.png ('N' number of internal frames)" << std::endl;
+ return 0;
+ }
+
+ QUrl url = QUrl::fromUserInput(QString::fromLatin1(argv[1]));
+ QString fileName = QString::fromLatin1(argv[2]);
+
+ QApplication a(argc, argv);
+ FrameCapture capture;
+ QObject::connect(&capture, SIGNAL(finished()), QApplication::instance(), SLOT(quit()));
+ capture.load(url, fileName);
+
+ return a.exec();
+}
+
diff --git a/examples/webkitwidgets/imageanalyzer/README b/examples/webkitwidgets/imageanalyzer/README
new file mode 100644
index 0000000..9415b57
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/README
@@ -0,0 +1,20 @@
+This example demonstrates the use of Qt WebKit to make a hybrid application.
+
+Build instructions:
+
+ On Mac OS X:
+ In this directory:
+ qmake -spec macx-g++
+ make clean all
+ open imageanalyzer.app
+ On Linux/Unix:
+ In this directory:
+ qmake
+ make clean all
+ ./imageanalyzer
+
+ On Windows:
+ In this directory:
+ qmake
+ nmake clean all
+ debug\imageanalyzer.exe
diff --git a/examples/webkitwidgets/imageanalyzer/imageanalyzer.cpp b/examples/webkitwidgets/imageanalyzer/imageanalyzer.cpp
new file mode 100644
index 0000000..973411c
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/imageanalyzer.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QNetworkAccessManager>
+#include <QNetworkDiskCache>
+#include <QtConcurrentMap>
+#include "imageanalyzer.h"
+
+/*!
+ * This class operates as follows:
+ * Parent calls the slot startAnalysis which shoves a list of QStrings into URLQueue and then calls fetchURLs.
+ * FetchURLs sends out HTTP GETs for each image it can't get out of the cache.
+ * As the responses come in, handleReply tries to create an image out of each and pushes those images into imageQueue.
+ * On the last (detected by no outstandingFetches and URLQueue.isEmpty()) call to queueImage (from handleReply)
+ * a thread is forked to process all the images. When it finishes, it emits a finished signal that is received
+ * by our JavaScript code.
+ */
+
+//! [ ImageAnalyzer - Constructor ]
+ImageAnalyzer::ImageAnalyzer(QNetworkDiskCache* netcache, QObject* parent)
+ : QObject(parent), m_cache(netcache), m_outstandingFetches(0)
+{
+ /* ImageAnalyzer only wants to receive http responses
+ for requests that it makes, so that's why it has its own
+ QNetworkAccessManager. */
+ m_network = new QNetworkAccessManager(this);
+ m_watcher = new QFutureWatcher<QRgb>(this);
+ /* We want to share a cache with the web browser,
+ in case it has some images we want: */
+ m_network->setCache(m_cache);
+
+ QObject::connect(m_network, SIGNAL(finished(QNetworkReply*)),
+ this, SLOT(handleReply(QNetworkReply*)));
+ QObject::connect(m_watcher, SIGNAL(finished()),
+ this, SLOT(doneProcessing()));
+ QObject::connect(m_watcher, SIGNAL(progressValueChanged(int)),
+ this, SLOT(progressStatus(int)));
+}
+//! [ ImageAnalyzer - Constructor ]
+ImageAnalyzer::~ImageAnalyzer()
+{
+ delete(m_watcher);
+}
+
+
+QRgb ImageAnalyzer::lastResults()
+{
+ int rTot = 0;
+ int bTot = 0;
+ int gTot = 0;
+ int count = m_watcher->future().results().size();
+ foreach(const QRgb & triplet, m_watcher->future().results())
+ {
+ rTot += qRed(triplet);
+ bTot += qBlue(triplet);
+ gTot += qGreen(triplet);
+ }
+ return qRgb(rTot/count, bTot/count, gTot/count);
+}
+
+float ImageAnalyzer::lastRed() { return qRed(lastResults())/2.55; }
+float ImageAnalyzer::lastGreen() { return qGreen(lastResults())/2.55; }
+float ImageAnalyzer::lastBlue() { return qBlue(lastResults())/2.55; }
+
+void ImageAnalyzer::progressStatus(int newstat)
+{
+ emit updateProgress(newstat, m_watcher->progressMaximum());
+}
+
+
+bool ImageAnalyzer::isBusy()
+{
+ return m_watcher->isRunning();
+}
+
+
+//! [ ImageAnalyzer - startAnalysis ]
+void ImageAnalyzer::startAnalysis(const QStringList & urls)
+{
+ m_URLQueue = urls;
+ fetchURLs();
+}
+//! [ ImageAnalyzer - startAnalysis ]
+
+/*!
+ * Analyzes the entire queue - just starts all our http GETs.
+ */
+//! [ ImageAnalyzer - fetchURLs ]
+void ImageAnalyzer::fetchURLs()
+{
+ while (!m_URLQueue.isEmpty())
+ {
+ QString url = m_URLQueue.takeFirst();
+ QUrl URL = QUrl(url);
+ QIODevice * pData = m_cache->data(URL);
+ // Is image already loaded in cache?
+ if (pData == 0) {
+ // HTTP Get image over network.
+ m_outstandingFetches++;
+ QNetworkRequest request = QNetworkRequest(URL);
+ request.setRawHeader("User-Agent", "Digia - Custom Qt app");
+ m_network->get(request);
+ } else {
+ // Get image from cache
+ QImage image;
+ image.load(pData, 0);
+ if (!image.isNull())
+ queueImage(image);
+ delete(pData);
+ }
+ }
+}
+//! [ ImageAnalyzer - fetchURLs ]
+/*
+ * Slot to handle the incoming responses from our http GETs
+ */
+//! [ ImageAnalyzer - handleReply ]
+void ImageAnalyzer::handleReply(QNetworkReply * pReply)
+{
+ m_outstandingFetches--;
+ if (pReply->error()) {
+ qDebug() << "Error code" << pReply->error();
+ qDebug() << "Http code" << pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+ return;
+ }
+ QImage image;
+ image.load(pReply, 0);
+ pReply->deleteLater();
+ if (image.isNull()) {
+ qDebug() << "bad image";
+ qDebug() << pReply->rawHeaderList();
+ foreach(QByteArray element, pReply->rawHeaderList()) {
+ qDebug() << element << " = " << pReply->rawHeader(element);
+ }
+ return;
+ }
+ queueImage(image);
+}
+//! [ ImageAnalyzer - handleReply ]
+
+void ImageAnalyzer::doneProcessing()
+{
+ m_imageQueue = QList<QImage>();
+ emit finishedAnalysis();
+}
+//! [ ImageAnalyzer - queueImage ]
+void ImageAnalyzer::queueImage(QImage img)
+{
+ if (!img.isNull())
+ m_imageQueue << img;
+
+ if (m_outstandingFetches == 0 && m_URLQueue.isEmpty()) {
+ m_watcher->setFuture(QtConcurrent::mapped(m_imageQueue, averageRGB));
+ }
+}
+//! [ ImageAnalyzer - queueImage ]
+
+//! [ ImageAnalyzer - averageRGB ]
+QRgb averageRGB(const QImage &img)
+{
+ int pixelCount = img.width() * img.height();
+ int rAvg, gAvg, bAvg;
+
+ // We waste some time here:
+ for (int timeWaster=0; timeWaster < 100; timeWaster++) {
+ quint64 rTot = 0;
+ quint64 gTot = 0;
+ quint64 bTot = 0;
+ for (int i=0; i < img.width(); i++) {
+ for (int j=0; j < img.height(); j++) {
+ QRgb pixel = img.pixel(i,j);
+ rTot += qRed(pixel);
+ gTot += qGreen(pixel);
+ bTot += qBlue(pixel);
+ }
+ }
+ rAvg = (rTot)/(pixelCount);
+ gAvg = (gTot)/(pixelCount);
+ bAvg = (bTot)/(pixelCount);
+ }
+ return qRgb(rAvg, gAvg, bAvg);
+}
+//! [ ImageAnalyzer - averageRGB ]
diff --git a/examples/webkitwidgets/imageanalyzer/imageanalyzer.h b/examples/webkitwidgets/imageanalyzer/imageanalyzer.h
new file mode 100644
index 0000000..1b0948c
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/imageanalyzer.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef IMAGEANALYZER_H
+#define IMAGEANALYZER_H
+
+#include <QFutureWatcher>
+#include <QtWidgets>
+
+QT_BEGIN_NAMESPACE
+class QNetworkAccessManager;
+class QNetworkReply;
+class QNetworkDiskCache;
+QT_END_NAMESPACE
+
+//! [ ImageAnalyzer - public interface ]
+class ImageAnalyzer : public QObject
+{
+ Q_OBJECT
+public:
+ ImageAnalyzer(QNetworkDiskCache * netcache, QObject * parent=0);
+
+ QRgb lastResults();
+ float lastRed();
+ float lastGreen();
+ float lastBlue();
+ bool isBusy();
+ Q_PROPERTY(bool busy READ isBusy);
+ Q_PROPERTY(float red READ lastRed);
+ Q_PROPERTY(float green READ lastGreen);
+ Q_PROPERTY(float blue READ lastBlue);
+ ~ImageAnalyzer();
+
+public slots:
+ /*! initiates analysis of all the urls in the list */
+ void startAnalysis(const QStringList & urls);
+
+signals:
+ void finishedAnalysis();
+ void updateProgress(int completed, int total);
+ //! [ ImageAnalyzer - public interface ]
+
+private slots:
+ void handleReply(QNetworkReply*);
+ void doneProcessing();
+ void progressStatus(int);
+
+private:
+ QRgb processImages();
+ void fetchURLs();
+ void queueImage(QImage img);
+
+ //! [ ImageAnalyzer - private members ]
+private:
+ QNetworkAccessManager* m_network;
+ QNetworkDiskCache* m_cache;
+ QStringList m_URLQueue;
+ QList<QImage> m_imageQueue;
+ int m_outstandingFetches;
+ QFutureWatcher<QRgb> * m_watcher;
+ //! [ ImageAnalyzer - private members ]
+};
+
+QRgb averageRGB(const QImage &img);
+
+#endif
diff --git a/examples/webkitwidgets/imageanalyzer/imageanalyzer.pro b/examples/webkitwidgets/imageanalyzer/imageanalyzer.pro
new file mode 100644
index 0000000..442a05f
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/imageanalyzer.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+HEADERS = imageanalyzer.h \
+ mainwindow.h
+SOURCES = imageanalyzer.cpp \
+ main.cpp \
+ mainwindow.cpp
+
+QT += network webkitwidgets widgets concurrent
+
+RESOURCES = resources/imageanalyzer.qrc
+
+EXAMPLE_FILES += html/index.html ../webkit-bridge-tutorial.qdoc outline.txt
+
+
diff --git a/examples/webkitwidgets/imageanalyzer/main.cpp b/examples/webkitwidgets/imageanalyzer/main.cpp
new file mode 100644
index 0000000..3601264
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/main.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "imageanalyzer.h"
+#include "mainwindow.h"
+
+int main(int argc, char* argv[])
+{
+ QApplication app(argc, argv);
+
+ MainWin win;
+ win.show();
+ return app.exec();
+}
+
diff --git a/examples/webkitwidgets/imageanalyzer/mainwindow.cpp b/examples/webkitwidgets/imageanalyzer/mainwindow.cpp
new file mode 100644
index 0000000..71193e7
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/mainwindow.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "mainwindow.h"
+#include "imageanalyzer.h"
+
+#include <QWebFrame>
+#include <QWebElementCollection>
+#include <QNetworkDiskCache>
+
+/*
+ * Default Constructor
+ */
+//! [MainWindow - constructor]
+MainWin::MainWin(QWidget * parent) : QWebView(parent)
+{
+ m_network = new QNetworkAccessManager(this);
+ m_cache = new QNetworkDiskCache(this);
+ m_cache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/imageanalyzer");
+ m_cache->setMaximumCacheSize(1000000); //set the cache to 10megs
+ m_network->setCache(m_cache);
+ page()->setNetworkAccessManager(m_network);
+
+ //! The object we will expose to JavaScript engine:
+ m_analyzer = new ImageAnalyzer(m_cache, this);
+
+ // Signal is emitted before frame loads any web content:
+ QObject::connect(page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
+ this, SLOT(addJSObject()));
+
+ // qrc:// URLs refer to resources. See imagenalayzer.qrc
+ QUrl startURL = QUrl("qrc:/index.html");
+
+ // Load web content now!
+ setUrl(startURL);
+}
+//! [MainWindow - constructor]
+
+//! [MainWindow - addJSObject]
+void MainWin::addJSObject() {
+ // Add pAnalyzer to JavaScript Frame as member "imageAnalyzer".
+ page()->mainFrame()->addToJavaScriptWindowObject(QString("imageAnalyzer"), m_analyzer);
+}
+//! [MainWindow - addJSObject]
diff --git a/examples/webkitwidgets/imageanalyzer/mainwindow.h b/examples/webkitwidgets/imageanalyzer/mainwindow.h
new file mode 100644
index 0000000..6fcd74a
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/mainwindow.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QWebView>
+
+class ImageAnalyzer;
+QT_BEGIN_NAMESPACE
+class QNetworkDiskCache;
+QT_END_NAMESPACE
+
+class MainWin : public QWebView
+{
+ Q_OBJECT
+
+public:
+ explicit MainWin(QWidget * parent = 0);
+
+private:
+ ImageAnalyzer * m_analyzer;
+ QNetworkAccessManager * m_network;
+ QNetworkDiskCache * m_cache;
+
+private slots:
+ void addJSObject();
+
+};
+#endif
diff --git a/examples/webkitwidgets/imageanalyzer/resources/imageanalyzer.qrc b/examples/webkitwidgets/imageanalyzer/resources/imageanalyzer.qrc
new file mode 100644
index 0000000..fe9a5df
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/resources/imageanalyzer.qrc
@@ -0,0 +1,10 @@
+<!DOCTYPE RCC><RCC version="1.0">
+ <qresource>
+ <file>index.html</file>
+ <file>images/mtRainier.jpg</file>
+ <file>images/bellaCoola.jpg</file>
+ <file>images/trees.jpg</file>
+ <file>images/flower.jpg</file>
+ <file>images/seaShell.jpg</file>
+</qresource>
+</RCC>
diff --git a/examples/webkitwidgets/imageanalyzer/resources/images/README b/examples/webkitwidgets/imageanalyzer/resources/images/README
new file mode 100644
index 0000000..176a1da
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/resources/images/README
@@ -0,0 +1,2 @@
+The images are under public domain and were obtained from
+http://publicdomainpictures.net
diff --git a/examples/webkitwidgets/imageanalyzer/resources/images/bellaCoola.jpg b/examples/webkitwidgets/imageanalyzer/resources/images/bellaCoola.jpg
new file mode 100644
index 0000000..f90ed54
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/resources/images/bellaCoola.jpg
Binary files differ
diff --git a/examples/webkitwidgets/imageanalyzer/resources/images/flower.jpg b/examples/webkitwidgets/imageanalyzer/resources/images/flower.jpg
new file mode 100644
index 0000000..6b7f6be
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/resources/images/flower.jpg
Binary files differ
diff --git a/examples/webkitwidgets/imageanalyzer/resources/images/mtRainier.jpg b/examples/webkitwidgets/imageanalyzer/resources/images/mtRainier.jpg
new file mode 100644
index 0000000..d09a3f2
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/resources/images/mtRainier.jpg
Binary files differ
diff --git a/examples/webkitwidgets/imageanalyzer/resources/images/seaShell.jpg b/examples/webkitwidgets/imageanalyzer/resources/images/seaShell.jpg
new file mode 100644
index 0000000..c5005a9
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/resources/images/seaShell.jpg
Binary files differ
diff --git a/examples/webkitwidgets/imageanalyzer/resources/images/trees.jpg b/examples/webkitwidgets/imageanalyzer/resources/images/trees.jpg
new file mode 100644
index 0000000..083b26d
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/resources/images/trees.jpg
Binary files differ
diff --git a/examples/webkitwidgets/imageanalyzer/resources/index.html b/examples/webkitwidgets/imageanalyzer/resources/index.html
new file mode 100644
index 0000000..6532951
--- /dev/null
+++ b/examples/webkitwidgets/imageanalyzer/resources/index.html
@@ -0,0 +1,133 @@
+
+<html>
+ <body>
+ <!-- [ images list ] -->
+ <div style="float:right; width:50%; border-left: solid 1px black">
+ <div id="listdiv" align="center">
+ <h5>Images to be analyzed:</h5>
+ <select multiple size=10 id=imglist style="width:80%"></select>
+ <br />
+ <input type="button" id="evalbutton" value="Analyze" onclick="analyzeImages()" />
+ </div>
+ </div>
+ <!-- [ images list ] -->
+ <div style="width:50%">
+ <div id="titleblock" align="center">
+ <h2>Image Analyzer</h2>
+ </div>
+ <div id=outputdiv align=center>
+ <h4>Status: <span id=status>Idle</span></h4>
+ <h5>
+ Latest Results:<br />
+ Red: <span id=redval style="color:red">n/a</span><br />
+ Green: <span id=greenval style="color:green">n/a</span><br />
+ Blue: <span id=blueval style="color:blue">n/a</span><br />
+ </h5>
+ <h3>Click on images below to select for analysis</h3>
+ </div>
+ </div>
+ <!-- [ sample images ] -->
+ <div id=imagediv style="clear:both; text-align:center">
+ <hr/>
+ <img src="images/mtRainier.jpg" height=150px onclick='return addImage(this);' />
+ <img src="images/bellaCoola.jpg" height=150px onclick='return addImage(this);'/>
+ <img src="images/seaShell.jpg" height=150px onclick='return addImage(this);'/>
+ <!-- [ sample images ] -->
+ <img src="images/flower.jpg" height=150px onclick='return addImage(this);'/>
+ <img src="images/trees.jpg" height=150px onclick='return addImage(this);'/>
+ </div>
+
+ </body>
+</html>
+
+<script type="text/javascript">
+ var remaining = 0;
+ var connected = false;
+ //We use this function because connect statements resolve their target once, imediately
+ //not at signal emission so they must be connected once the imageAnalyzer object has been added to the frame
+ //! <!-- [ connect slots ] -->
+ function connectSlots()
+ {
+ if ( !connected ) {
+ connected = true;
+ imageAnalyzer.finishedAnalysis.connect(this, finished);
+ imageAnalyzer.updateProgress.connect(this, updateProg);
+ }
+ }
+ //! <!-- [ connect slots ] -->
+
+ function finished() {
+ setStatus('Idle');
+ setResults(imageAnalyzer.red.toFixed(2), imageAnalyzer.green.toFixed(2), imageAnalyzer.blue.toFixed(2));
+ }
+ //This will function as the recieving "slot" for the progress signal
+ function updateProg(complete, max)
+ {
+ var oldRemaining = remaining;
+ remaining = max - complete;
+ pullList(oldRemaining - remaining);
+ //Prevent results getting messed up if we don't get signals in order
+ if( imageAnalyzer.busy ) {
+ setStatus('Processing (' + complete + ' of ' + max + ' completed)');
+ setResults('Calculating','Calculating','Calculating');
+ }
+ }
+
+//! <!-- [ analyzeImages ] -->
+function analyzeImages() {
+ connectSlots();
+ var imglist = document.getElementsByTagName('option');
+ if (imglist.length > 0) {
+ stringlist = [];
+ for(var i=0; i<imglist.length; i++) {
+ stringlist[i]=imglist[i].value;
+ }
+ if (!imageAnalyzer.busy) {
+ remaining = stringlist.length;
+ imageAnalyzer.startAnalysis(stringlist);
+ } else {
+ alert("Processing, please wait until finished.");
+ }
+//! <!-- [ analyzeImages ] -->
+ } else {
+ alert('No images selected. Click on one or more images to select them for analysis.');
+ }
+}
+function clearList() {
+ var imglist = document.getElementById('imglist');
+ while(imglist.length > 0) {
+ imglist.removeChild(imglist.childNodes[0]);
+ }
+}
+function pullList(count) {
+ var imglist = document.getElementById('imglist');
+ while(imglist.length > 0 && count > 0) {
+ imglist.removeChild(imglist.childNodes[0]);
+ count--;
+ }
+}
+function setStatus(statusString) {
+ document.getElementById('status').innerHTML = statusString;
+}
+
+function setResults(red, green, blue) {
+ if (! isNaN(red) ) { red += " %"; }
+ if (! isNaN(green) ) { green += " %"; }
+ if (! isNaN(blue) ) { blue += " %"; }
+ document.getElementById('redval').innerHTML = red;
+ document.getElementById('greenval').innerHTML = green;
+ document.getElementById('blueval').innerHTML = blue;
+}
+//! <!-- [ addImage ] -->
+function addImage(newimg) {
+ var imglist = document.getElementById('imglist');
+ var curChildren = imglist.childNodes;
+ var newline = document.createElement('option');
+ newline.innerHTML = newimg.src.substring(newimg.src.lastIndexOf('/')+1);
+ newline.value = newimg.src;
+ imglist.appendChild(newline);
+}
+//! <!-- [ addImage ] -->
+</script>
+
+
diff --git a/examples/webkitwidgets/previewer/doc/images/previewer-example.png b/examples/webkitwidgets/previewer/doc/images/previewer-example.png
new file mode 100644
index 0000000..d930250
--- /dev/null
+++ b/examples/webkitwidgets/previewer/doc/images/previewer-example.png
Binary files differ
diff --git a/examples/webkitwidgets/previewer/doc/images/previewer-ui.png b/examples/webkitwidgets/previewer/doc/images/previewer-ui.png
new file mode 100644
index 0000000..c92d136
--- /dev/null
+++ b/examples/webkitwidgets/previewer/doc/images/previewer-ui.png
Binary files differ
diff --git a/examples/webkitwidgets/previewer/doc/src/previewer.qdoc b/examples/webkitwidgets/previewer/doc/src/previewer.qdoc
new file mode 100644
index 0000000..5a3bdc3
--- /dev/null
+++ b/examples/webkitwidgets/previewer/doc/src/previewer.qdoc
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example previewer
+ \title Previewer Example
+
+ \brief The Previewer example shows how to use QtWebKit's QWebView to preview
+ HTML data written in a QPlainTextEdit.
+
+ \image previewer-example.png
+
+ \section1 The User Interface
+
+ Before we begin, we create a user interface using Qt Designer. Two QGroupBox
+ objects - the editor group box and the previewer group box are separated
+ by a QSplitter. In the editor group box, we have a QPlainTextEdit object,
+ \c plainTextEdit, and two QPushButton objects. In the previewer group box,
+ we have a QWebView object, \c webView.
+
+ \image previewer-ui.png
+
+ \section1 Previewer Class Definition
+
+ The \c Previewer class is a subclass of both QWidget and Ui::Form.
+ We subclass Ui::Form in order to embed the Qt Designer user interface form
+ created earlier. This method of embedding forms is known as the
+ \l{The Multiple Inheritance Approach}{multiple inheritance approach}.
+
+ In our \c previewer.h file, we have a constructor and a slot,
+ \c on_previewButton_clicked().
+
+ \snippet previewer/previewer.h 0
+
+ \section1 Previewer Class Implementation
+
+ The \c{Previewer}'s constructor is only responsible for setting up the
+ user interface.
+
+ \snippet previewer/previewer.cpp 0
+
+ The \c on_previewButton_clicked() is a slot corresponding to the
+ \c{previewButton}'s \l{QPushButton::}{clicked()} signal. When the
+ \c previewButton is clicked, we extract the contents of \c plainTextEdit,
+ and then invoke the \l{QWebView::}{setHtml()} function to display our
+ contents as HTML.
+
+ \snippet previewer/previewer.cpp 1
+
+ \section1 MainWindow Class Definition
+
+ The \c MainWindow class for the Previewer example is a subclass of
+ QMainWindow with a constructor and five private slots: \c open(),
+ \c openUrl(), \c save(), \c about() and \c updateTextEdit().
+
+ \snippet previewer/mainwindow.h 0
+
+ The private objects in \c MainWindow are \c centralWidget, which is
+ a \c Previewer object, \c fileMenu, \c helpMenu and the QAction objects
+ \c openAct, \c openUrlAct, \c saveAct, \c exitAct, \c aboutAct and
+ \c aboutQtAct.
+
+ \snippet previewer/mainwindow.h 1
+
+ There are three private functions: \c createActions(), \c createMenus()
+ and \c setStartupText(). The \c createActions() and \c createMenus()
+ functions are necessary to set up the main window's actions and
+ assign them to the \gui File and \gui Help menus. The \c setStartupText()
+ function, on the other hand, displays a description about the example
+ in its HTML Previewer window.
+
+ \section1 MainWindow Class Implementation
+
+ The \c{MainWindow}'s constructor invokes \c createActions() and
+ \c createMenus() to set up the \gui File menu and \gui Help menu. Then,
+ the \c Previewer object, \c centralWidget, is set to the main window's
+ central widget. Also, we connect \c webView's
+ \l{QWebView::}{loadFinished()} signal to our \c updateTextEdit() slot.
+ Finally, we call the \c setStartupText() function to display the
+ description of the example.
+
+ \snippet previewer/mainwindow.cpp 0
+
+ Within the \c createActions() function, we instantiate all our private
+ QAction objects which we declared in \c{mainwindow.h}. We set the
+ short cut and status tip for these actions and connect their
+ \l{QAction::}{triggered()} signal to appropriate slots.
+
+ \snippet previewer/mainwindow.cpp 1
+ \dots
+
+ The \c createMenus() function instantiates the QMenu items, \c fileMenu
+ and \c helpMenu and adds them to the main window's
+ \l{QMainWindow::menuBar()}{menu bar}.
+
+ \snippet previewer/mainwindow.cpp 2
+
+ The example also provides an \c about() slot to describe its purpose.
+
+ \snippet previewer/mainwindow.cpp 3
+
+ The \c MainWindow class provides two types of \gui Open functions:
+ \c open() and \c openUrl(). The \c open() function opens an HTML file
+ with \c fileName, and reads it with QTextStream. The function then
+ displays the output on \c plainTextEdit. The file's name is obtained
+ using QFileDialog's \l{QFileDialog::}{getOpenFileName()} function.
+
+ \snippet previewer/mainwindow.cpp 4
+
+ The \c openUrl() function, on the other hand, displays a QInputDialog
+ to obtain a URL, and displays it on \c webView.
+
+ \snippet previewer/mainwindow.cpp 5
+
+ In order to save a HTML file, the \c save() function first extracts the
+ contents of \c plainTextEdit and displays a QFileDialog to obtain
+ \c fileName. Then, we use a QTextStream object, \c in, to write to
+ \c file.
+
+ \snippet previewer/mainwindow.cpp 6
+
+ Earlier, in \c{MainWindow}'s constructor, we connected \c{webView}'s
+ \l{QWebView::}{loadFinished()} signal to our private \c updateTextEdit()
+ slot. This slot updates the contents of \c plainTextEdit with the HTML
+ source of the web page's main frame, obtained using \l{QWebFrame}'s
+ \l{QWebFrame::}{toHtml()} function.
+
+ \snippet previewer/mainwindow.cpp 7
+
+ To provide a description about the Previewer example, when it starts up,
+ we use the \c setStartupText() function, as shown below:
+
+ \snippet previewer/mainwindow.cpp 8
+
+
+ \section1 The \c{main()} Function
+
+ The \c main() function instantiates a \c MainWindow object, \c mainWindow,
+ and displays it with the \l{QWidget::}{show()} function.
+
+ \snippet previewer/main.cpp 0
+
+*/
diff --git a/examples/webkitwidgets/previewer/main.cpp b/examples/webkitwidgets/previewer/main.cpp
new file mode 100644
index 0000000..f08fa58
--- /dev/null
+++ b/examples/webkitwidgets/previewer/main.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+#include "mainwindow.h"
+
+//! [0]
+int main(int argc, char * argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow mainWindow;
+ mainWindow.show();
+ return app.exec();
+}
+//! [0]
diff --git a/examples/webkitwidgets/previewer/mainwindow.cpp b/examples/webkitwidgets/previewer/mainwindow.cpp
new file mode 100644
index 0000000..e0dc069
--- /dev/null
+++ b/examples/webkitwidgets/previewer/mainwindow.cpp
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+#include <QtWebKitWidgets>
+#include "mainwindow.h"
+
+//! [0]
+MainWindow::MainWindow()
+{
+ createActions();
+ createMenus();
+ centralWidget = new Previewer(this);
+ setCentralWidget(centralWidget);
+
+ connect(centralWidget->webView, SIGNAL(loadFinished(bool)),
+ this, SLOT(updateTextEdit()));
+ setStartupText();
+}
+//! [0]
+
+//! [1]
+void MainWindow::createActions()
+{
+ openAct = new QAction(tr("&Open..."), this);
+ openAct->setShortcuts(QKeySequence::Open);
+ openAct->setStatusTip(tr("Open an existing HTML file"));
+ connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
+
+ openUrlAct = new QAction(tr("&Open URL..."), this);
+ openUrlAct->setShortcut(tr("Ctrl+U"));
+ openUrlAct->setStatusTip(tr("Open a URL"));
+ connect(openUrlAct, SIGNAL(triggered()), this, SLOT(openUrl()));
+//! [1]
+
+ saveAct = new QAction(tr("&Save"), this);
+ saveAct->setShortcuts(QKeySequence::Save);
+ saveAct->setStatusTip(tr("Save the HTML file to disk"));
+ connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));
+
+ exitAct = new QAction(tr("E&xit"), this);
+ exitAct->setStatusTip(tr("Exit the application"));
+ exitAct->setShortcuts(QKeySequence::Quit);
+ connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
+
+ aboutAct = new QAction(tr("&About"), this);
+ aboutAct->setStatusTip(tr("Show the application's About box"));
+ connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
+
+ aboutQtAct = new QAction(tr("About &Qt"), this);
+ aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
+ connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
+}
+
+//! [2]
+void MainWindow::createMenus()
+{
+ fileMenu = menuBar()->addMenu(tr("&File"));
+ fileMenu->addAction(openAct);
+ fileMenu->addAction(openUrlAct);
+ fileMenu->addAction(saveAct);
+ fileMenu->addSeparator();
+ fileMenu->addAction(exitAct);
+
+ menuBar()->addSeparator();
+
+ helpMenu = menuBar()->addMenu(tr("&Help"));
+ helpMenu->addAction(aboutAct);
+ helpMenu->addAction(aboutQtAct);
+}
+//! [2]
+
+//! [3]
+void MainWindow::about()
+{
+ QMessageBox::about(this, tr("About Previewer"),
+ tr("The <b>Previewer</b> example demonstrates how to "
+ "view HTML documents using a QWebView."));
+}
+//! [3]
+
+//! [4]
+void MainWindow::open()
+{
+ QString fileName = QFileDialog::getOpenFileName(this);
+ if (!fileName.isEmpty()) {
+ // read from file
+ QFile file(fileName);
+
+ if (!file.open(QIODevice::ReadOnly)) {
+ QMessageBox::information(this, tr("Unable to open file"),
+ file.errorString());
+ return;
+ }
+
+ QTextStream out(&file);
+ QString output = out.readAll();
+
+ // display contents
+ centralWidget->plainTextEdit->setPlainText(output);
+ centralWidget->setBaseUrl(QUrl::fromLocalFile(fileName));
+ }
+}
+//! [4]
+
+//! [5]
+void MainWindow::openUrl()
+{
+ bool ok;
+ QString url = QInputDialog::getText(this, tr("Enter a URL"),
+ tr("URL:"), QLineEdit::Normal, "http://", &ok);
+
+ if (ok && !url.isEmpty()) {
+ centralWidget->webView->setUrl(url);
+ }
+}
+//! [5]
+
+//! [6]
+void MainWindow::save()
+{
+ QString content = centralWidget->plainTextEdit->toPlainText();
+ QString fileName = QFileDialog::getSaveFileName(this);
+
+ if (!fileName.isEmpty()) {
+ // save to file
+ QFile file(fileName);
+
+ if (!file.open(QIODevice::WriteOnly)) {
+ QMessageBox::information(this, tr("Unable to open file"),
+ file.errorString());
+ return;
+ }
+
+ QTextStream in(&file);
+ in << content;
+ }
+}
+//! [6]
+
+//! [7]
+void MainWindow::updateTextEdit()
+{
+ QWebFrame *mainFrame = centralWidget->webView->page()->mainFrame();
+ QString frameText = mainFrame->toHtml();
+ centralWidget->plainTextEdit->setPlainText(frameText);
+}
+//! [7]
+
+//! [8]
+void MainWindow::setStartupText()
+{
+ QString string = "<html><body><h1>HTML Previewer</h1>"
+ " <p>This example shows you how to use QWebView to"
+ " preview HTML data written in a QPlainTextEdit.</p>"
+ " </body></html>";
+ centralWidget->webView->setHtml(string);
+}
+//! [8]
diff --git a/examples/webkitwidgets/previewer/mainwindow.h b/examples/webkitwidgets/previewer/mainwindow.h
new file mode 100644
index 0000000..9fd9deb
--- /dev/null
+++ b/examples/webkitwidgets/previewer/mainwindow.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include "previewer.h"
+
+QT_BEGIN_NAMESPACE
+class QAction;
+class QMenu;
+QT_END_NAMESPACE
+
+//! [0]
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+private slots:
+ void open();
+ void openUrl();
+ void save();
+ void about();
+ void updateTextEdit();
+//! [0]
+
+//! [1]
+private:
+ Previewer *centralWidget;
+ QMenu *fileMenu;
+ QMenu *helpMenu;
+ QAction *openAct;
+ QAction *openUrlAct;
+ QAction *saveAct;
+ QAction *exitAct;
+ QAction *aboutAct;
+ QAction *aboutQtAct;
+
+ void createActions();
+ void createMenus();
+ void setStartupText();
+};
+//! [1]
+
+#endif
diff --git a/examples/webkitwidgets/previewer/previewer.cpp b/examples/webkitwidgets/previewer/previewer.cpp
new file mode 100644
index 0000000..dfd6dd4
--- /dev/null
+++ b/examples/webkitwidgets/previewer/previewer.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+#include "previewer.h"
+
+//! [0]
+Previewer::Previewer(QWidget *parent)
+ : QWidget(parent)
+{
+ setupUi(this);
+}
+//! [0]
+
+void Previewer::setBaseUrl(const QUrl &url)
+{
+ baseUrl = url;
+}
+
+//! [1]
+void Previewer::on_previewButton_clicked()
+{
+ // Update the contents in web viewer
+ QString text = plainTextEdit->toPlainText();
+ webView->setHtml(text, baseUrl);
+}
+//! [1]
diff --git a/examples/webkitwidgets/previewer/previewer.h b/examples/webkitwidgets/previewer/previewer.h
new file mode 100644
index 0000000..5692e3b
--- /dev/null
+++ b/examples/webkitwidgets/previewer/previewer.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PREVIEWER_H
+#define PREVIEWER_H
+
+#include "ui_previewer.h"
+
+//! [0]
+class Previewer : public QWidget, public Ui::Form
+{
+ Q_OBJECT
+
+public:
+ Previewer(QWidget *parent = 0);
+
+ void setBaseUrl(const QUrl &url);
+
+public slots:
+ void on_previewButton_clicked();
+
+private:
+ QUrl baseUrl;
+};
+//! [0]
+
+#endif
diff --git a/examples/webkitwidgets/previewer/previewer.pro b/examples/webkitwidgets/previewer/previewer.pro
new file mode 100644
index 0000000..8bca084
--- /dev/null
+++ b/examples/webkitwidgets/previewer/previewer.pro
@@ -0,0 +1,11 @@
+QT += webkitwidgets network widgets
+HEADERS = previewer.h \
+ mainwindow.h
+SOURCES = main.cpp \
+ previewer.cpp \
+ mainwindow.cpp
+FORMS = previewer.ui
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/previewer
+INSTALLS += target
diff --git a/examples/webkitwidgets/previewer/previewer.ui b/examples/webkitwidgets/previewer/previewer.ui
new file mode 100644
index 0000000..d4c9992
--- /dev/null
+++ b/examples/webkitwidgets/previewer/previewer.ui
@@ -0,0 +1,99 @@
+<ui version="4.0" >
+ <class>Form</class>
+ <widget class="QWidget" name="Form" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>911</width>
+ <height>688</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4" >
+ <item>
+ <widget class="QSplitter" name="splitter" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QGroupBox" name="editorBox" >
+ <property name="title" >
+ <string>HTML Editor</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2" >
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <widget class="QPlainTextEdit" name="plainTextEdit" />
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QPushButton" name="clearButton" >
+ <property name="text" >
+ <string>Clear</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="previewButton" >
+ <property name="text" >
+ <string>Preview</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QGroupBox" name="previewerBox" >
+ <property name="title" >
+ <string>HTML Preview</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3" >
+ <item>
+ <widget class="QWebView" name="webView" >
+ <property name="url" >
+ <url>
+ <string>about:blank</string>
+ </url>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QWebView</class>
+ <extends>QWidget</extends>
+ <header>QtWebKit/QWebView</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>clearButton</sender>
+ <signal>clicked()</signal>
+ <receiver>plainTextEdit</receiver>
+ <slot>clear()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>56</x>
+ <y>653</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>98</x>
+ <y>551</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webkitwidgets/scroller/plot/main.cpp b/examples/webkitwidgets/scroller/plot/main.cpp
new file mode 100644
index 0000000..f6806a8
--- /dev/null
+++ b/examples/webkitwidgets/scroller/plot/main.cpp
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QListWidget>
+#include <QListWidgetItem>
+#include <QSplitter>
+#include <QStackedWidget>
+#include <QSignalMapper>
+#include <QMainWindow>
+#include <QMenuBar>
+#include <QActionGroup>
+#include <QWebView>
+#include <QTimer>
+#include <QScroller>
+
+#include <QtDebug>
+
+#include <QGesture>
+
+#include "settingswidget.h"
+#include "plotwidget.h"
+
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow(bool smallscreen, bool touch)
+ : QMainWindow(), m_touch(touch)
+ {
+ m_list = new QListWidget();
+ m_list->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ m_list_scroller = installKineticScroller(m_list);
+
+ for (int i = 0; i < 1000; ++i)
+ new QListWidgetItem(QString("This is a test text %1 %2").arg(i).arg(QString("--------").left(i % 8)), m_list);
+
+ connect(m_list, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(listItemActivated(QListWidgetItem*)));
+ connect(m_list, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(listItemClicked(QListWidgetItem*)));
+ connect(m_list, SIGNAL(itemPressed(QListWidgetItem*)), this, SLOT(listItemPressed(QListWidgetItem*)));
+ connect(m_list, SIGNAL(itemSelectionChanged()), this, SLOT(listItemSelectionChanged()));
+ connect(m_list, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(listItemCurrentChanged(QListWidgetItem*)));
+
+ m_web = new QWebView();
+ m_web_scroller = installKineticScroller(m_web);
+
+ QTimer::singleShot(1000, this, SLOT(loadUrl()));
+
+ m_settings = new SettingsWidget(smallscreen);
+ installKineticScroller(m_settings);
+ m_plot = new PlotWidget(smallscreen);
+
+ QStackedWidget *stack = new QStackedWidget();
+ stack->addWidget(m_list);
+ stack->addWidget(m_web);
+
+ QActionGroup *pages = new QActionGroup(this);
+ pages->setExclusive(true);
+ QSignalMapper *mapper = new QSignalMapper(this);
+ connect(mapper, SIGNAL(mapped(int)), stack, SLOT(setCurrentIndex(int)));
+
+ createAction("List", pages, mapper, 0, true);
+ createAction("Web", pages, mapper, 1);
+
+ if (smallscreen) {
+ stack->addWidget(m_settings);
+ stack->addWidget(m_plot);
+
+ createAction("Settings", pages, mapper, 2);
+ createAction("Plot", pages, mapper, 3);
+
+ setCentralWidget(stack);
+ } else {
+ QSplitter *split = new QSplitter();
+ m_settings->setMinimumWidth(m_settings->sizeHint().width());
+ split->addWidget(stack);
+ split->addWidget(m_settings);
+ split->addWidget(m_plot);
+ setCentralWidget(split);
+ }
+ menuBar()->addMenu(QLatin1String("Pages"))->addActions(pages->actions());
+ connect(stack, SIGNAL(currentChanged(int)), this, SLOT(pageChanged(int)));
+ pageChanged(0);
+ }
+
+private slots:
+ void pageChanged(int page)
+ {
+ if (page < 0 || page > 1)
+ return;
+ switch (page) {
+ case 0:
+ m_settings->setScroller(m_list);
+ m_plot->setScroller(m_list);
+ break;
+ case 1:
+ m_settings->setScroller(m_web);
+ m_plot->setScroller(m_web);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void loadUrl()
+ {
+ m_web->load(QUrl("http://www.google.com"));
+ }
+
+ void listItemActivated(QListWidgetItem *lwi) { qWarning() << "Item ACTIVATED: " << lwi->text(); }
+ void listItemClicked(QListWidgetItem *lwi) { qWarning() << "Item CLICKED: " << lwi->text(); }
+ void listItemPressed(QListWidgetItem *lwi) { qWarning() << "Item PRESSED: " << lwi->text(); }
+ void listItemCurrentChanged(QListWidgetItem *lwi) { qWarning() << "Item CURRENT: " << (lwi ? lwi->text() : QString("(none)")); }
+ void listItemSelectionChanged()
+ {
+ int n = m_list->selectedItems().count();
+ qWarning("Item%s SELECTED: %d", n == 1 ? "" : "s", n);
+ foreach (QListWidgetItem *lwi, m_list->selectedItems())
+ qWarning() << " " << lwi->text();
+ }
+
+private:
+ QAction *createAction(const char *text, QActionGroup *group, QSignalMapper *mapper, int mapping, bool checked = false)
+ {
+ QAction *a = new QAction(QLatin1String(text), group);
+ a->setCheckable(true);
+ a->setChecked(checked);
+#if defined(Q_WS_MAC)
+ a->setMenuRole(QAction::NoRole);
+#endif
+ mapper->setMapping(a, mapping);
+ connect(a, SIGNAL(toggled(bool)), mapper, SLOT(map()));
+ return a;
+ }
+
+ QScroller *installKineticScroller(QWidget *w)
+ {
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(w)) {
+ QScroller::grabGesture(area->viewport(), m_touch ? QScroller::TouchGesture : QScroller::LeftMouseButtonGesture);
+ return QScroller::scroller(area->viewport());
+ } else if (QWebView *web = qobject_cast<QWebView *>(w)) {
+ QScroller::grabGesture(web, m_touch ? QScroller::TouchGesture : QScroller::LeftMouseButtonGesture);
+ }
+ return QScroller::scroller(w);
+ }
+
+private:
+ QListWidget *m_list;
+ QWebView *m_web;
+ QScroller *m_list_scroller, *m_web_scroller;
+ SettingsWidget *m_settings;
+ PlotWidget *m_plot;
+ bool m_touch;
+};
+
+int main(int argc, char **argv)
+{
+ QApplication a(argc, argv);
+
+#if defined(Q_WS_MAEMO_5) || defined(Q_WS_S60) || defined(Q_WS_WINCE)
+ bool smallscreen = true;
+#else
+ bool smallscreen = false;
+#endif
+ bool touch = false;
+
+ if (a.arguments().contains(QLatin1String("--small")))
+ smallscreen = true;
+ if (a.arguments().contains(QLatin1String("--touch")))
+ touch = true;
+
+ MainWindow mw(smallscreen, touch);
+ if (smallscreen)
+ mw.showMaximized();
+ else
+ mw.show();
+#if defined(Q_WS_MAC)
+ mw.raise();
+#endif
+ return a.exec();
+}
+
+#include "main.moc"
diff --git a/examples/webkitwidgets/scroller/plot/plot.pro b/examples/webkitwidgets/scroller/plot/plot.pro
new file mode 100644
index 0000000..d89c50b
--- /dev/null
+++ b/examples/webkitwidgets/scroller/plot/plot.pro
@@ -0,0 +1,11 @@
+HEADERS = settingswidget.h \
+ plotwidget.h
+SOURCES = settingswidget.cpp \
+ plotwidget.cpp \
+ main.cpp
+
+QT += webkitwidgets widgets
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/scroller/plot
+INSTALLS += target
diff --git a/examples/webkitwidgets/scroller/plot/plotwidget.cpp b/examples/webkitwidgets/scroller/plot/plotwidget.cpp
new file mode 100644
index 0000000..12d3e8c
--- /dev/null
+++ b/examples/webkitwidgets/scroller/plot/plotwidget.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QPushButton>
+#include <QTextStream>
+#include <QColor>
+#include <QPainter>
+#include <QLabel>
+#include <QResizeEvent>
+#include <QAbstractScrollArea>
+
+#include "plotwidget.h"
+#include "qscroller.h"
+
+PlotWidget::PlotWidget(bool /*smallscreen*/)
+ : QWidget(), m_widget(0)
+{
+ setWindowTitle(QLatin1String("Plot"));
+ m_clear = new QPushButton(QLatin1String("Clear"), this);
+ connect(m_clear, SIGNAL(clicked()), this, SLOT(reset()));
+ m_legend = new QLabel(this);
+ QString legend;
+ QTextStream ts(&legend);
+ // ok. this wouldn't pass the w3c html verification...
+ ts << "<table style=\"color:#000;\" border=\"0\">";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::red).light().name() << "\" /><td>Velocity X</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::red).dark().name() << "\" /><td>Velocity Y</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::green).light().name() << "\" /><td>Content Position X</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::green).dark().name() << "\" /><td>Content Position Y</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::blue).light().name() << "\" /><td>Overshoot Position X</td></tr>";
+ ts << "<tr><td width=\"30\" bgcolor=\"" << QColor(Qt::blue).dark().name() << "\" /><td>Overshoot Position Y</td></tr>";
+ ts << "</table>";
+ m_legend->setText(legend);
+}
+
+void PlotWidget::setScroller(QWidget *widget)
+{
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(widget))
+ widget = area->viewport();
+
+ if (m_widget)
+ m_widget->removeEventFilter(this);
+ m_widget = widget;
+ reset();
+ if (m_widget)
+ m_widget->installEventFilter(this);
+}
+
+bool PlotWidget::eventFilter(QObject *obj, QEvent *ev)
+{
+ if (ev->type() == QEvent::Scroll) {
+ QScrollEvent *se = static_cast<QScrollEvent *>(ev);
+ QScroller *scroller = QScroller::scroller(m_widget);
+
+ QPointF v = scroller->velocity();
+ //v.rx() *= scroller->pixelPerMeter().x();
+ //v.ry() *= scroller->pixelPerMeter().y();
+
+ PlotItem pi = { v, se->contentPos(), se->overshootDistance() };
+ addPlotItem(pi);
+ }
+
+ return QWidget::eventFilter(obj, ev);
+}
+
+static inline void doMaxMin(const QPointF &v, qreal &minmaxv)
+{
+ minmaxv = qMax(minmaxv, qMax(qAbs(v.x()), qAbs(v.y())));
+}
+
+void PlotWidget::addPlotItem(const PlotItem &pi)
+{
+ m_plotitems.append(pi);
+ minMaxVelocity = minMaxPosition = 0;
+
+ while (m_plotitems.size() > 500)
+ m_plotitems.removeFirst();
+
+ foreach (const PlotItem &pi, m_plotitems) {
+ doMaxMin(pi.velocity, minMaxVelocity);
+ doMaxMin(pi.contentPosition, minMaxPosition);
+ doMaxMin(pi.overshootPosition, minMaxPosition);
+ }
+ update();
+}
+
+void PlotWidget::reset()
+{
+ m_plotitems.clear();
+ minMaxVelocity = minMaxPosition = 0;
+ update();
+}
+
+void PlotWidget::resizeEvent(QResizeEvent *)
+{
+ QSize cs = m_clear->sizeHint();
+ QSize ls = m_legend->sizeHint();
+ m_clear->setGeometry(4, 4, cs.width(), cs.height());
+ m_legend->setGeometry(4, height() - ls.height() - 4, ls.width(), ls.height());
+}
+
+void PlotWidget::paintEvent(QPaintEvent *)
+{
+#define SCALE(v, mm) ((qreal(1) - (v / mm)) * qreal(0.5) * height())
+
+ QColor rvColor = Qt::red;
+ QColor cpColor = Qt::green;
+ QColor opColor = Qt::blue;
+
+
+ QPainter p(this);
+ //p.setRenderHints(QPainter::Antialiasing); //too slow for 60fps
+ p.fillRect(rect(), Qt::white);
+
+ p.setPen(Qt::black);
+ p.drawLine(0, SCALE(0, 1), width(), SCALE(0, 1));
+
+ if (m_plotitems.isEmpty())
+ return;
+
+ int x = 2;
+ int offset = m_plotitems.size() - width() / 2;
+ QList<PlotItem>::const_iterator it = m_plotitems.constBegin();
+ if (offset > 0)
+ it += (offset - 1);
+
+ const PlotItem *last = &(*it++);
+
+ while (it != m_plotitems.constEnd()) {
+ p.setPen(rvColor.light());
+ p.drawLine(qreal(x - 2), SCALE(last->velocity.x(), minMaxVelocity),
+ qreal(x), SCALE(it->velocity.x(), minMaxVelocity));
+ p.setPen(rvColor.dark());
+ p.drawLine(qreal(x - 2), SCALE(last->velocity.y(), minMaxVelocity),
+ qreal(x), SCALE(it->velocity.y(), minMaxVelocity));
+
+ p.setPen(cpColor.light());
+ p.drawLine(qreal(x - 2), SCALE(last->contentPosition.x(), minMaxPosition),
+ qreal(x), SCALE(it->contentPosition.x(), minMaxPosition));
+ p.setPen(cpColor.dark());
+ p.drawLine(qreal(x - 2), SCALE(last->contentPosition.y(), minMaxPosition),
+ qreal(x), SCALE(it->contentPosition.y(), minMaxPosition));
+
+ p.setPen(opColor.light());
+ p.drawLine(qreal(x - 2), SCALE(last->overshootPosition.x(), minMaxPosition),
+ qreal(x), SCALE(it->overshootPosition.x(), minMaxPosition));
+ p.setPen(opColor.dark());
+ p.drawLine(qreal(x - 2), SCALE(last->overshootPosition.y(), minMaxPosition),
+ qreal(x), SCALE(it->overshootPosition.y(), minMaxPosition));
+
+ last = &(*it++);
+ x += 2;
+ }
+
+ QString toptext = QString("%1 [m/s] / %2 [pix]").arg(minMaxVelocity, 0, 'f', 2).arg(minMaxPosition, 0, 'f', 2);
+ QString bottomtext = QString("-%1 [m/s] / -%2 [pix]").arg(minMaxVelocity, 0, 'f', 2).arg(minMaxPosition, 0, 'f', 2);
+
+ p.setPen(Qt::black);
+ p.drawText(rect(), Qt::AlignTop | Qt::AlignHCenter, toptext);
+ p.drawText(rect(), Qt::AlignBottom | Qt::AlignHCenter, bottomtext);
+#undef SCALE
+}
diff --git a/examples/webkitwidgets/scroller/plot/plotwidget.h b/examples/webkitwidgets/scroller/plot/plotwidget.h
new file mode 100644
index 0000000..2260195
--- /dev/null
+++ b/examples/webkitwidgets/scroller/plot/plotwidget.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLOTWIDGET_H
+#define PLOTWIDGET_H
+
+#include <QWidget>
+#include <QPointF>
+
+QT_BEGIN_NAMESPACE
+class QPushButton;
+class QLabel;
+class QScroller;
+QT_END_NAMESPACE
+
+class PlotWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ PlotWidget(bool smallscreen = false);
+
+ void setScroller(QWidget *widget);
+
+public slots:
+ void reset();
+
+protected:
+ void resizeEvent(QResizeEvent *);
+ void paintEvent(QPaintEvent *);
+
+ bool eventFilter(QObject *obj, QEvent *ev);
+
+private:
+
+ struct PlotItem {
+ QPointF velocity;
+ QPointF contentPosition;
+ QPointF overshootPosition;
+ };
+
+ void addPlotItem(const PlotItem &pi);
+
+ QWidget *m_widget;
+ QList<PlotItem> m_plotitems;
+ qreal minMaxVelocity, minMaxPosition;
+ QPushButton *m_clear;
+ QLabel *m_legend;
+};
+
+#endif
diff --git a/examples/webkitwidgets/scroller/plot/settingswidget.cpp b/examples/webkitwidgets/scroller/plot/settingswidget.cpp
new file mode 100644
index 0000000..dd7efca
--- /dev/null
+++ b/examples/webkitwidgets/scroller/plot/settingswidget.cpp
@@ -0,0 +1,689 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QVariant>
+#include <QSlider>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QComboBox>
+#include <QSpinBox>
+#include <QGroupBox>
+#include <QToolButton>
+#include <QCheckBox>
+#include <QScrollBar>
+#include <QPainter>
+#include <QScrollArea>
+#include <QScrollPrepareEvent>
+#include <QApplication>
+#include <QPlainTextEdit>
+#include <QTextBlock>
+#include <qnumeric.h>
+
+#include <QEasingCurve>
+
+#include <QDebug>
+
+#include "math.h"
+
+#include "settingswidget.h"
+#include "qscroller.h"
+#include "qscrollerproperties.h"
+
+class SnapOverlay : public QWidget
+{
+ Q_OBJECT
+public:
+ SnapOverlay(QWidget *w)
+ : QWidget(w)
+ {
+ setAttribute(Qt::WA_TransparentForMouseEvents);
+
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(w)) {
+ connect(area->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(update()));
+ connect(area->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(update()));
+ area->viewport()->installEventFilter(this);
+ }
+ }
+ void clear(Qt::Orientation o)
+ {
+ m_snap[o].clear();
+ update();
+ }
+
+ void set(Qt::Orientation o, qreal first, qreal step)
+ {
+ m_snap[o] = QList<qreal>() << -Q_INFINITY << first << step;
+ update();
+ }
+
+ void set(Qt::Orientation o, const QList<qreal> &list)
+ {
+ m_snap[o] = list;
+ update();
+ }
+
+protected:
+ bool eventFilter(QObject *o, QEvent *e)
+ {
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(parentWidget())) {
+ if (area->viewport() == o) {
+ if (e->type() == QEvent::Move || e->type() == QEvent::Resize) {
+ setGeometry(area->viewport()->rect());
+ }
+ }
+ }
+ return false;
+ }
+
+ void paintEvent(QPaintEvent *e)
+ {
+ if (QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(parentWidget())) {
+ int dx = area->horizontalScrollBar()->value();
+ int dy = area->verticalScrollBar()->value();
+
+ QPainter paint(this);
+ paint.fillRect(e->rect(), Qt::transparent);
+ paint.setPen(QPen(Qt::red, 9));
+
+ if (m_snap[Qt::Horizontal].isEmpty()) {
+ } else if (m_snap[Qt::Horizontal][0] == -Q_INFINITY) {
+ int start = int(m_snap[Qt::Horizontal][1]);
+ int step = int(m_snap[Qt::Horizontal][2]);
+ if (step > 0) {
+ for (int i = start; i < area->horizontalScrollBar()->maximum(); i += step)
+ paint.drawPoint(i - dx, 5);
+ }
+ } else {
+ foreach (qreal r, m_snap[Qt::Horizontal])
+ paint.drawPoint(int(r) - dx, 5);
+ }
+ paint.setPen(QPen(Qt::green, 9));
+ if (m_snap[Qt::Vertical].isEmpty()) {
+ } else if (m_snap[Qt::Vertical][0] == -Q_INFINITY) {
+ int start = int(m_snap[Qt::Vertical][1]);
+ int step = int(m_snap[Qt::Vertical][2]);
+ if (step > 0) {
+ for (int i = start; i < area->verticalScrollBar()->maximum(); i += step)
+ paint.drawPoint(5, i - dy);
+ }
+ } else {
+ foreach (qreal r, m_snap[Qt::Vertical])
+ paint.drawPoint(5, int(r) - dy);
+ }
+ }
+ }
+
+private:
+ QMap<Qt::Orientation, QList<qreal> > m_snap;
+};
+
+struct MetricItem
+{
+ QScrollerProperties::ScrollMetric metric;
+ const char *name;
+ int scaling;
+ const char *unit;
+ QVariant min, max;
+ QVariant step;
+};
+
+class MetricItemUpdater : public QObject
+{
+ Q_OBJECT
+public:
+ MetricItemUpdater(MetricItem *item)
+ : m_item(item)
+ , m_widget(0)
+ , m_slider(0)
+ , m_combo(0)
+ , m_valueLabel(0)
+ {
+ m_frameRateType = QVariant::fromValue(QScrollerProperties::Standard).userType();
+ m_overshootPolicyType = QVariant::fromValue(QScrollerProperties::OvershootWhenScrollable).userType();
+
+ if (m_item->min.type() == QVariant::EasingCurve) {
+ m_combo = new QComboBox();
+ m_combo->addItem("OutQuad", QEasingCurve::OutQuad);
+ m_combo->addItem("OutCubic", QEasingCurve::OutCubic);
+ m_combo->addItem("OutQuart", QEasingCurve::OutQuart);
+ m_combo->addItem("OutQuint", QEasingCurve::OutQuint);
+ m_combo->addItem("OutExpo", QEasingCurve::OutExpo);
+ m_combo->addItem("OutSine", QEasingCurve::OutSine);
+ m_combo->addItem("OutCirc", QEasingCurve::OutCirc);
+ } else if (m_item->min.userType() == m_frameRateType) {
+ m_combo = new QComboBox();
+ m_combo->addItem("Standard", QScrollerProperties::Standard);
+ m_combo->addItem("60 FPS", QScrollerProperties::Fps60);
+ m_combo->addItem("30 FPS", QScrollerProperties::Fps30);
+ m_combo->addItem("20 FPS", QScrollerProperties::Fps20);
+ } else if (m_item->min.userType() == m_overshootPolicyType) {
+ m_combo = new QComboBox();
+ m_combo->addItem("When Scrollable", QScrollerProperties::OvershootWhenScrollable);
+ m_combo->addItem("Always On", QScrollerProperties::OvershootAlwaysOn);
+ m_combo->addItem("Always Off", QScrollerProperties::OvershootAlwaysOff);
+ } else {
+ m_slider = new QSlider(Qt::Horizontal);
+ m_slider->setSingleStep(1);
+ m_slider->setMinimum(-1);
+ m_slider->setMaximum(qRound((m_item->max.toReal() - m_item->min.toReal()) / m_item->step.toReal()));
+ m_slider->setValue(-1);
+ m_valueLabel = new QLabel();
+ }
+ m_nameLabel = new QLabel(QLatin1String(m_item->name));
+ if (m_item->unit && m_item->unit[0])
+ m_nameLabel->setText(m_nameLabel->text() + QLatin1String(" [") + QLatin1String(m_item->unit) + QLatin1String("]"));
+ m_resetButton = new QToolButton();
+ m_resetButton->setText(QLatin1String("Reset"));
+ m_resetButton->setEnabled(false);
+
+ connect(m_resetButton, SIGNAL(clicked()), this, SLOT(reset()));
+ if (m_slider) {
+ connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(controlChanged(int)));
+ m_slider->setMinimum(0);
+ } else if (m_combo) {
+ connect(m_combo, SIGNAL(currentIndexChanged(int)), this, SLOT(controlChanged(int)));
+ }
+ }
+
+ void setScroller(QWidget *widget)
+ {
+ m_widget = widget;
+ QScroller *scroller = QScroller::scroller(widget);
+ QScrollerProperties properties = QScroller::scroller(widget)->scrollerProperties();
+
+ if (m_slider)
+ m_slider->setEnabled(scroller);
+ if (m_combo)
+ m_combo->setEnabled(scroller);
+ m_nameLabel->setEnabled(scroller);
+ if (m_valueLabel)
+ m_valueLabel->setEnabled(scroller);
+ m_resetButton->setEnabled(scroller);
+
+ if (!scroller)
+ return;
+
+ m_default_value = properties.scrollMetric(m_item->metric);
+ valueChanged(m_default_value);
+ }
+
+ QWidget *nameLabel() { return m_nameLabel; }
+ QWidget *valueLabel() { return m_valueLabel; }
+ QWidget *valueControl() { if (m_combo) return m_combo; else return m_slider; }
+ QWidget *resetButton() { return m_resetButton; }
+
+private slots:
+ void valueChanged(const QVariant &v)
+ {
+ m_value = v;
+ if (m_slider) {
+ switch (m_item->min.type()) {
+ case QMetaType::Float:
+ case QVariant::Double: {
+ m_slider->setValue(qRound((m_value.toReal() * m_item->scaling - m_item->min.toReal()) / m_item->step.toReal()));
+ break;
+ }
+ case QVariant::Int: {
+ m_slider->setValue((m_value.toInt() * m_item->scaling - m_item->min.toInt()) / m_item->step.toInt());
+ break;
+ }
+ default: break;
+ }
+ } else if (m_combo) {
+ if (m_item->min.type() == QVariant::EasingCurve) {
+ m_combo->setCurrentIndex(m_combo->findData(v.toEasingCurve().type()));
+ } else if (m_item->min.userType() == m_overshootPolicyType) {
+ m_combo->setCurrentIndex(m_combo->findData(v.value<QScrollerProperties::OvershootPolicy>()));
+ } else if (m_item->min.userType() == m_frameRateType) {
+ m_combo->setCurrentIndex(m_combo->findData(v.value<QScrollerProperties::FrameRates>()));
+ }
+ }
+ }
+
+ void controlChanged(int value)
+ {
+ bool combo = (m_combo && (sender() == m_combo));
+ QString text;
+
+ if (m_slider && !combo) {
+ switch (m_item->min.type()) {
+ case QMetaType::Float:
+ case QVariant::Double: {
+ qreal d = m_item->min.toReal() + qreal(value) * m_item->step.toReal();
+ text = QString::number(d);
+ m_value = d / qreal(m_item->scaling);
+ break;
+ }
+ case QVariant::Int: {
+ int i = m_item->min.toInt() + qRound(qreal(value) * m_item->step.toReal());
+ text = QString::number(i);
+ m_value = i / m_item->scaling;
+ break;
+ }
+ default: break;
+ }
+ } else if (m_combo && combo) {
+ if (m_item->min.type() == QVariant::EasingCurve) {
+ m_value = QVariant(QEasingCurve(static_cast<QEasingCurve::Type>(m_combo->itemData(value).toInt())));
+ } else if (m_item->min.userType() == m_overshootPolicyType) {
+ m_value = QVariant::fromValue(static_cast<QScrollerProperties::OvershootPolicy>(m_combo->itemData(value).toInt()));
+ } else if (m_item->min.userType() == m_frameRateType) {
+ m_value = QVariant::fromValue(static_cast<QScrollerProperties::FrameRates>(m_combo->itemData(value).toInt()));
+ }
+ }
+ if (m_valueLabel)
+ m_valueLabel->setText(text);
+ if (m_widget && QScroller::scroller(m_widget)) {
+ QScrollerProperties properties = QScroller::scroller(m_widget)->scrollerProperties();
+ properties.setScrollMetric(m_item->metric, m_value);
+ QScroller::scroller(m_widget)->setScrollerProperties(properties);
+ }
+
+ m_resetButton->setEnabled(m_value != m_default_value);
+ }
+
+ void reset()
+ {
+ QScrollerProperties properties = QScroller::scroller(m_widget)->scrollerProperties();
+ properties.setScrollMetric(m_item->metric, m_value);
+ QScroller::scroller(m_widget)->setScrollerProperties(properties);
+ valueChanged(m_default_value);
+ }
+
+private:
+ MetricItem *m_item;
+ int m_frameRateType;
+ int m_overshootPolicyType;
+
+ QWidget *m_widget;
+ QSlider *m_slider;
+ QComboBox *m_combo;
+ QLabel *m_nameLabel, *m_valueLabel;
+ QToolButton *m_resetButton;
+
+ QVariant m_value, m_default_value;
+};
+
+#define METRIC(x) QScrollerProperties::x, #x
+
+MetricItem items[] = {
+ { METRIC(MousePressEventDelay), 1000, "ms", qreal(0), qreal(2000), qreal(10) },
+ { METRIC(DragStartDistance), 1000, "mm", qreal(1), qreal(20), qreal(0.1) },
+ { METRIC(DragVelocitySmoothingFactor), 1, "", qreal(0), qreal(1), qreal(0.1) },
+ { METRIC(AxisLockThreshold), 1, "", qreal(0), qreal(1), qreal(0.01) },
+
+ { METRIC(ScrollingCurve), 1, "", QEasingCurve(), 0, 0 },
+ { METRIC(DecelerationFactor), 1, "", qreal(0), qreal(3), qreal(0.01) },
+
+ { METRIC(MinimumVelocity), 1, "m/s", qreal(0), qreal(7), qreal(0.01) },
+ { METRIC(MaximumVelocity), 1, "m/s", qreal(0), qreal(7), qreal(0.01) },
+ { METRIC(MaximumClickThroughVelocity), 1, "m/s", qreal(0), qreal(7), qreal(0.01) },
+
+ { METRIC(AcceleratingFlickMaximumTime), 1000, "ms", qreal(100), qreal(5000), qreal(100) },
+ { METRIC(AcceleratingFlickSpeedupFactor), 1, "", qreal(1), qreal(7), qreal(0.1) },
+
+ { METRIC(SnapPositionRatio), 1, "", qreal(0.1), qreal(0.9), qreal(0.1) },
+ { METRIC(SnapTime), 1000, "ms", qreal(0), qreal(2000), qreal(10) },
+
+ { METRIC(OvershootDragResistanceFactor), 1, "", qreal(0), qreal(1), qreal(0.01) },
+ { METRIC(OvershootDragDistanceFactor), 1, "", qreal(0), qreal(1), qreal(0.01) },
+ { METRIC(OvershootScrollDistanceFactor), 1, "", qreal(0), qreal(1), qreal(0.01) },
+ { METRIC(OvershootScrollTime), 1000, "ms", qreal(0), qreal(2000), qreal(10) },
+
+ { METRIC(HorizontalOvershootPolicy), 1, "", QVariant::fromValue(QScrollerProperties::OvershootWhenScrollable), 0, 0 },
+ { METRIC(VerticalOvershootPolicy), 1, "", QVariant::fromValue(QScrollerProperties::OvershootWhenScrollable), 0, 0 },
+ { METRIC(FrameRate), 1, "", QVariant::fromValue(QScrollerProperties::Standard), 0, 0 },
+};
+
+#undef METRIC
+
+void SettingsWidget::addToGrid(QGridLayout *grid, QWidget *label, int widgetCount, ...)
+{
+ va_list args;
+ va_start(args, widgetCount);
+
+ int rows = grid->rowCount();
+ int cols = grid->columnCount();
+
+ if (label) {
+ if (m_smallscreen)
+ grid->addWidget(label, rows++, 0, 1, qMax(cols, widgetCount));
+ else
+ grid->addWidget(label, rows, 0);
+ }
+ for (int i = 0; i < widgetCount; i++) {
+ if (QWidget *w = va_arg(args, QWidget *))
+ grid->addWidget(w, rows, m_smallscreen ? i : i + 1);
+ }
+ va_end(args);
+}
+
+SettingsWidget::SettingsWidget(bool smallscreen)
+ : QScrollArea()
+ , m_widget(0)
+ , m_snapoverlay(0)
+ , m_smallscreen(smallscreen)
+{
+ setWindowTitle(QLatin1String("Settings"));
+ QWidget *view = new QWidget();
+ QVBoxLayout *layout = new QVBoxLayout(view);
+ QGroupBox *grp;
+ QGridLayout *grid;
+
+ // GROUP: SCROLL METRICS
+
+ grp = new QGroupBox(QLatin1String("Scroll Metrics"));
+ grid = new QGridLayout();
+ grid->setVerticalSpacing(m_smallscreen ? 4 : 2);
+
+ for (int i = 0; i < int(sizeof(items) / sizeof(items[0])); i++) {
+ MetricItemUpdater *u = new MetricItemUpdater(items + i);
+ u->setParent(this);
+ addToGrid(grid, u->nameLabel(), 3, u->valueControl(), u->valueLabel(), u->resetButton());
+ m_metrics.append(u);
+ }
+ grp->setLayout(grid);
+ layout->addWidget(grp);
+
+ // GROUP: SCROLL TO
+
+ grp = new QGroupBox(QLatin1String("Scroll To"));
+ grid = new QGridLayout();
+ grid->setVerticalSpacing(m_smallscreen ? 4 : 2);
+
+ m_scrollx = new QSpinBox();
+ m_scrolly = new QSpinBox();
+ m_scrolltime = new QSpinBox();
+ m_scrolltime->setRange(0, 10000);
+ m_scrolltime->setValue(1000);
+ m_scrolltime->setSuffix(QLatin1String(" ms"));
+ QPushButton *go = new QPushButton(QLatin1String("Go"));
+ connect(go, SIGNAL(clicked()), this, SLOT(scrollTo()));
+ connect(m_scrollx, SIGNAL(editingFinished()), this, SLOT(scrollTo()));
+ connect(m_scrolly, SIGNAL(editingFinished()), this, SLOT(scrollTo()));
+ connect(m_scrolltime, SIGNAL(editingFinished()), this, SLOT(scrollTo()));
+ grid->addWidget(new QLabel(QLatin1String("X:")), 0, 0);
+ grid->addWidget(m_scrollx, 0, 1);
+ grid->addWidget(new QLabel(QLatin1String("Y:")), 0, 2);
+ grid->addWidget(m_scrolly, 0, 3);
+ int row = smallscreen ? 1 : 0;
+ int col = smallscreen ? 0 : 4;
+ grid->addWidget(new QLabel(QLatin1String("in")), row, col++);
+ grid->addWidget(m_scrolltime, row, col++);
+ if (smallscreen) {
+ grid->addWidget(go, row, col + 1);
+ } else {
+ grid->addWidget(go, row, col);
+ grid->setColumnStretch(5, 1);
+ grid->setColumnStretch(6, 1);
+ }
+ grid->setColumnStretch(1, 1);
+ grid->setColumnStretch(3, 1);
+ grp->setLayout(grid);
+ layout->addWidget(grp);
+
+ QLayout *snapbox = new QHBoxLayout();
+
+ // GROUP: SNAP POINTS X
+
+ grp = new QGroupBox(QLatin1String("Snap Positions X"));
+ QBoxLayout *vbox = new QVBoxLayout();
+ vbox->setSpacing(m_smallscreen ? 4 : 2);
+ m_snapx = new QComboBox();
+ m_snapx->addItem(QLatin1String("No Snapping"), NoSnap);
+ m_snapx->addItem(QLatin1String("Snap to Interval"), SnapToInterval);
+ m_snapx->addItem(QLatin1String("Snap to List"), SnapToList);
+ connect(m_snapx, SIGNAL(currentIndexChanged(int)), this, SLOT(snapModeChanged(int)));
+ vbox->addWidget(m_snapx);
+
+ m_snapxinterval = new QWidget();
+ grid = new QGridLayout();
+ grid->setVerticalSpacing(m_smallscreen ? 4 : 2);
+ m_snapxfirst = new QSpinBox();
+ connect(m_snapxfirst, SIGNAL(valueChanged(int)), this, SLOT(snapPositionsChanged()));
+ grid->addWidget(new QLabel("First:"), 0, 0);
+ grid->addWidget(m_snapxfirst, 0, 1);
+ m_snapxstep = new QSpinBox();
+ connect(m_snapxstep, SIGNAL(valueChanged(int)), this, SLOT(snapPositionsChanged()));
+ grid->addWidget(new QLabel("Interval:"), 0, 2);
+ grid->addWidget(m_snapxstep, 0, 3);
+ m_snapxinterval->setLayout(grid);
+ vbox->addWidget(m_snapxinterval);
+ m_snapxinterval->hide();
+
+ m_snapxlist = new QPlainTextEdit();
+ m_snapxlist->setToolTip(QLatin1String("One snap position per line. Empty lines are ignored."));
+ m_snapxlist->installEventFilter(this);
+ connect(m_snapxlist, SIGNAL(textChanged()), this, SLOT(snapPositionsChanged()));
+ vbox->addWidget(m_snapxlist);
+ m_snapxlist->hide();
+
+ vbox->addStretch(100);
+ grp->setLayout(vbox);
+ snapbox->addWidget(grp);
+
+ // GROUP: SNAP POINTS Y
+
+ grp = new QGroupBox(QLatin1String("Snap Positions Y"));
+ vbox = new QVBoxLayout();
+ vbox->setSpacing(m_smallscreen ? 4 : 2);
+ m_snapy = new QComboBox();
+ m_snapy->addItem(QLatin1String("No Snapping"), NoSnap);
+ m_snapy->addItem(QLatin1String("Snap to Interval"), SnapToInterval);
+ m_snapy->addItem(QLatin1String("Snap to List"), SnapToList);
+ connect(m_snapy, SIGNAL(currentIndexChanged(int)), this, SLOT(snapModeChanged(int)));
+ vbox->addWidget(m_snapy);
+
+ m_snapyinterval = new QWidget();
+ grid = new QGridLayout();
+ grid->setVerticalSpacing(m_smallscreen ? 4 : 2);
+ m_snapyfirst = new QSpinBox();
+ connect(m_snapyfirst, SIGNAL(valueChanged(int)), this, SLOT(snapPositionsChanged()));
+ grid->addWidget(new QLabel("First:"), 0, 0);
+ grid->addWidget(m_snapyfirst, 0, 1);
+ m_snapystep = new QSpinBox();
+ connect(m_snapystep, SIGNAL(valueChanged(int)), this, SLOT(snapPositionsChanged()));
+ grid->addWidget(new QLabel("Interval:"), 0, 2);
+ grid->addWidget(m_snapystep, 0, 3);
+ m_snapyinterval->setLayout(grid);
+ vbox->addWidget(m_snapyinterval);
+ m_snapyinterval->hide();
+
+ m_snapylist = new QPlainTextEdit();
+ m_snapylist->setToolTip(QLatin1String("One snap position per line. Empty lines are ignored."));
+ m_snapylist->installEventFilter(this);
+ connect(m_snapylist, SIGNAL(textChanged()), this, SLOT(snapPositionsChanged()));
+ vbox->addWidget(m_snapylist);
+ m_snapylist->hide();
+
+ vbox->addStretch(100);
+ grp->setLayout(vbox);
+ snapbox->addWidget(grp);
+
+ layout->addLayout(snapbox);
+
+ layout->addStretch(100);
+ setWidget(view);
+ setWidgetResizable(true);
+}
+
+void SettingsWidget::setScroller(QWidget *widget)
+{
+ delete m_snapoverlay;
+ if (m_widget)
+ m_widget->removeEventFilter(this);
+ QAbstractScrollArea *area = qobject_cast<QAbstractScrollArea *>(widget);
+ if (area)
+ widget = area->viewport();
+ m_widget = widget;
+ m_widget->installEventFilter(this);
+ m_snapoverlay = new SnapOverlay(area);
+ QScrollerProperties properties = QScroller::scroller(widget)->scrollerProperties();
+
+ QMutableListIterator<MetricItemUpdater *> it(m_metrics);
+ while (it.hasNext())
+ it.next()->setScroller(widget);
+
+ if (!widget)
+ return;
+
+ updateScrollRanges();
+}
+
+bool SettingsWidget::eventFilter(QObject *o, QEvent *e)
+{
+ if (o == m_widget && e->type() == QEvent::Resize)
+ updateScrollRanges();
+ return false;
+}
+
+void SettingsWidget::updateScrollRanges()
+{
+ QScrollPrepareEvent spe(QPoint(0, 0));
+ QApplication::sendEvent(m_widget, &spe);
+
+ QSizeF vp = spe.viewportSize();
+ QRectF maxc = spe.contentPosRange();
+
+ m_scrollx->setRange(qRound(-vp.width()), qRound(maxc.width() + vp.width()));
+ m_scrolly->setRange(qRound(-vp.height()), qRound(maxc.height() + vp.height()));
+
+ m_snapxfirst->setRange(maxc.left(), maxc.right());
+ m_snapxstep->setRange(0, maxc.width());
+ m_snapyfirst->setRange(maxc.top(), maxc.bottom());
+ m_snapystep->setRange(0, maxc.height());
+}
+
+void SettingsWidget::scrollTo()
+{
+ if (QApplication::activePopupWidget())
+ return;
+ if ((sender() == m_scrollx) && !m_scrollx->hasFocus())
+ return;
+ if ((sender() == m_scrolly) && !m_scrolly->hasFocus())
+ return;
+ if ((sender() == m_scrolltime) && !m_scrolltime->hasFocus())
+ return;
+
+ if (QScroller *scroller = QScroller::scroller(m_widget))
+ scroller->scrollTo(QPointF(m_scrollx->value(), m_scrolly->value()), m_scrolltime->value());
+}
+
+void SettingsWidget::snapModeChanged(int mode)
+{
+ if (sender() == m_snapx) {
+ m_snapxmode = static_cast<SnapMode>(mode);
+ m_snapxinterval->setVisible(mode == SnapToInterval);
+ m_snapxlist->setVisible(mode == SnapToList);
+ snapPositionsChanged();
+ } else if (sender() == m_snapy) {
+ m_snapymode = static_cast<SnapMode>(mode);
+ m_snapyinterval->setVisible(mode == SnapToInterval);
+ m_snapylist->setVisible(mode == SnapToList);
+ snapPositionsChanged();
+ }
+}
+
+void SettingsWidget::snapPositionsChanged()
+{
+ QScroller *s = QScroller::scroller(m_widget);
+ if (!s)
+ return;
+
+ switch (m_snapxmode) {
+ case NoSnap:
+ s->setSnapPositionsX(QList<qreal>());
+ m_snapoverlay->clear(Qt::Horizontal);
+ break;
+ case SnapToInterval:
+ s->setSnapPositionsX(m_snapxfirst->value(), m_snapxstep->value());
+ m_snapoverlay->set(Qt::Horizontal, m_snapxfirst->value(), m_snapxstep->value());
+ break;
+ case SnapToList:
+ s->setSnapPositionsX(toPositionList(m_snapxlist, m_snapxfirst->minimum(), m_snapxfirst->maximum()));
+ m_snapoverlay->set(Qt::Horizontal, toPositionList(m_snapxlist, m_snapxfirst->minimum(), m_snapxfirst->maximum()));
+ break;
+ }
+ switch (m_snapymode) {
+ case NoSnap:
+ s->setSnapPositionsY(QList<qreal>());
+ m_snapoverlay->clear(Qt::Vertical);
+ break;
+ case SnapToInterval:
+ s->setSnapPositionsY(m_snapyfirst->value(), m_snapystep->value());
+ m_snapoverlay->set(Qt::Vertical, m_snapyfirst->value(), m_snapystep->value());
+ break;
+ case SnapToList:
+ s->setSnapPositionsY(toPositionList(m_snapylist, m_snapyfirst->minimum(), m_snapyfirst->maximum()));
+ m_snapoverlay->set(Qt::Vertical, toPositionList(m_snapylist, m_snapyfirst->minimum(), m_snapyfirst->maximum()));
+ break;
+ }
+}
+
+QList<qreal> SettingsWidget::toPositionList(QPlainTextEdit *list, int vmin, int vmax)
+{
+ QList<qreal> snaps;
+ QList<QTextEdit::ExtraSelection> extrasel;
+ QTextEdit::ExtraSelection uline;
+ uline.format.setUnderlineColor(Qt::red);
+ uline.format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ int line = 0;
+
+ foreach (const QString &str, list->toPlainText().split(QLatin1Char('\n'))) {
+ ++line;
+ if (str.isEmpty())
+ continue;
+ bool ok = false;
+ double d = str.toDouble(&ok);
+ if (ok && d >= vmin && d <= vmax) {
+ snaps << d;
+ } else {
+ QTextEdit::ExtraSelection esel = uline;
+ esel.cursor = QTextCursor(list->document()->findBlockByLineNumber(line - 1));
+ esel.cursor.select(QTextCursor::LineUnderCursor);
+ extrasel << esel;
+ }
+ }
+ list->setExtraSelections(extrasel);
+ return snaps;
+}
+
+#include "settingswidget.moc"
diff --git a/examples/webkitwidgets/scroller/plot/settingswidget.h b/examples/webkitwidgets/scroller/plot/settingswidget.h
new file mode 100644
index 0000000..e31ea97
--- /dev/null
+++ b/examples/webkitwidgets/scroller/plot/settingswidget.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SETTINGSWIDGET_H
+#define SETTINGSWIDGET_H
+
+#include <QScrollArea>
+
+QT_BEGIN_NAMESPACE
+class QScroller;
+class QGridLayout;
+class QSpinBox;
+class QComboBox;
+class QCheckBox;
+class QPlainTextEdit;
+QT_END_NAMESPACE
+
+class MetricItemUpdater;
+class SnapOverlay;
+
+class SettingsWidget : public QScrollArea
+{
+ Q_OBJECT
+
+public:
+ SettingsWidget(bool smallscreen = false);
+
+ void setScroller(QWidget *widget);
+
+protected:
+ bool eventFilter(QObject *, QEvent *);
+
+private slots:
+ void scrollTo();
+ void snapModeChanged(int);
+ void snapPositionsChanged();
+
+private:
+ enum SnapMode {
+ NoSnap,
+ SnapToInterval,
+ SnapToList
+ };
+
+ void addToGrid(QGridLayout *grid, QWidget *label, int widgetCount, ...);
+ QList<qreal> toPositionList(QPlainTextEdit *list, int vmin, int vmax);
+ void updateScrollRanges();
+
+ QWidget *m_widget;
+ QSpinBox *m_scrollx, *m_scrolly, *m_scrolltime;
+ QList<MetricItemUpdater *> m_metrics;
+
+ SnapMode m_snapxmode;
+ QComboBox *m_snapx;
+ QWidget *m_snapxinterval;
+ QPlainTextEdit *m_snapxlist;
+ QSpinBox *m_snapxfirst;
+ QSpinBox *m_snapxstep;
+
+ SnapMode m_snapymode;
+ QComboBox *m_snapy;
+ QWidget *m_snapyinterval;
+ QPlainTextEdit *m_snapylist;
+ QSpinBox *m_snapyfirst;
+ QSpinBox *m_snapystep;
+ SnapOverlay *m_snapoverlay;
+
+ bool m_smallscreen;
+};
+
+#endif
diff --git a/examples/webkitwidgets/scroller/scroller.pro b/examples/webkitwidgets/scroller/scroller.pro
new file mode 100644
index 0000000..2b9ea53
--- /dev/null
+++ b/examples/webkitwidgets/scroller/scroller.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += plot wheel
diff --git a/examples/webkitwidgets/scroller/wheel/main.cpp b/examples/webkitwidgets/scroller/wheel/main.cpp
new file mode 100644
index 0000000..176eb7f
--- /dev/null
+++ b/examples/webkitwidgets/scroller/wheel/main.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+#include <qmath.h>
+
+#include "wheelwidget.h"
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow(bool touch)
+ : QMainWindow()
+ {
+ makeSlotMachine(touch);
+ setCentralWidget(m_slotMachine);
+ }
+
+ void makeSlotMachine(bool touch)
+ {
+ if (QApplication::desktop()->width() > 1000) {
+ QFont f = font();
+ f.setPointSize(f.pointSize() * 2);
+ setFont(f);
+ }
+
+ m_slotMachine = new QWidget(this);
+ QGridLayout *grid = new QGridLayout(m_slotMachine);
+ grid->setSpacing(20);
+
+ QStringList colors;
+ colors << "Red" << "Magenta" << "Peach" << "Orange" << "Yellow" << "Citro" << "Green" << "Cyan" << "Blue" << "Violet";
+
+ m_wheel1 = new StringWheelWidget(touch);
+ m_wheel1->setItems( colors );
+ grid->addWidget( m_wheel1, 0, 0 );
+
+ m_wheel2 = new StringWheelWidget(touch);
+ m_wheel2->setItems( colors );
+ grid->addWidget( m_wheel2, 0, 1 );
+
+ m_wheel3 = new StringWheelWidget(touch);
+ m_wheel3->setItems( colors );
+ grid->addWidget( m_wheel3, 0, 2 );
+
+ QPushButton *shakeButton = new QPushButton(tr("Shake"));
+ connect(shakeButton, SIGNAL(clicked()), this, SLOT(rotateRandom()));
+
+ grid->addWidget( shakeButton, 1, 0, 1, 3 );
+ }
+
+private slots:
+ void rotateRandom()
+ {
+ m_wheel1->scrollTo(m_wheel1->currentIndex() + (qrand() % 200));
+ m_wheel2->scrollTo(m_wheel2->currentIndex() + (qrand() % 200));
+ m_wheel3->scrollTo(m_wheel3->currentIndex() + (qrand() % 200));
+ }
+
+private:
+ QWidget *m_slotMachine;
+
+ StringWheelWidget *m_wheel1;
+ StringWheelWidget *m_wheel2;
+ StringWheelWidget *m_wheel3;
+};
+
+int main(int argc, char **argv)
+{
+ QApplication a(argc, argv);
+ bool touch = a.arguments().contains(QLatin1String("--touch"));
+ MainWindow mw(touch);
+#ifdef Q_WS_S60
+ mw.showMaximized();
+#else
+ mw.show();
+#endif
+#ifdef Q_WS_MAC
+ mw.raise();
+#endif
+ return a.exec();
+}
+
+#include "main.moc"
diff --git a/examples/webkitwidgets/scroller/wheel/wheel.pro b/examples/webkitwidgets/scroller/wheel/wheel.pro
new file mode 100644
index 0000000..4fb5e44
--- /dev/null
+++ b/examples/webkitwidgets/scroller/wheel/wheel.pro
@@ -0,0 +1,9 @@
+HEADERS = wheelwidget.h
+SOURCES = wheelwidget.cpp \
+ main.cpp
+
+QT += webkitwidgets widgets
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/scroller/wheel
+INSTALLS += target
diff --git a/examples/webkitwidgets/scroller/wheel/wheelwidget.cpp b/examples/webkitwidgets/scroller/wheel/wheelwidget.cpp
new file mode 100644
index 0000000..8864e82
--- /dev/null
+++ b/examples/webkitwidgets/scroller/wheel/wheelwidget.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+
+#include "wheelwidget.h"
+
+#define WHEEL_SCROLL_OFFSET 50000.0
+
+AbstractWheelWidget::AbstractWheelWidget(bool touch, QWidget *parent)
+ : QWidget(parent)
+ , m_currentItem(0)
+ , m_itemOffset(0)
+{
+// ![0]
+ QScroller::grabGesture(this, touch ? QScroller::TouchGesture : QScroller::LeftMouseButtonGesture);
+// ![0]
+}
+
+AbstractWheelWidget::~AbstractWheelWidget()
+{ }
+
+int AbstractWheelWidget::currentIndex() const
+{
+ return m_currentItem;
+}
+
+void AbstractWheelWidget::setCurrentIndex(int index)
+{
+ if (index >= 0 && index < itemCount()) {
+ m_currentItem = index;
+ m_itemOffset = 0;
+ update();
+ }
+}
+
+bool AbstractWheelWidget::event(QEvent *e)
+{
+ switch (e->type()) {
+// ![1]
+ case QEvent::ScrollPrepare:
+ {
+ // We set the snap positions as late as possible so that we are sure
+ // we get the correct itemHeight
+ QScroller *scroller = QScroller::scroller(this);
+ scroller->setSnapPositionsY( WHEEL_SCROLL_OFFSET, itemHeight() );
+
+ QScrollPrepareEvent *se = static_cast<QScrollPrepareEvent *>(e);
+ se->setViewportSize(QSizeF(size()));
+ // we claim a huge scrolling area and a huge content position and
+ // hope that the user doesn't notice that the scroll area is restricted
+ se->setContentPosRange(QRectF(0.0, 0.0, 0.0, WHEEL_SCROLL_OFFSET * 2));
+ se->setContentPos(QPointF(0.0, WHEEL_SCROLL_OFFSET + m_currentItem * itemHeight() + m_itemOffset));
+ se->accept();
+ return true;
+ }
+// ![1]
+// ![2]
+ case QEvent::Scroll:
+ {
+ QScrollEvent *se = static_cast<QScrollEvent *>(e);
+
+ qreal y = se->contentPos().y();
+ int iy = y - WHEEL_SCROLL_OFFSET;
+ int ih = itemHeight();
+
+// ![2]
+
+ // -- calculate the current item position and offset and redraw the widget
+ int ic = itemCount();
+ if (ic>0) {
+ m_currentItem = iy / ih % ic;
+ m_itemOffset = iy % ih;
+
+ // take care when scrolling backwards. Modulo returns negative numbers
+ if (m_itemOffset < 0) {
+ m_itemOffset += ih;
+ m_currentItem--;
+ }
+
+ if (m_currentItem < 0)
+ m_currentItem += ic;
+ }
+ // -- repaint
+ update();
+
+ se->accept();
+ return true;
+ }
+ default:
+ return QWidget::event(e);
+ }
+ return true;
+}
+
+void AbstractWheelWidget::paintEvent(QPaintEvent* event)
+{
+ Q_UNUSED( event );
+
+ // -- first calculate size and position.
+ int w = width();
+ int h = height();
+
+ QPainter painter(this);
+ QPalette palette = QApplication::palette();
+ QPalette::ColorGroup colorGroup = isEnabled() ? QPalette::Active : QPalette::Disabled;
+
+ // linear gradient brush
+ QLinearGradient grad(0.5, 0, 0.5, 1.0);
+ grad.setColorAt(0, palette.color(colorGroup, QPalette::ButtonText));
+ grad.setColorAt(0.2, palette.color(colorGroup, QPalette::Button));
+ grad.setColorAt(0.8, palette.color(colorGroup, QPalette::Button));
+ grad.setColorAt(1.0, palette.color(colorGroup, QPalette::ButtonText));
+ grad.setCoordinateMode( QGradient::ObjectBoundingMode );
+ QBrush gBrush( grad );
+
+ // paint a border and background
+ painter.setPen(palette.color(colorGroup, QPalette::ButtonText));
+ painter.setBrush(gBrush);
+ // painter.setBrushOrigin( QPointF( 0.0, 0.0 ) );
+ painter.drawRect( 0, 0, w-1, h-1 );
+
+ // paint inner border
+ painter.setPen(palette.color(colorGroup, QPalette::Button));
+ painter.setBrush(Qt::NoBrush);
+ painter.drawRect( 1, 1, w-3, h-3 );
+
+ // paint the items
+ painter.setClipRect( QRect( 3, 3, w-6, h-6 ) );
+ painter.setPen(palette.color(colorGroup, QPalette::ButtonText));
+
+ int iH = itemHeight();
+ int iC = itemCount();
+ if (iC > 0) {
+
+ m_itemOffset = m_itemOffset % iH;
+
+ for (int i=-h/2/iH; i<=h/2/iH+1; i++) {
+
+ int itemNum = m_currentItem + i;
+ while (itemNum < 0)
+ itemNum += iC;
+ while (itemNum >= iC)
+ itemNum -= iC;
+
+ paintItem(&painter, itemNum, QRect(6, h/2 +i*iH - m_itemOffset - iH/2, w-6, iH ));
+ }
+ }
+
+ // draw a transparent bar over the center
+ QColor highlight = palette.color(colorGroup, QPalette::Highlight);
+ highlight.setAlpha(150);
+
+ QLinearGradient grad2(0.5, 0, 0.5, 1.0);
+ grad2.setColorAt(0, highlight);
+ grad2.setColorAt(1.0, highlight.lighter());
+ grad2.setCoordinateMode( QGradient::ObjectBoundingMode );
+ QBrush gBrush2( grad2 );
+
+ QLinearGradient grad3(0.5, 0, 0.5, 1.0);
+ grad3.setColorAt(0, highlight);
+ grad3.setColorAt(1.0, highlight.darker());
+ grad3.setCoordinateMode( QGradient::ObjectBoundingMode );
+ QBrush gBrush3( grad3 );
+
+ painter.fillRect( QRect( 0, h/2 - iH/2, w, iH/2 ), gBrush2 );
+ painter.fillRect( QRect( 0, h/2, w, iH/2 ), gBrush3 );
+}
+
+/*!
+ Rotates the wheel widget to a given index.
+ You can also give an index greater than itemCount or less than zero in which
+ case the wheel widget will scroll in the given direction and end up with
+ (index % itemCount)
+*/
+void AbstractWheelWidget::scrollTo(int index)
+{
+ QScroller *scroller = QScroller::scroller(this);
+
+ scroller->scrollTo(QPointF(0, WHEEL_SCROLL_OFFSET + index * itemHeight()), 5000);
+}
+
+/*!
+ \class StringWheelWidget
+ \brief The StringWheelWidget class is an implementation of the AbstractWheelWidget class that draws QStrings as items.
+ \sa AbstractWheelWidget
+*/
+
+StringWheelWidget::StringWheelWidget(bool touch)
+ : AbstractWheelWidget(touch)
+{ }
+
+QStringList StringWheelWidget::items() const
+{
+ return m_items;
+}
+
+void StringWheelWidget::setItems( const QStringList &items )
+{
+ m_items = items;
+ if (m_currentItem >= items.count())
+ m_currentItem = items.count()-1;
+ update();
+}
+
+
+QSize StringWheelWidget::sizeHint() const
+{
+ // determine font size
+ QFontMetrics fm(font());
+
+ return QSize( fm.width("m") * 10 + 6, fm.height() * 7 + 6 );
+}
+
+QSize StringWheelWidget::minimumSizeHint() const
+{
+ QFontMetrics fm(font());
+
+ return QSize( fm.width("m") * 5 + 6, fm.height() * 3 + 6 );
+}
+
+void StringWheelWidget::paintItem(QPainter* painter, int index, const QRect &rect)
+{
+ painter->drawText(rect, Qt::AlignCenter, m_items.at(index));
+}
+
+int StringWheelWidget::itemHeight() const
+{
+ QFontMetrics fm(font());
+ return fm.height();
+}
+
+int StringWheelWidget::itemCount() const
+{
+ return m_items.count();
+}
+
+
diff --git a/examples/webkitwidgets/scroller/wheel/wheelwidget.h b/examples/webkitwidgets/scroller/wheel/wheelwidget.h
new file mode 100644
index 0000000..77f6c53
--- /dev/null
+++ b/examples/webkitwidgets/scroller/wheel/wheelwidget.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WHEELWIDGET_H
+#define WHEELWIDGET_H
+
+#include <QWidget>
+#include <QStringList>
+
+QT_BEGIN_NAMESPACE
+class QPainter;
+class QRect;
+QT_END_NAMESPACE
+
+class AbstractWheelWidget : public QWidget {
+ Q_OBJECT
+
+public:
+ AbstractWheelWidget(bool touch, QWidget *parent = 0);
+ virtual ~AbstractWheelWidget();
+
+ int currentIndex() const;
+ void setCurrentIndex(int index);
+
+ bool event(QEvent*);
+ void paintEvent(QPaintEvent *e);
+ virtual void paintItem(QPainter* painter, int index, const QRect &rect) = 0;
+
+ virtual int itemHeight() const = 0;
+ virtual int itemCount() const = 0;
+
+public slots:
+ void scrollTo(int index);
+
+signals:
+ void stopped(int index);
+
+protected:
+ int m_currentItem;
+ int m_itemOffset; // 0-itemHeight()
+ qreal m_lastY;
+};
+
+
+class StringWheelWidget : public AbstractWheelWidget {
+ Q_OBJECT
+
+public:
+ StringWheelWidget(bool touch);
+
+ QStringList items() const;
+ void setItems( const QStringList &items );
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ void paintItem(QPainter* painter, int index, const QRect &rect);
+
+ int itemHeight() const;
+ int itemCount() const;
+
+private:
+ QStringList m_items;
+};
+
+#endif // WHEELWIDGET_H
diff --git a/examples/webkitwidgets/simpleselector/main.cpp b/examples/webkitwidgets/simpleselector/main.cpp
new file mode 100644
index 0000000..a6da134
--- /dev/null
+++ b/examples/webkitwidgets/simpleselector/main.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [main program]
+#include <QtWidgets>
+#include "window.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ Window window;
+ window.setUrl(QUrl("http://www.webkit.org"));
+ window.show();
+ return app.exec();
+}
+//! [main program]
diff --git a/examples/webkitwidgets/simpleselector/simpleselector.pro b/examples/webkitwidgets/simpleselector/simpleselector.pro
new file mode 100644
index 0000000..aa08390
--- /dev/null
+++ b/examples/webkitwidgets/simpleselector/simpleselector.pro
@@ -0,0 +1,9 @@
+QT += webkitwidgets network widgets
+FORMS = window.ui
+HEADERS = window.h
+SOURCES = main.cpp \
+ window.cpp
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/simpleselector
+INSTALLS += target
diff --git a/examples/webkitwidgets/simpleselector/window.cpp b/examples/webkitwidgets/simpleselector/window.cpp
new file mode 100644
index 0000000..d3f60d3
--- /dev/null
+++ b/examples/webkitwidgets/simpleselector/window.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QWebElement>
+#include <QWebFrame>
+#include "window.h"
+
+//! [Window class constructor]
+Window::Window(QWidget *parent)
+ : QWidget(parent)
+{
+ setupUi(this);
+}
+//! [Window class constructor]
+
+//! [return pressed]
+void Window::on_elementLineEdit_returnPressed()
+{
+ QWebFrame *frame = webView->page()->mainFrame();
+
+//! [select elements]
+ QWebElement document = frame->documentElement();
+ QWebElementCollection elements = document.findAll(elementLineEdit->text());
+//! [select elements]
+
+ foreach (QWebElement element, elements)
+ element.setAttribute("style", "background-color: #f0f090");
+}
+//! [return pressed]
+
+//! [button clicked]
+void Window::on_highlightButton_clicked()
+{
+ on_elementLineEdit_returnPressed();
+}
+//! [button clicked]
+
+//! [set URL]
+void Window::setUrl(const QUrl &url)
+{
+ webView->setUrl(url);
+}
+//! [set URL]
diff --git a/examples/webkitwidgets/simpleselector/window.h b/examples/webkitwidgets/simpleselector/window.h
new file mode 100644
index 0000000..a1a1316
--- /dev/null
+++ b/examples/webkitwidgets/simpleselector/window.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <QUrl>
+#include <QWidget>
+//! [Window class definition]
+#include "ui_window.h"
+
+class Window : public QWidget, private Ui::Window
+{
+ Q_OBJECT
+
+public:
+ Window(QWidget *parent = 0);
+ void setUrl(const QUrl &url);
+
+public slots:
+ void on_elementLineEdit_returnPressed();
+ void on_highlightButton_clicked();
+};
+//! [Window class definition]
+
+#endif
diff --git a/examples/webkitwidgets/simpleselector/window.ui b/examples/webkitwidgets/simpleselector/window.ui
new file mode 100644
index 0000000..aa824df
--- /dev/null
+++ b/examples/webkitwidgets/simpleselector/window.ui
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Window</class>
+ <widget class="QWidget" name="Window">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>640</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Web Element Selector</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QWebView" name="webView">
+ <property name="url">
+ <url>
+ <string>http://webkit.org/</string>
+ </url>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="elementLabel">
+ <property name="text">
+ <string>&amp;Element:</string>
+ </property>
+ <property name="buddy">
+ <cstring>elementLineEdit</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="elementLineEdit">
+ <property name="text">
+ <string>li a</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QPushButton" name="highlightButton">
+ <property name="text">
+ <string>&amp;Highlight</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QWebView</class>
+ <extends>QWidget</extends>
+ <header>QtWebKit/QWebView</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/webkitwidgets/webkitwidgets.pro b/examples/webkitwidgets/webkitwidgets.pro
new file mode 100644
index 0000000..ab20df4
--- /dev/null
+++ b/examples/webkitwidgets/webkitwidgets.pro
@@ -0,0 +1,12 @@
+TEMPLATE = subdirs
+SUBDIRS += domtraversal \
+ formextractor \
+ previewer \
+ fancybrowser \
+ simpleselector \
+ imageanalyzer \
+ framecapture \
+ browser \
+ embedded \
+ scroller \
+ xmlpatterns
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/forms/mainwindow.ui b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/forms/mainwindow.ui
new file mode 100644
index 0000000..ad43284
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/forms/mainwindow.ui
@@ -0,0 +1,196 @@
+<ui version="4.0" >
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>QObjectXmlModel Example</string>
+ </property>
+ <widget class="QWidget" name="centralwidget" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>29</y>
+ <width>800</width>
+ <height>549</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="font" >
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text" >
+ <string>See the About menu entry for a description of this example.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="inheritanceTab" >
+ <property name="autoFillBackground" >
+ <bool>true</bool>
+ </property>
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="wholeTreeTab" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>778</width>
+ <height>475</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Whole QObjectTree</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QSplitter" name="splitter" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <widget class="QTextEdit" name="wholeTree" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Minimum" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ <property name="html" >
+ <string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
+p, li { white-space: pre-wrap; }
+&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&lt;/p>&lt;/body>&lt;/html></string>
+ </property>
+ <property name="acceptRichText" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QTextEdit" name="wholeTreeOutput" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ <property name="html" >
+ <string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
+p, li { white-space: pre-wrap; }
+&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&lt;/p>&lt;/body>&lt;/html></string>
+ </property>
+ <property name="acceptRichText" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="htmlTab" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>778</width>
+ <height>475</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Statistics in HTML </string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_2" >
+ <item>
+ <widget class="QSplitter" name="splitter_2" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <widget class="QTextEdit" name="htmlQueryEdit" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ <property name="html" >
+ <string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
+p, li { white-space: pre-wrap; }
+&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&lt;/p>&lt;/body>&lt;/html></string>
+ </property>
+ <property name="acceptRichText" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QWebView" name="htmlOutput" >
+ <property name="url" >
+ <url>
+ <string>about:blank</string>
+ </url>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuHelp" >
+ <property name="title" >
+ <string>Help</string>
+ </property>
+ <addaction name="actionAbout" />
+ </widget>
+ <addaction name="menuHelp" />
+ </widget>
+ <widget class="QStatusBar" name="statusbar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>578</y>
+ <width>800</width>
+ <height>22</height>
+ </rect>
+ </property>
+ </widget>
+ <action name="actionAbout" >
+ <property name="text" >
+ <string>About</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+B</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QWebView</class>
+ <extends>QWidget</extends>
+ <header>QtWebKit/QWebView</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/main.cpp b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/main.cpp
new file mode 100644
index 0000000..090c14b
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/main.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+
+#include "mainwindow.h"
+
+int main(int argc, char* argv[])
+{
+ Q_INIT_RESOURCE(queries);
+ QApplication app(argc, argv);
+ MainWindow mainWindow;
+ mainWindow.show();
+ return app.exec();
+}
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/mainwindow.cpp b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/mainwindow.cpp
new file mode 100644
index 0000000..c20e0a4
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/mainwindow.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets>
+#include <QtXmlPatterns>
+
+#include "mainwindow.h"
+#include "qobjectxmlmodel.h"
+#include "xmlsyntaxhighlighter.h"
+
+MainWindow::MainWindow()
+{
+ setupUi(this);
+
+ new XmlSyntaxHighlighter(wholeTreeOutput->document());
+
+ /* Setup the font. */
+ {
+ QFont font("Courier");
+ font.setFixedPitch(true);
+
+ wholeTree->setFont(font);
+ wholeTreeOutput->setFont(font);
+ htmlQueryEdit->setFont(font);
+ }
+
+ QXmlNamePool namePool;
+ QObjectXmlModel qObjectModel(this, namePool);
+ QXmlQuery query(namePool);
+
+ /* The QObject tree as XML view. */
+ {
+ query.bindVariable("root", qObjectModel.root());
+ query.setQuery(QUrl("qrc:/queries/wholeTree.xq"));
+
+ Q_ASSERT(query.isValid());
+ QByteArray output;
+ QBuffer buffer(&output);
+ buffer.open(QIODevice::WriteOnly);
+
+ /* Let's the use the formatter, so it's a bit easier to read. */
+ QXmlFormatter serializer(query, &buffer);
+
+ query.evaluateTo(&serializer);
+ buffer.close();
+
+ {
+ QFile queryFile(":/queries/wholeTree.xq");
+ queryFile.open(QIODevice::ReadOnly);
+ wholeTree->setPlainText(QString::fromUtf8(queryFile.readAll()));
+ wholeTreeOutput->setPlainText(QString::fromUtf8(output.constData()));
+ }
+ }
+
+ /* The QObject occurrence statistics as HTML view. */
+ {
+ query.setQuery(QUrl("qrc:/queries/statisticsInHTML.xq"));
+ Q_ASSERT(query.isValid());
+
+ QByteArray output;
+ QBuffer buffer(&output);
+ buffer.open(QIODevice::WriteOnly);
+
+ /* Let's the use the serializer, so we gain a bit of speed. */
+ QXmlSerializer serializer(query, &buffer);
+
+ query.evaluateTo(&serializer);
+ buffer.close();
+
+ {
+ QFile queryFile(":/queries/statisticsInHTML.xq");
+ queryFile.open(QIODevice::ReadOnly);
+ htmlQueryEdit->setPlainText(QString::fromUtf8(queryFile.readAll()));
+ htmlOutput->setHtml(QString(output));
+ }
+ }
+}
+
+void MainWindow::on_actionAbout_triggered()
+{
+ QMessageBox::about(this,
+ tr("About QObject XML Model"),
+ tr("<p>The <b>QObject XML Model</b> example shows "
+ "how to use XQuery on top of data of your choice "
+ "without converting it to an XML document.</p>"
+ "<p>In this example a QSimpleXmlNodeModel subclass "
+ "makes it possible to query a QObject tree using "
+ "XQuery and retrieve the result as pointers to "
+ "QObjects, or as XML.</p>"
+ "<p>A possible use case of this could be to write "
+ "an application that tests a graphical interface "
+ "against Human Interface Guidelines, or that "
+ "queries an application's data which is modeled "
+ "using a QObject tree and dynamic properties."));
+}
+
+
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/mainwindow.h b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/mainwindow.h
new file mode 100644
index 0000000..8297151
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/mainwindow.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QFile>
+
+#include "ui_mainwindow.h"
+
+//! [0]
+class MainWindow : public QMainWindow,
+ private Ui_MainWindow
+{
+ Q_OBJECT
+
+ public:
+ MainWindow();
+
+ private slots:
+ void on_actionAbout_triggered();
+};
+//! [0]
+
+#endif
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp
new file mode 100644
index 0000000..18aba24
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.cpp
@@ -0,0 +1,458 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QVector>
+#include <QtDebug>
+
+#include <QCoreApplication>
+#include <QMetaProperty>
+#include <QXmlQuery>
+#include <QXmlResultItems>
+
+#include "qobjectxmlmodel.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+<metaObjects>
+ <metaObject className="QObject"/>
+ <metaObject className="QWidget" superClass="QObject">
+ </metaObject>
+ ...
+</metaObjects>
+<QObject objectName="MyWidget" property1="..." property2="..."> <!-- This is root() -->
+ <QObject objectName="MyFOO" property1="..."/>
+ ....
+</QObject>
+*/
+
+QObjectXmlModel::QObjectXmlModel(QObject *const object, const QXmlNamePool &np)
+ : QSimpleXmlNodeModel(np),
+ m_baseURI(QUrl::fromLocalFile(QCoreApplication::applicationFilePath())),
+ m_root(object),
+ m_allMetaObjects(allMetaObjects())
+{
+ Q_ASSERT(m_baseURI.isValid());
+}
+
+//! [5]
+QXmlNodeModelIndex QObjectXmlModel::qObjectSibling(const int pos, const QXmlNodeModelIndex &n) const
+{
+ Q_ASSERT(pos == 1 || pos == -1);
+ Q_ASSERT(asQObject(n));
+
+ const QObject *parent = asQObject(n)->parent();
+ if (parent) {
+ const QList<QObject *> &children = parent->children();
+ const int siblingPos = children.indexOf(asQObject(n)) + pos;
+
+ if (siblingPos >= 0 && siblingPos < children.count())
+ return createIndex(children.at(siblingPos));
+ else
+ return QXmlNodeModelIndex();
+ }
+ else
+ return QXmlNodeModelIndex();
+}
+//! [5]
+
+//! [1]
+QObjectXmlModel::QObjectNodeType QObjectXmlModel::toNodeType(const QXmlNodeModelIndex &n)
+{
+ return QObjectNodeType(n.additionalData() & (15 << 26));
+}
+//! [1]
+
+//! [9]
+QObjectXmlModel::AllMetaObjects QObjectXmlModel::allMetaObjects() const
+{
+ QXmlQuery query(namePool());
+ query.bindVariable("root", root());
+ query.setQuery("declare variable $root external;"
+ "$root/descendant-or-self::QObject");
+ Q_ASSERT(query.isValid());
+
+ QXmlResultItems result;
+ query.evaluateTo(&result);
+ QXmlItem i(result.next());
+
+ AllMetaObjects objects;
+ while (!i.isNull()) {
+ const QMetaObject *moo = asQObject(i.toNodeModelIndex())->metaObject();
+ while (moo) {
+ if (!objects.contains(moo))
+ objects.append(moo);
+ moo = moo->superClass();
+ }
+ i = result.next();
+ }
+
+ Q_ASSERT(!objects.contains(0));
+ return objects;
+}
+//! [9]
+
+QXmlNodeModelIndex QObjectXmlModel::metaObjectSibling(const int pos, const QXmlNodeModelIndex &n) const
+{
+ Q_ASSERT(pos == 1 || pos == -1);
+ Q_ASSERT(!n.isNull());
+
+ const int indexOf = m_allMetaObjects.indexOf(static_cast<const QMetaObject *>(n.internalPointer())) + pos;
+
+ if (indexOf >= 0 && indexOf < m_allMetaObjects.count())
+ return createIndex(const_cast<QMetaObject *>(m_allMetaObjects.at(indexOf)), MetaObject);
+ else
+ return QXmlNodeModelIndex();
+}
+
+//! [2]
+QXmlNodeModelIndex QObjectXmlModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &n) const
+{
+ switch (toNodeType(n))
+ {
+ case IsQObject:
+ {
+ switch (axis)
+ {
+ case Parent:
+ return createIndex(asQObject(n)->parent());
+
+ case FirstChild:
+ {
+ if (!asQObject(n) || asQObject(n)->children().isEmpty())
+ return QXmlNodeModelIndex();
+ else
+ return createIndex(asQObject(n)->children().first());
+ }
+
+ case NextSibling:
+ return qObjectSibling(1, n);
+
+//! [10]
+ case PreviousSibling:
+ {
+ if (asQObject(n) == m_root)
+ return createIndex(qint64(0), MetaObjects);
+ else
+ return qObjectSibling(-1, n);
+ }
+//! [10]
+ }
+ Q_ASSERT(false);
+ }
+
+//! [7]
+ case QObjectClassName:
+ case QObjectProperty:
+ {
+ Q_ASSERT(axis == Parent);
+ return createIndex(asQObject(n));
+ }
+//! [7]
+//! [2]
+//! [3]
+
+//! [11]
+ case MetaObjects:
+ {
+ switch (axis)
+ {
+ case Parent:
+ return QXmlNodeModelIndex();
+ case PreviousSibling:
+ return QXmlNodeModelIndex();
+ case NextSibling:
+ return root();
+ case FirstChild:
+ {
+ return createIndex(const_cast<QMetaObject*>(m_allMetaObjects.first()),MetaObject);
+ }
+ }
+ Q_ASSERT(false);
+ }
+//! [11]
+
+ case MetaObject:
+ {
+ switch (axis)
+ {
+ case FirstChild:
+ return QXmlNodeModelIndex();
+ case Parent:
+ return createIndex(qint64(0), MetaObjects);
+ case PreviousSibling:
+ return metaObjectSibling(-1, n);
+ case NextSibling:
+ return metaObjectSibling(1, n);
+ }
+ }
+
+ case MetaObjectClassName:
+ case MetaObjectSuperClass:
+ {
+ Q_ASSERT(axis == Parent);
+ return createIndex(asQObject(n), MetaObject);
+ }
+//! [3]
+//! [4]
+ }
+
+ Q_ASSERT(false);
+ return QXmlNodeModelIndex();
+}
+//! [4]
+
+//! [6]
+QVector<QXmlNodeModelIndex> QObjectXmlModel::attributes(const QXmlNodeModelIndex& n) const
+{
+ QVector<QXmlNodeModelIndex> result;
+ QObject *const object = asQObject(n);
+
+ switch(toNodeType(n))
+ {
+ case IsQObject:
+ {
+ const QMetaObject *const metaObject = object->metaObject();
+ const int count = metaObject->propertyCount();
+ result.append(createIndex(object, QObjectClassName));
+
+ for (int i = 0; i < count; ++i) {
+ const QMetaProperty qmp(metaObject->property(i));
+ const int ii = metaObject->indexOfProperty(qmp.name());
+ if (i == ii)
+ result.append(createIndex(object, QObjectProperty | i));
+ }
+ return result;
+ }
+//! [6]
+
+ case MetaObject:
+ {
+ result.append(createIndex(object, MetaObjectClassName));
+ result.append(createIndex(object, MetaObjectSuperClass));
+ return result;
+ }
+//! [8]
+ default:
+ return QVector<QXmlNodeModelIndex>();
+ }
+}
+//! [8]
+
+QObject *QObjectXmlModel::asQObject(const QXmlNodeModelIndex &n)
+{
+ return static_cast<QObject *>(n.internalPointer());
+}
+
+bool QObjectXmlModel::isProperty(const QXmlNodeModelIndex n)
+{
+ return n.additionalData() & QObjectProperty;
+}
+
+QUrl QObjectXmlModel::documentUri(const QXmlNodeModelIndex& ) const
+{
+ return m_baseURI;
+}
+
+QXmlNodeModelIndex::NodeKind QObjectXmlModel::kind(const QXmlNodeModelIndex& n) const
+{
+ switch (toNodeType(n))
+ {
+ case IsQObject:
+ case MetaObject:
+ case MetaObjects:
+ return QXmlNodeModelIndex::Element;
+
+ case QObjectProperty:
+ case MetaObjectClassName:
+ case MetaObjectSuperClass:
+ case QObjectClassName:
+ return QXmlNodeModelIndex::Attribute;
+ }
+
+ Q_ASSERT(false);
+ return QXmlNodeModelIndex::Element;
+}
+
+QXmlNodeModelIndex::DocumentOrder QObjectXmlModel::compareOrder(const QXmlNodeModelIndex& , const QXmlNodeModelIndex& ) const
+{
+ return QXmlNodeModelIndex::Follows; // TODO
+}
+
+//! [0]
+QXmlNodeModelIndex QObjectXmlModel::root() const
+{
+ return createIndex(m_root);
+}
+//! [0]
+
+QXmlNodeModelIndex QObjectXmlModel::root(const QXmlNodeModelIndex& n) const
+{
+ QObject *p = asQObject(n);
+ Q_ASSERT(p);
+
+ do {
+ QObject *const candidate = p->parent();
+ if (candidate)
+ p = candidate;
+ else
+ break;
+ }
+ while (true);
+
+ return createIndex(p);
+}
+
+/*!
+ We simply throw all of them into a QList and
+ return an iterator over it.
+ */
+QXmlNodeModelIndex::List QObjectXmlModel::ancestors(const QXmlNodeModelIndex n) const
+{
+ const QObject *p = asQObject(n);
+ Q_ASSERT(p);
+
+ QXmlNodeModelIndex::List result;
+ do {
+ QObject *const candidate = p->parent();
+ if (candidate) {
+ result.append(createIndex(candidate, 0));
+ p = candidate;
+ }
+ else
+ break;
+ }
+ while (true);
+
+ return result;
+}
+
+QMetaProperty QObjectXmlModel::toMetaProperty(const QXmlNodeModelIndex &n)
+{
+ const int propertyOffset = n.additionalData() & (~QObjectProperty);
+ const QObject *const qo = asQObject(n);
+ return qo->metaObject()->property(propertyOffset);
+}
+
+QXmlName QObjectXmlModel::name(const QXmlNodeModelIndex &n) const
+{
+ switch (toNodeType(n))
+ {
+ case IsQObject:
+ return QXmlName(namePool(), QLatin1String("QObject"));
+ case MetaObject:
+ return QXmlName(namePool(), QLatin1String("metaObject"));
+ case QObjectClassName:
+ case MetaObjectClassName:
+ return QXmlName(namePool(), QLatin1String("className"));
+ case QObjectProperty:
+ return QXmlName(namePool(), toMetaProperty(n).name());
+ case MetaObjects:
+ return QXmlName(namePool(), QLatin1String("metaObjects"));
+ case MetaObjectSuperClass:
+ return QXmlName(namePool(), QLatin1String("superClass"));
+ }
+
+ Q_ASSERT(false);
+ return QXmlName();
+}
+
+QVariant QObjectXmlModel::typedValue(const QXmlNodeModelIndex &n) const
+{
+ switch (toNodeType(n))
+ {
+ case QObjectProperty:
+ {
+ const QVariant &candidate = toMetaProperty(n).read(asQObject(n));
+ if (isTypeSupported(candidate.type()))
+ return candidate;
+ else
+ return QVariant();
+ }
+
+ case MetaObjectClassName:
+ return QVariant(static_cast<QMetaObject*>(n.internalPointer())->className());
+
+ case MetaObjectSuperClass:
+ {
+ const QMetaObject *const superClass = static_cast<QMetaObject*>(n.internalPointer())->superClass();
+ if (superClass)
+ return QVariant(superClass->className());
+ else
+ return QVariant();
+ }
+
+ case QObjectClassName:
+ return QVariant(asQObject(n)->metaObject()->className());
+
+ default:
+ return QVariant();
+ }
+}
+
+/*!
+ Returns \c true if QVariants of type \a type can be used
+ in QtXmlPatterns, otherwise \c false.
+ */
+bool QObjectXmlModel::isTypeSupported(QVariant::Type type)
+{
+ /* See data/qatomicvalue.cpp too. */
+ switch (type)
+ {
+ /* Fallthrough all these. */
+ case QVariant::Char:
+ case QVariant::String:
+ case QVariant::Url:
+ case QVariant::Bool:
+ case QVariant::ByteArray:
+ case QVariant::Int:
+ case QVariant::LongLong:
+ case QVariant::ULongLong:
+ case QVariant::Date:
+ case QVariant::DateTime:
+ case QVariant::Time:
+ case QVariant::Double:
+ return true;
+ default:
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.h b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.h
new file mode 100644
index 0000000..46bf7df
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Patternist_QObjectNodeModel_H
+#define Patternist_QObjectNodeModel_H
+
+#include <QSimpleXmlNodeModel>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class PropertyToAtomicValue;
+
+/**
+ * @short Delegates QtCore's QObject into Patternist's QAbstractXmlNodeModel.
+ * known as pre/post numbering.
+ *
+ * QObjectXmlModel sets the toggle on QXmlNodeModelIndex to @c true, if it
+ * represents a property of the QObject. That is, if the QXmlNodeModelIndex is
+ * an attribute.
+ *
+ * @author Frans Englich <frans.englich@nokia.com>
+ */
+class QObjectXmlModel : public QSimpleXmlNodeModel
+{
+ public:
+ QObjectXmlModel(QObject *const object, const QXmlNamePool &np);
+
+ QXmlNodeModelIndex root() const;
+
+//! [0]
+ virtual QXmlNodeModelIndex::DocumentOrder compareOrder(const QXmlNodeModelIndex &n1, const QXmlNodeModelIndex &n2) const;
+ virtual QXmlName name(const QXmlNodeModelIndex &n) const;
+ virtual QUrl documentUri(const QXmlNodeModelIndex &n) const;
+ virtual QXmlNodeModelIndex::NodeKind kind(const QXmlNodeModelIndex &n) const;
+ virtual QXmlNodeModelIndex root(const QXmlNodeModelIndex &n) const;
+ virtual QVariant typedValue(const QXmlNodeModelIndex &n) const;
+ virtual QVector<QXmlNodeModelIndex> attributes(const QXmlNodeModelIndex&) const;
+ virtual QXmlNodeModelIndex nextFromSimpleAxis(SimpleAxis, const QXmlNodeModelIndex&) const;
+//! [0]
+
+ private:
+ /**
+ * The highest three bits are used to signify whether the node index
+ * is an artificial node.
+ *
+ * @short if QXmlNodeModelIndex::additionalData() has the
+ * QObjectPropery flag set, then the QXmlNodeModelIndex is an
+ * attribute of the QObject element, and the remaining bits form
+ * an offset to the QObject property that the QXmlNodeModelIndex
+ * refers to.
+ *
+ */
+//! [3]
+ enum QObjectNodeType
+ {
+ IsQObject = 0,
+ QObjectProperty = 1 << 26,
+ MetaObjects = 2 << 26,
+ MetaObject = 3 << 26,
+ MetaObjectClassName = 4 << 26,
+ MetaObjectSuperClass = 5 << 26,
+ QObjectClassName = 6 << 26
+ };
+//! [3]
+
+//! [1]
+ typedef QVector<const QMetaObject *> AllMetaObjects;
+//! [1]
+ AllMetaObjects allMetaObjects() const;
+
+ static QObjectNodeType toNodeType(const QXmlNodeModelIndex &n);
+ static bool isTypeSupported(QVariant::Type type);
+ static inline QObject *asQObject(const QXmlNodeModelIndex &n);
+ static inline bool isProperty(const QXmlNodeModelIndex n);
+ static inline QMetaProperty toMetaProperty(const QXmlNodeModelIndex &n);
+ /**
+ * Returns the ancestors of @p n. Does therefore not include
+ * @p n.
+ */
+ inline QXmlNodeModelIndex::List ancestors(const QXmlNodeModelIndex n) const;
+ QXmlNodeModelIndex qObjectSibling(const int pos,
+ const QXmlNodeModelIndex &n) const;
+ QXmlNodeModelIndex metaObjectSibling(const int pos,
+ const QXmlNodeModelIndex &n) const;
+
+//! [2]
+ const QUrl m_baseURI;
+ QObject *const m_root;
+//! [4]
+ const AllMetaObjects m_allMetaObjects;
+//! [4]
+//! [2]
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.pro b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.pro
new file mode 100644
index 0000000..6ade863
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/qobjectxmlmodel.pro
@@ -0,0 +1,10 @@
+
+FORMS += forms/mainwindow.ui
+QT += xmlpatterns webkitwidgets widgets
+SOURCES += qobjectxmlmodel.cpp main.cpp mainwindow.cpp xmlsyntaxhighlighter.cpp
+HEADERS += qobjectxmlmodel.h mainwindow.h xmlsyntaxhighlighter.h
+RESOURCES = queries.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webkitwidgets/xmlpatterns/qobjectxmlmodel
+INSTALLS += target
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries.qrc b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries.qrc
new file mode 100644
index 0000000..ec8cc6b
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC>
+ <RCC version="1.0">
+<qresource>
+ <file>queries/wholeTree.xq</file>
+ <file>queries/statisticsInHTML.xq</file>
+</qresource>
+</RCC>
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries/statisticsInHTML.xq b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries/statisticsInHTML.xq
new file mode 100644
index 0000000..14a7a14
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries/statisticsInHTML.xq
@@ -0,0 +1,58 @@
+<html>
+ <head>
+ <title></title>
+ </head>
+ <body>
+ <p>In total the tree has {count($root//QObject)} QObject instances.</p>
+ <p>Order by occurrence, the QObjects are:</p>
+
+ <ol>
+ {
+ for $i in $root/preceding-sibling::metaObjects/metaObject
+ let $count := count($root//QObject[@className eq $i/@className])
+ stable order by $count descending
+ return if($count > 1)
+ then <li>{string($i/@className), $count} occurrences</li>
+ else ()
+ }
+ </ol>
+
+ <h1>Properties</h1>
+ {
+ (: For each QObject, we create a table listing
+ : the properties of that object. :)
+ for $object in $root//QObject
+ return (<h2>{let $name := string($object/@objectName)
+ return if(string-length($name))
+ then $name
+ else "[no name]",
+ '(', string($object/@className), ')'}</h2>,
+ <table border="1">
+ <thead>
+ <tr>
+ <td>Property Name</td>
+ <td>Value</td>
+ </tr>
+ </thead>
+ <tbody>
+ {
+ $object/@*/<tr>
+ <td>
+ {
+ name()
+ }
+ </td>
+ <td>
+ {
+ if(data(.))
+ then string(.)
+ else "N/A"
+ }
+ </td>
+ </tr>
+ }
+ </tbody>
+ </table>)
+ }
+ </body>
+</html>
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries/wholeTree.xq b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries/wholeTree.xq
new file mode 100644
index 0000000..253cd43
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/queries/wholeTree.xq
@@ -0,0 +1,3 @@
+<!-- This is the QObject tree for this application, rendered as XML. -->,
+$root/preceding-sibling::metaObjects,
+$root
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/xmlsyntaxhighlighter.cpp b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/xmlsyntaxhighlighter.cpp
new file mode 100644
index 0000000..790a66f
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/xmlsyntaxhighlighter.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "xmlsyntaxhighlighter.h"
+
+XmlSyntaxHighlighter::XmlSyntaxHighlighter(QTextDocument *parent)
+ : QSyntaxHighlighter(parent)
+{
+ HighlightingRule rule;
+
+ // tag format
+ tagFormat.setForeground(Qt::darkBlue);
+ tagFormat.setFontWeight(QFont::Bold);
+ rule.pattern = QRegExp("(<[a-zA-Z:]+\\b|<\\?[a-zA-Z:]+\\b|\\?>|>|/>|</[a-zA-Z:]+>)");
+ rule.format = tagFormat;
+ highlightingRules.append(rule);
+
+ // attribute format
+ attributeFormat.setForeground(Qt::darkGreen);
+ rule.pattern = QRegExp("[a-zA-Z:]+=");
+ rule.format = attributeFormat;
+ highlightingRules.append(rule);
+
+ // attribute content format
+ attributeContentFormat.setForeground(Qt::red);
+ rule.pattern = QRegExp("(\"[^\"]*\"|'[^']*')");
+ rule.format = attributeContentFormat;
+ highlightingRules.append(rule);
+
+ commentFormat.setForeground(Qt::lightGray);
+ commentFormat.setFontItalic(true);
+
+ commentStartExpression = QRegExp("<!--");
+ commentEndExpression = QRegExp("-->");
+}
+
+void XmlSyntaxHighlighter::highlightBlock(const QString &text)
+{
+ foreach (const HighlightingRule &rule, highlightingRules) {
+ QRegExp expression(rule.pattern);
+ int index = text.indexOf(expression);
+ while (index >= 0) {
+ int length = expression.matchedLength();
+ setFormat(index, length, rule.format);
+ index = text.indexOf(expression, index + length);
+ }
+ }
+ setCurrentBlockState(0);
+
+ int startIndex = 0;
+ if (previousBlockState() != 1)
+ startIndex = text.indexOf(commentStartExpression);
+
+ while (startIndex >= 0) {
+ int endIndex = text.indexOf(commentEndExpression, startIndex);
+ int commentLength;
+ if (endIndex == -1) {
+ setCurrentBlockState(1);
+ commentLength = text.length() - startIndex;
+ } else {
+ commentLength = endIndex - startIndex
+ + commentEndExpression.matchedLength();
+ }
+ setFormat(startIndex, commentLength, commentFormat);
+ startIndex = text.indexOf(commentStartExpression,
+ startIndex + commentLength);
+ }
+}
diff --git a/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/xmlsyntaxhighlighter.h b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/xmlsyntaxhighlighter.h
new file mode 100644
index 0000000..b4fb9dd
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/qobjectxmlmodel/xmlsyntaxhighlighter.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * 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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "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 THE COPYRIGHT
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef XMLSYNTAXHIGHLIGHTER_H
+#define XMLSYNTAXHIGHLIGHTER_H
+
+#include <QtGui/QSyntaxHighlighter>
+
+class XmlSyntaxHighlighter : public QSyntaxHighlighter
+{
+ public:
+ XmlSyntaxHighlighter(QTextDocument *parent = 0);
+
+ protected:
+ virtual void highlightBlock(const QString &text);
+
+ private:
+ struct HighlightingRule
+ {
+ QRegExp pattern;
+ QTextCharFormat format;
+ };
+ QVector<HighlightingRule> highlightingRules;
+
+ QRegExp commentStartExpression;
+ QRegExp commentEndExpression;
+
+ QTextCharFormat tagFormat;
+ QTextCharFormat attributeFormat;
+ QTextCharFormat attributeContentFormat;
+ QTextCharFormat commentFormat;
+};
+
+#endif
diff --git a/examples/webkitwidgets/xmlpatterns/xmlpatterns.pro b/examples/webkitwidgets/xmlpatterns/xmlpatterns.pro
new file mode 100644
index 0000000..4e8c909
--- /dev/null
+++ b/examples/webkitwidgets/xmlpatterns/xmlpatterns.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += qobjectxmlmodel