From a2feb3c4610111ad86efa197f8711ee902891d3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= <juri.valdmann@qt.io> Date: Wed, 19 Jul 2017 17:05:00 +0200 Subject: [PATCH] Remove DemoBrowser [ChangeLog][Examples] Removed WebEngine Demo Browser example, which got superseded by the improved WebEngine Widgets Simple Browser. Task-number: QTBUG-59819 Change-Id: I214e6f5f3a946ed617a9f4d628d3259a69874ca1 Reviewed-by: Kai Koehne <kai.koehne@qt.io> Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io> --- .../demobrowser/Info_mac.plist | 47 - .../demobrowser/addbookmarkdialog.ui | 98 -- .../demobrowser/autosaver.cpp | 102 -- .../webenginewidgets/demobrowser/autosaver.h | 84 -- .../demobrowser/bookmarks.cpp | 993 ------------- .../webenginewidgets/demobrowser/bookmarks.h | 318 ---- .../webenginewidgets/demobrowser/bookmarks.ui | 106 -- .../demobrowser/browserapplication.cpp | 587 -------- .../demobrowser/browserapplication.h | 140 -- .../demobrowser/browsermainwindow.cpp | 1032 ------------- .../demobrowser/browsermainwindow.h | 189 --- .../demobrowser/chasewidget.cpp | 150 -- .../demobrowser/chasewidget.h | 94 -- .../demobrowser/cookiejar.cpp | 746 ---------- .../webenginewidgets/demobrowser/cookiejar.h | 212 --- .../webenginewidgets/demobrowser/cookies.ui | 106 -- .../demobrowser/cookiesexceptions.ui | 184 --- .../demobrowser/data/addtab.png | Bin 469 -> 0 bytes .../demobrowser/data/closetab.png | Bin 516 -> 0 bytes .../demobrowser/data/data.qrc | 11 - .../demobrowser/data/defaultbookmarks.xbel | 40 - .../demobrowser/data/defaulticon.png | Bin 1473 -> 0 bytes .../demobrowser/data/demobrowser.svg | 24 - .../demobrowser/data/history.png | Bin 1527 -> 0 bytes .../demobrowser/data/loading.gif | Bin 847 -> 0 bytes .../demobrowser/demobrowser.icns | Bin 31513 -> 0 bytes .../demobrowser/demobrowser.ico | Bin 82726 -> 0 bytes .../demobrowser/demobrowser.pro | 95 -- .../demobrowser/demobrowser.rc | 1 - .../demobrowser/doc/images/browser-demo.png | Bin 199354 -> 0 bytes .../demobrowser/doc/src/demobrowser.qdoc | 40 - .../demobrowser/downloaditem.ui | 133 -- .../demobrowser/downloadmanager.cpp | 505 ------- .../demobrowser/downloadmanager.h | 163 -- .../webenginewidgets/demobrowser/downloads.ui | 83 -- .../demobrowser/edittableview.cpp | 86 -- .../demobrowser/edittableview.h | 69 - .../demobrowser/edittreeview.cpp | 86 -- .../demobrowser/edittreeview.h | 69 - .../demobrowser/featurepermissionbar.cpp | 137 -- .../demobrowser/featurepermissionbar.h | 83 -- .../demobrowser/fullscreennotification.cpp | 121 -- .../demobrowser/fullscreennotification.h | 86 -- .../webenginewidgets/demobrowser/history.cpp | 1314 ----------------- .../webenginewidgets/demobrowser/history.h | 360 ----- .../webenginewidgets/demobrowser/history.ui | 106 -- .../demobrowser/htmls/htmls.qrc | 5 - .../demobrowser/htmls/notfound.html | 63 - .../webenginewidgets/demobrowser/main.cpp | 65 - .../demobrowser/modelmenu.cpp | 235 --- .../webenginewidgets/demobrowser/modelmenu.h | 113 -- .../demobrowser/passworddialog.ui | 111 -- .../demobrowser/printtopdfdialog.cpp | 125 -- .../demobrowser/printtopdfdialog.h | 86 -- .../demobrowser/printtopdfdialog.ui | 119 -- .../webenginewidgets/demobrowser/proxy.ui | 104 -- .../demobrowser/savepagedialog.cpp | 139 -- .../demobrowser/savepagedialog.h | 90 -- .../demobrowser/savepagedialog.ui | 139 -- .../demobrowser/searchlineedit.cpp | 249 ---- .../demobrowser/searchlineedit.h | 111 -- .../webenginewidgets/demobrowser/settings.cpp | 323 ---- .../webenginewidgets/demobrowser/settings.h | 85 -- .../webenginewidgets/demobrowser/settings.ui | 621 -------- .../demobrowser/squeezelabel.cpp | 69 - .../demobrowser/squeezelabel.h | 68 - .../demobrowser/tabwidget.cpp | 1012 ------------- .../webenginewidgets/demobrowser/tabwidget.h | 263 ---- .../demobrowser/toolbarsearch.cpp | 172 --- .../demobrowser/toolbarsearch.h | 92 -- .../demobrowser/urllineedit.cpp | 345 ----- .../demobrowser/urllineedit.h | 123 -- .../webenginewidgets/demobrowser/webview.cpp | 470 ------ .../webenginewidgets/demobrowser/webview.h | 128 -- .../webenginewidgets/demobrowser/xbel.cpp | 291 ---- examples/webenginewidgets/demobrowser/xbel.h | 120 -- .../webenginewidgets/webenginewidgets.pro | 1 - .../doc/src/qtwebengine-features.qdoc | 30 +- .../doc/src/qwebengineview_lgpl.qdoc | 2 +- 79 files changed, 16 insertions(+), 14753 deletions(-) delete mode 100644 examples/webenginewidgets/demobrowser/Info_mac.plist delete mode 100644 examples/webenginewidgets/demobrowser/addbookmarkdialog.ui delete mode 100644 examples/webenginewidgets/demobrowser/autosaver.cpp delete mode 100644 examples/webenginewidgets/demobrowser/autosaver.h delete mode 100644 examples/webenginewidgets/demobrowser/bookmarks.cpp delete mode 100644 examples/webenginewidgets/demobrowser/bookmarks.h delete mode 100644 examples/webenginewidgets/demobrowser/bookmarks.ui delete mode 100644 examples/webenginewidgets/demobrowser/browserapplication.cpp delete mode 100644 examples/webenginewidgets/demobrowser/browserapplication.h delete mode 100644 examples/webenginewidgets/demobrowser/browsermainwindow.cpp delete mode 100644 examples/webenginewidgets/demobrowser/browsermainwindow.h delete mode 100644 examples/webenginewidgets/demobrowser/chasewidget.cpp delete mode 100644 examples/webenginewidgets/demobrowser/chasewidget.h delete mode 100644 examples/webenginewidgets/demobrowser/cookiejar.cpp delete mode 100644 examples/webenginewidgets/demobrowser/cookiejar.h delete mode 100644 examples/webenginewidgets/demobrowser/cookies.ui delete mode 100644 examples/webenginewidgets/demobrowser/cookiesexceptions.ui delete mode 100644 examples/webenginewidgets/demobrowser/data/addtab.png delete mode 100644 examples/webenginewidgets/demobrowser/data/closetab.png delete mode 100644 examples/webenginewidgets/demobrowser/data/data.qrc delete mode 100644 examples/webenginewidgets/demobrowser/data/defaultbookmarks.xbel delete mode 100644 examples/webenginewidgets/demobrowser/data/defaulticon.png delete mode 100644 examples/webenginewidgets/demobrowser/data/demobrowser.svg delete mode 100644 examples/webenginewidgets/demobrowser/data/history.png delete mode 100644 examples/webenginewidgets/demobrowser/data/loading.gif delete mode 100644 examples/webenginewidgets/demobrowser/demobrowser.icns delete mode 100644 examples/webenginewidgets/demobrowser/demobrowser.ico delete mode 100644 examples/webenginewidgets/demobrowser/demobrowser.pro delete mode 100644 examples/webenginewidgets/demobrowser/demobrowser.rc delete mode 100644 examples/webenginewidgets/demobrowser/doc/images/browser-demo.png delete mode 100644 examples/webenginewidgets/demobrowser/doc/src/demobrowser.qdoc delete mode 100644 examples/webenginewidgets/demobrowser/downloaditem.ui delete mode 100644 examples/webenginewidgets/demobrowser/downloadmanager.cpp delete mode 100644 examples/webenginewidgets/demobrowser/downloadmanager.h delete mode 100644 examples/webenginewidgets/demobrowser/downloads.ui delete mode 100644 examples/webenginewidgets/demobrowser/edittableview.cpp delete mode 100644 examples/webenginewidgets/demobrowser/edittableview.h delete mode 100644 examples/webenginewidgets/demobrowser/edittreeview.cpp delete mode 100644 examples/webenginewidgets/demobrowser/edittreeview.h delete mode 100644 examples/webenginewidgets/demobrowser/featurepermissionbar.cpp delete mode 100644 examples/webenginewidgets/demobrowser/featurepermissionbar.h delete mode 100644 examples/webenginewidgets/demobrowser/fullscreennotification.cpp delete mode 100644 examples/webenginewidgets/demobrowser/fullscreennotification.h delete mode 100644 examples/webenginewidgets/demobrowser/history.cpp delete mode 100644 examples/webenginewidgets/demobrowser/history.h delete mode 100644 examples/webenginewidgets/demobrowser/history.ui delete mode 100644 examples/webenginewidgets/demobrowser/htmls/htmls.qrc delete mode 100644 examples/webenginewidgets/demobrowser/htmls/notfound.html delete mode 100644 examples/webenginewidgets/demobrowser/main.cpp delete mode 100644 examples/webenginewidgets/demobrowser/modelmenu.cpp delete mode 100644 examples/webenginewidgets/demobrowser/modelmenu.h delete mode 100644 examples/webenginewidgets/demobrowser/passworddialog.ui delete mode 100644 examples/webenginewidgets/demobrowser/printtopdfdialog.cpp delete mode 100644 examples/webenginewidgets/demobrowser/printtopdfdialog.h delete mode 100644 examples/webenginewidgets/demobrowser/printtopdfdialog.ui delete mode 100644 examples/webenginewidgets/demobrowser/proxy.ui delete mode 100644 examples/webenginewidgets/demobrowser/savepagedialog.cpp delete mode 100644 examples/webenginewidgets/demobrowser/savepagedialog.h delete mode 100644 examples/webenginewidgets/demobrowser/savepagedialog.ui delete mode 100644 examples/webenginewidgets/demobrowser/searchlineedit.cpp delete mode 100644 examples/webenginewidgets/demobrowser/searchlineedit.h delete mode 100644 examples/webenginewidgets/demobrowser/settings.cpp delete mode 100644 examples/webenginewidgets/demobrowser/settings.h delete mode 100644 examples/webenginewidgets/demobrowser/settings.ui delete mode 100644 examples/webenginewidgets/demobrowser/squeezelabel.cpp delete mode 100644 examples/webenginewidgets/demobrowser/squeezelabel.h delete mode 100644 examples/webenginewidgets/demobrowser/tabwidget.cpp delete mode 100644 examples/webenginewidgets/demobrowser/tabwidget.h delete mode 100644 examples/webenginewidgets/demobrowser/toolbarsearch.cpp delete mode 100644 examples/webenginewidgets/demobrowser/toolbarsearch.h delete mode 100644 examples/webenginewidgets/demobrowser/urllineedit.cpp delete mode 100644 examples/webenginewidgets/demobrowser/urllineedit.h delete mode 100644 examples/webenginewidgets/demobrowser/webview.cpp delete mode 100644 examples/webenginewidgets/demobrowser/webview.h delete mode 100644 examples/webenginewidgets/demobrowser/xbel.cpp delete mode 100644 examples/webenginewidgets/demobrowser/xbel.h diff --git a/examples/webenginewidgets/demobrowser/Info_mac.plist b/examples/webenginewidgets/demobrowser/Info_mac.plist deleted file mode 100644 index 25443f7be..000000000 --- a/examples/webenginewidgets/demobrowser/Info_mac.plist +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> -<plist version="1.0"> -<dict> - <key>NSPrincipalClass</key> - <string>NSApplication</string> - <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 The Qt Company Ltd.</string> - <key>NSSupportsAutomaticGraphicsSwitching</key> - <string>YES</string> -</dict> -</plist> diff --git a/examples/webenginewidgets/demobrowser/addbookmarkdialog.ui b/examples/webenginewidgets/demobrowser/addbookmarkdialog.ui deleted file mode 100644 index 3460d7bb8..000000000 --- a/examples/webenginewidgets/demobrowser/addbookmarkdialog.ui +++ /dev/null @@ -1,98 +0,0 @@ -<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/webenginewidgets/demobrowser/autosaver.cpp b/examples/webenginewidgets/demobrowser/autosaver.cpp deleted file mode 100644 index 005e291bd..000000000 --- a/examples/webenginewidgets/demobrowser/autosaver.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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/webenginewidgets/demobrowser/autosaver.h b/examples/webenginewidgets/demobrowser/autosaver.h deleted file mode 100644 index be6eeeb4c..000000000 --- a/examples/webenginewidgets/demobrowser/autosaver.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/bookmarks.cpp b/examples/webenginewidgets/demobrowser/bookmarks.cpp deleted file mode 100644 index 3d6d9c294..000000000 --- a/examples/webenginewidgets/demobrowser/bookmarks.cpp +++ /dev/null @@ -1,993 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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 <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/webenginewidgets/demobrowser/bookmarks.h b/examples/webenginewidgets/demobrowser/bookmarks.h deleted file mode 100644 index 922e7ce39..000000000 --- a/examples/webenginewidgets/demobrowser/bookmarks.h +++ /dev/null @@ -1,318 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/bookmarks.ui b/examples/webenginewidgets/demobrowser/bookmarks.ui deleted file mode 100644 index c893e941d..000000000 --- a/examples/webenginewidgets/demobrowser/bookmarks.ui +++ /dev/null @@ -1,106 +0,0 @@ -<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>&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/webenginewidgets/demobrowser/browserapplication.cpp b/examples/webenginewidgets/demobrowser/browserapplication.cpp deleted file mode 100644 index c3f3ef9b9..000000000 --- a/examples/webenginewidgets/demobrowser/browserapplication.cpp +++ /dev/null @@ -1,587 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "browserapplication.h" - -#include "bookmarks.h" -#include "browsermainwindow.h" -#include "cookiejar.h" -#include "downloadmanager.h" -#include "history.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 <QWebEngineProfile> -#include <QWebEngineSettings> -#include <QWebEngineScript> -#include <QWebEngineScriptCollection> - -#include <QtCore/QDebug> - -DownloadManager *BrowserApplication::s_downloadManager = 0; -HistoryManager *BrowserApplication::s_historyManager = 0; -QNetworkAccessManager *BrowserApplication::s_networkAccessManager = 0; -BookmarksManager *BrowserApplication::s_bookmarksManager = 0; - -static void setUserStyleSheet(QWebEngineProfile *profile, const QString &styleSheet, BrowserMainWindow *mainWindow = 0) -{ - Q_ASSERT(profile); - QString scriptName(QStringLiteral("userStyleSheet")); - QWebEngineScript script; - QList<QWebEngineScript> styleSheets = profile->scripts()->findScripts(scriptName); - if (!styleSheets.isEmpty()) - script = styleSheets.first(); - Q_FOREACH (const QWebEngineScript &s, styleSheets) - profile->scripts()->remove(s); - - if (script.isNull()) { - script.setName(scriptName); - script.setInjectionPoint(QWebEngineScript::DocumentReady); - script.setRunsOnSubFrames(true); - script.setWorldId(QWebEngineScript::ApplicationWorld); - } - QString source = QString::fromLatin1("(function() {"\ - "var css = document.getElementById(\"_qt_testBrowser_userStyleSheet\");"\ - "if (css == undefined) {"\ - " css = document.createElement(\"style\");"\ - " css.type = \"text/css\";"\ - " css.id = \"_qt_testBrowser_userStyleSheet\";"\ - " document.head.appendChild(css);"\ - "}"\ - "css.innerText = \"%1\";"\ - "})()").arg(styleSheet); - script.setSourceCode(source); - profile->scripts()->insert(script); - // run the script on the already loaded views - // this has to be deferred as it could mess with the storage initialization on startup - if (mainWindow) - QMetaObject::invokeMethod(mainWindow, "runScriptOnOpenViews", Qt::QueuedConnection, Q_ARG(QString, source)); -} - -BrowserApplication::BrowserApplication(int &argc, char **argv) - : QApplication(argc, argv) - , m_localServer(0) - , m_privateProfile(0) - , m_privateBrowsing(false) -{ - QCoreApplication::setOrganizationName(QLatin1String("Qt")); - QCoreApplication::setApplicationName(QLatin1String("demobrowser")); - QCoreApplication::setApplicationVersion(QLatin1String("0.1")); - QString serverName = QCoreApplication::applicationName() - + QString::fromLatin1(QT_VERSION_STR).remove('.') + QLatin1String("webengine"); - QLocalSocket socket; - socket.connectToServer(serverName); - if (socket.waitForConnected(500)) { - QTextStream stream(&socket); - stream << getCommandLineUrlArgument(); - stream.flush(); - socket.waitForBytesWritten(); - return; - } - -#if defined(Q_OS_OSX) - 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) - && m_localServer->serverError() == QAbstractSocket::AddressInUseError) { - QLocalServer::removeServer(serverName); - if (!m_localServer->listen(serverName)) - qWarning("Could not create local socket %s.", qPrintable(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_OS_OSX) - 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; -} - -void BrowserApplication::lastWindowClosed() -{ -#if defined(Q_OS_OSX) - clean(); - BrowserMainWindow *mw = new BrowserMainWindow; - mw->slotHome(); - m_mainWindows.prepend(mw); -#endif -} - -BrowserApplication *BrowserApplication::instance() -{ - return (static_cast<BrowserApplication *>(QCoreApplication::instance())); -} - -void BrowserApplication::quitBrowser() -{ -#if defined(Q_OS_OSX) - 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(); -#if defined(QWEBENGINESETTINGS_PATHS) - QWebEngineSettings::setIconDatabasePath(directory); - QWebEngineSettings::setOfflineStoragePath(directory); -#endif - - setWindowIcon(QIcon(QLatin1String(":demobrowser.svg"))); - - loadSettings(); - - // newMainWindow() needs to be called in main() for this to happen - if (m_mainWindows.count() > 0) { - const QString url = getCommandLineUrlArgument(); - if (!url.isEmpty()) { - mainWindow()->loadPage(url); - } else { - mainWindow()->slotHome(); - } - - } - BrowserApplication::historyManager(); -} - -void BrowserApplication::loadSettings() -{ - QSettings settings; - settings.beginGroup(QLatin1String("websettings")); - - QWebEngineSettings *defaultSettings = QWebEngineSettings::globalSettings(); - QWebEngineProfile *defaultProfile = QWebEngineProfile::defaultProfile(); - - QString standardFontFamily = defaultSettings->fontFamily(QWebEngineSettings::StandardFont); - int standardFontSize = defaultSettings->fontSize(QWebEngineSettings::DefaultFontSize); - QFont standardFont = QFont(standardFontFamily, standardFontSize); - standardFont = qvariant_cast<QFont>(settings.value(QLatin1String("standardFont"), standardFont)); - defaultSettings->setFontFamily(QWebEngineSettings::StandardFont, standardFont.family()); - defaultSettings->setFontSize(QWebEngineSettings::DefaultFontSize, standardFont.pointSize()); - - QString fixedFontFamily = defaultSettings->fontFamily(QWebEngineSettings::FixedFont); - int fixedFontSize = defaultSettings->fontSize(QWebEngineSettings::DefaultFixedFontSize); - QFont fixedFont = QFont(fixedFontFamily, fixedFontSize); - fixedFont = qvariant_cast<QFont>(settings.value(QLatin1String("fixedFont"), fixedFont)); - defaultSettings->setFontFamily(QWebEngineSettings::FixedFont, fixedFont.family()); - defaultSettings->setFontSize(QWebEngineSettings::DefaultFixedFontSize, fixedFont.pointSize()); - - defaultSettings->setAttribute(QWebEngineSettings::JavascriptEnabled, settings.value(QLatin1String("enableJavascript"), true).toBool()); - defaultSettings->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, settings.value(QLatin1String("enableScrollAnimator"), true).toBool()); - - defaultSettings->setAttribute(QWebEngineSettings::PluginsEnabled, settings.value(QLatin1String("enablePlugins"), true).toBool()); - - defaultSettings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); - - QString css = settings.value(QLatin1String("userStyleSheet")).toString(); - setUserStyleSheet(defaultProfile, css, mainWindow()); - - defaultProfile->setHttpUserAgent(settings.value(QLatin1String("httpUserAgent")).toString()); - defaultProfile->setHttpAcceptLanguage(settings.value(QLatin1String("httpAcceptLanguage")).toString()); - - switch (settings.value(QLatin1String("faviconDownloadMode"), 1).toInt()) { - case 0: - defaultSettings->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, false); - break; - case 1: - defaultSettings->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, true); - defaultSettings->setAttribute(QWebEngineSettings::TouchIconsEnabled, false); - break; - case 2: - defaultSettings->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, true); - defaultSettings->setAttribute(QWebEngineSettings::TouchIconsEnabled, true); - break; - } - - settings.endGroup(); - settings.beginGroup(QLatin1String("cookies")); - - QWebEngineProfile::PersistentCookiesPolicy persistentCookiesPolicy = - QWebEngineProfile::PersistentCookiesPolicy(settings.value(QLatin1String("persistentCookiesPolicy"), - QWebEngineProfile::AllowPersistentCookies).toInt()); - defaultProfile->setPersistentCookiesPolicy(persistentCookiesPolicy); - QString pdataPath = settings.value(QLatin1String("persistentDataPath")).toString(); - defaultProfile->setPersistentStoragePath(pdataPath); - - settings.endGroup(); - - 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()); - QNetworkProxy::setApplicationProxy(proxy); - } - 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() -{ - if (m_privateBrowsing) - 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); -} - -QString BrowserApplication::getCommandLineUrlArgument() const -{ - const QStringList args = QCoreApplication::arguments(); - if (args.count() > 1) { - const QString lastArg = args.last(); - const bool isValidUrl = QUrl::fromUserInput(lastArg).isValid(); - if (isValidUrl) - return lastArg; - } - - return QString(); -} - -#if defined(Q_OS_OSX) -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() -{ -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) - return (CookieJar*)networkAccessManager()->cookieJar(); -#else - return 0; -#endif -} - -DownloadManager *BrowserApplication::downloadManager() -{ - if (!s_downloadManager) { - s_downloadManager = new DownloadManager(); - } - return s_downloadManager; -} - -QNetworkAccessManager *BrowserApplication::networkAccessManager() -{ - if (!s_networkAccessManager) { - s_networkAccessManager = new QNetworkAccessManager(); - } - return s_networkAccessManager; -} - -HistoryManager *BrowserApplication::historyManager() -{ - if (!s_historyManager) - s_historyManager = new HistoryManager(); - return s_historyManager; -} - -BookmarksManager *BrowserApplication::bookmarksManager() -{ - if (!s_bookmarksManager) { - s_bookmarksManager = new BookmarksManager; - } - return s_bookmarksManager; -} - -QIcon BrowserApplication::icon(const QUrl &url) const -{ -#if defined(QTWEBENGINE_ICONDATABASE) - QIcon icon = QWebEngineSettings::iconForUrl(url); - if (!icon.isNull()) - return icon.pixmap(16, 16); -#else - Q_UNUSED(url); -#endif - return defaultIcon(); -} - -QIcon BrowserApplication::defaultIcon() const -{ - if (m_defaultIcon.isNull()) - m_defaultIcon = QIcon(QLatin1String(":defaulticon.png")); - return m_defaultIcon; -} - -void BrowserApplication::setPrivateBrowsing(bool privateBrowsing) -{ - if (m_privateBrowsing == privateBrowsing) - return; - m_privateBrowsing = privateBrowsing; - if (privateBrowsing) { - if (!m_privateProfile) - m_privateProfile = new QWebEngineProfile(this); - Q_FOREACH (BrowserMainWindow* window, mainWindows()) { - window->tabWidget()->setProfile(m_privateProfile); - } - } else { - Q_FOREACH (BrowserMainWindow* window, mainWindows()) { - window->tabWidget()->setProfile(QWebEngineProfile::defaultProfile()); - window->m_lastSearch = QString(); - window->tabWidget()->clear(); - } - } - emit privateBrowsingChanged(privateBrowsing); -} diff --git a/examples/webenginewidgets/demobrowser/browserapplication.h b/examples/webenginewidgets/demobrowser/browserapplication.h deleted file mode 100644 index 5c75d41b3..000000000 --- a/examples/webenginewidgets/demobrowser/browserapplication.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 BROWSERAPPLICATION_H -#define BROWSERAPPLICATION_H - -#include <QtWidgets/QApplication> - -#include <QtCore/QUrl> -#include <QtCore/QPointer> - -#include <QtGui/QIcon> - -#include <QtNetwork/QAuthenticator> - -QT_BEGIN_NAMESPACE -class QLocalServer; -class QNetworkAccessManager; -class QWebEngineProfile; -QT_END_NAMESPACE - -class BookmarksManager; -class BrowserMainWindow; -class CookieJar; -class DownloadManager; -class HistoryManager; -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; - QIcon defaultIcon() const; - - void saveSession(); - bool canRestoreSession() const; - bool privateBrowsing() const { return m_privateBrowsing; } - - static HistoryManager *historyManager(); - static CookieJar *cookieJar(); - static DownloadManager *downloadManager(); - static QNetworkAccessManager *networkAccessManager(); - static BookmarksManager *bookmarksManager(); - -#if defined(Q_OS_OSX) - bool event(QEvent *event); -#endif - -public slots: - BrowserMainWindow *newMainWindow(); - void restoreLastSession(); - void lastWindowClosed(); - void quitBrowser(); - void setPrivateBrowsing(bool); - -signals: - void privateBrowsingChanged(bool); - -private slots: - void postLaunch(); - void openUrl(const QUrl &url); - void newLocalSocketConnection(); - -private: - void clean(); - void installTranslator(const QString &name); - QString getCommandLineUrlArgument() const; - - static HistoryManager *s_historyManager; - static DownloadManager *s_downloadManager; - static QNetworkAccessManager *s_networkAccessManager; - static BookmarksManager *s_bookmarksManager; - - QList<QPointer<BrowserMainWindow> > m_mainWindows; - QLocalServer *m_localServer; - QByteArray m_lastSession; - QWebEngineProfile *m_privateProfile; - bool m_privateBrowsing; - mutable QIcon m_defaultIcon; - - QAuthenticator m_lastAuthenticator; - QAuthenticator m_lastProxyAuthenticator; -}; - -#endif // BROWSERAPPLICATION_H diff --git a/examples/webenginewidgets/demobrowser/browsermainwindow.cpp b/examples/webenginewidgets/demobrowser/browsermainwindow.cpp deleted file mode 100644 index 14d49f7f3..000000000 --- a/examples/webenginewidgets/demobrowser/browsermainwindow.cpp +++ /dev/null @@ -1,1032 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "browsermainwindow.h" - -#include "autosaver.h" -#include "bookmarks.h" -#include "browserapplication.h" -#include "chasewidget.h" -#include "downloadmanager.h" -#include "history.h" -#include "printtopdfdialog.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 <QWebEngineHistory> -#include <QWebEngineProfile> -#include <QWebEngineSettings> - -#include <QtCore/QDebug> - -template<typename Arg, typename R, typename C> -struct InvokeWrapper { - R *receiver; - void (C::*memberFun)(Arg); - void operator()(Arg result) { - (receiver->*memberFun)(result); - } -}; - -template<typename Arg, typename R, typename C> -InvokeWrapper<Arg, R, C> invoke(R *receiver, void (C::*memberFun)(Arg)) -{ - InvokeWrapper<Arg, R, C> wrapper = {receiver, memberFun}; - return wrapper; -} - -const char *BrowserMainWindow::defaultHome = "http://qt.io/"; - -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) - , m_currentPrinter(nullptr) -{ - setToolButtonStyle(Qt::ToolButtonFollowStyle); - setAttribute(Qt::WA_DeleteOnClose, true); - statusBar()->setSizeGripEnabled(true); - setupMenu(); - setupToolBar(); - - QWidget *centralWidget = new QWidget(this); - BookmarksModel *bookmarksModel = BrowserApplication::bookmarksManager()->bookmarksModel(); - m_bookmarksToolbar = new BookmarksToolBar(bookmarksModel, 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_OS_OSX) - 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))); -#if defined(QWEBENGINEPAGE_PRINTREQUESTED) - connect(m_tabWidget, SIGNAL(printRequested(QWebEngineFrame*)), - this, SLOT(printRequested(QWebEngineFrame*))); -#endif - 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))); - - connect(m_tabWidget, SIGNAL(lastTabClosed()), - m_tabWidget, SLOT(newTab())); - - 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::runScriptOnOpenViews(const QString &source) -{ - for (int i =0; i < tabWidget()->count(); ++i) - tabWidget()->webView(i)->page()->runJavaScript(source); -} - -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(); -#if defined(QWEBENGINE_SAVE_AS_FILE) - fileMenu->addAction(tr("&Save As..."), this, - SLOT(slotFileSaveAs()), QKeySequence(QKeySequence::Save)); - fileMenu->addSeparator(); -#endif - BookmarksManager *bookmarksManager = BrowserApplication::bookmarksManager(); - fileMenu->addAction(tr("&Import Bookmarks..."), bookmarksManager, SLOT(importBookmarks())); - fileMenu->addAction(tr("&Export Bookmarks..."), bookmarksManager, SLOT(exportBookmarks())); - fileMenu->addSeparator(); -#if defined(QWEBENGINEPAGE_PRINT) - fileMenu->addAction(tr("P&rint Preview..."), this, SLOT(slotFilePrintPreview())); -#endif - fileMenu->addAction(tr("&Print..."), this, SLOT(slotFilePrint()), QKeySequence::Print); - fileMenu->addAction(tr("&Print to PDF..."), this, SLOT(slotFilePrintToPDF())); - fileMenu->addSeparator(); - - QAction *action = fileMenu->addAction(tr("Private &Browsing..."), this, SLOT(slotPrivateBrowsing())); - action->setCheckable(true); - action->setChecked(BrowserApplication::instance()->privateBrowsing()); - connect(BrowserApplication::instance(), SIGNAL(privateBrowsingChanged(bool)), action, SLOT(setChecked(bool))); - fileMenu->addSeparator(); - -#if defined(Q_OS_OSX) - 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, QWebEnginePage::Undo); - QAction *m_redo = editMenu->addAction(tr("&Redo")); - m_redo->setShortcuts(QKeySequence::Redo); - m_tabWidget->addWebAction(m_redo, QWebEnginePage::Redo); - editMenu->addSeparator(); - QAction *m_cut = editMenu->addAction(tr("Cu&t")); - m_cut->setShortcuts(QKeySequence::Cut); - m_tabWidget->addWebAction(m_cut, QWebEnginePage::Cut); - QAction *m_copy = editMenu->addAction(tr("&Copy")); - m_copy->setShortcuts(QKeySequence::Copy); - m_tabWidget->addWebAction(m_copy, QWebEnginePage::Copy); - QAction *m_paste = editMenu->addAction(tr("&Paste")); - m_paste->setShortcuts(QKeySequence::Paste); - m_tabWidget->addWebAction(m_paste, QWebEnginePage::Paste); - editMenu->addSeparator(); - - QAction *m_find = editMenu->addAction(tr("&Find")); - m_find->setShortcuts(QKeySequence::Find); - connect(m_find, SIGNAL(triggered()), 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, QWebEnginePage::Stop); - - m_reload = viewMenu->addAction(tr("Reload Page")); - m_reload->setShortcuts(QKeySequence::Refresh); - m_tabWidget->addWebAction(m_reload, QWebEnginePage::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)); - - viewMenu->addSeparator(); - QAction *m_pageSource = viewMenu->addAction(tr("Page S&ource")); - m_pageSource->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_U)); - m_tabWidget->addWebAction(m_pageSource, QWebEnginePage::ViewSource); - - 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, QWebEnginePage::Back); - QList<QKeySequence> backShortcuts = QKeySequence::keyBindings(QKeySequence::Back); - for (auto it = backShortcuts.begin(); it != backShortcuts.end();) { - // Chromium already handles navigate on backspace when appropriate. - if ((*it)[0] == Qt::Key_Backspace) - it = backShortcuts.erase(it); - else - ++it; - } - // For some reason Qt doesn't bind the dedicated Back key to Back. - backShortcuts.append(QKeySequence(Qt::Key_Back)); - m_historyBack->setShortcuts(backShortcuts); - m_historyBack->setIconVisibleInMenu(false); - historyActions.append(m_historyBack); - - m_historyForward = new QAction(tr("Forward"), this); - m_tabWidget->addWebAction(m_historyForward, QWebEnginePage::Forward); - QList<QKeySequence> fwdShortcuts = QKeySequence::keyBindings(QKeySequence::Forward); - for (auto it = fwdShortcuts.begin(); it != fwdShortcuts.end();) { - if (((*it)[0] & Qt::Key_unknown) == Qt::Key_Backspace) - it = fwdShortcuts.erase(it); - else - ++it; - } - fwdShortcuts.append(QKeySequence(Qt::Key_Forward)); - m_historyForward->setShortcuts(fwdShortcuts); - m_historyForward->setIconVisibleInMenu(false); - historyActions.append(m_historyForward); - - 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)); - historyActions.append(m_historyHome); - -#if defined(QWEBENGINEHISTORY_RESTORESESSION) - 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_tabWidget->recentlyClosedTabsAction()); - historyActions.append(m_restoreLastSession); -#endif - - 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"))); -#if defined(QWEBENGINEINSPECTOR) - a = toolsMenu->addAction(tr("Enable Web &Inspector"), this, SLOT(slotToggleInspector(bool))); - a->setCheckable(true); -#endif - - 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() -{ - 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::handleFindTextResult(bool found) -{ - if (!found) - slotUpdateStatusbar(tr("\"%1\" not found.").arg(m_lastSearch)); -} - -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() -{ - // not implemented yet. -} - -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_OS_OSX) - 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 the facilities " - "of Qt WebEngine in action, providing an example " - "browser for you to experiment with.<p>" - "<p>Qt WebEngine is based on the Chromium open source project " - "developed at <a href=\"http://www.chromium.org/\">http://www.chromium.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() -{ - if (!currentTab()) - return; - QPrintPreviewDialog *dialog = new QPrintPreviewDialog(this); - connect(dialog, SIGNAL(paintRequested(QPrinter*)), - currentTab(), SLOT(print(QPrinter*))); - dialog->exec(); -} - -void BrowserMainWindow::slotFilePrint() -{ - if (!currentTab()) - return; - printRequested(currentTab()->page()); -} - -void BrowserMainWindow::slotHandlePdfPrinted(const QByteArray& result) -{ - if (!result.size()) - return; - - QFile file(m_printerOutputFileName); - - m_printerOutputFileName.clear(); - if (!file.open(QFile::WriteOnly)) - return; - - file.write(result.data(), result.size()); - file.close(); -} - -void BrowserMainWindow::slotFilePrintToPDF() -{ - if (!currentTab() || !m_printerOutputFileName.isEmpty()) - return; - - QFileInfo info(QStringLiteral("printout.pdf")); - PrintToPdfDialog *dialog = new PrintToPdfDialog(info.absoluteFilePath(), this); - dialog->setWindowTitle(tr("Print to PDF")); - if (dialog->exec() != QDialog::Accepted || dialog->filePath().isEmpty()) - return; - - m_printerOutputFileName = dialog->filePath(); - currentTab()->page()->printToPdf(invoke(this, &BrowserMainWindow::slotHandlePdfPrinted), dialog->pageLayout()); -} - -void BrowserMainWindow::slotHandlePagePrinted(bool result) -{ - Q_UNUSED(result); - - delete m_currentPrinter; - m_currentPrinter = nullptr; -} - - -void BrowserMainWindow::printRequested(QWebEnginePage *page) -{ - if (m_currentPrinter) - return; - m_currentPrinter = new QPrinter(); - QScopedPointer<QPrintDialog> dialog(new QPrintDialog(m_currentPrinter, this)); - dialog->setWindowTitle(tr("Print Document")); - if (dialog->exec() != QDialog::Accepted) { - slotHandlePagePrinted(false); - return; - } - page->print(m_currentPrinter, invoke(this, &BrowserMainWindow::slotHandlePagePrinted)); -} - -void BrowserMainWindow::slotPrivateBrowsing() -{ - if (!BrowserApplication::instance()->privateBrowsing()) { - QString title = tr("Are you sure you want to turn on private browsing?"); - QString text = tr("<b>%1</b><br><br>" - "This action will reload all open tabs.<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) - BrowserApplication::instance()->setPrivateBrowsing(true); - } else { - // TODO: Also ask here - BrowserApplication::instance()->setPrivateBrowsing(false); - } -} - -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; - currentTab()->findText(m_lastSearch, 0, invoke(this, &BrowserMainWindow::handleFindTextResult)); - } -} - -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, QWebEnginePage::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::slotViewFullScreen(bool makeFullScreen) -{ - if (makeFullScreen) { - showFullScreen(); - } else { - if (isMinimized()) - showMinimized(); - else if (isMaximized()) - showMaximized(); - else showNormal(); - } -} - -void BrowserMainWindow::slotHome() -{ - QSettings settings; - settings.beginGroup(QLatin1String("MainWindow")); - QString home = settings.value(QLatin1String("home"), QLatin1String(defaultHome)).toString(); - loadPage(home); -} - -void BrowserMainWindow::slotWebSearch() -{ - m_toolbarSearch->lineEdit()->selectAll(); - m_toolbarSearch->lineEdit()->setFocus(); -} - -void BrowserMainWindow::slotToggleInspector(bool enable) -{ -#if defined(QWEBENGINEINSPECTOR) - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::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(); - } - } -#else - Q_UNUSED(enable); -#endif -} - -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; - QWebEngineHistory *history = currentTab()->history(); - int historyCount = history->count(); - for (int i = history->backItems(historyCount).count() - 1; i >= 0; --i) { - QWebEngineHistoryItem 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; - QWebEngineHistory *history = currentTab()->history(); - int historyCount = history->count(); - for (int i = 0; i < history->forwardItems(history->count()).count(); ++i) { - QWebEngineHistoryItem 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(); - QWebEngineHistory *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/webenginewidgets/demobrowser/browsermainwindow.h b/examples/webenginewidgets/demobrowser/browsermainwindow.h deleted file mode 100644 index 5bbbb2924..000000000 --- a/examples/webenginewidgets/demobrowser/browsermainwindow.h +++ /dev/null @@ -1,189 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 BROWSERMAINWINDOW_H -#define BROWSERMAINWINDOW_H - -#include <QtWidgets/QMainWindow> -#include <QtGui/QIcon> -#include <QtCore/QUrl> - -QT_BEGIN_NAMESPACE -class QPrinter; -class QWebEnginePage; -QT_END_NAMESPACE - -class AutoSaver; -class BookmarksToolBar; -class ChaseWidget; -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; - - static const char *defaultHome; - -public: - TabWidget *tabWidget() const; - WebView *currentTab() const; - QByteArray saveState(bool withTabs = true) const; - bool restoreState(const QByteArray &state); - Q_INVOKABLE void runScriptOnOpenViews(const QString &); - -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 slotFilePrintToPDF(); - void slotPrivateBrowsing(); - void slotFileSaveAs(); - void slotEditFind(); - void slotEditFindNext(); - void slotEditFindPrevious(); - void slotShowBookmarksDialog(); - void slotAddBookmark(); - void slotViewZoomIn(); - void slotViewZoomOut(); - void slotViewResetZoom(); - void slotViewToolbar(); - void slotViewBookmarksBar(); - void slotViewStatusbar(); - 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 slotHandlePdfPrinted(const QByteArray&); - - void slotHandlePagePrinted(bool result); - void printRequested(QWebEnginePage *page); - void geometryChangeRequested(const QRect &geometry); - void updateToolbarActionText(bool visible); - void updateBookmarksToolbarActionText(bool visible); - -private: - void loadDefaultState(); - void setupMenu(); - void setupToolBar(); - void updateStatusbarActionText(bool visible); - void handleFindTextResult(bool found); - -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; - - QPrinter *m_currentPrinter; - - QIcon m_reloadIcon; - QIcon m_stopIcon; - - QString m_lastSearch; - QString m_printerOutputFileName; - friend class BrowserApplication; -}; - -#endif // BROWSERMAINWINDOW_H diff --git a/examples/webenginewidgets/demobrowser/chasewidget.cpp b/examples/webenginewidgets/demobrowser/chasewidget.cpp deleted file mode 100644 index 0f066bc73..000000000 --- a/examples/webenginewidgets/demobrowser/chasewidget.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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/webenginewidgets/demobrowser/chasewidget.h b/examples/webenginewidgets/demobrowser/chasewidget.h deleted file mode 100644 index 63a8ff310..000000000 --- a/examples/webenginewidgets/demobrowser/chasewidget.h +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/cookiejar.cpp b/examples/webenginewidgets/demobrowser/cookiejar.cpp deleted file mode 100644 index 479601ee3..000000000 --- a/examples/webenginewidgets/demobrowser/cookiejar.cpp +++ /dev/null @@ -1,746 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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 <QWebEngineSettings> - -#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(); - - QWebEngineSettings *globalSettings = QWebEngineSettings::globalSettings(); - if (globalSettings->testAttribute(QWebEngineSettings::PrivateBrowsingEnabled)) { - QList<QNetworkCookie> noCookies; - return noCookies; - } - - return QNetworkCookieJar::cookiesForUrl(url); -} - -bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) -{ - if (!m_loaded) - load(); - - QWebEngineSettings *globalSettings = QWebEngineSettings::globalSettings(); - if (globalSettings->testAttribute(QWebEngineSettings::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/webenginewidgets/demobrowser/cookiejar.h b/examples/webenginewidgets/demobrowser/cookiejar.h deleted file mode 100644 index 3f8707955..000000000 --- a/examples/webenginewidgets/demobrowser/cookiejar.h +++ /dev/null @@ -1,212 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/cookies.ui b/examples/webenginewidgets/demobrowser/cookies.ui deleted file mode 100644 index c4bccc548..000000000 --- a/examples/webenginewidgets/demobrowser/cookies.ui +++ /dev/null @@ -1,106 +0,0 @@ -<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>&Remove</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="removeAllButton" > - <property name="text" > - <string>Remove &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/webenginewidgets/demobrowser/cookiesexceptions.ui b/examples/webenginewidgets/demobrowser/cookiesexceptions.ui deleted file mode 100644 index 3d9ef6241..000000000 --- a/examples/webenginewidgets/demobrowser/cookiesexceptions.ui +++ /dev/null @@ -1,184 +0,0 @@ -<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>&Remove</string> - </property> - </widget> - </item> - <item row="2" column="1" > - <widget class="QPushButton" name="removeAllButton" > - <property name="text" > - <string>Remove &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/webenginewidgets/demobrowser/data/addtab.png b/examples/webenginewidgets/demobrowser/data/addtab.png deleted file mode 100644 index 20928fb402aab20c838fca4dae2e9c1db2c54373..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 469 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf_5hy{*Z=?jtE;Q)=;&BlTH4v$ z+1uL#*}A&A4h{~Ej*i;e+Q!Dlc6N3yF0McT6t}Xn0*ZThco-QOnVXxtySsaOdg|-z z12sB1IeB<^dU$%8nVETcc?ARnL`Fse&G+;31F8uM3i9#s@%8luni&`vsHUa{RO9dO z4>ZKW!otSJ251Y=5Qx1lE-oP<A>m=+Kue>eqhn%XQc_Y<Q&Y3DvJ4Fk!^6XQdhf^r zy&zW-<QL3f0s`qk&;SAlfZ!?+yaj=eAETt-{s5|6@9E+gA|aW3@TFK|fC$@#^ExwC zgYOpaYUU6XJoVdNeDziTYUckYY?H5M8D%WE7CT3;u*On%*NQKDLfE`mjlNd>$h0zd zv@G^}^vs0uM)=2?=VyNY)?8=S@N!}tt6}iRMUO=eSShUw+`_gYuqoRqm*I>{!9DpI z{J)D8(iqy@T&)uQN|u}vaLAUd^Dy$>)qYy6?pNK6lbfbQzW5%vF=nwme{Kx-)^8d6 gZl60Y`{y%j_;1m)-KBXCflg=eboFyt=akR{0MYZR8~^|S diff --git a/examples/webenginewidgets/demobrowser/data/closetab.png b/examples/webenginewidgets/demobrowser/data/closetab.png deleted file mode 100644 index ab9d669eeebed9718363bd06ba84fdfd9e7cd6b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 516 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf)c~Im*Z=?jtE;Q)=;&BlTH4uz z0FbS#tLxz4;OOY6t*vcrY;0#|=i=((>goy<x3aPVihH<w0D+N_k-53KyE}-Zudff( z>*VC*;Rym}W@bPVXt<Y`m%qP%KtMoHP>_v{4bWI$Utd2zKcFE%#ZggFv9Yla9z1yT z=+WcHkDoq$`uzEGpmovF(ca$PK*OD#o#W!-l9G~KTwJoUva++Yi;Iif+uLW(oH={; z>^XDh+`D%V=rEugfYybCgoK8MIyyQW>XKdu^q_o6kY6x^2?(SEK?4XJ0D-GluU>l# z0v|tqT5?z%sC2)li(`m{WbVQ1Vh0^WST8Itzqt7R8J}4qF1|`02mjX#o&J=O|6qPh ztW^KfDn9$C2OYoKd^ON`yn53GBWDif%VMH6PulHvw?8kgNdITRzaVjwbgtfX-n%ny zGF%9px6S#suI0Djmkcuuyx+tsmFw%6F&c<|%X}`hbN6K3WemISa9w+1v4v0P9_xiG z^5I>frpsPC=QC;a^n{j}#2?Q{?cw^dLN8eNq0PlhsiN_wkryqmi|%ZjpS0V4_V*~& bKcCs&oRdi2E+elG^a_KgtDnm{r-UW|i^$5o diff --git a/examples/webenginewidgets/demobrowser/data/data.qrc b/examples/webenginewidgets/demobrowser/data/data.qrc deleted file mode 100644 index 5cb8a97c0..000000000 --- a/examples/webenginewidgets/demobrowser/data/data.qrc +++ /dev/null @@ -1,11 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource> - <file>addtab.png</file> - <file>closetab.png</file> - <file>history.png</file> - <file>demobrowser.svg</file> - <file>defaultbookmarks.xbel</file> - <file>loading.gif</file> - <file>defaulticon.png</file> -</qresource> -</RCC> diff --git a/examples/webenginewidgets/demobrowser/data/defaultbookmarks.xbel b/examples/webenginewidgets/demobrowser/data/defaultbookmarks.xbel deleted file mode 100644 index fef7f5514..000000000 --- a/examples/webenginewidgets/demobrowser/data/defaultbookmarks.xbel +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE xbel> -<xbel version="1.0"> - <folder folded="yes"> - <title>Bookmarks Bar</title> - <bookmark href="http://qt.io/"> - <title>Qt Home Page</title> - </bookmark> - <bookmark href="http://doc.qt.io/"> - <title>Qt Documentation</title> - </bookmark> - <bookmark href="http://planet.qt.io/"> - <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://wiki.qt.io/OnlineCommunities"> - <title>Online Communities</title> - </bookmark> - <bookmark href="http://www.chromium.org/"> - <title>The Chromium Projects</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/webenginewidgets/demobrowser/data/defaulticon.png b/examples/webenginewidgets/demobrowser/data/defaulticon.png deleted file mode 100644 index 01a0920c93c67e94ee3c9b8317fd6dd1437e8e4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1473 zcmV;y1wQ(TP)<h;3K|Lk000e1NJLTq000&M000&U1^@s6#I$TX000GuNkl<ZIE{Uk zU5H$F8ODGA|M{Oe=giER&z+f_-OcW1lTBi1+>#iI23lH6uvH4ZNN=n~#N4zON-uJu zc;k&A(yQ8Bh$zJyTM<kUg(j_v3T-JQ{fOCRH*WSL+1=SQpJ!&y_wiz}Acnm6&+mO7 zczGU?rYR4a)0aLe4*kxv#|}@u>h$`vx0g5bnpASSS&5`B)`BGY&1Wm^U!=ePM(;s- z@gVRsudV*j?F@gsx!;kC(-Z9Wx@05>P3Op=IeN}Mj<d%o2-D`=)a7?BoqFY=;OAan zsjh5#*R?cV(xk^;yG^}dGLg?<DUHKNj$mX=%#4YQHCFH3VtH+YiRPqpV|DlB-mjn8 z`#<nEf4N!x@YCJRqtg@C`K2j-^42vL8+j&dlbNzf&d&4r7w2)@1SJ&hA?&*;o0}`# z-QL5CMY8PnCtI&S+X7Jk-LSTo++3QgTjx(Vv28`OWU)Az=j_o6jgrAVCuC*2!&ero zbjAmoI1vQ(8GLU**F~PIm6m}DfCM=IbLXcyzd!xu6E!>~`DCX@(Nr{wCXJH8Of}0F zW(%A<W}~!(jkZhA8`1N6bi;sBsY<m{#A)@*_3vEyE`YY%c%`(ywfTp$$7e)jDSr0W zUs=0zk9xsms%%os8c0oJyA#o@7}RWy>5@*A92mBZJg%SM`7X6`jpfzVr{DPV-W$@< zv<sE2E{tN9-@SX2et(3n38a8+$K!rC;MUfdQqCZV1Z7K-%}7qqW_V)JpiuzJF!58c z3nplKHWcyGY8d!0*|{8_t?w}QLxcb!#OI&Vc0(qL8T#XdCz}c-Ax_|47rY1->p-gG z4^lFkVq&63uRnM~%I>})Or2wgswgQ5<CHK?h~ktuN%4XhKZvN>2iHc)0XRv)apBf| z$Y?3Yr}Ic9al;6a@|bkTgEM(cF;U2I>B1QnnnlJz%s7nkqlA$c;En_C><$@)DWd?q z5P}Gz7)%9*j0j>uy=XBQ1(3uiw5i8l`oW>ex^lgUFpel@B{%Q1Fm(+>X(&yQrYU}q z;75|Iq2u}yLExha*zRkzI&D%kx}l9T93a9lRtWuLcQ`sbTRKG9(wI7CQO+B@{g-7- zC6NNs6#Ova!<7VgG-fak`FOpDoi&+kO!M!p7TLlymX%O1*%WkfU*&A$cHec+#!*7w z)6k^JmkuB1-0>#2*LT?1?egeck-3^hs~7P1f3@hiA%2vwy6bXA*Aco+Hd`bN6I%N{ zYQ@|?)b`%simkifT9_Y^p~x_RoB;*X<nc%5F_%JK{nbAi`{{uLDM*qOFNzs>5wioI zMr8&eB&$x3a2#USb63@{A6^Tzp}Tdjl|MYIfE-&L*y(|(L+H2pV68*mR2WJkg&;{& z{3yZoBKF>2=i=8Fh?1CYw?jr#Zezy2rgd+;>AiM!eY@>A&)2GDqz+1END+hyIQ=f0 z&X_0>_)*F@Oo&s7u4ky&dFrJC13%_|dx+ca^T^`t#mg^N-~T+_=DvO9dc9J4>cpuj z>}-*oZZTQXc<;tGgR#fh4+x`}Bu$Y*kWmWD$dI>8@`g^o?_*oWyTASZ%vb*>-GW$u zVRPsHnvikv<Wj<PC19ai$9lBM-F=T%->2_|oSHExWfgZ?5q(dPk&2cxAn=2ps_8F0 zFz6dE{;8VLqPI&0_2lf4CbOkE4%PECY>BBuO2TYeP%lbuY$SZN=JL_X4n{_QPi3PE zSHE}Md1y5qefgb>mWnS6lx7(=)k>L?okQ0%WMs%_?6KpF=?(p1v1q=0{YNL?d}uWZ zAuON<)KvM%ynXU(PwB<^Gs<o(=w_uNgcK?n^wZ(a#&Gxc&Gx5%{9Dl7xC`t8TR<;O b(-`1CE1{QKcOYYB00000NkvXXu0mjfy$tXg diff --git a/examples/webenginewidgets/demobrowser/data/demobrowser.svg b/examples/webenginewidgets/demobrowser/data/demobrowser.svg deleted file mode 100644 index 9f39deb66..000000000 --- a/examples/webenginewidgets/demobrowser/data/demobrowser.svg +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" - width="94px" height="94px" viewBox="0 0 94 94" enable-background="new 0 0 94 94" xml:space="preserve"> -<g> - <circle fill="none" cx="47" cy="47" r="47"/> - <g> - <path fill="#46A2DA" d="M47,92.979c-11.779,0-23.559-4.484-32.526-13.451C-3.461,61.591-3.461,32.409,14.472,14.474 - C32.41-3.463,61.592-3.461,79.526,14.473c17.935,17.936,17.935,47.119,0.002,65.054l-0.002,0.001 - C70.559,88.495,58.779,92.979,47,92.979z"/> - </g> - <path fill="#80C342" d="M93,47C93,21.595,72.405,1,47,1C34.297,1,22.797,6.149,14.473,14.473l65.054,65.054 - C87.851,71.203,93,59.703,93,47z"/> - <g> - <path fill="#46A2DA" d="M47,65c-4.808,0-9.328-1.873-12.728-5.272c-7.018-7.019-7.018-18.438,0-25.456 - C37.672,30.873,42.192,29,47,29s9.328,1.873,12.728,5.272c7.018,7.019,7.018,18.438,0,25.456C56.328,63.127,51.808,65,47,65z"/> - <path fill="#FFFFFF" d="M62.248,59.919c6.671-7.858,6.312-19.644-1.105-27.061C57.237,28.953,52.118,27,47,27 - c-5.118,0-10.237,1.953-14.142,5.858c-7.81,7.81-7.81,20.474,0,28.284C36.763,65.047,41.882,67,47,67 - c4.379,0,8.752-1.441,12.372-4.3L77.88,81.209c0.989-0.895,1.935-1.837,2.843-2.814L62.248,59.919z M35.686,58.314 - c-6.238-6.238-6.238-16.389,0-22.627C38.708,32.664,42.726,31,47,31c4.274,0,8.292,1.664,11.314,4.686 - c6.238,6.238,6.238,16.389,0,22.627C55.292,61.336,51.274,63,47,63C42.726,63,38.708,61.336,35.686,58.314z"/> - </g> -</g> -</svg> diff --git a/examples/webenginewidgets/demobrowser/data/history.png b/examples/webenginewidgets/demobrowser/data/history.png deleted file mode 100644 index 552a1cbd88459475f69668ebd438353d6303ea16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1527 zcmV<T1qk|yP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00009a7bBm000XU z000XU0RWnu7ytkO2XskIMF-Xb4G$zE*vbjU00006VoOIv0RI600RN!9r;`8x1%ydN zK~zYI#guDI(`OjPmu1OjjM<jB56g^;n^QxgS=2Gb$#g1+fTD3+dgWSZ3kZr6H&H=E z85f~UiU@KmAc#ZcP6t$O<x)^V5NHbnWIBZc)?T5U{rguMoY#HYNlx1I!}*=}d7r-T zyz_s`%VPBh7i_n-WVk!sPxYcaO7)~DQ#~lk6c&9n#f#b<vCHx&mgSm7|2demb=AB4 zJ=;XtT#xah_!zactqu43`!Upa7X!UL7?nvOYnR}9Laa9X=t0@fPCMP17GExStMC9D z^Cg*V#!zl}h_0`_4c%>GGzrU4Q+5q$sqy&Hg@)SlA~aN%psTqNy#%O$7p)HSqFnU1 zwOIMuaG&j8FU{~_j+ZCIpr^SBG*?etzEXgW?g2DQC(u9q5P?UI!2n=lY6=wult!hX zv#}2K`MJml;>f(Mzj--?{@t?o(!FUT#W814C=^4~Btc=R5G-yW+I!__l}};h?+HZw zdJZ#&S!i{7usK|mm6f5Xt_HOQx%eYJ1;KQOl)W21TlfNiZNG_{alp&an45+Cnl6-z zrKo6?<Hp@_w8$n+fWZe-Fc1L!%nZ~TE$PQkl#tZdpe|2<^pin4&OS@dbK!e7E?dBJ zvFp7W5ei#67lD!4C>QsjP;?7ose%}ff&fh7&-)789(V+!W@l$f6D;Vary*)+0M*3_ zrRU=j?d>dfu=rxJ3E*hCYD+T9S$*M1Aj0?su<<yKs9X_h+GVJ0=_AAE+|d0O2{4Xn z4l*=60ydY6it-X<9Y2hV2RyWn->=$l0vy`0E<ZDng(x-~oHLhkI=vPVX+lH_YQZmT zMs0@-!aH)bNXN+&7(<O38X7`)_$lysJn|GuwFZ~Mf{`8M2g(m-=_WuTbMF|j^F(+O z0%Hpilu!)+sC<O*OAwh^jrhwVoG-42ME(>oGi!jaw<nGs4aUumb|@w$P0+$LKJtTn zacrmgJtBGu3E(kyE3-IEuucg;|K%c>A*o;-Gdcy_2m$G^<Wii7OT#uR8_<|em?j#} z5Enf+s&T~xZr|-gV(eLD6IszzJEaK_L)$$m@N|Kly*>8scLIe%0n^nDbOsYlCKFUD zmHf@l&JNaAR;a41cmd$+=MQ%;791TNkr%{8G|gUV8c{scVKmRr9oI6F@G2R{Vw6^^ zg-WG*4nX?Zh{~@JYaSeclh)>=rW1tQT8IUQIQTs=j=U(He%drsqYTe%lwPklg-_2I z$Tgk&<EgYd6eRPIb0h#>HmkEu0Jj}0tuqh%XiAcJsIIOiR?ZJ<qUl_#*?FG^g8};K zr{Qz$H98%9IKB{xL@46NBj+FsHtRq4GXY$;EnjrWpCPYI<&!fnuPA%@n26TKaI(E& z9)M_WEJkB6P?eU9^Z?fpv!x%ceeT~J?6SclEAqs|tvV69ZneJ<ZftA}pKoKZTC0ch zi3&Y;I&rhE7P&E}o-j9=6`0!3$$#I91!-J*Pf1b&I*FI`hPWQrN{Zl3JZLJ7h75c# zHby>h#_uZPuDsb?2&*d5)!l`zwiZ<9q#@LHbLS@?zQ6UQFKQ_L+Z6&o*ZZaXbLj8s z0mIc5mF2}4Qz*z2NF)++eT{cBF*yZcWjQ$(d4C_SrX(VYZYy<J`_<_e+RxXO(}&#z z2beuq<3ct4w>vN}D2Jr270pc|<m6?;$;BDXjUu!*H$X0zqE1+aEMBB4&~9VvzD>)m zUK>8ANcVLMFHyH&&pYJ#s30V0R(4Z@;Q<*&hlemYIEa>pdejk%P>>j_kEiZ>nCfQD zU$g9Evo{9+TW9I!i+^+6ax#NUlV-80lZ4fAbO%iw&EavZv#lc7dOdHm*{AE?s`VSR d<PCnM{sD77$9c@rLfZfU002ovPDHLkV1fxwzES`H diff --git a/examples/webenginewidgets/demobrowser/data/loading.gif b/examples/webenginewidgets/demobrowser/data/loading.gif deleted file mode 100644 index c1545eb0eddb8d69e9d0cd70f30dd19c872829ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 847 zcmZ?wbhEHb6krfw_`<;O|Nnmn2Zx_Oe`aQ8E?Tt6#l<BiCg#C|2YdJK4G0LBF=Iwg zPtU7YuQqPnc;(8K($dm~h6V;wfZ~5{Ki808XU70nBRvCVMxb8Be^Smxsfi`2DGKG8 zB^e5dS&0=n`H3ldnR#jX42nNlIJtnTbU?O%9Lc~MprFu~k~wdwfk=*`R!hRFwKGJH zO_VZi_`r6vqanJN#fB-fHDIDZD`RKtqP{hnIt`vtKNhJZec0tOX@W(|3R5-NicZsP z1sh?JPnEJq-}gIVvm`@7q09YJPllG%(FZG5IH<VR9yoCD+EFHso+%Bf86rYF2M;JX z2y*!xX!wvE=-$lawB_lx0Mi)?HmgiSQv$bXzfjt@IDLx23bA#I7WO-43!GPWWZ<?5 zFgIYg;bdtr;EQCl(BkE6S60Mkc>>Uf%AY4_+!FE7;yMx_!l}EY-SE9}BbSx)X+!TV z9xY7|**x@SsNCFG$-p77@8TKO8(G|Xjo~g1claV178!VOinZz(^f_JO>dO}JdiItl z)ZVn5nWaW0n>R+2pQjtEr9qHjZBUrPWGHgfVMVjE9NQZ4W7*wJa~Kt!o+Q{aG;U|w zH$mC8$)d_BFrp!OckZGxZXu<G3NH^WPH0SM;|+CNCRubxl5c6jYt7GT{~NGc1M(X% z_EtFXxEcx^Iw_GGD{*|Mgh$VXwi_Dk0$nU7ObX96bR?F!DJFU_L<G;^Xv{TTvXwE( z#bXN_!>XN$NjhA8stpCkV#!C8H>m&MeWS!~VrCworWK*zpwZK-g4NP^sHGl2k8vz> zFkv{f>6oLE=R}STvlb?B*yXjddK##7Nc75in{VRv&|yE=saw*l)zs`NB_goou<pf# q6&(o&n0^Wvc5+B;nC{Te=WL$Ap>N2N#u}s9-J_<+U=2#1U;qGeCkTrG diff --git a/examples/webenginewidgets/demobrowser/demobrowser.icns b/examples/webenginewidgets/demobrowser/demobrowser.icns deleted file mode 100644 index f24ac6ee77a720c3f6c732408239d7c8d5f69066..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31513 zcmdUYX;4&Iw(j010dJKZQGL5BqTh?xaqpk*{?Ye#|G3=|-4Pw#8VMYSXH8a9ef4Tp zg#$C<KtYvLo+L?<d9Xx9urd#blsHr|B#<bDZAv){Wg%uBKvcj996$k;;k<93WJn+p zs6sQ|iIB6`T6^!cr?vLC*V$mu>UEn4+48@GBL47Sg#4ctf@gq~kbeyh3=R$p-w?KO zW7vl9uwamF#8VR-vOaQKs^GaTa(zgUrh$0K{vi?DGX;<B5h4C^9Z_k5!nTNlYD-v< zriO59!y@tpE+TC0c|rrjj|en8@LR%Zf;JWk+{PfyNkW67%mR%Hsv>l4xCQdH#|ZUb zUn$V_{^f)Qd{QOQPXf$@t_rt8x~d4$&D8?k?Ef{P!J5+o)dU{_FYLTP!~6@7FY=;5 zBiDS1`XXus8nN~Oq><l&=f9uOm0Q0T=+?j-!g<dRtV7b@L_Byk&od%&?H7cqeYHGc zRK%KWLYMgH98{!#79qZRg&<*jkv2He!Fvc<5RWt}*7)xtbe>OwgW9|*1KE-kf`sox zI>nI=*g?p=G^8)1Z~o~Jq$>njpGI~%QUR&pvh;TX2~R<Kmm?jNO!gpEiy_k_lD$ao z6z1r5>@k`4?9deoBq)&(AI44*JhfRB_J@Ny*>mury&_9{SRfk{P*XOfi2|2V-I*+N zoz)qK1QHkz{yy;I1p0;axlE-m4nl7np$q4K0k&SCsr9>MTA%u*K-L<d!UV2Pprw78 zGVLqP7f2Ym-XgeyK;y3(<hi{U4(|}6qJ$lXFZ3E@dNn=|L#olEY%Z?~6w*8Nvg%1` z#3BQ)S`<<GL@(2h^gMJxPx5%G>xz-N2U+hV^V~aG4`XE7m9ZZ>^khFzKWf*>+~C*m zrSsf-U!!}pD<xN;TVx#}3v+q;ehXOb8#8#i5gBQFT&_U;A@j-M>4Iu->>upr=?8Y5 zOs+x{;t-LYkkr1F$<w!MAt}odNJKQD8Xu9TE1pK9)Z1B**^%l?6$QFoqlLO0o>;+Y z|6m_#Y>!5bC>I2YFGgY`B!dw~o<<Bpk}V1(R7+6eEU2#`{~GT`aMx=IsI|!bXeqQU zeFXkalRzRB{vlR2mnYeHSA)AvP)46FXxGZL`#p5{y>6r)YfXYG7)`>&tV7oFJf4)} zooN!dK*AL41r-Hu6yC?cMP_i%pzPDd81cnVwKB1d@b7@C&F4ui-VebIBgBMEgCLKB zeH4|%7zHkzvB}4vc7nST?^JL%DBK`W(co(F-V3f$1x8gSo59_Tw+Y;hN?zAo=Nd9c zYH-$;GOTTE)1tvf)6l=+e$=4h4;=lN(CaHBy&gA4t_E~B#u)<&0~j|2qziKyEHI_c zb7p08Hg<;JV>7(NF~d&l;VW=$j`iST{p@k99~W!x3f5e(*7aI_maMGRXl412uJO0n z8ZTjM+_hoU4H<?Dd+Lj4_7pQ}h)3RqA-;QL5C&}5LE9ENhFNexyORY!h+{(Z7#2)? zApNLito0`{xe>M#OAf$<t0(%8vyYhR>h>`w5{pU>@Z5r(PcvnYr|EovLzb<0A-Jr3 z*sK-q>g4|jXoy3Y1;-T!!#oJTa26i!T)1vTmI+_SJm4XoTYIP-Ua{lQs@M_f9{5N2 zO`pTO=Yn;6&)gY|kv-b0jlppG!<FxXYfU6Y{G7!f2Sr2#fBb(_M?@LuR1&!`LVwOY zcM_D1vUVT~bMd2`G&Besz=De-#ZuAyG~^lOB*Sy06YAr{O2l@u3VVz1rIB(80tsL{ z&nPDjb!V_$YLpd=?R3>H=&Kni7sEC)>}<ZHEFG2^+xJE}S`2s=+arfqo_3ueMEYaf zR1fD;*>w@Cu&eUw;bIrpnh5otuaIy){l{_$^#$n}@JN>XEZC#HkyjP)=<yls+&rtu z{~UI6wGaC4qs9)u#P>W;eU}_TTh8*t7dT*nPc>u<fDPvPS|OWfhU}k^0YUiqR)XUL zRKfdNkm9Q#D}&4mj!z-V@uvyr>pLH_Ki}8)JmD7d-uXP|%`dD~7Ax_oC#nTLzCM|} z3O^S#0>3Qu$>2Gkg_<_hzc7)f3w;=5QeacL*<4y`DXTbktfI_PT52|z12z?um@SpZ zQ>~uID=p@-0tTDRW#z{+tsckA%ghRFDzTgpt*R525(b+}%1-24xf5k2fKA1gBUWlD zX0WNWve3#^mNM8>Qf{`=@)E!%^Kpxn9yg<dMV3nBEJCMCs;aECssym9#9{@n1Vdx4 zss_*e6``{Etd*MO!zfX4-byQqFsQ|q7p=6i5CdIesbM8B_$5`}v05-CM~{7PrN@c^ zo4ydubx4+&2+0vd!icI8Oz;7d)<IbcvkA$JaS)Y7STS;}gQ$=*Nt}`-<~@Yw8ixsh zCZjO{5-6!E0cbKMDFm@#>E@(3(j_~P%ajV@GIABAlO0NuSkeeJWepJ}sU!pJ@2uoF zEGlQ0BV7V}llLH9iy;GSA~~5Lc3S70x^U_8<x3Y%6<SFt*rvT;r&?9D*Y5YiKlR?f zR(r%sDq;MlY)BHV+{M<Xa1T#gFCMazVz>;`KJeqL^t%UeDG$CoXeAbarrfMAz}8#o zxpsJ=j&omHNr?fOP2lRRv~d8SX`nIRO3Gp}8AcIo!Aehe!0Yw3T{-hjMa4H~uC(<5 zHFccMv(gg`H5qe7mDzf}2km+$S#k`bD#s!{gVXIfpNHy^!?a(dC!fLV_Fl+K7P-6& zy}(V+F78L0fSW{mw433ktNH07mw%Pvrf27JQ8~j+xw#_!vJ<TCvJ8=yAtUWMoohvF zQEjeBZi3N%aJNVg0#cC<NXj5F=7{7hB)9W2MVfaTlBOIhPzNEJ9FZRGXUHfo3!)CB z2F{6Cr3Ju7xhQrWobH4BP+>QAy$%#Bfg}ebQ3lCixlyF$3^mn?m>Ede7`1}FiuYB# zAAoORd<<zJO7!N7BF*oG<e~{PHYBM7eF4qCfOiY{$AO(PO(M-<i0OGgI-UO<xZoM= zu6$^Ekh39ABn^1in5-Q92sE<t72sCj-8{l=Vcsh@Po%m1sHDSWRh2p_c?|M)zDRE4 z-8;lahjJNsst3Ow)l?g;oCVoM1xlR(_YAn_j8;_{xJHo_gFFFt72Y*qSD>?CTR<KM z`xxGr!9F%A+eIZDDw$N{*!G=5-K>4cKCU|)dWkU^+xvEmii1CHtW+35W!<B_!vlK> zV*<A8nIPquBsQ%RCeP(`pC6iTlhXoW<J&Q`KqfA!nxQ2%aT&G`EyHoE7r37GpH)^b zmiEL&-@q2VOG9ZNG87l)HK3RmVAQZ(UO51}JaC1<sQag&>;zzxV$wz3&L#~Yb^jFl z43j2Cti7Y1V;us3)P2mI;t=Emu<Dx=ol477814O2`<Q0|lrrUu^lU$nRNrZ_$RWyx zfg6|~gXr*e_^|7T1(6O3vrs#bl<6QmMJwE1YpHHTmWh@zw|Ge83hTPzD!c2xiXD;e zfzxEp^swleW4_Sx7)VOhee+Ur!bpx?Fka@L3&lCPM~f|%;-mXhM}!#;FD+jf;e5{g zIh=dWC~F5=mqIR%WJ!bBr?Re$W=Vx(OCy&?vLvI?ID}`8auV4-1R!M^WhJ0q>_$$U zI1~erG8#uS#j<kP&2pW1dT84NM>afsI?$Qek48CKY{4@2$;=^^=lxSwYh@8&)B#hC zqnzsgDNFGe=;&~%R<;3up-^x`gN-?g%(LjJEDtp7S466!r#&~Zi|4RPid()U<Uox` z4irGqMUiA4CY&r9Pm7#Ulz|CyjnyJG<^m@eO;(YbjKB^#rYfXz$_bY#W*rl`EHM-Q z#&k?1CV;4%GLht*L@ha{LXk7&$lqckHXT6;6F^k1Xv}AI=K{^hMr<OS$tYi8IpFn8 zCI+H%O@a|;X(MOK1(5QBKM>(6v_>!X5>1&SkV>QZ?9+&F|B%(IL;S-dKK)FC?4Fvf zk-;k#rK&v_tq6|Xu4yEy=ubXckf~NJ{OFVDD~Llyhb<P>s>NZ^3{b^xcrRbgy|*D2 zP1COSKBVTnS8Exh+On)r%`Mx)Al3HeW;I>D9gxbf(xRp-4aW!<7wmlud4uBssx*tL z)O3*s1C!`)Ra5^&43=(5wVE!`eT7a&`J7gBK2Z!-C9OTLrfZV`s}fgUL`^AxRfhL# z)bxD=CPcsBJ2hRP2dv6k@;yq&09IYK3w2295shl7lN4fs0kEpcE=W`%-%kOqYSRr- zE0gvDI@n`|$hCl0#1`wINECp(J&qBm-baT8*<2q#L@r4LzOp4cDB_PL-H<#)Xn?Sq zZ7GbpjE=^^ChTbriUb2?HP)pw3XS)U#p%TUxq~7rQ^>BN<aUO%b~B<DL&>0)Z4aY% zs^{=4{WomzU&$A$$ri@XWc(Dhr+3Jn)3=o<)$P-JLc9;F$ujr|dlnNXs<~AM@4=1S zJGknQnrP$6KE{qy({*RydCsgms3xlcxTHFTuUFG$|77RBW%;a)fLwMX%O8yy+<~(q z_iTsv0X5kWi=nfbm_$(1cTT}W4s<`bd#kne*4+o)1Atwp-pNzb_W-+cB@erxUcpYQ z1CLr743es$<<S6qbjyl7HHikUk~sS=cGT@}Z%mfB#`b=IuJ%>?)k?5RqRoAvA2wp( z8d(^t{U5n%vKVe(qD{}>h5K4EB-+x4)Qxu_iPk|v9)s*{!YDTNB6Z3;M@>G#{$k6K z$UQK68ZdN?J%C#~A^8Y<lAI&aYk*6%w-LkE2pB}4E)&&sA%ax7s1I~s6Go`14?Ck3 zg|;IQB@qP5NQ=?&4i%vUJFH!l$P?sxi1$Oh&w-EN0wP0_0^0f;MQ8xDBOja8WCa2n z5_tfs9eP**>`QPLVFzylzYm^ipfMNu2axLUHmOw_M@=`8volX3op=YB)EwBz&&s!g z+lqH4GJl5VK<yLe;2QEI+Q0zRDP;dt$<Cl#PrgKY@V<@g5z2Hc(Cs1E4_UEAMzsoo zAS?sYj9Tx3e-H2fHmW&)cruCH0Cfx8TX+Y78=`PqK(&I)TCxG$)i2;W*AM`8sA0Ui ze}D~jjLm?h(mK3()Xbt(5*h9aa4ESp)RhT6|K~{0T?`bPALmhB;~4A-(?HrWp&DWQ zwB@mBb2-f`9n*~E;=C+QIhMt^MdS}I7SV(y_fIUjt*G6_I_>sT)+rY8nC0ETmUk*! z-V-f?RKZeU5EE_asbWKlbvfHztW3Y<(X_<~ElczUEOOLZfv3LZ(M1HN4!~M*pmH{J zps8;$OU%&WY*D!B@kD3wq#s84Ex(U>48SRSzC`a00!|Iym2Nmh+3-1lQ&Js7*B-+` zJ-!C7J|x`BTvZ$?fFF1QpZ4S?T>OwI6W$GI%6>@Vu0QC58|-^<9X@_Yx(5ysp3-(i zQr&ES@*FMid)#p&VMM+Qo|HM-LTOGz^Np648_f-=Bf<=a7nU!Ka6V@aJBeHzVeEjP zz#-Z`nk7w5Rsu^k)Qz%I(0T&`Q})qv$?zBmOf@;N60w~m?jSWIbthmEV(YP88sWsL zi9gU(bNwhQ78_zB!cz9paxrW_!|rAqW$Dx;Dw9pmC`*gYmjSA_T1WMs-|}kp$|L}) zrr}(wZ~6BVvA;Id4Hv6408w34O2BjUodKe<*Gir@`ek|W3ij%&$f>%~|MW3-@CH^* z<6}UorW%PfVV`fapT~aEhP_|5ot3DKK`MKFwM6UfKncw@D|pR74h^;{q#6LJn(TGQ zB(BchguqRs-Gb7MRm37OKxM<6aW)$O6=#>~F#A9Rz%7#9mJhyNs(~rNI{{9S2If;5 z5l)h9c3ZmSfuE8LFx6y}?2_HCmAveDOSUEkrh)?5C%)HymquP&6M&C<_^21K#z<6t zf#IJS1l4EZfqt2UTNC<8vcP>3x+a5g{-N8_1#VlYKcGQCL<WMd_%KENLNf&#>X(EM za2v7&x*<3LypLIEHaHHo@%&n(H~1NdmM2J(P;9uq^M{B4oNJcEK#-06_%IWzBuOY- zz&r!edO?+zot>5{&~0nrGkoK~(+b?)+FmU}8?}28_YB1b<Cnmz)(UZ#F;@?ntG^tV zD0qD0hXRTG8&UUV`SiB8c>b+zr)BwmYN8Ue_f6nEmbS_dBK5pS<OBJBT!O$h2Yjwm zRmu-O#)qhnAIO&z1nx894PK}$N5=E2NLk*SAkZ}^%^j1^B=X!D`2q{8BFlm<c{>=} z<!&&7!T3;?-%8|FZ^?2}yu#ta<wy94^+?VF9fm4~={*kGsYJ4)#Au~mP#f&5wg!xV zu}#~9=B^pnh40WW?49GfJCNk)F2-l>iq_Hb!PqtH<COvOOTy=;%ApbUEH(7W&3Xf3 z%6=GcU-TmMSeI6Q?Lm0}&uf@07E^&KnwQFZEch@y^nY}`hr&njc-xw2k~Kska2yK! zvSgUnvWbsjOJeU(4gtd%OR{+{rMM6Z<mQ*ndon80FHRv;nm$_z+#UE-Ta`pOKYsph zo}176rJ`}W5zobWZAk`?e=G`|%2VHYnOKazzCM^(A75WTBO=Sb2>Sbarx93yxdahd z1Yb+cuz-RRi^YJ5hoz(d7GN%~O15%U<z`qwQTfSqD|fQI2o_Lc$zYLDSU^E}CXSv3 zuz-S!EF9koU;zb%I8h%jfCUto#A2i?3Sa?<<m^Ly02@P2v?E=Du4nGkfyidjS{6Cb zD+CLj(Y!1~ON;eZ)%n`m^Ql&P(u@%{AyQhbwQ@CgfvLE@yEQnnB2GdJvg1WnvGw#l z%vmq&gWfxxX!WSV5zmw;zHz)qmRl<Ki{k#u7Fq5&muOX$K$0MO<af$F7QN_U>5+R+ zCpaQK38Jb=?m3FU;?W-YUILm%5)pEgWeapzWVr?`GorLyqui1xaxL<0FiKDx_f)O~ zqf&m3GqM@g9FgTb6wQ<6v+)QdAV;a(i-=^eTnoC~iN55Z$CjXF&XqnJul5c*iH~m? z0(B_l)PcJry>jmC;MpN|qB!?(=jiBQ<Q`SWTRkv51=)!R3pNc6sHb#tKz>whz`4Ev zMqolO%#HX``dV*8ktlw{WU=THzP{yUrK0Dh=EFMCL*d7;xr0+P?Hyv^;Eym7rhb@# zbHAks-Y_R?D2ITa!3;z%r2=a?FhhYUOY~&qH&|F`oT&O{;6XE6Z4l5C%{XrrWQn8z zYcgjaVz>Kpb`UPpl!ahYmMIhKH_w!fMrWJya6l{&Oa@Ufkpd&(L?Z(BIFpNtF(hd> zM@2+LZPq5i7&Mx7ZyVIAx7TSjFovY{i;~scqV-9rENRoCbfh;W!5FklGt_jcHWg>+ zP2Rh4!rBD%Kz9aascGO&G_Y<55YdXAFbCN##UmZ4fjLM7NwNtWf~}4b*}xB47(|;* z=b)A*!658<g&><?5VpEl5HUC?E)NY|?hU}PC<!Kk^DT+js<|Kwd=l4X2?Fd`50j8_ z(pAN)-#LyM>_=dh9)BlMty+W=Mw0Z#Zuq??Z4Hvt(Dp=@TmKspb|OiTJQ|<N{jGY* zqqSddeJ4T9ts^8+QgzAw%{cQl_shq@dz;iJ0BfNjRG_Ay1T{@UVXjktk|=Rc<YF+i zb};(oHZa=chrl_TQKngz8&F+?EdM<oa0NMT%KbPl_RArlBb;b|2klhigLpNKa;~%; zS~feYEn{lOHqD<kZEO!J5-_C`I@{;x=xmZS_uBK(!NIuIEQ(iqV07eq1PdB5$jWef zKDs?9*DNxyKnM)Nj!xX{#4x|s-+4ol+L$aB69I#;)up22H*a3kNgfIx*lke~48p#5 zhymob2?o(-8)g8vElt8=u+{CA{zWOHR(oq<5t5gK+60S`5gPDhWT*xfQI{>L+6Hf( zWebkQ4B8%IYmlY7-3&CzunL<ECv2MyR?%ih`~rZh4GY<3uSd)4?KUiMK&N=XDoKV_ z)Y|}=IJ>PrjRb`<u;i(YBd@Iv3R%Bl1MWMmPA6PoxJEB<n()A6+-QnO#9oHmGgK1_ zz!D1lPgjJe<DOD5P7J<*JCM@oh{_lDi*{fa#B%nTFW{04h(Il2SBui|5uR<YG5qVe zIum{P`<9mP4@U!y1%jyub62~3y|VJU+`cQ8!IgRQ_4qj2+qO~5t2VYh-L1!m+SReR zL(|gwcO9?#ds}<7o_$B>IfJ}W&vP5)BcMa@Is3#715a;!4{ALqdnKsKR!|!zP>!6J z9XUtpIqaxsRMTB(;({Cv>S<9L)FM{`ziCzz-&lTbK#Qa0Ef)um#3)b;cc$hpGMunW zCk%@hpB_8{WDqEjG+xCBEk*+C#%F%2g9a!F#B%XX<2{*J2!*Qz;Q=B;gH_@Of?Hg; z3v0r6elkzz`vM;LB=h*Ee9uMa@jVwota*B#%!?y&gexp5(^hb0C54zrv*n~78@t7f zc`PYI#J8-3&0`t%+%h(g7E3z(b3qIih{?PINj8y)OCpVrRD_CI0>0a^aI+Snc<k-w zbO_ic5hK2Cwpvfw?sawDvz-F0Fe8H=%uC(!!=|Q(a`&ZJw&xaP=|xphUsst{RF!r0 zUt-NEL`GFkXXlqXQT1h4_bEh=OJYUtq+F&KxiZ-Xx(osJ=0^sRKDvibj1>S6w7m&r zQ`ZENR5<5llygnAY=Sbb#L=kdol2uR<?BEqCku%&R-9YZ>1ciDtwCFi12Y)Jxj84B z+dG<1=H|8x+E{2C(<!PLp+!qEog&*88O=5~wjHL4o{Y5O3nG<4d4Rge=Cc3<mwWYc zEF1AGY+6|+88adpu^}5p%&EzU0pqfargZXJ0lo;bD6tXSA}lmb6B!a17!s*T!^~>e z_~;RdU8BX!#;(NKb7gEicBx2j>|@@MY;F_%(-FVj$>!E3>_C#uEzU_ulgMb|d9_Xg zfjr)^S`y6yh3Po@3M59FYZugN-<Ya~hN>7}Y?7FJ1YyBleM|1`>gttmt&UX#kz><R zU4Q<xMJuUVp7yR`?MZ9UV+(lpyh$ginx3}#>Tw2+mAKn-i(Uep(u0n~>AvfkL886i zAeI?|ZIJeMf$VAo890U{fzEkh;G;F^kU4UUvQ{Xg8rG&81J9H;J(Kt8)heGfVvm*P z-gqWI>*~Uf?m>MFYdwjR<~H2!>V4XEyP@I9pdOwY)=6ye=#122Ffg@O;o;{n8eTe< zIrcQkQz0YS)Y{S{4^TVV)YgIE8ae=OIN4qY&s%55)RL>o68<4DVn-kC5~j5ddovEK zQbS!F3EIRQF!!;R%n1nD6cx281V=|2v`vT8MG(||Y*0>uoG%|}5NHq%o1TF}^3kKo zIA3fFh~_=BY{|*C0#G470zYSY-C~|!Y)cjdy2%^&f|63SJWcr;WYjovY;J%M-pf#z zoc#T*6u6`i9Y1$@Qu6Y3H&TRc0nE>-kPH$C-03=o_u#bQ&B+{|_wn}j;dw1V2a3x| z%gam4igg$O^D&*3J7$&{SSd7Ey~<=*g=jXgug&l&o@VP=yZtP{;j!Xq(eqMAb#+HQ zs4}A<&N*~9R}^#G&*Hj3sR^Its;jm5A%QF(CGCtHo12tIi(V)1R#)GBd=ApGtY~rW zq3Y^G=11qO$BKz5R`fy=eo8hlgsZg81jk~Mb!1K!up)qBmeP~>sI|+Mt&NIjJ=wBY zr{)%KQF4E7P<w@<C$JlXdhQld$G&2yKS)XW03dB~JU(N1*$X@F-04WfE+1tRq&e4m z7!Yg!Kv3g=FVQ=9*pF0D%SNaa#OIee<@E!-mIXC#_uRSD)A0{M%|+D#N4|dT&Yf#F zZv8{OIGz|JFQm4xu1MUC3uqj}13Co{pfhy{kRVo4rzH`84nwSV{=bm_Kc8PMkISpL zP~Xtp+)#g^A}?<FuU=I@ygoQ^rE^f8@C<fdIpF8@a$7;)Eoyh6dbBNr?M3g>m(&K% z|01G+Q$PI|{khq1!k;SprdB<iqp$K$v)h98w}-2q?)&!oS!)58)ID9T&iT5NW@j4o z2&DY5rw7+Ge(bXx_acAz^Jw{x)BkT*ez<N&$t(Z%BU+F&@MG2ELIi>&KkWJU>pxyQ ztKs^;{~-M#)ABacX<|Qix|u$-a5^<lH&5YAo${Lqw9Mvn^UWCzz<(k@G`r7}|Cm7o zd}iS5r`yavpJ_K>=`5Jt#AXdFon`};zHp15Sn+f@gR7?1fZyTs(aU)Tr!xY-y7zLF zvswqHUIV|FC8y`Q6Ma)z!Ru#T7o08blNb8|dT_QBO;*p%7ka{tlNFmie&Gv@;IA*i z?@Va<<eSk?@uBMFKmC(#$M|OTDxT|;%z)pkP|kF?Mnpfo^Q!a@xWt6JUX^;8U7eWl z{NW|-Ixc&)Y=U}H<uc<-Vm_LnAD0$h<um?dL~CB9c6<*XcQ$<Y)vBLhgBM@5{_Zg= z;BT*5y)2K358%?ktA1`f4ZtsF?Wi?_UO0tlHqW5gtYxhn832k;)35&N8!^E@zk20N zqyO*#B)CWa#bNzT?$O^r1Vw-A9`&;Pu44eg-KD?Cp}*K&`r8%#T$j7_4=Uk$w@tq+ z`>_F7?XK?Qq8ihm;XeHe4n5&M{hh4;?e5b*2=#BcPrWSTtJ&|}sUP9_CGOOZJ5+1k zsUHRy<xc$-gv7g3{{=$Q+^N4Fcaz+yzX6vY+^N6W{rcTK{_b9X?zTU7`yY4vUw7|6 z?%sdhjX&Itzlgi>=T7%+01Ezg_xZz(=dTYK{&)BJleqc(P23%SaN7bHioXyy$Dc@o zdpy8M{LS6*M=H5v07m1l#Le+%;_mo6ar5^F;_mM+#LeHIh`YbPx%>MgdF$1>fbrj7 ziMzi)lmB{^-``zbi*@t;1M<d<?^yrPB{Sgq2F%}oXniv+=lcE$A#T2ZL)?A;h`9Ow z6(MfEe@5JW|Bkr%{vjbR`Tpg9vJ>A6pO<<6ba3kXr-Zz``?qq;3wu5+{L}rJI<#r# z#~(JC*7Li2)2wht*#<+WrJQB@)l0Yp+_qxc>R|=5ehv8SFJ_>gkk@DVBJjc2XQZAG zx^Wio;`VKP;jLrWP5bMt-NtSCt7{EYaDO^Wcp&emQz)8L>^BQnV(%!I941xqV!<1` zek3X$-1WwbHB2S_L)DC&%(%=|f0(NNspW6gjH`6oWX)Ss*FKFL^xYqHI=(oIzlr*{ zBQyM!oPi^Mn?}!OkmZ+KW^hTcVaqRPQ1vvk(my9mD^S^#@aG@k?WWg={|GO6;ccz1 zlJKd1!)1DkCeOwFc1^|!7k75rPh_n5?Z}nN$;;1<<c;4i!Jh$0GvP_Y9|c(Q`yc6M zW~Ws@pq4=8?*P2!>hA#jCOG@6s;aNDgMTx1y<S_d;14JbKhLjhec^Ay|HeAOoCmCv zYI)N-T<_So)%EW(MNA4D`XVNF#A}ku9jdJ3yYZ7LKtan-#;EYBAKT=K)P3gys)C6b z#&cSnnxq>qbVXZ7TBM#Z>aOz3!=v>24VU5x%)X&{h@K#sgyCq>o74Zja%E{~C#lT^ zn<-G;bs?C9HGnbYCy}{iZzW{6OTi>ed}y^zB67)oPJZr^KPmG!f0<O|QV{&1OZKG9 z?Ddn1TnfJ0?vgzzvudXKXWE{b_IIY^In()?>3W#)dYkEbo~gZ%8QLS6slAgK`V%r! ze??~K4+)u}zs27|opiyE2wI)|Iq^C^!k;A3{l7-sIZJp=p`mL0*-xc=!6q=EQ;n%z zA=Hy@12@zYbA$7Gv`f$46Fq4R;7#oWXMI=edUqevsN#1!IaJ$j-bKU5H}2<u`EdRA z?dw1M%g@J4K!++g$io>2{bIYt*3x3LY<C$t+3fVW;`Zk8HLiR-cK#l(bk4!KnC9c7 z*mbVU@YD5Sq(CQ$3tS(nVe44cqttPw4S$^cm%Wrmo*6ALKJ^$CywI;;9KIf3$eF%P ze)7zjo{;{<!U?P~jP0L}Atw-)tO=|!4BHg;(lV8Ns`{sD-&FmZYJ8>|-zn#Z;BSIY z_OSUSQ>_m&#rncu19n~io#7Sk<uXIfzbea<{h(VXtkM3hV-B@{9Jfl({Bfl4P=fz@ zWTid(njbG^^iLLknpIGc_36T4!(z-$iXWhgANcj5J3T#j4*i<((Ws+?j(!auWlf>q zjP|k~j18ltEFUF5d*n<H{yNN=l;uO?E`8mp9V_n{Pmj+(zP|DL#<vIm-Oi|nYf1+; X3^no5hM}STSy*vxZE@JoSa1IyCvxNg diff --git a/examples/webenginewidgets/demobrowser/demobrowser.ico b/examples/webenginewidgets/demobrowser/demobrowser.ico deleted file mode 100644 index d197d0358c299285ba7b6a14a7251c3523df66f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82726 zcmeHQdvFs+nirc?a<z3;N!6up?~kj4KeAV;+edBf{*kS^+CYIVhb-C6i)6#Xh9bd$ zfjF=RE`%WS$dYUb$x?(sAn}8c2LTemwlLVSmq)<7OcF4XWn+V1*fJRWl5NTA>)%K% zkA@k|NScvac-ke;^mO<4ef|Bueojxf#WKcnw<R~%La*a25B<v+i`8PW{OVT$|K~ro zSYD>j#*GX5@3&a~{g-1b_tPul&%N7X`R0)^mWOB>N&*js=eV`dbfz;kFj_QFzcuYX zNB*O~tSzukaTZu-*XCQ7IrFV=(fjvm^Q`&eAD$shh=aH^4bp<fXwg@y=9AcLKdRmF z=>ItK(_V7sS>Jc$St}{FZi*q%<wt3Ora+tW059-NRejwFa=Y>~epZ{GmR(zrUQ}C< z)~yT9QP~T4Qr=Vs$Z{v>l;=DUVi{ALm-bs)KmVO#U7vWoRqK*^K{hHQWaU|xsU#b% zYyXqB&96D~Cb>AoT(*6ItdJS9r;@IDlGT}?{zz?p`ko5~6NXa-cd49$>@*L^3s1V` zRTk8njza4bv>$g?s>@XOBTvYi**3^qUu|Lf;}qlSRL5C^{ME>-ycR~^)4F`?Z=40` z6&my=+t#LPI^-F7AAN`ia*TNus)NlJwpsnDiebERBk$0`Xq#hl6{b&h<Xf-BtG_!X zJ#+z`-05{eL*DrN9r@`y?-bnh&Ifb@9o>m`;M|e%yPCYTCcSlbr_qCspsPE@281zP zLHc4kAMd@>ure$^R96nFvs51|wrrj9W7@y@!Z1BWHD9kff6LwY0=k0^Q?V|n|8(L{ z=zEze6Z?4WF0Bf>OeGs|6<QypbDoVR_VHpLNMCm#v!$o$)bv!aflD7x`o)EUi5({P z`e1)${~Y2QxJd^3d;C3DPcGou2AqZI57!n<xNc&vFZLwp{KH;y(N(&RM;k!7H?h|T zca$Gi?iu#%>h=4`$-2X9d9net_hy}MJod~6%A3#n*A>l9<G}{dH#PfuiNpTe>rP@l zwuU@in&W-@z^tDq(*`g$HOF{~$A03`T!P<>@}<4&_h&wk3>(1QlsUJPJnWeb%s#a6 zYBJ^tF+XYc^Yy`BsjtV{dsgQ&%%#_5#aa6jSqI?#ggKwj2llXqw4*k%rZ{tcB5VNf zC(ZYG{9w=Of+-cteQy`d8f&x-nD6iT!=BkdW@&b#k@(Z~*w2`4e*E~y+uk$0<*v4( zIqQwEf#7<*HWUB&@HY~B*u&(CCBsIv16ZeMV$V1BtUkypedVH_b%1L}#;-^7I$b^N z-sp1Au*Y>0{jDpWJxwngpk;s5t<Tp3b4DYP*fTqrQI>sE5B!7Q<#4w)is_d3YcjBB zHn6g2-W&1Q0Ol2`en-PMS%%nmGO>pZOgp%&-xkL{75H9}_wp63e6Agjk%ql9$&~~1 zNK<K!@Vjy#OL*q`<oCMSL9(%Db--&S^I{$kru=ufg&E{(@yo=0=0nokbdn79TqDHq zXVdDkS8t!2^jtkoI?v@%8_A;fkP)>_@Pa*T;Q8{!eX+Cw!uR(ny1u$`-)wT@!j}YC z#_PO&odT`KuV!ho1D>#Fb-=0vb6<(p2C(-+v~_E;<2TtCliud4cp+Cz-`jkOTrJ5~ zv;!WohYh?~n%x!+{@AzV!nO&%WaFuo|K;7&Nl)WZMcnib=xIDcF7N(xm>uwnJ@ChT zz~72yKdjXTocU?Xwdy{(@iIt9)h6Qi4d@NADm}k<fV7|ZhhPIdW6#=vMfQc|TJR67 z>#^1*7gzOp*80z%7W!$bKm{WVdp)GD<qWxTaW`o{xskMflS`TpEfapY$1{W>4&rKc zy-iiZ`h2DMYHK$bK1N@ktjzIh84C(~ta0A&YuNh&8NAh`r1H@7;lW;Vv$jMS<GBha zht=1S>>F`0Hbh#`h}H3eJ+rOVMe{P%>VV+>dYW|=NsmT^p{`Zy*ZVv-=$LOCsoVL- zxbp!Tpaq)IINq>_4J<5OcvcmEKKE7>a74L}h&>(KcU{~=>OOrUZrr7|3!0#<Hh%yc z;Sqb_|5)W~J_{j=dsAXxTWP*|@uR(uROiDkF#a=IUhs%yg9G#%tv{Z4OIV-H>Rq0$ ztBW(AP^tq0`{}Cpy^PlJ?esGu_Vqk&C#nD9S;Mhsa)B3kD!B^x1#a<QVxPZX34cdk z+5whFo~{_<DY^c(^Tf6D@q}T|^a7sXt>oTy6>(_;FC5Hq%i%BVp`Mg|v?JFynA=er z-=hrH?fgT+v1c{_-b(dApKp*%t$K$$8+f#ArQf#8c8}Bscy0TY=Jn79C$i3Gm`ksa zL8(9RPxnRc@JC-{MN!tXx8Yxy{-QK*$@ZhKCF^KEzv*C3(#pM5FOWrPT##A4g*zKq zQnFy@ZTRO~H%arAY`@aGoUTh>bAvt8QCH1ZvZi{h)4?77a_d8dGgCO4_rp6}Ip_1- zBz2!X#U1{2pFK(Eh;GV>OlF+k$dwIDFJF4=w(_s%c{w`R5#Ha+Iro|E++ok^0LUii zb~YX53jfJvulvRL<J%6F2QIF3-Hu$JYIvxRmi;HW#UHXkMyYcTc5{V4`hd2BSr0NB z2%eF~jb5>4OU~VL9ppwvrE&rp<=ji>KH$m*Y{hd!-v`jVOi{{DGM;0-o}9z`+GNNR z4Nu4@=e9N+<_iB;i?iNj<)5Bag!2x$(Jj_$N*(5auy&UxIpt)5jB@i;yv+stUrAPI z42Ux?<?@oOXTmyNi2-1)HCggR%eSwsS|U9mt@QmdPw#<pN){dpm4BRj%1QZ0`H`DT z>8jbAGWbJQIcGh#nj0I)F3mm@!XM}1a)Lj;&5&~)CpV=G{*YD9J$GsYH~44T7u7KQ zY5kwa3;y^nN6xiYu1*>JTPs${Wr578-pURB^A9a_h49B&*qoGqth<wQ&1K6|2LI;6 z%jL2_7JZ-34gN14Uff{fZ_Jn{<?uJ_e_iVqrTTwf^@rS)e{ua!$Ny&kPsjF8ssHz< zQ}1$vzqtSBG{=9smVdeNAHF)Ce0(i8_>0GX=KPPo{Q$Xjfo+~HZm`EZRM`BFIsdC$ z`B$3%<!v2E*!-{g{zo_bQ}O+e`TkeG`d{h&FHdtn!ux;G`(JbYhd%f#t^ep8?4jS_ zui~ox7q9=oJP_T_-ObA!Amq4{)_;B8bet>frR%?dzq$T1zB&MFQkB+!&OEz`EBxiw ze>(H5@AFjtAxlcF|E6ow<=m+obzEVOwqI`jH{Ivc{Qe`xIlxHYe=In^ojd$xzyIL$ z+wWBV{_AMxCGN0C`KSBBPDPt9cINk=(YOD?_n)2e-+^Nvfaf`y?+5PqDSiJ5TQI-> z)@}p9UT&V3^#L~3+qo?JO5cA2e{=r_ZTPG0|8R`f``B}jl{ucSk@kP!^&4=E1yW`I zmn;2ly8p|YTw)J9jI{rYPzR*?{!erqX2dsQpo#B}<<=&%Iv?M8@wCQMTJNas{}gBg ztbgZi9)QV1*Qt=rN7fMNIg&GG|F^D4ECrcnoqeC%at~Y3wEtUP+HaY@dAb7o+~T={ zey5-Q2Wjf>jEDyU6Se;%WPwc5^2VEA%l?np|J9K<$;B)7OsCjm4gD;w&ZzxgAp_6* zy)k`h-TxJB08jfri_1OB3%jC^y|J!@V62^JH%NJcH?RGCrXzOMy8pA#2jFD?_ej{Y zeBp|DmVdfy5@rHNI%~L`+Y#$Td>`%p?}2_`a?gLzioH0WFMszjIeDYjFgpNk@DTG% zh5KmFe+aYz>5n9<4-gCXVjR#9|DyRg=@_^bw=IAMXz|{+7w2DkAIteKuz_Tp{}eCw z;=E(c&HVG*$d=28$cgJtf;G5)`lsX&hB%0eG)T+ax*c);wA{yf{*!=zg3o``6MH4y zSdXnCGtO)zndi0$-{aw%Jlx|M!j#gb>hpNce@o=~kBPuORWXcJ?s(6CL>-Wb^IuKu zjd@oT@A<F5AI`}0pH1wI!CtTPpMif}zV$aood0fOZw&T<@&26Wft_BC)&ZOK91oh< z8-qRi3Ucc^<F$i^yz%!t@~zkOumKZ$<FKDxv1Ito{h9w2FWz$LU4`jW<Hg^^-Z<=0 z_H9LTVm|L%4s+=<M}GRwSZ%<>-dOB2OS2oLc<Jp&J5ZCC))cJ`nAjVO{gjI3zPF2J zjnx}(IeN|=8NZ|73wpKMfQh}a*ry$}ku}Ac^X0HI>Y1Y;eX$n&P3(=u9&P@z;;el} z;jBbAa87jk7m;kh#NK%9XCGR46<8?YWaRUfty6wnTaZ>IX9Fho#$!LDd};6c{h1FK ziLn~(`cEhR#F?MoD7FC;d*iWxx-`eTVc$zXQ^O|_;jTjKgBJ=WcEAQq?2X4hqhjgs zx}w=>iNIDXk4qm<`h~M#!gaPrJJxrWX1d7sGv)9K{~JY_Pie&^k@2?eo$(apGck;e zVXXRrZr2`|J1dcxM#~GfiTWwlJeuj`Z3jB#wcJZ>1Z@-gCnlEiSVpTC=#sbgUW&QY z|Mr1dKgaka+Ps?a!)*pS<fWf4#aPXcu_@*!OiaTu)v6EZF4^OIHH_85F*k+zNz74e z&G%@J2VFsD$(q+w!!(v~yq~~3s?m<ETK=J<M8C_41<zR0;Qb`tQLE`-w1z`BiF$_{ z3x0Z~!5S5;QyQ%}OY;p~7`<*sFYNT9gEeYcr<f|=PfIb=!;ic}2S%;e(+evj>8vZB zJq>Hs_0VT3(LkP&cO!M1O0@B<3cgoLB@APc6?xR_yPQ<QSBtDRo9##VUJ>7{#-dxE z(;!dC8}g_{7o$B6zFEh<1*zOWfb7Uatl!^{b{jzc|5h~nVeDOl{fl@m-(uMyD`bZ3 zCWiWG0QDyJFT);o*vC+;ZyxR;6J&#oW*x5&=89AZ8H0UHv6n6OGtMYmnea6S*hd?@ zA%n1|DwRo5UNgW@4cK<s?paZk_3YB(`JZAujq^=##*JR}0%(CIXoJT}`@E^(X=tWQ z;&E#LXI$CnIcKjHXT6E@4sqrs&OOE1w>bY8XQ1PUdptuJ;vg>4Ag%PAthj|T378t- zNCWbFVfif<n>ZxbVi_ay`;dY0BM&O!ziY$~uf-Db3(-Xh8iioXy(~gyz#k$I@P-Hk zlZOZlu<)?~0*%ZcBv{G(L4wR1BuMkdoDBp*<bw=C<Smx52*1f<TP*j%-#FqI7*>w> z1%|mJenDp=UO@m6dqK$}_JROXzepTGAdxtNKvI9Bm>(6eQtYP!O8vRwa4N9WFAk;| z2os-XK+PYP9hyO@KP-DRgHnH3_GpHq^xxYUF2Ab3GCclWdi!(3>5nn}VG0>j8RoU< zuK&hx`uD2&CH8i&#II_PQhS#ArR72DS1VuAa1x%s+skvVI07y2m14h4{m>{5r}asg z0%(OO^@n9}Y*_UwTfc>6z((s=F+b`RS4cvAS~(IysBarb{6c*!5=f}8MFNclJ&}gT z!!HuR2ERxE!8@WMft{!U5ZDnCVlXxkKg3{sz#k$Q^fH1$av_32av=#>awZW=9>gq^ zJSf4~k#Oit&=q?`^JruD;n#<#_I^cwGwE-PWgPu)vE=?#xES`YreM;)Ir7r~*O_nq z3;ky375ZBl{Jnx_2typh1c;I_*){d9+Wd4Y-TUGLdPb51-#Kae(YS#$=~mE)l5O14 z9XrQAK)=mfRkPjNu1Veq`2r2l0?oJuQz3xwN~s;JrhAU{$1ArqJ!pb9c&LaGQ?R2j zeWK$d>lG<qz5U<;UNH$NlSr`f0_&RZ3dRrXEvpi}Ag?v?mW>O$rrtv_-KE6G=;tk! zt17x0D(;t2tLh`jPUR~zT1F-ME#KIPpPpsVdc)CI)ll>wssf850Jo&-Jt#X`wCbA; zWWhH}n{8B|A`v6rQk|?((u>j0nckV~laIe4tdIWd!39Sn3LOkY*-vCy73)JucFecp zo#(2eIXRK?fVwvkb);Bkb{|Q0HedWy$s%v0b@ymL7`;SZwaCu$pkzmAzx8WZGf2ap zzmTgX+2m^R0&;oxpB4K>(a4TGOg{2DSzr9pe@pEMeUNx{4q0#29VWhk+s_fh*<rU_ z2g#NFb3%EER(6KLE0VH|`ZAur7|xjQt}hSoz*C=(?pcqY)ZMHtA#F$23H3X|P)D+Q zhRGP|YOPp2EUr({2aZ+umv>JmL${hkBK9_&AT8yu6W1q?hxCklJVTh&MJqeYm#t{- z3T8t>Upzt|S1E7MJCohle}goaE)B`7lm>AS7tZS+CR3}{$MpTn%ca>Dnfy_WJw*9r zHUoJY_Rdt5o#hE}Sso6xe;1SdQ%YVPg8UfIF}l%QQC6ALqIW56q+u?zdP_`sKs|&p zsg$-BKk6B{-lmh9^)980v~c!o)iKFW+v6<SW?`%yr3@LNI<lpFWt3@0cp)tu&TVAn zGMel1;;ijdcFYq*B?H<f=3F~R>X~TiAT4vxR=pE-9+ug&zM?!a#}SqMXjkEUo|{pn zlj8##a5(EC8r>sq&cTHhyvUC;Sz?r*3;TH{hIRn<!$bM)8tRK$_rMC}mxucEK--y^ z<VXF<L;E$a`ooyyXZ`48_8-bRzK=<E)_*`BB3b>nX3zDQ&-4!Ozs25v{-A6bY3{!+ z)ZzH2wf~GXf1>9jMq6jH_~QO^tmBur4$Kz#<6Lyufz&CDUl2E*v(%;I7uZm=<3}bt z(+937ho$Z3Nw?P{&5H00VX>A~F(2vpQ78jZjNj#C7t_aF&9u|+kp<_s3qRcJwccK7 z{2stSef~sEc5yz8xL2A#f&6OoSIL%LZT?EIBZc|HWXrB){t)uR(LQO|{B5#jhaE<; zn}F0K|52Z^`Ewp*pL=LglX$*oL{jBDyuaAEZ)S}VWiT3=)5~(MZ`zghuga1thaesD z9t}S|<AQgrva?(PH`tzD^|zM%ffsm2Ycot{xhvisp#IXrKb|<?q4u6aPChNq@a_P5 zK^qv4jB;r~6SO0}pU@(smN*zUpbvt6l$<QlJOd5TVq+04{Pl_h`$Rt$eQ}H@w91XR zNQ1O`+IYPAf(|hz#kd-C1DKz|5BGS6FunCmS1Hl;Nr45RHeBhdr?I#;S}gbCT8S0F z^oq>Uf5NINo5dn5h8l0N2#ch~j$DORTK8EjG&v<Oa;=1)u9RWdT=?miHA+_m>*;bq zECRnugp1^BgkK~-%a=62Ob<*iR7HZGLV9Zq>XGSHSh7W<1oe(}TI1+%0{w;7Y00cO z7#<#8OMm<6&mR8s*@p-F?SuU{?EP-1{Z?I>z2nT5Lro=%PB(lx%~|*96HTs9{?LXW z?(qy^h=aIDgS4PAJWOfbMql6w-uvjUi~c-;pU>kP>h}!wUib80uk&=bobj}u+&oyn z=Y`?g?Gx4KHEA5gMH-|94bTEjDo2oqzzaOV8?prlX7sG*;UVJf>mdED)ujFOhot`V zXVrNs%+n%m$C+)UzwJ9pvy=G!UON5@oF^T~Ye?rF8c2q{{lweTO8T0s=sTlj<f4}R zD)44=x}eca-;v#N*O2}J`reP`4>E-F_j&yE`A~N&>AqY}8oqup<~%dL;;U=NW2D1* zfLwK7Bt3!*UMh!x1$1xs4S77?J~!!WIb{fM%zgN&ez#O_C70Y6h`aY1=^yNaEl~bG z`%rJE2Y5FhTBdux8Sgh7dxW-qZRJXGruigs_gwP~4iD1uF<|#l8|^srp)Pncy+h|x z-e||r2mAQ+X5zeF>**Wpv(xu=_U`7>p1NJn>6UjT-mD#+Np1UNTeYX7yUjj8>j{)q zCb!zvRXACAN8Q~}Njz>R8R)DfxW{{I@Kxi@WY~IYqxbu^@9ekg%j}m?x2TjOgyS9m z;H@TM4rj2dQFynGccr+8Ls(zyS;5vA-i)90I`43fe}Bzhp-$COuYvdQP`|*V$-ekD ztniG<_EBTGYCkgVh>dJI@oqWlY_+^Y=b(*u+V!75a~p4#9$^FBEu^`xounUItt!LH z(j_jm8!Wxj71+Yb<y)Etap2ZCcB}HwIhgIPr)`&%hSU%H8oYT$G2hbo9vb%>4fEGo zhZpst{gkGc`eEm=GwE|BKjPMPH>>7<&Y{JgWb-#p|39eaANn`S{?y7p>I2xH5#_Ii zwxwFjANp%r>Yqkh{|wRjYm{%fa)@UL^Y{kHOXogN)jg|!wA8=sjF1=4Z6>WWZ*U$_ z{fm1zgdvW!u9fq%`d6*}VZ0d)=yffvTPiw!Ag=Bv;fH%X)1q@mhqXVf{gvxyN_n%i z@m|I4uTuZRDBkFQd?f0Bu>Myc?SEYj_P>nc4ZW?ZSV2yU`(MHS=Mc4>j+T?;0`2=6 zbtcJzvL)nO%DcU{P1OGs`k=HgIz+l?oqfLkFv%`ks>z0<u><fftuG}_l*iEUU|9bf zV*&J!2fclylZKz8<B!!;PkPJ^f(CSsd^gkb(nr?>fLHkVBQXB*({YK{H$*z9e$Yoo zKlKILSBxf~;<!i)8o(PghkSzqZ`2hc{$b-!pU>yP*udS>?m-{<L~FGNWfk=W>MSvR zxqHMxT%<u-&;Tva1nnSST-o?jcKq$5V*~Wh(MLu<b$`uQ_Dxmqm9H#a>O#ALwhQey zez?aogdq;%A`Q|CeSC~F0^?lq6=VLjbb27E4)YY4mKaBWY@TAm-P9v-z)bA07Psrt z*QB{@1?`t-3P0TAncO<vk+go&b#V{5^x2b&{V9YY4jZeB)3$&6u3|cIf9y)}%jAbE z6=5_$QyfR>9%)-?AM&|V8_3SHTLt#Wlbp<#znn&{9bZp>?-1OJ)51P~U$&Cm=xrDD zBISpEb$|N>AuZDPxBoyo>HGuuif#Lo>g|G_#p%HdX))en&vEZ|JLuZg@HKCLEzcG3 zVexPc$h;wxmW5qAzJY9TejUdDg~I`iSsb<W@7CU)9=0J)A4z`cnmx!5yAr2I8@2D; zHqzPY2<Z>^Z`bS!lO1}5{>1o++c)sq;M^<xq<qEr!3bbK;<RFnl<t}R2u4Kf*RPJh zb(?%jY1bZIOOplWs{-lq-!IrC>`Eye!UBAyX-BBQCZQMT7Wm?adptv!)Jdv?sJ;IW DCiPgP diff --git a/examples/webenginewidgets/demobrowser/demobrowser.pro b/examples/webenginewidgets/demobrowser/demobrowser.pro deleted file mode 100644 index aef7b9eac..000000000 --- a/examples/webenginewidgets/demobrowser/demobrowser.pro +++ /dev/null @@ -1,95 +0,0 @@ -TEMPLATE = app -TARGET = demobrowser -QT += webenginewidgets network widgets printsupport -CONFIG += c++11 - -qtHaveModule(uitools):!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 \ - printtopdfdialog.ui \ - proxy.ui \ - savepagedialog.ui \ - settings.ui - -HEADERS += \ - autosaver.h \ - bookmarks.h \ - browserapplication.h \ - browsermainwindow.h \ - chasewidget.h \ - downloadmanager.h \ - edittableview.h \ - edittreeview.h \ - featurepermissionbar.h\ - fullscreennotification.h \ - history.h \ - modelmenu.h \ - printtopdfdialog.h \ - savepagedialog.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 \ - downloadmanager.cpp \ - edittableview.cpp \ - edittreeview.cpp \ - featurepermissionbar.cpp\ - fullscreennotification.cpp \ - history.cpp \ - modelmenu.cpp \ - printtopdfdialog.cpp \ - savepagedialog.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 = demobrowser.rc -} - -mac { - ICON = demobrowser.icns - QMAKE_INFO_PLIST = Info_mac.plist - TARGET = Demobrowser -} - -EXAMPLE_FILES = \ - Info_mac.plist demobrowser.icns demobrowser.ico demobrowser.rc \ - cookiejar.h cookiejar.cpp # FIXME: these are currently unused. - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/demobrowser -INSTALLS += target diff --git a/examples/webenginewidgets/demobrowser/demobrowser.rc b/examples/webenginewidgets/demobrowser/demobrowser.rc deleted file mode 100644 index 70cd8bb1c..000000000 --- a/examples/webenginewidgets/demobrowser/demobrowser.rc +++ /dev/null @@ -1 +0,0 @@ -IDI_ICON1 ICON DISCARDABLE "demobrowser.ico" diff --git a/examples/webenginewidgets/demobrowser/doc/images/browser-demo.png b/examples/webenginewidgets/demobrowser/doc/images/browser-demo.png deleted file mode 100644 index e8695dbca93f77521b42290d897aa940f488ce80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199354 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%0AkhU5Cr^#?xrk#|YN9)oDd_1uh1mH{3~G3i+9 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	nh%}6y;@_@+(Rz)>u2HrGY4~FJqh5 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⩔>hM1FmqL};UJ>j{uSZAko?*U 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%0AJZCnC>Jd7aZ=y%^>G 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 HqoDr>Lq~X5 diff --git a/examples/webenginewidgets/demobrowser/doc/src/demobrowser.qdoc b/examples/webenginewidgets/demobrowser/doc/src/demobrowser.qdoc deleted file mode 100644 index dfd7a7a3d..000000000 --- a/examples/webenginewidgets/demobrowser/doc/src/demobrowser.qdoc +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/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: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \example webenginewidgets/demobrowser - \title WebEngine Demo Browser Example - \ingroup webengine-widgetexamples - \brief A demo browser based on Qt WebEngine Widgets - - \e {Demo Browser} demonstrates how to use the \l{Qt WebEngine Widgets C++ Classes} - {Qt WebEngine C++ classes} to develop a small Web browser application with support for tabs. - - \image browser-demo.png - - \include examples-run.qdocinc -*/ diff --git a/examples/webenginewidgets/demobrowser/downloaditem.ui b/examples/webenginewidgets/demobrowser/downloaditem.ui deleted file mode 100644 index e506f28b6..000000000 --- a/examples/webenginewidgets/demobrowser/downloaditem.ui +++ /dev/null @@ -1,133 +0,0 @@ -<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="leftMargin"> - <number>5</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>5</number> - </property> - <property name="bottomMargin"> - <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="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/webenginewidgets/demobrowser/downloadmanager.cpp b/examples/webenginewidgets/demobrowser/downloadmanager.cpp deleted file mode 100644 index 012d0620e..000000000 --- a/examples/webenginewidgets/demobrowser/downloadmanager.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "downloadmanager.h" - -#include "autosaver.h" -#include "browserapplication.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 <QWebEngineSettings> -#include <QWebEngineDownloadItem> - -/*! - DownloadWidget is a widget that is displayed in the download manager list. - It moves the data from the QWebEngineDownloadItem into the QFile as well - as update the information/progressbar and report errors. - */ - -DownloadWidget::DownloadWidget(QWebEngineDownloadItem *download, QWidget *parent) - : QWidget(parent) - , m_bytesReceived(0) - , m_download(download) -{ - setupUi(this); - QPalette p = downloadInfoLabel->palette(); - p.setColor(QPalette::Text, Qt::darkGray); - downloadInfoLabel->setPalette(p); - progressBar->setMaximum(0); - connect(stopButton, SIGNAL(clicked()), this, SLOT(stop())); - connect(openButton, SIGNAL(clicked()), this, SLOT(open())); - - if (download) { - m_file.setFile(download->path()); - m_url = download->url(); - } - - init(); -} - -void DownloadWidget::init() -{ - if (m_download) { - connect(m_download.data(), SIGNAL(downloadProgress(qint64,qint64)), - this, SLOT(downloadProgress(qint64,qint64))); - connect(m_download.data(), SIGNAL(finished()), - this, SLOT(finished())); - } - - // reset info - downloadInfoLabel->clear(); - progressBar->setValue(0); - getFileName(); - - // start timer for the download estimation - m_downloadTime.start(); -} - -bool DownloadWidget::getFileName(bool promptForFileName) -{ - QSettings settings; - settings.beginGroup(QLatin1String("downloadmanager")); - QString defaultLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - if (m_file.absoluteDir().exists()) - defaultLocation = m_file.absolutePath(); - QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString(); - if (!downloadDirectory.isEmpty()) - downloadDirectory += QLatin1Char('/'); - - QString defaultFileName = QFileInfo(downloadDirectory, m_file.fileName()).absoluteFilePath(); - QString fileName = defaultFileName; - if (promptForFileName) { - fileName = QFileDialog::getSaveFileName(this, tr("Save File"), defaultFileName); - if (fileName.isEmpty()) { - if (m_download) - m_download->cancel(); - fileNameLabel->setText(tr("Download canceled: %1").arg(QFileInfo(defaultFileName).fileName())); - return false; - } - } - m_file.setFile(fileName); - - if (m_download && m_download->state() == QWebEngineDownloadItem::DownloadRequested) - m_download->setPath(m_file.absoluteFilePath()); - - fileNameLabel->setText(m_file.fileName()); - return true; -} - -void DownloadWidget::stop() -{ - setUpdatesEnabled(false); - stopButton->setEnabled(false); - stopButton->hide(); - setUpdatesEnabled(true); - if (m_download) - m_download->cancel(); - - emit statusChanged(); -} - -void DownloadWidget::open() -{ - QUrl url = QUrl::fromLocalFile(m_file.absoluteFilePath()); - QDesktopServices::openUrl(url); -} - -void DownloadWidget::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 DownloadWidget::updateInfoLabel() -{ - qint64 bytesTotal = progressBar->maximum(); - - // 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 (!downloadedSuccessfully()) { - 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 = tr("%1 of %2 - Stopped") - .arg(dataString(m_bytesReceived)) - .arg(dataString(bytesTotal)); - } else - info = dataString(m_bytesReceived); - } - downloadInfoLabel->setText(info); -} - -QString DownloadWidget::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 DownloadWidget::downloading() const -{ - return (progressBar->isVisible()); -} - -bool DownloadWidget::downloadedSuccessfully() const -{ - bool completed = m_download - && m_download->isFinished() - && m_download->state() == QWebEngineDownloadItem::DownloadCompleted; - return completed || !stopButton->isVisible(); -} - -void DownloadWidget::finished() -{ - if (m_download) { - QWebEngineDownloadItem::DownloadState state = m_download->state(); - QString message; - bool interrupted = false; - - switch (state) { - case QWebEngineDownloadItem::DownloadRequested: // Fall-through. - case QWebEngineDownloadItem::DownloadInProgress: - Q_UNREACHABLE(); - break; - case QWebEngineDownloadItem::DownloadCompleted: - break; - case QWebEngineDownloadItem::DownloadCancelled: - message = QStringLiteral("Download cancelled"); - interrupted = true; - break; - case QWebEngineDownloadItem::DownloadInterrupted: - message = QStringLiteral("Download interrupted: %1").arg(m_download->interruptReasonString()); - interrupted = true; - break; - } - - if (interrupted) { - downloadInfoLabel->setText(message); - return; - } - } - - progressBar->hide(); - stopButton->setEnabled(false); - stopButton->hide(); - updateInfoLabel(); - emit statusChanged(); -} - -/*! - DownloadManager is a Dialog that contains a list of DownloadWidgets - - 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_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(QWebEngineDownloadItem *download) -{ - DownloadWidget *widget = new DownloadWidget(download, this); - addItem(widget); -} - -void DownloadManager::addItem(DownloadWidget *widget) -{ - connect(widget, SIGNAL(statusChanged()), this, SLOT(updateRow())); - int row = m_downloads.count(); - m_model->beginInsertRows(QModelIndex(), row, row); - m_downloads.append(widget); - m_model->endInsertRows(); - updateItemCount(); - if (row == 0) - show(); - downloadsView->setIndexWidget(m_model->index(row, 0), widget); - QIcon icon = style()->standardIcon(QStyle::SP_FileIcon); - widget->fileIcon->setPixmap(icon.pixmap(48, 48)); - downloadsView->setRowHeight(row, widget->sizeHint().height()); -} - -void DownloadManager::updateRow() -{ - DownloadWidget *widget = qobject_cast<DownloadWidget*>(sender()); - int row = m_downloads.indexOf(widget); - if (-1 == row) - return; - if (!m_iconProvider) - m_iconProvider = new QFileIconProvider(); - QIcon icon = m_iconProvider->icon(widget->m_file); - if (icon.isNull()) - icon = style()->standardIcon(QStyle::SP_FileIcon); - widget->fileIcon->setPixmap(icon.pixmap(48, 48)); - downloadsView->setRowHeight(row, widget->minimumSizeHint().height()); - - bool remove = false; - if (!widget->downloading() - && BrowserApplication::instance()->privateBrowsing()) - remove = true; - - if (widget->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"), m_downloads[i]->m_file.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 (done && !url.isEmpty() && !fileName.isEmpty()) { - DownloadWidget *widget = new DownloadWidget(0, this); - widget->m_file.setFile(fileName); - widget->fileNameLabel->setText(widget->m_file.fileName()); - widget->m_url = url; - widget->stopButton->setVisible(false); - widget->stopButton->setEnabled(false); - widget->progressBar->hide(); - addItem(widget); - } - 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()) { - beginRemoveRows(parent, i, i); - m_downloadManager->m_downloads.takeAt(i)->deleteLater(); - endRemoveRows(); - } - } - m_downloadManager->m_autoSaver->changeOccurred(); - return true; -} diff --git a/examples/webenginewidgets/demobrowser/downloadmanager.h b/examples/webenginewidgets/demobrowser/downloadmanager.h deleted file mode 100644 index ea5a7e79d..000000000 --- a/examples/webenginewidgets/demobrowser/downloadmanager.h +++ /dev/null @@ -1,163 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 DOWNLOADMANAGER_H -#define DOWNLOADMANAGER_H - -#include "ui_downloads.h" -#include "ui_downloaditem.h" - -#include <QtCore/QFileInfo> -#include <QtCore/QTime> -#include <QtCore/QUrl> - -#include <QWebEngineDownloadItem> - -class DownloadManager; -class DownloadWidget : public QWidget, public Ui_DownloadItem -{ - Q_OBJECT - -signals: - void statusChanged(); - -public: - DownloadWidget(QWebEngineDownloadItem *download, QWidget *parent = 0); - bool downloading() const; - bool downloadedSuccessfully() const; - - void init(); - bool getFileName(bool promptForFileName = false); - -private slots: - void stop(); - void open(); - - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); - void finished(); - -private: - friend class DownloadManager; - void updateInfoLabel(); - QString dataString(int size) const; - - QUrl m_url; - QFileInfo m_file; - qint64 m_bytesReceived; - QTime m_downloadTime; - bool m_stopped; - - QScopedPointer<QWebEngineDownloadItem> m_download; -}; - -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) - -public: - enum RemovePolicy { - Never, - Exit, - SuccessFullDownload - }; - Q_ENUM(RemovePolicy) - - DownloadManager(QWidget *parent = 0); - ~DownloadManager(); - int activeDownloads() const; - - RemovePolicy removePolicy() const; - void setRemovePolicy(RemovePolicy policy); - -public slots: - void download(QWebEngineDownloadItem *download); - void cleanup(); - -private slots: - void save() const; - void updateRow(); - -private: - void addItem(DownloadWidget *item); - void updateItemCount(); - void load(); - - AutoSaver *m_autoSaver; - DownloadModel *m_model; - QFileIconProvider *m_iconProvider; - QList<DownloadWidget*> 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/webenginewidgets/demobrowser/downloads.ui b/examples/webenginewidgets/demobrowser/downloads.ui deleted file mode 100644 index a2e256935..000000000 --- a/examples/webenginewidgets/demobrowser/downloads.ui +++ /dev/null @@ -1,83 +0,0 @@ -<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/webenginewidgets/demobrowser/edittableview.cpp b/examples/webenginewidgets/demobrowser/edittableview.cpp deleted file mode 100644 index 4d237ecd9..000000000 --- a/examples/webenginewidgets/demobrowser/edittableview.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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/webenginewidgets/demobrowser/edittableview.h b/examples/webenginewidgets/demobrowser/edittableview.h deleted file mode 100644 index 1acee59f1..000000000 --- a/examples/webenginewidgets/demobrowser/edittableview.h +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/edittreeview.cpp b/examples/webenginewidgets/demobrowser/edittreeview.cpp deleted file mode 100644 index f4c9a0d70..000000000 --- a/examples/webenginewidgets/demobrowser/edittreeview.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "edittreeview.h" -#include "browserapplication.h" -#include "history.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(); - BrowserApplication::historyManager()->removeHistoryEntry(model()->data(ci,HistoryModel::UrlStringRole).toString()); -} - -void EditTreeView::removeAll() -{ - if (!model()) - return; - BrowserApplication::historyManager()->clear(); -} diff --git a/examples/webenginewidgets/demobrowser/edittreeview.h b/examples/webenginewidgets/demobrowser/edittreeview.h deleted file mode 100644 index f9dcd5e63..000000000 --- a/examples/webenginewidgets/demobrowser/edittreeview.h +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/featurepermissionbar.cpp b/examples/webenginewidgets/demobrowser/featurepermissionbar.cpp deleted file mode 100644 index 4cac05082..000000000 --- a/examples/webenginewidgets/demobrowser/featurepermissionbar.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "featurepermissionbar.h" - -#include <QLabel> -#include <QPushButton> -#include <QHBoxLayout> -#include <QUrl> -#include <QPropertyAnimation> - -static const int defaultHeight = 30; - -static QString textForPermissionType(QWebEnginePage::Feature type) -{ - switch (type) { - case QWebEnginePage::Notifications: - return QObject::tr("use desktop notifications"); - case QWebEnginePage::Geolocation: - return QObject::tr("use your position"); - case QWebEnginePage::MediaAudioCapture: - return QObject::tr("use your microphone"); - case QWebEnginePage::MediaVideoCapture: - return QObject::tr("use your camera"); - case QWebEnginePage::MediaAudioVideoCapture: - return QObject::tr("use your camera and microphone"); - case QWebEnginePage::MouseLock: - return QObject::tr("lock your mouse"); - default: - Q_UNREACHABLE(); - } - return QString(); -} - -FeaturePermissionBar::FeaturePermissionBar(QWidget *view) - : QWidget(view) - , m_messageLabel(new QLabel(this)) -{ - setAutoFillBackground(true); - QHBoxLayout *l = new QHBoxLayout; - setLayout(l); - l->setContentsMargins(defaultHeight, 0, 0, 0); - l->addWidget(m_messageLabel); - l->addStretch(); - QPushButton *allowButton = new QPushButton(tr("Allow"), this); - QPushButton *denyButton = new QPushButton(tr("Deny"), this); - QPushButton *discardButton = new QPushButton(QIcon(QStringLiteral(":closetab.png")), QString(), this); - connect(allowButton, &QPushButton::clicked, this, &FeaturePermissionBar::permissionGranted); - connect(denyButton, &QPushButton::clicked, this, &FeaturePermissionBar::permissionDenied); - connect(discardButton, &QPushButton::clicked, this, &FeaturePermissionBar::permissionUnknown); - connect(allowButton, &QPushButton::clicked, this, &QObject::deleteLater); - connect(denyButton, &QPushButton::clicked, this, &QObject::deleteLater); - connect(discardButton, &QPushButton::clicked, this, &QObject::deleteLater); - l->addWidget(denyButton); - l->addWidget(allowButton); - l->addWidget(discardButton); - setGeometry(0, -defaultHeight, view->width(), defaultHeight); -} - -void FeaturePermissionBar::requestPermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature) -{ - m_securityOrigin = securityOrigin; - m_feature = feature; - m_messageLabel->setText(tr("%1 wants to %2.").arg(securityOrigin.host()).arg(textForPermissionType(feature))); - show(); - // Ease in - QPropertyAnimation *animation = new QPropertyAnimation(this); - animation->setTargetObject(this); - animation->setPropertyName(QByteArrayLiteral("pos")); - animation->setDuration(300); - animation->setStartValue(QVariant::fromValue(pos())); - animation->setEndValue(QVariant::fromValue(QPoint(0,0))); - animation->setEasingCurve(QEasingCurve::InOutQuad); - animation->start(QPropertyAnimation::DeleteWhenStopped); -} - -void FeaturePermissionBar::permissionDenied() -{ - emit featurePermissionProvided(m_securityOrigin, m_feature, QWebEnginePage::PermissionDeniedByUser); -} - -void FeaturePermissionBar::permissionGranted() -{ - emit featurePermissionProvided(m_securityOrigin, m_feature, QWebEnginePage::PermissionGrantedByUser); -} - -void FeaturePermissionBar::permissionUnknown() -{ - emit featurePermissionProvided(m_securityOrigin, m_feature, QWebEnginePage::PermissionUnknown); -} diff --git a/examples/webenginewidgets/demobrowser/featurepermissionbar.h b/examples/webenginewidgets/demobrowser/featurepermissionbar.h deleted file mode 100644 index 63290df3b..000000000 --- a/examples/webenginewidgets/demobrowser/featurepermissionbar.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 FEATUREPERMISSIONBAR_H -#define FEATUREPERMISSIONBAR_H - -#include <QWidget> -#include <QWebEnginePage> - -QT_BEGIN_NAMESPACE -class QLabel; -class QPushButton; -QT_END_NAMESPACE - -class FeaturePermissionBar : public QWidget { -Q_OBJECT - -public: - FeaturePermissionBar(QWidget*); - void requestPermission(const QUrl &, QWebEnginePage::Feature feature); - -signals: - void featurePermissionProvided(const QUrl &securityOrigin, QWebEnginePage::Feature, QWebEnginePage::PermissionPolicy); - -private slots: - void permissionDenied(); - void permissionGranted(); - void permissionUnknown(); - -private: - QWebEnginePage::Feature m_feature; - QLabel *m_messageLabel; - QUrl m_securityOrigin; -}; - -#endif // FEATUREPERMISSIONBAR_H diff --git a/examples/webenginewidgets/demobrowser/fullscreennotification.cpp b/examples/webenginewidgets/demobrowser/fullscreennotification.cpp deleted file mode 100644 index aadabbadb..000000000 --- a/examples/webenginewidgets/demobrowser/fullscreennotification.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "fullscreennotification.h" - -#include <QApplication> -#include <QDesktopWidget> -#include <QGridLayout> -#include <QLabel> -#include <QPropertyAnimation> -#include <QTimer> - -FullScreenNotification::FullScreenNotification(QWidget *parent) - : QWidget(parent) - , width(400) - , height(80) - , x((parent->geometry().width() - width) / 2) - , y(80) -{ - setVisible(false); - setWindowFlags(Qt::ToolTip | Qt::WindowDoesNotAcceptFocus); - - QGridLayout *layout = new QGridLayout(this); - - m_label = new QLabel(tr("You are now in fullscreen mode. Press ESC to quit!"), this); - layout->addWidget(m_label, 0, 0, 0, 0, Qt::AlignHCenter | Qt::AlignVCenter); - - setGeometry(x, y, width, height); - - setStyleSheet("background-color: white;\ - color: black;"); - - m_animation = new QPropertyAnimation(this, "windowOpacity"); - connect(m_animation, SIGNAL(finished()), this, SLOT(fadeOutFinished())); -} - -FullScreenNotification::~FullScreenNotification() -{ -} - -void FullScreenNotification::show() -{ - setWindowOpacity(1.0); - QTimer::singleShot(300, [&] { - QWidget *parent = parentWidget(); - x = (parent->geometry().width() - width) / 2; - QPoint topLeft = parent->mapToGlobal(QPoint(x, y)); - QWidget::move(topLeft.x(), topLeft.y()); - QWidget::show(); - QWidget::raise(); - }); - QTimer::singleShot(5000, this, SLOT(fadeOut())); -} - -void FullScreenNotification::hide() -{ - QWidget::hide(); - m_animation->stop(); -} - -void FullScreenNotification::fadeOut() -{ - m_animation->setDuration(800); - m_animation->setStartValue(1.0); - m_animation->setEndValue(0.0); - m_animation->setEasingCurve(QEasingCurve::OutQuad); - m_animation->start(); -} - -void FullScreenNotification::fadeOutFinished() -{ - hide(); - setWindowOpacity(1.0); -} diff --git a/examples/webenginewidgets/demobrowser/fullscreennotification.h b/examples/webenginewidgets/demobrowser/fullscreennotification.h deleted file mode 100644 index 260f8e72f..000000000 --- a/examples/webenginewidgets/demobrowser/fullscreennotification.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 FULLSCREENNOTIFICATION_H -#define FULLSCREENNOTIFICATION_H - -#include <QWidget> - -QT_BEGIN_NAMESPACE -class QLabel; -class QGridLayout; -class QPropertyAnimation; -QT_END_NAMESPACE - -class FullScreenNotification : public QWidget -{ - Q_OBJECT -public: - FullScreenNotification(QWidget *parent = 0); - ~FullScreenNotification(); - - void show(); - void hide(); - -public slots: - void fadeOut(); - void fadeOutFinished(); - -private: - QLabel *m_label; - QGridLayout *m_layout; - QPropertyAnimation *m_animation; - int width; - int height; - int x; - int y; -}; - -#endif // FULLSCREENNOTIFICATION_H diff --git a/examples/webenginewidgets/demobrowser/history.cpp b/examples/webenginewidgets/demobrowser/history.cpp deleted file mode 100644 index bce65b917..000000000 --- a/examples/webenginewidgets/demobrowser/history.cpp +++ /dev/null @@ -1,1314 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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 <QWebEngineSettings> - -#include <QtCore/QDebug> - -static const unsigned int HISTORY_VERSION = 23; - -HistoryManager::HistoryManager(QObject *parent) - : QObject(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); -} - -HistoryManager::~HistoryManager() -{ - m_saveTimer->saveIfNeccessary(); -} - -QList<HistoryItem> &HistoryManager::history() -{ - 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::removeHistoryEntry(const QString &url) -{ - QUrl cleanUrl(url); - cleanUrl.setPassword(QString()); - cleanUrl.setHost(cleanUrl.host().toLower()); - HistoryItem item(cleanUrl.toString(), QDateTime::currentDateTime()); - removeHistoryItem(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(loadedAndSorted); - - 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(bool removeEntriesDirectly) -{ - 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; - const HistoryItem& item = m_history.last(); - // remove from saved file also - m_lastSavedUrl = QString(); - - if (removeEntriesDirectly) - m_history.takeLast(); - else - emit entryRemoved(item); - } - - if (nextTimeout > 0) - m_expiredTimer.start(nextTimeout * 1000); -} - -void HistoryManager::addHistoryItem(const HistoryItem &item) -{ - if (BrowserApplication::instance()->privateBrowsing()) - return; - - emit entryAdded(item); - if (m_history.count() == 1) - checkForExpired(); -} - -void HistoryManager::removeHistoryItem(const HistoryItem &item) -{ - for (int i = m_history.count() - 1 ; i >= 0; --i) { - if (item.url == m_history.at(i).url) { - //delete all related entries with that url - emit entryRemoved(m_history.at(i)); - } - } -} - -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_lastSavedUrl = QString(); - emit historyReset(); - m_saveTimer->changeOccurred(); - m_saveTimer->saveIfNeccessary(); -} - -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(entryRemoved(HistoryItem))); - - connect(m_history, SIGNAL(entryAdded(HistoryItem)), - this, SLOT(entryAdded(HistoryItem))); - connect(m_history, SIGNAL(entryUpdated(int)), - this, SLOT(entryUpdated(int))); -} - -void HistoryModel::historyReset() -{ - beginResetModel(); - m_history->history().clear(); - endResetModel(); -} - -void HistoryModel::entryAdded(const HistoryItem &item) -{ - beginInsertRows(QModelIndex(), 0, 0); - m_history->history().prepend(item); - endInsertRows(); -} - -void HistoryModel::entryRemoved(const HistoryItem &item) -{ - int index = m_history->history().indexOf(item); - Q_ASSERT(index > -1); - beginRemoveRows(QModelIndex(),index, index); - m_history->history().takeAt(index); - endRemoveRows(); -} - -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); - 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() == quintptr(-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() == quintptr(-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, quintptr(-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 -{ - 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->historyFilterModel(); - 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()), tree, SLOT(removeAll())); - proxyModel->setSourceModel(model); - proxyModel->setFilterKeyColumn(1); - tree->setModel(proxyModel); - tree->setSortingEnabled(true); - 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); -} - -void HistoryFilterModel::setSourceModel(QAbstractItemModel *newSourceModel) -{ - beginResetModel(); - if (sourceModel()) { - disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); - disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(sourceDataChanged(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()) { - 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))); - } - load(); - endResetModel(); -} - -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() -{ - beginResetModel(); - load(); - endResetModel(); -} - -int HistoryFilterModel::rowCount(const QModelIndex &parent) const -{ - 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 -{ - int sourceRow = sourceModel()->rowCount() - proxyIndex.internalId(); - return sourceModel()->index(sourceRow, proxyIndex.column()); -} - -QModelIndex HistoryFilterModel::mapFromSource(const QModelIndex &sourceIndex) const -{ - 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 -{ - 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 -{ - 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; - } - } -} - -void HistoryFilterModel::sourceRowsInserted(const QModelIndex &parent, int start, int end) -{ - Q_ASSERT(start == end && start == 0); - Q_UNUSED(end); - 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) -{ - beginResetModel(); - 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))); - disconnect(sourceModel(), &QAbstractItemModel::dataChanged, this, - &HistoryTreeModel::sourceDataChanged); - } - - 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))); - connect(sourceModel(), &QAbstractItemModel::dataChanged, this, - &HistoryTreeModel::sourceDataChanged); - } - 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(); - } -} - -void HistoryTreeModel::sourceDataChanged(const QModelIndex &topLeft, - const QModelIndex &bottomRight, - const QVector<int> roles) -{ - emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); -} diff --git a/examples/webenginewidgets/demobrowser/history.h b/examples/webenginewidgets/demobrowser/history.h deleted file mode 100644 index 2a6dce9e1..000000000 --- a/examples/webenginewidgets/demobrowser/history.h +++ /dev/null @@ -1,360 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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> - -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 QObject -{ - 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 removeHistoryEntry(const QString &url); - - void updateHistoryItem(const QUrl &url, const QString &title); - - int historyLimit() const; - void setHistoryLimit(int limit); - - QList<HistoryItem>& history(); - 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(bool removeExpiredEntriesDirectly = false); - -protected: - void addHistoryItem(const HistoryItem &item); - void removeHistoryItem(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(const HistoryItem &item); - void entryRemoved(const HistoryItem &item); - 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); } - - 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()); - -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); - void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, - const QVector<int> roles); -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/webenginewidgets/demobrowser/history.ui b/examples/webenginewidgets/demobrowser/history.ui deleted file mode 100644 index 0944940e7..000000000 --- a/examples/webenginewidgets/demobrowser/history.ui +++ /dev/null @@ -1,106 +0,0 @@ -<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>&Remove</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="removeAllButton" > - <property name="text" > - <string>Remove &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/webenginewidgets/demobrowser/htmls/htmls.qrc b/examples/webenginewidgets/demobrowser/htmls/htmls.qrc deleted file mode 100644 index 03b256ccb..000000000 --- a/examples/webenginewidgets/demobrowser/htmls/htmls.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource> - <file>notfound.html</file> -</qresource> -</RCC> diff --git a/examples/webenginewidgets/demobrowser/htmls/notfound.html b/examples/webenginewidgets/demobrowser/htmls/notfound.html deleted file mode 100644 index e89845aa6..000000000 --- a/examples/webenginewidgets/demobrowser/htmls/notfound.html +++ /dev/null @@ -1,63 +0,0 @@ -<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/webenginewidgets/demobrowser/main.cpp b/examples/webenginewidgets/demobrowser/main.cpp deleted file mode 100644 index 41cae306a..000000000 --- a/examples/webenginewidgets/demobrowser/main.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "browserapplication.h" - -#include <qtwebenginewidgetsglobal.h> - -int main(int argc, char **argv) -{ - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - Q_INIT_RESOURCE(data); - BrowserApplication application(argc, argv); - if (!application.isTheOnlyBrowser()) - return 0; - - application.newMainWindow(); - return application.exec(); -} diff --git a/examples/webenginewidgets/demobrowser/modelmenu.cpp b/examples/webenginewidgets/demobrowser/modelmenu.cpp deleted file mode 100644 index 9064320f4..000000000 --- a/examples/webenginewidgets/demobrowser/modelmenu.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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/webenginewidgets/demobrowser/modelmenu.h b/examples/webenginewidgets/demobrowser/modelmenu.h deleted file mode 100644 index 718b1d3cf..000000000 --- a/examples/webenginewidgets/demobrowser/modelmenu.h +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/passworddialog.ui b/examples/webenginewidgets/demobrowser/passworddialog.ui deleted file mode 100644 index 7c1665867..000000000 --- a/examples/webenginewidgets/demobrowser/passworddialog.ui +++ /dev/null @@ -1,111 +0,0 @@ -<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/webenginewidgets/demobrowser/printtopdfdialog.cpp b/examples/webenginewidgets/demobrowser/printtopdfdialog.cpp deleted file mode 100644 index 50a8bb91a..000000000 --- a/examples/webenginewidgets/demobrowser/printtopdfdialog.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "printtopdfdialog.h" -#include "ui_printtopdfdialog.h" - -#include <QtCore/QDir> -#include <QtPrintSupport/QPageSetupDialog> -#include <QtPrintSupport/QPrinter> -#include <QtWidgets/QFileDialog> - -PrintToPdfDialog::PrintToPdfDialog(const QString &filePath, QWidget *parent) : - QDialog(parent), - currentPageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0))), - ui(new Ui::PrintToPdfDialog) -{ - ui->setupUi(this); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - connect(ui->chooseFilePathButton, &QToolButton::clicked, this, &PrintToPdfDialog::onChooseFilePathButtonClicked); - connect(ui->choosePageLayoutButton, &QToolButton::clicked, this, &PrintToPdfDialog::onChoosePageLayoutButtonClicked); - ui->choosePageLayoutButton->hide(); - updatePageLayoutLabel(); - setFilePath(filePath); -} - -PrintToPdfDialog::~PrintToPdfDialog() -{ - delete ui; -} - -void PrintToPdfDialog::onChoosePageLayoutButtonClicked() -{ - QPrinter printer; - printer.setPageLayout(currentPageLayout); - - QPageSetupDialog dlg(&printer, this); - if (dlg.exec() != QDialog::Accepted) - return; - currentPageLayout.setPageSize(printer.pageLayout().pageSize()); - currentPageLayout.setOrientation(printer.pageLayout().orientation()); - updatePageLayoutLabel(); -} - -void PrintToPdfDialog::onChooseFilePathButtonClicked() -{ - QFileInfo fi(filePath()); - QFileDialog dlg(this, tr("Save PDF as"), fi.absolutePath()); - dlg.setAcceptMode(QFileDialog::AcceptSave); - dlg.setDefaultSuffix(QStringLiteral(".pdf")); - dlg.selectFile(fi.absoluteFilePath()); - if (dlg.exec() != QDialog::Accepted) - return; - setFilePath(dlg.selectedFiles().first()); -} - -QString PrintToPdfDialog::filePath() const -{ - return QDir::fromNativeSeparators(ui->filePathLineEdit->text()); -} - -void PrintToPdfDialog::setFilePath(const QString &filePath) -{ - ui->filePathLineEdit->setText(QDir::toNativeSeparators(filePath)); -} - -QPageLayout PrintToPdfDialog::pageLayout() const -{ - return currentPageLayout; -} - -void PrintToPdfDialog::updatePageLayoutLabel() -{ - ui->pageLayoutLabel->setText(QString("%1, %2").arg( - currentPageLayout.pageSize().name()).arg( - currentPageLayout.orientation() == QPageLayout::Portrait - ? tr("Portrait") : tr("Landscape") - )); -} diff --git a/examples/webenginewidgets/demobrowser/printtopdfdialog.h b/examples/webenginewidgets/demobrowser/printtopdfdialog.h deleted file mode 100644 index 87fca72c3..000000000 --- a/examples/webenginewidgets/demobrowser/printtopdfdialog.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 PRINTTOPDFDIALOG_H -#define PRINTTOPDFDIALOG_H - -#include <QDialog> -#include <QPageLayout> - -QT_BEGIN_NAMESPACE -namespace Ui { -class PrintToPdfDialog; -} -QT_END_NAMESPACE - -class PrintToPdfDialog : public QDialog -{ - Q_OBJECT - -public: - explicit PrintToPdfDialog(const QString &filePath, QWidget *parent = 0); - ~PrintToPdfDialog(); - - QString filePath() const; - QPageLayout pageLayout() const; - -private slots: - void onChoosePageLayoutButtonClicked(); - void onChooseFilePathButtonClicked(); - -private: - void setFilePath(const QString &); - void updatePageLayoutLabel(); - - QPageLayout currentPageLayout; - Ui::PrintToPdfDialog *ui; -}; - -#endif // PRINTTOPDFDIALOG_H diff --git a/examples/webenginewidgets/demobrowser/printtopdfdialog.ui b/examples/webenginewidgets/demobrowser/printtopdfdialog.ui deleted file mode 100644 index dcfd5a3aa..000000000 --- a/examples/webenginewidgets/demobrowser/printtopdfdialog.ui +++ /dev/null @@ -1,119 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>PrintToPdfDialog</class> - <widget class="QDialog" name="PrintToPdfDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>372</width> - <height>117</height> - </rect> - </property> - <property name="windowTitle"> - <string>Dialog</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <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="0" column="0" colspan="2"> - <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="3"> - <widget class="QToolButton" name="choosePageLayoutButton"> - <property name="text"> - <string>...</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="filePathLabel"> - <property name="text"> - <string>Save as:</string> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLineEdit" name="filePathLineEdit"/> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="layoutLabel"> - <property name="text"> - <string>Page layout:</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QToolButton" name="chooseFilePathButton"> - <property name="text"> - <string>...</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QLabel" name="pageLayoutLabel"> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item row="1" column="0"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>PrintToPdfDialog</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>PrintToPdfDialog</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/webenginewidgets/demobrowser/proxy.ui b/examples/webenginewidgets/demobrowser/proxy.ui deleted file mode 100644 index 62a8be627..000000000 --- a/examples/webenginewidgets/demobrowser/proxy.ui +++ /dev/null @@ -1,104 +0,0 @@ -<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/webenginewidgets/demobrowser/savepagedialog.cpp b/examples/webenginewidgets/demobrowser/savepagedialog.cpp deleted file mode 100644 index 8ec21f821..000000000 --- a/examples/webenginewidgets/demobrowser/savepagedialog.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "savepagedialog.h" -#include "ui_savepagedialog.h" - -#include <QtCore/QDir> -#include <QtWidgets/QFileDialog> - -const QWebEngineDownloadItem::SavePageFormat SavePageDialog::m_indexToFormatTable[] = { - QWebEngineDownloadItem::SingleHtmlSaveFormat, - QWebEngineDownloadItem::CompleteHtmlSaveFormat, - QWebEngineDownloadItem::MimeHtmlSaveFormat -}; - -SavePageDialog::SavePageDialog(QWidget *parent, QWebEngineDownloadItem::SavePageFormat format, - const QString &filePath) - : QDialog(parent) - , ui(new Ui::SavePageDialog) -{ - ui->setupUi(this); - ui->formatComboBox->setCurrentIndex(formatToIndex(format)); - setFilePath(filePath); -} - -SavePageDialog::~SavePageDialog() -{ - delete ui; -} - -QWebEngineDownloadItem::SavePageFormat SavePageDialog::pageFormat() const -{ - return indexToFormat(ui->formatComboBox->currentIndex()); -} - -QString SavePageDialog::filePath() const -{ - return QDir::fromNativeSeparators(ui->filePathLineEdit->text()); -} - -void SavePageDialog::on_chooseFilePathButton_clicked() -{ - QFileInfo fi(filePath()); - QFileDialog dlg(this, tr("Save Page As"), fi.absolutePath()); - dlg.setAcceptMode(QFileDialog::AcceptSave); - dlg.setDefaultSuffix(suffixOfFormat(pageFormat())); - dlg.selectFile(fi.absoluteFilePath()); - if (dlg.exec() != QDialog::Accepted) - return; - setFilePath(dlg.selectedFiles().first()); - ensureFileSuffix(pageFormat()); -} - -void SavePageDialog::on_formatComboBox_currentIndexChanged(int idx) -{ - ensureFileSuffix(indexToFormat(idx)); -} - -int SavePageDialog::formatToIndex(QWebEngineDownloadItem::SavePageFormat format) -{ - for (auto i : m_indexToFormatTable) { - if (m_indexToFormatTable[i] == format) - return i; - } - Q_UNREACHABLE(); -} - -QWebEngineDownloadItem::SavePageFormat SavePageDialog::indexToFormat(int idx) -{ - Q_ASSERT(idx >= 0 && size_t(idx) < (sizeof(m_indexToFormatTable) - / sizeof(QWebEngineDownloadItem::SavePageFormat))); - return m_indexToFormatTable[idx]; -} - -QString SavePageDialog::suffixOfFormat(QWebEngineDownloadItem::SavePageFormat format) -{ - if (format == QWebEngineDownloadItem::MimeHtmlSaveFormat) - return QStringLiteral(".mhtml"); - return QStringLiteral(".html"); -} - -void SavePageDialog::setFilePath(const QString &filePath) -{ - ui->filePathLineEdit->setText(QDir::toNativeSeparators(filePath)); -} - -void SavePageDialog::ensureFileSuffix(QWebEngineDownloadItem::SavePageFormat format) -{ - QFileInfo fi(filePath()); - setFilePath(fi.absolutePath() + QLatin1Char('/') + fi.completeBaseName() - + suffixOfFormat(format)); -} diff --git a/examples/webenginewidgets/demobrowser/savepagedialog.h b/examples/webenginewidgets/demobrowser/savepagedialog.h deleted file mode 100644 index 77095543c..000000000 --- a/examples/webenginewidgets/demobrowser/savepagedialog.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 SAVEPAGEDIALOG_H -#define SAVEPAGEDIALOG_H - -#include <QtWidgets/QDialog> -#include <QtWebEngineWidgets/QWebEngineDownloadItem> - -QT_BEGIN_NAMESPACE -namespace Ui { -class SavePageDialog; -} -QT_END_NAMESPACE - -class SavePageDialog : public QDialog -{ - Q_OBJECT - -public: - explicit SavePageDialog(QWidget *parent, QWebEngineDownloadItem::SavePageFormat format, - const QString &filePath); - ~SavePageDialog(); - - QWebEngineDownloadItem::SavePageFormat pageFormat() const; - QString filePath() const; - -private slots: - void on_chooseFilePathButton_clicked(); - void on_formatComboBox_currentIndexChanged(int idx); - -private: - static int formatToIndex(QWebEngineDownloadItem::SavePageFormat format); - static QWebEngineDownloadItem::SavePageFormat indexToFormat(int idx); - static QString suffixOfFormat(QWebEngineDownloadItem::SavePageFormat format); - void setFilePath(const QString &filePath); - void ensureFileSuffix(QWebEngineDownloadItem::SavePageFormat format); - - static const QWebEngineDownloadItem::SavePageFormat m_indexToFormatTable[]; - Ui::SavePageDialog *ui; -}; - -#endif // SAVEPAGEDIALOG_H diff --git a/examples/webenginewidgets/demobrowser/savepagedialog.ui b/examples/webenginewidgets/demobrowser/savepagedialog.ui deleted file mode 100644 index 9aa7cbe55..000000000 --- a/examples/webenginewidgets/demobrowser/savepagedialog.ui +++ /dev/null @@ -1,139 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>SavePageDialog</class> - <widget class="QDialog" name="SavePageDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>121</height> - </rect> - </property> - <property name="windowTitle"> - <string>Dialog</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>&Format:</string> - </property> - <property name="buddy"> - <cstring>formatComboBox</cstring> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QComboBox" name="formatComboBox"> - <item> - <property name="text"> - <string>Single HTML</string> - </property> - </item> - <item> - <property name="text"> - <string>Complete HTML</string> - </property> - </item> - <item> - <property name="text"> - <string>MIME HTML</string> - </property> - </item> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>&Save to:</string> - </property> - <property name="buddy"> - <cstring>filePathLineEdit</cstring> - </property> - </widget> - </item> - <item row="1" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLineEdit" name="filePathLineEdit"/> - </item> - <item> - <widget class="QToolButton" name="chooseFilePathButton"> - <property name="text"> - <string>...</string> - </property> - </widget> - </item> - </layout> - </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>12</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> - </widget> - </item> - </layout> - </widget> - <tabstops> - <tabstop>formatComboBox</tabstop> - <tabstop>filePathLineEdit</tabstop> - <tabstop>chooseFilePathButton</tabstop> - </tabstops> - <resources/> - <connections> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>SavePageDialog</receiver> - <slot>accept()</slot> - <hints> - <hint type="sourcelabel"> - <x>227</x> - <y>104</y> - </hint> - <hint type="destinationlabel"> - <x>157</x> - <y>120</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>rejected()</signal> - <receiver>SavePageDialog</receiver> - <slot>reject()</slot> - <hints> - <hint type="sourcelabel"> - <x>295</x> - <y>110</y> - </hint> - <hint type="destinationlabel"> - <x>286</x> - <y>120</y> - </hint> - </hints> - </connection> - </connections> -</ui> diff --git a/examples/webenginewidgets/demobrowser/searchlineedit.cpp b/examples/webenginewidgets/demobrowser/searchlineedit.cpp deleted file mode 100644 index 04f75df91..000000000 --- a/examples/webenginewidgets/demobrowser/searchlineedit.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "searchlineedit.h" - -#include <QtGui/QPainter> -#include <QtGui/QMouseEvent> -#include <QtWidgets/QMenu> -#include <QtWidgets/QStyle> -#include <QtWidgets/QStyleOptionFrame> - -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); - 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); - QStyleOptionFrame 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/webenginewidgets/demobrowser/searchlineedit.h b/examples/webenginewidgets/demobrowser/searchlineedit.h deleted file mode 100644 index 9b9587082..000000000 --- a/examples/webenginewidgets/demobrowser/searchlineedit.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/settings.cpp b/examples/webenginewidgets/demobrowser/settings.cpp deleted file mode 100644 index aa3110ae7..000000000 --- a/examples/webenginewidgets/demobrowser/settings.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "settings.h" - -#include "browserapplication.h" -#include "browsermainwindow.h" -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) -#include "cookiejar.h" -#endif -#include "history.h" -#include "webview.h" - -#include <QtCore/QLocale> -#include <QtCore/QSettings> -#include <QtWidgets/QtWidgets> -#include <QtWebEngineWidgets/QtWebEngineWidgets> - -SettingsDialog::SettingsDialog(QWidget *parent) - : QDialog(parent) -{ - setupUi(this); - connect(setHomeToCurrentPageButton, SIGNAL(clicked()), this, SLOT(setHomeToCurrentPage())); - connect(standardFontButton, SIGNAL(clicked()), this, SLOT(chooseFont())); - connect(fixedFontButton, SIGNAL(clicked()), this, SLOT(chooseFixedFont())); - - loadDefaults(); - loadFromSettings(); -} - -static QString defaultAcceptLanguage() -{ - const QStringList langs = QLocale().uiLanguages(); - if (langs.isEmpty()) - return QString(); - QString str = langs.first(); - const float qstep = 1.0f / float(langs.count()); - float q = 1.0f - qstep; - for (int i = 1; i < langs.count(); ++i) { - str += QStringLiteral(", ") + langs.at(i) + QStringLiteral(";q=") + QString::number(q, 'f', 2); - q -= qstep; - } - return str; -} - -void SettingsDialog::loadDefaults() -{ - QWebEngineSettings *defaultSettings = QWebEngineSettings::globalSettings(); - QString standardFontFamily = defaultSettings->fontFamily(QWebEngineSettings::StandardFont); - int standardFontSize = defaultSettings->fontSize(QWebEngineSettings::DefaultFontSize); - standardFont = QFont(standardFontFamily, standardFontSize); - standardLabel->setText(QString(QLatin1String("%1 %2")).arg(standardFont.family()).arg(standardFont.pointSize())); - - QString fixedFontFamily = defaultSettings->fontFamily(QWebEngineSettings::FixedFont); - int fixedFontSize = defaultSettings->fontSize(QWebEngineSettings::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(QWebEngineSettings::JavascriptEnabled)); - enablePlugins->setChecked(defaultSettings->testAttribute(QWebEngineSettings::PluginsEnabled)); - - enableScrollAnimator->setChecked(defaultSettings->testAttribute(QWebEngineSettings::ScrollAnimatorEnabled)); - - persistentDataPath->setText(QWebEngineProfile::defaultProfile()->persistentStoragePath()); - sessionCookiesCombo->setCurrentIndex(QWebEngineProfile::defaultProfile()->persistentCookiesPolicy()); - httpUserAgent->setText(QWebEngineProfile::defaultProfile()->httpUserAgent()); - httpAcceptLanguage->setText(defaultAcceptLanguage()); - - if (!defaultSettings->testAttribute(QWebEngineSettings::AutoLoadIconsForPage)) - faviconDownloadMode->setCurrentIndex(0); - else if (!defaultSettings->testAttribute(QWebEngineSettings::TouchIconsEnabled)) - faviconDownloadMode->setCurrentIndex(1); - else - faviconDownloadMode->setCurrentIndex(2); -} - -void SettingsDialog::loadFromSettings() -{ - QSettings settings; - settings.beginGroup(QLatin1String("MainWindow")); - const QString defaultHome = QLatin1String(BrowserMainWindow::defaultHome); - 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->setPlainText(settings.value(QLatin1String("userStyleSheet")).toString()); - enableScrollAnimator->setChecked(settings.value(QLatin1String("enableScrollAnimator"), enableScrollAnimator->isChecked()).toBool()); - httpUserAgent->setText(settings.value(QLatin1String("httpUserAgent"), httpUserAgent->text()).toString()); - httpAcceptLanguage->setText(settings.value(QLatin1String("httpAcceptLanguage"), httpAcceptLanguage->text()).toString()); - faviconDownloadMode->setCurrentIndex(settings.value(QLatin1String("faviconDownloadMode"), faviconDownloadMode->currentIndex()).toInt()); - settings.endGroup(); - - // Privacy - settings.beginGroup(QLatin1String("cookies")); - - int persistentCookiesPolicy = settings.value(QLatin1String("persistentCookiesPolicy"), sessionCookiesCombo->currentIndex()).toInt(); - sessionCookiesCombo->setCurrentIndex(persistentCookiesPolicy); - - QString pdataPath = settings.value(QLatin1String("persistentDataPath"), persistentDataPath->text()).toString(); - persistentDataPath->setText(pdataPath); - - 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()); - settings.setValue(QLatin1String("enableScrollAnimator"), enableScrollAnimator->isChecked()); - settings.setValue(QLatin1String("userStyleSheet"), userStyleSheet->toPlainText()); - settings.setValue(QLatin1String("httpUserAgent"), httpUserAgent->text()); - settings.setValue(QLatin1String("httpAcceptLanguage"), httpAcceptLanguage->text()); - settings.setValue(QLatin1String("faviconDownloadMode"), faviconDownloadMode->currentIndex()); - settings.endGroup(); - - //Privacy - settings.beginGroup(QLatin1String("cookies")); - - int persistentCookiesPolicy = sessionCookiesCombo->currentIndex(); - settings.setValue(QLatin1String("persistentCookiesPolicy"), persistentCookiesPolicy); - - QString pdataPath = persistentDataPath->text(); - settings.setValue(QLatin1String("persistentDataPath"), pdataPath); - - 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(); -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) - BrowserApplication::cookieJar()->loadSettings(); -#endif - BrowserApplication::historyManager()->loadSettings(); -} - -void SettingsDialog::accept() -{ - saveToSettings(); - QDialog::accept(); -} - -void SettingsDialog::showCookies() -{ -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) - CookiesDialog *dialog = new CookiesDialog(BrowserApplication::cookieJar(), this); - dialog->exec(); -#endif -} - -void SettingsDialog::showExceptions() -{ -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) - CookiesExceptionsDialog *dialog = new CookiesExceptionsDialog(BrowserApplication::cookieJar(), this); - dialog->exec(); -#endif -} - -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::on_httpUserAgent_editingFinished() -{ - QWebEngineProfile::defaultProfile()->setHttpUserAgent(httpUserAgent->text()); -} - -void SettingsDialog::on_httpAcceptLanguage_editingFinished() -{ - QWebEngineProfile::defaultProfile()->setHttpAcceptLanguage(httpAcceptLanguage->text()); -} - -void SettingsDialog::setHomeToCurrentPage() -{ - BrowserMainWindow *mw = static_cast<BrowserMainWindow*>(parent()); - WebView *webView = mw->currentTab(); - if (webView) - homeLineEdit->setText(webView->url().toString()); -} diff --git a/examples/webenginewidgets/demobrowser/settings.h b/examples/webenginewidgets/demobrowser/settings.h deleted file mode 100644 index ff5795609..000000000 --- a/examples/webenginewidgets/demobrowser/settings.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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(); - - void on_httpUserAgent_editingFinished(); - void on_httpAcceptLanguage_editingFinished(); - -private: - QFont standardFont; - QFont fixedFont; -}; - -#endif // SETTINGS_H diff --git a/examples/webenginewidgets/demobrowser/settings.ui b/examples/webenginewidgets/demobrowser/settings.ui deleted file mode 100644 index c78a52dfe..000000000 --- a/examples/webenginewidgets/demobrowser/settings.ui +++ /dev/null @@ -1,621 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<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>336</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"> - <attribute name="title"> - <string>General</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_4"> - <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="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="7" 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> - <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="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="6" column="1" colspan="2"> - <widget class="QCheckBox" name="enableScrollAnimator"> - <property name="text"> - <string>Enable Scroll Animator</string> - </property> - <property name="checked"> - <bool>true</bool> - </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="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="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="3" column="1" colspan="2"> - <widget class="QLineEdit" name="downloadsLocation"/> - </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="5" column="0"> - <widget class="QLabel" name="label_17"> - <property name="text"> - <string>Favicon download mode:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="5" column="1" colspan="2"> - <widget class="QComboBox" name="faviconDownloadMode"> - <property name="currentIndex"> - <number>1</number> - </property> - <item> - <property name="text"> - <string>Disable icons</string> - </property> - </item> - <item> - <property name="text"> - <string>Enable favicons</string> - </property> - </item> - <item> - <property name="text"> - <string>Enable favicons and touch icons</string> - </property> - </item> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_3"> - <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 hsizetype="Expanding" vsizetype="Preferred"> - <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"> - <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"> - <property name="leftMargin"> - <number>9</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Persistent Cookie Policy</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="sessionCookiesCombo"> - <item> - <property name="text"> - <string>Treat all cookies as session cookies</string> - </property> - </item> - <item> - <property name="text"> - <string>Allow persistent cookies</string> - </property> - </item> - <item> - <property name="text"> - <string>Treat all cookies as persistent cookies</string> - </property> - </item> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Persistent Data Path:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="persistentDataPath"/> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer_4"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_4"> - <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_15"> - <property name="text"> - <string>HTTP User-Agent:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="httpUserAgent"/> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_16"> - <property name="text"> - <string>HTTP Accept-&Language:</string> - </property> - <property name="buddy"> - <cstring>httpAcceptLanguage</cstring> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="httpAcceptLanguage"/> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_14"> - <property name="text"> - <string>Style Sheet:</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QTextEdit" name="userStyleSheet"/> - </item> - <item row="3" 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/webenginewidgets/demobrowser/squeezelabel.cpp b/examples/webenginewidgets/demobrowser/squeezelabel.cpp deleted file mode 100644 index 9607bb784..000000000 --- a/examples/webenginewidgets/demobrowser/squeezelabel.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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/webenginewidgets/demobrowser/squeezelabel.h b/examples/webenginewidgets/demobrowser/squeezelabel.h deleted file mode 100644 index 8acd1fb6e..000000000 --- a/examples/webenginewidgets/demobrowser/squeezelabel.h +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/tabwidget.cpp b/examples/webenginewidgets/demobrowser/tabwidget.cpp deleted file mode 100644 index aa730d1b6..000000000 --- a/examples/webenginewidgets/demobrowser/tabwidget.cpp +++ /dev/null @@ -1,1012 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "tabwidget.h" - -#include "browserapplication.h" -#include "browsermainwindow.h" -#include "downloadmanager.h" -#include "fullscreennotification.h" -#include "history.h" -#include "savepagedialog.h" -#include "urllineedit.h" -#include "webview.h" - -#include <QWebEngineDownloadItem> -#include <QWebEngineProfile> -#include <QWebEngineFullScreenRequest> -#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) { - QShortcut *shortCut = new QShortcut(ctrl.arg(i), 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); - 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); - - // Audio mute / unmute. - action = menu.addAction(tr("Mute tab"), - this, SLOT(muteTab())); - action->setData(index); - - action = menu.addAction(tr("Unmute tab"), - this, SLOT(unmuteTab())); - 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); - - // Middle click on tab should close it. - if (event->button() == Qt::MiddleButton) { - const QPoint pos = event->pos(); - int index = tabAt(pos); - if (index != -1) { - emit closeTab(index); - } - } -} - -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); - } -} - -void TabBar::muteTab() -{ - if (QAction *action = qobject_cast<QAction*>(sender())) { - int index = action->data().toInt(); - emit muteTab(index, true); - } -} - -void TabBar::unmuteTab() -{ - if (QAction *action = qobject_cast<QAction*>(sender())) { - int index = action->data().toInt(); - emit muteTab(index, false); - } -} - -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)) - , m_profile(QWebEngineProfile::defaultProfile()) - , m_fullScreenView(0) - , m_fullScreenNotification(0) -{ - setElideMode(Qt::ElideRight); - - connect(m_tabBar, SIGNAL(newTab()), this, SLOT(newTab())); - connect(m_tabBar, SIGNAL(closeTab(int)), this, SLOT(requestCloseTab(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))); - connect(m_tabBar, SIGNAL(tabBarDoubleClicked(int)), this, SLOT(handleTabBarDoubleClicked(int))); - connect(m_tabBar, SIGNAL(muteTab(int,bool)), this, SLOT(setAudioMutedForTab(int,bool))); - 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(requestCloseTab())); - - 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); -} - -TabWidget::~TabWidget() -{ - if (m_fullScreenView) - delete m_fullScreenView; -} - -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::setAudioMutedForTab(int index, bool mute) -{ - if (index < 0) - index = currentIndex(); - if (index < 0 || index >= count()) - return; - - QWidget *widget = this->widget(index); - if (WebView *tab = qobject_cast<WebView*>(widget)) - tab->page()->setAudioMuted(mute); -} - -void TabWidget::addWebAction(QAction *action, QWebEnginePage::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) { -#if defined(QWEBENGINEVIEW_STATUSBARMESSAGE) - disconnect(oldWebView, SIGNAL(statusBarMessage(QString)), - this, SIGNAL(showStatusBarMessage(QString))); -#endif - disconnect(oldWebView->page(), SIGNAL(linkHovered(const QString&)), - this, SIGNAL(linkHovered(const QString&))); - disconnect(oldWebView, SIGNAL(loadProgress(int)), - this, SIGNAL(loadProgress(int))); - disconnect(oldWebView->page()->profile(), SIGNAL(downloadRequested(QWebEngineDownloadItem*)), - this, SLOT(downloadRequested(QWebEngineDownloadItem*))); - disconnect(oldWebView->page(), SIGNAL(fullScreenRequested(QWebEngineFullScreenRequest)), - this, SLOT(fullScreenRequested(QWebEngineFullScreenRequest))); - } - -#if defined(QWEBENGINEVIEW_STATUSBARMESSAGE) - connect(webView, SIGNAL(statusBarMessage(QString)), - this, SIGNAL(showStatusBarMessage(QString))); -#endif - connect(webView->page(), SIGNAL(linkHovered(const QString&)), - this, SIGNAL(linkHovered(const QString&))); - connect(webView, SIGNAL(loadProgress(int)), - this, SIGNAL(loadProgress(int))); - connect(webView->page()->profile(), SIGNAL(downloadRequested(QWebEngineDownloadItem*)), - this, SLOT(downloadRequested(QWebEngineDownloadItem*))); - connect(webView->page(), SIGNAL(fullScreenRequested(QWebEngineFullScreenRequest)), - this, SLOT(fullScreenRequested(QWebEngineFullScreenRequest))); - - 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(); -} - -void TabWidget::fullScreenRequested(QWebEngineFullScreenRequest request) -{ - WebPage *webPage = qobject_cast<WebPage*>(sender()); - if (request.toggleOn()) { - if (!m_fullScreenView) { - m_fullScreenView = new QWebEngineView(); - m_fullScreenNotification = new FullScreenNotification(m_fullScreenView); - - QAction *exitFullScreenAction = new QAction(m_fullScreenView); - exitFullScreenAction->setShortcut(Qt::Key_Escape); - connect(exitFullScreenAction, &QAction::triggered, [webPage] { - webPage->triggerAction(QWebEnginePage::ExitFullScreen); - }); - m_fullScreenView->addAction(exitFullScreenAction); - } - m_oldWindowGeometry = window()->geometry(); - m_fullScreenView->setGeometry(m_oldWindowGeometry); - webPage->setView(m_fullScreenView); - request.accept(); - m_fullScreenView->showFullScreen(); - m_fullScreenNotification->show(); - window()->hide(); - } else { - if (!m_fullScreenView) - return; - WebView *oldWebView = this->webView(m_lineEdits->currentIndex()); - webPage->setView(oldWebView); - request.accept(); - delete m_fullScreenView; - m_fullScreenView = 0; - window()->show(); - window()->setGeometry(m_oldWindowGeometry); - } -} - -void TabWidget::handleTabBarDoubleClicked(int index) -{ - if (index != -1) return; - newTab(); -} - -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; -} - -void TabWidget::setupPage(QWebEnginePage* page) -{ - connect(page, SIGNAL(windowCloseRequested()), - this, SLOT(windowCloseRequested())); - connect(page, SIGNAL(geometryChangeRequested(QRect)), - this, SIGNAL(geometryChangeRequested(QRect))); -#if defined(QWEBENGINEPAGE_PRINTREQUESTED) - connect(page, SIGNAL(printRequested(QWebEngineFrame*)), - this, SIGNAL(printRequested(QWebEngineFrame*))); -#endif -#if defined(QWEBENGINEPAGE_MENUBARVISIBILITYCHANGEREQUESTED) - connect(page, SIGNAL(menuBarVisibilityChangeRequested(bool)), - this, SIGNAL(menuBarVisibilityChangeRequested(bool))); -#endif -#if defined(QWEBENGINEPAGE_STATUSBARVISIBILITYCHANGEREQUESTED) - connect(page, SIGNAL(statusBarVisibilityChangeRequested(bool)), - this, SIGNAL(statusBarVisibilityChangeRequested(bool))); -#endif -#if defined(QWEBENGINEPAGE_TOOLBARVISIBILITYCHANGEREQUESTED) - connect(page, SIGNAL(toolBarVisibilityChangeRequested(bool)), - this, SIGNAL(toolBarVisibilityChangeRequested(bool))); -#endif - - // webview actions - for (int i = 0; i < m_actions.count(); ++i) { - WebActionMapper *mapper = m_actions[i]; - mapper->addChild(page->action(mapper->webAction())); - } -} - -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; - webView->setPage(new WebPage(m_profile, webView)); - urlLineEdit->setWebView(webView); - connect(webView, SIGNAL(loadStarted()), - this, SLOT(webViewLoadStarted())); - connect(webView, SIGNAL(iconChanged(QIcon)), - this, SLOT(webViewIconChanged(QIcon))); - connect(webView, SIGNAL(titleChanged(QString)), - this, SLOT(webViewTitleChanged(QString))); - connect(webView->page(), SIGNAL(audioMutedChanged(bool)), - this, SLOT(webPageMutedOrAudibleChanged())); - connect(webView->page(), SIGNAL(recentlyAudibleChanged(bool)), - this, SLOT(webPageMutedOrAudibleChanged())); - connect(webView, SIGNAL(urlChanged(QUrl)), - this, SLOT(webViewUrlChanged(QUrl))); - - - addTab(webView, tr("(Untitled)")); - if (makeCurrent) - setCurrentWidget(webView); - - setupPage(webView->page()); - - 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) - 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::requestCloseTab(int index) -{ - if (index < 0) - index = currentIndex(); - if (index < 0 || index >= count()) - return; - WebView *tab = webView(index); - if (!tab) - return; - tab->page()->triggerAction(QWebEnginePage::RequestClose); -} - -void TabWidget::closeTab(int index) -{ - if (index < 0 || index >= count()) - return; - - bool hasFocus = false; - if (WebView *tab = webView(index)) { - hasFocus = tab->hasFocus(); - - if (m_profile == QWebEngineProfile::defaultProfile()) { - 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::setProfile(QWebEngineProfile *profile) -{ - m_profile = profile; - for (int i = 0; i < count(); ++i) { - QWidget *tabWidget = widget(i); - if (WebView *tab = qobject_cast<WebView*>(tabWidget)) { - WebPage* webPage = new WebPage(m_profile, tab); - setupPage(webPage); - webPage->load(tab->page()->url()); - tab->setPage(webPage); - } - } -} - -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(const QIcon &icon) -{ - WebView *webView = qobject_cast<WebView*>(sender()); - int index = webViewIndex(webView); - if (-1 != index) - 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::webPageMutedOrAudibleChanged() { - QWebEnginePage* webPage = qobject_cast<QWebEnginePage*>(sender()); - WebView *webView = qobject_cast<WebView*>(webPage->view()); - - int index = webViewIndex(webView); - if (-1 != index) { - QString title = webView->title(); - - bool muted = webPage->isAudioMuted(); - bool audible = webPage->recentlyAudible(); - if (muted) title += tr(" (muted)"); - else if (audible) title += tr(" (audible)"); - - setTabText(index, 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); - HistoryManager *manager = BrowserApplication::historyManager(); - if (url.isValid()) - manager->addHistoryEntry(url.toString()); - } - 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()); - } - } - 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; -} - -void TabWidget::downloadRequested(QWebEngineDownloadItem *download) -{ - if (download->savePageFormat() != QWebEngineDownloadItem::UnknownSaveFormat) { - SavePageDialog dlg(this, download->savePageFormat(), download->path()); - if (dlg.exec() != SavePageDialog::Accepted) - return; - download->setSavePageFormat(dlg.pageFormat()); - download->setPath(dlg.filePath()); - } - - BrowserApplication::downloadManager()->download(download); - download->accept(); -} - -WebActionMapper::WebActionMapper(QAction *root, QWebEnginePage::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())); -} - -QWebEnginePage::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(QWebEnginePage *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/webenginewidgets/demobrowser/tabwidget.h b/examples/webenginewidgets/demobrowser/tabwidget.h deleted file mode 100644 index 82dcf960d..000000000 --- a/examples/webenginewidgets/demobrowser/tabwidget.h +++ /dev/null @@ -1,263 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 TABWIDGET_H -#define TABWIDGET_H - -#include <QtWebEngineWidgets/QWebEngineFullScreenRequest> -#include <QtWidgets/QTabBar> -#include <QtWidgets/QShortcut> - -QT_BEGIN_NAMESPACE -class QWebEngineDownloadItem; -class QWebEngineProfile; -class QWebEngineView; -QT_END_NAMESPACE - -/* - 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 muteTab(int index, bool mute); - 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 muteTab(); - void unmuteTab(); - void contextMenuRequested(const QPoint &position); - -private: - QList<QShortcut*> m_tabShortcuts; - friend class TabWidget; - - QPoint m_dragStartPos; - int m_dragCurrentIndex; -}; - -#include <QWebEnginePage> - -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, QWebEnginePage::WebAction webAction, QObject *parent); - QWebEnginePage::WebAction webAction() const; - void addChild(QAction *action); - void updateCurrent(QWebEnginePage *currentParent); - -private slots: - void rootTriggered(); - void childChanged(); - void rootDestroyed(); - void currentDestroyed(); - -private: - QWebEnginePage *m_currentParent; - QAction *m_root; - QWebEnginePage::WebAction m_webAction; -}; - -#include <QtCore/QUrl> -#include <QtWidgets/QTabWidget> - -class FullScreenNotification; - -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); -#if defined(QWEBENGINEPAGE_PRINTREQUESTED) - void printRequested(QWebEngineFrame *frame); -#endif - -public: - TabWidget(QWidget *parent = 0); - ~TabWidget(); - void clear(); - void addWebAction(QAction *action, QWebEnginePage::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); - - void setProfile(QWebEngineProfile *profile); - -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 requestCloseTab(int index = -1); - void closeTab(int index); - void closeOtherTabs(int index); - void reloadTab(int index = -1); - void reloadAllTabs(); - void nextTab(); - void previousTab(); - void setAudioMutedForTab(int index, bool mute); - -private slots: - void currentChanged(int index); - void aboutToShowRecentTabsMenu(); - void aboutToShowRecentTriggeredAction(QAction *action); - void downloadRequested(QWebEngineDownloadItem *download); - void webViewLoadStarted(); - void webViewIconChanged(const QIcon &icon); - void webViewTitleChanged(const QString &title); - void webViewUrlChanged(const QUrl &url); - void lineEditReturnPressed(); - void windowCloseRequested(); - void moveTab(int fromIndex, int toIndex); - void fullScreenRequested(QWebEngineFullScreenRequest request); - void handleTabBarDoubleClicked(int index); - void webPageMutedOrAudibleChanged(); - -private: - void setupPage(QWebEnginePage* page); - - 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; - QWebEngineProfile *m_profile; - QWebEngineView *m_fullScreenView; - FullScreenNotification *m_fullScreenNotification; - QRect m_oldWindowGeometry; -}; - -#endif // TABWIDGET_H diff --git a/examples/webenginewidgets/demobrowser/toolbarsearch.cpp b/examples/webenginewidgets/demobrowser/toolbarsearch.cpp deleted file mode 100644 index 41c5ef314..000000000 --- a/examples/webenginewidgets/demobrowser/toolbarsearch.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "toolbarsearch.h" -#include "autosaver.h" -#include "browserapplication.h" - -#include <QtCore/QSettings> -#include <QtCore/QUrl> -#include <QtCore/QUrlQuery> - -#include <QtWidgets/QCompleter> -#include <QtWidgets/QMenu> -#include <QtCore/QStringListModel> - -#include <QWebEngineSettings> - -/* - 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(); - - if (!BrowserApplication::instance()->privateBrowsing()) { - 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/webenginewidgets/demobrowser/toolbarsearch.h b/examples/webenginewidgets/demobrowser/toolbarsearch.h deleted file mode 100644 index d3e914055..000000000 --- a/examples/webenginewidgets/demobrowser/toolbarsearch.h +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/demobrowser/urllineedit.cpp b/examples/webenginewidgets/demobrowser/urllineedit.cpp deleted file mode 100644 index 8203e4f0f..000000000 --- a/examples/webenginewidgets/demobrowser/urllineedit.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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/QStyleOptionFrame> - -#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() -{ - QStyleOptionFrame 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(QStyleOptionFrame *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 = QStyleOptionFrame::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); - QStyleOptionFrame 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); -} - -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(iconChanged(QIcon)), - this, SLOT(webViewIconChanged(QIcon))); - 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(const QIcon &icon) -{ - Q_ASSERT(m_webView); - m_iconLabel->setPixmap(icon.pixmap(16, 16)); -} - -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); - QStyleOptionFrame 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.0f * progress; - QRect progressRect(backgroundRect.x(), backgroundRect.y(), mid, backgroundRect.height()); - painter.drawRect(progressRect); - } -} diff --git a/examples/webenginewidgets/demobrowser/urllineedit.h b/examples/webenginewidgets/demobrowser/urllineedit.h deleted file mode 100644 index 51c5c0836..000000000 --- a/examples/webenginewidgets/demobrowser/urllineedit.h +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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(QStyleOptionFrame *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(const QIcon &icon); - -private: - QLinearGradient generateGradient(const QColor &color) const; - WebView *m_webView; - UrlIconLabel *m_iconLabel; - QColor m_defaultBaseColor; - -}; - - -#endif // URLLINEEDIT_H diff --git a/examples/webenginewidgets/demobrowser/webview.cpp b/examples/webenginewidgets/demobrowser/webview.cpp deleted file mode 100644 index 498df74fc..000000000 --- a/examples/webenginewidgets/demobrowser/webview.cpp +++ /dev/null @@ -1,470 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "browserapplication.h" -#include "browsermainwindow.h" -#include "cookiejar.h" -#include "downloadmanager.h" -#include "featurepermissionbar.h" -#include "ui_passworddialog.h" -#include "ui_proxy.h" -#include "tabwidget.h" -#include "webview.h" - -#include <QtGui/QClipboard> -#include <QtNetwork/QAuthenticator> -#include <QtNetwork/QNetworkReply> -#include <QtWidgets/QMenu> -#include <QtWidgets/QMessageBox> -#include <QtGui/QMouseEvent> - -#include <QWebEngineContextMenuData> - -#ifndef QT_NO_UITOOLS -#include <QtUiTools/QUiLoader> -#endif //QT_NO_UITOOLS - -#include <QtCore/QDebug> -#include <QtCore/QBuffer> -#include <QtCore/QTimer> - -WebPage::WebPage(QWebEngineProfile *profile, QObject *parent) - : QWebEnginePage(profile, parent) - , m_keyboardModifiers(Qt::NoModifier) - , m_pressedButtons(Qt::NoButton) -{ -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) - setNetworkAccessManager(BrowserApplication::networkAccessManager()); -#endif -#if defined(QWEBENGINEPAGE_UNSUPPORTEDCONTENT) - connect(this, SIGNAL(unsupportedContent(QNetworkReply*)), - this, SLOT(handleUnsupportedContent(QNetworkReply*))); -#endif - connect(this, SIGNAL(authenticationRequired(const QUrl &, QAuthenticator*)), - SLOT(authenticationRequired(const QUrl &, QAuthenticator*))); - connect(this, SIGNAL(proxyAuthenticationRequired(const QUrl &, QAuthenticator *, const QString &)), - SLOT(proxyAuthenticationRequired(const QUrl &, QAuthenticator *, const QString &))); -} - -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::certificateError(const QWebEngineCertificateError &error) -{ - if (error.isOverridable()) { - QMessageBox msgBox; - msgBox.setIcon(QMessageBox::Warning); - msgBox.setText(error.errorDescription()); - msgBox.setInformativeText(tr("If you wish so, you may continue with an unverified certificate. " - "Accepting an unverified certificate means " - "you may not be connected with the host you tried to connect to.\n" - "Do you wish to override the security check and continue?")); - msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox.setDefaultButton(QMessageBox::No); - return msgBox.exec() == QMessageBox::Yes; - } - QMessageBox::critical(view(), tr("Certificate Error"), error.errorDescription(), QMessageBox::Ok, QMessageBox::NoButton); - return false; -} - -class PopupWindow : public QWidget { - Q_OBJECT -public: - PopupWindow(QWebEngineProfile *profile) - : m_addressBar(new QLineEdit(this)) - , m_view(new WebView(this)) - { - m_view->setPage(new WebPage(profile, m_view)); - QVBoxLayout *layout = new QVBoxLayout; - layout->setMargin(0); - setLayout(layout); - layout->addWidget(m_addressBar); - layout->addWidget(m_view); - m_view->setFocus(); - - connect(m_view, &WebView::titleChanged, this, &QWidget::setWindowTitle); - connect(m_view, &WebView::urlChanged, this, &PopupWindow::setUrl); - connect(page(), &WebPage::geometryChangeRequested, this, &PopupWindow::adjustGeometry); - connect(page(), &WebPage::windowCloseRequested, this, &QWidget::close); - } - - QWebEnginePage* page() const { return m_view->page(); } - -private Q_SLOTS: - void setUrl(const QUrl &url) - { - m_addressBar->setText(url.toString()); - } - - void adjustGeometry(const QRect &newGeometry) - { - const int x1 = frameGeometry().left() - geometry().left(); - const int y1 = frameGeometry().top() - geometry().top(); - const int x2 = frameGeometry().right() - geometry().right(); - const int y2 = frameGeometry().bottom() - geometry().bottom(); - - setGeometry(newGeometry.adjusted(x1, y1 - m_addressBar->height(), x2, y2)); - } - -private: - QLineEdit *m_addressBar; - WebView *m_view; - -}; - -#include "webview.moc" - -QWebEnginePage *WebPage::createWindow(QWebEnginePage::WebWindowType type) -{ - if (type == QWebEnginePage::WebBrowserTab) { - return mainWindow()->tabWidget()->newTab()->page(); - } else if (type == QWebEnginePage::WebBrowserBackgroundTab) { - return mainWindow()->tabWidget()->newTab(false)->page(); - } else if (type == QWebEnginePage::WebBrowserWindow) { - BrowserApplication::instance()->newMainWindow(); - BrowserMainWindow *mainWindow = BrowserApplication::instance()->mainWindow(); - return mainWindow->currentTab()->page(); - } else { - PopupWindow *popup = new PopupWindow(profile()); - popup->setAttribute(Qt::WA_DeleteOnClose); - popup->show(); - return popup->page(); - } -} - -#if !defined(QT_NO_UITOOLS) -QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues) -{ - Q_UNUSED(url); - Q_UNUSED(paramNames); - Q_UNUSED(paramValues); - QUiLoader loader; - return loader.createWidget(classId, view()); -} -#endif // !defined(QT_NO_UITOOLS) - -#if defined(QWEBENGINEPAGE_UNSUPPORTEDCONTENT) -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<QWebEngineFrame*> frames; - frames.append(mainFrame()); - while (!frames.isEmpty()) { - QWebEngineFrame *frame = frames.takeFirst(); - if (frame->url() == reply->url()) { - frame->setHtml(html, reply->url()); - return; - } - QList<QWebEngineFrame *> children = frame->childFrames(); - foreach (QWebEngineFrame *frame, children) - frames.append(frame); - } - if (m_loadingUrl == reply->url()) { - mainFrame()->setHtml(html, reply->url()); - } -} -#endif - -void WebPage::authenticationRequired(const QUrl &requestUrl, 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(auth->realm()).arg(requestUrl.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()); - } else { - // Set authenticator null if dialog is cancelled - *auth = QAuthenticator(); - } -} - -void WebPage::proxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth, const QString &proxyHost) -{ - Q_UNUSED(requestUrl); - 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(proxyHost.toHtmlEscaped()); - proxyDialog.introLabel->setText(introMessage); - proxyDialog.introLabel->setWordWrap(true); - - if (dialog.exec() == QDialog::Accepted) { - auth->setUser(proxyDialog.userNameLineEdit->text()); - auth->setPassword(proxyDialog.passwordLineEdit->text()); - } else { - // Set authenticator null if dialog is cancelled - *auth = QAuthenticator(); - } -} - -WebView::WebView(QWidget* parent) - : QWebEngineView(parent) - , m_progress(0) - , m_page(0) -{ - connect(this, SIGNAL(loadProgress(int)), - this, SLOT(setProgress(int))); - connect(this, SIGNAL(loadFinished(bool)), - this, SLOT(loadFinished(bool))); - connect(this, &QWebEngineView::renderProcessTerminated, - [=](QWebEnginePage::RenderProcessTerminationStatus termStatus, int statusCode) { - const char *status = ""; - switch (termStatus) { - case QWebEnginePage::NormalTerminationStatus: - status = "(normal exit)"; - break; - case QWebEnginePage::AbnormalTerminationStatus: - status = "(abnormal exit)"; - break; - case QWebEnginePage::CrashedTerminationStatus: - status = "(crashed)"; - break; - case QWebEnginePage::KilledTerminationStatus: - status = "(killed)"; - break; - } - - qInfo() << "Render process exited with code" << statusCode << status; - QTimer::singleShot(0, [this] { reload(); }); - }); -} - -void WebView::setPage(WebPage *_page) -{ - if (m_page) - m_page->deleteLater(); - m_page = _page; - QWebEngineView::setPage(_page); -#if defined(QWEBENGINEPAGE_STATUSBARMESSAGE) - connect(page(), SIGNAL(statusBarMessage(QString)), - SLOT(setStatusBarText(QString))); -#endif - disconnect(page(), &QWebEnginePage::iconChanged, this, &WebView::iconChanged); - connect(page(), SIGNAL(iconChanged(QIcon)), - this, SLOT(onIconChanged(QIcon))); - connect(page(), &WebPage::featurePermissionRequested, this, &WebView::onFeaturePermissionRequested); -#if defined(QWEBENGINEPAGE_UNSUPPORTEDCONTENT) - page()->setForwardUnsupportedContent(true); -#endif -} - -void WebView::contextMenuEvent(QContextMenuEvent *event) -{ - QMenu *menu; - if (page()->contextMenuData().linkUrl().isValid()) { - menu = new QMenu(this); - menu->setAttribute(Qt::WA_DeleteOnClose, true); - menu->addAction(page()->action(QWebEnginePage::OpenLinkInThisWindow)); - menu->addAction(page()->action(QWebEnginePage::OpenLinkInNewWindow)); - menu->addAction(page()->action(QWebEnginePage::OpenLinkInNewTab)); - menu->addAction(page()->action(QWebEnginePage::OpenLinkInNewBackgroundTab)); - menu->addSeparator(); - menu->addAction(page()->action(QWebEnginePage::DownloadLinkToDisk)); - menu->addAction(page()->action(QWebEnginePage::CopyLinkToClipboard)); - } else { - menu = page()->createStandardContextMenu(); - } - if (page()->contextMenuData().selectedText().isEmpty()) - menu->addAction(page()->action(QWebEnginePage::SavePage)); - menu->popup(event->globalPos()); -} - -void WebView::wheelEvent(QWheelEvent *event) -{ -#if defined(QWEBENGINEPAGE_SETTEXTSIZEMULTIPLIER) - if (QApplication::keyboardModifiers() & Qt::ControlModifier) { - int numDegrees = event->delta() / 8; - int numSteps = numDegrees / 15; - setTextSizeMultiplier(textSizeMultiplier() + numSteps * 0.1); - event->accept(); - return; - } -#endif - QWebEngineView::wheelEvent(event); -} - -void WebView::onFeaturePermissionRequested(const QUrl &securityOrigin, QWebEnginePage::Feature feature) -{ - FeaturePermissionBar *permissionBar = new FeaturePermissionBar(this); - connect(permissionBar, &FeaturePermissionBar::featurePermissionProvided, page(), &QWebEnginePage::setFeaturePermission); - - // Discard the bar on new loads (if we navigate away or reload). - connect(page(), &QWebEnginePage::loadStarted, permissionBar, &QObject::deleteLater); - - permissionBar->requestPermission(securityOrigin, feature); -} - -void WebView::setProgress(int progress) -{ - m_progress = progress; -} - -void WebView::loadFinished(bool success) -{ - if (success && 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 = QWebEngineView::url(); - if (!url.isEmpty()) - return url; - - return m_initialUrl; -} - -void WebView::onIconChanged(const QIcon &icon) -{ - if (icon.isNull()) - emit iconChanged(BrowserApplication::instance()->defaultIcon()); - else - emit iconChanged(icon); -} - -void WebView::mousePressEvent(QMouseEvent *event) -{ - m_page->m_pressedButtons = event->buttons(); - m_page->m_keyboardModifiers = event->modifiers(); - QWebEngineView::mousePressEvent(event); -} - -void WebView::mouseReleaseEvent(QMouseEvent *event) -{ - QWebEngineView::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; -} diff --git a/examples/webenginewidgets/demobrowser/webview.h b/examples/webenginewidgets/demobrowser/webview.h deleted file mode 100644 index 7531254d6..000000000 --- a/examples/webenginewidgets/demobrowser/webview.h +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 WEBVIEW_H -#define WEBVIEW_H - -#include <QIcon> -#include <QWebEngineView> - -QT_BEGIN_NAMESPACE -class QAuthenticator; -class QMouseEvent; -class QNetworkProxy; -class QNetworkReply; -class QSslError; -QT_END_NAMESPACE - -class BrowserMainWindow; -class WebPage : public QWebEnginePage { - Q_OBJECT -public: - WebPage(QWebEngineProfile *profile, QObject *parent = 0); - BrowserMainWindow *mainWindow(); - -protected: - QWebEnginePage *createWindow(QWebEnginePage::WebWindowType type) Q_DECL_OVERRIDE; -#if !defined(QT_NO_UITOOLS) - QObject *createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues); -#endif - virtual bool certificateError(const QWebEngineCertificateError &error) Q_DECL_OVERRIDE; - -private slots: -#if defined(QWEBENGINEPAGE_UNSUPPORTEDCONTENT) - void handleUnsupportedContent(QNetworkReply *reply); -#endif - void authenticationRequired(const QUrl &requestUrl, QAuthenticator *auth); - void proxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth, const QString &proxyHost); - -private: - friend class WebView; - - // set the webview mousepressedevent - Qt::KeyboardModifiers m_keyboardModifiers; - Qt::MouseButtons m_pressedButtons; -}; - -class WebView : public QWebEngineView { - Q_OBJECT - -public: - WebView(QWidget *parent = 0); - WebPage *webPage() const { return m_page; } - void setPage(WebPage *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(bool success); - void setStatusBarText(const QString &string); - void onFeaturePermissionRequested(const QUrl &securityOrigin, QWebEnginePage::Feature); - void onIconChanged(const QIcon &icon); - -private: - QString m_statusBarText; - QUrl m_initialUrl; - int m_progress; - WebPage *m_page; -}; - -#endif diff --git a/examples/webenginewidgets/demobrowser/xbel.cpp b/examples/webenginewidgets/demobrowser/xbel.cpp deleted file mode 100644 index d66c44faa..000000000 --- a/examples/webenginewidgets/demobrowser/xbel.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 "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/webenginewidgets/demobrowser/xbel.h b/examples/webenginewidgets/demobrowser/xbel.h deleted file mode 100644 index 89f5e259f..000000000 --- a/examples/webenginewidgets/demobrowser/xbel.h +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the demonstration applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, 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 The Qt Company Ltd 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 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/webenginewidgets/webenginewidgets.pro b/examples/webenginewidgets/webenginewidgets.pro index 217c4f016..cb7c8aa22 100644 --- a/examples/webenginewidgets/webenginewidgets.pro +++ b/examples/webenginewidgets/webenginewidgets.pro @@ -4,7 +4,6 @@ SUBDIRS += \ minimal \ contentmanipulation \ cookiebrowser \ - demobrowser \ html2pdf \ markdowneditor \ simplebrowser \ diff --git a/src/webengine/doc/src/qtwebengine-features.qdoc b/src/webengine/doc/src/qtwebengine-features.qdoc index 11d3a4ca1..c8ff2250d 100644 --- a/src/webengine/doc/src/qtwebengine-features.qdoc +++ b/src/webengine/doc/src/qtwebengine-features.qdoc @@ -77,8 +77,8 @@ This feature can be tested by launching a Qt WebEngine application with the command line option \c {--remote-debugging-port=[your-port]} or by setting the environment variable \c QTWEBENGINE_REMOTE_DEBUGGING, and then using a - Chromium based browser (such as \l{WebEngine Demo Browser Example} - {Demo Browser} or \l{WebEngine Quick Nano Browser}{Nano Browser}) to connect + Chromium based browser (such as \l{WebEngine Widgets Simple Browser Example} + {Simple Browser} or \l{WebEngine Quick Nano Browser}{Nano Browser}) to connect to \c {http://localhost:[your-port]}. For more information, see \l {Qt WebEngine Debugging and Profiling}. @@ -89,8 +89,8 @@ This feature can be tested by opening an HTML5 drag and drop demo, such as \l{HTML5 Demos - Drag and Drop}, \l{HTML5 Demos - Simple Drag and Drop}, or - \l{HTML5 Demos - Drag and Drop, Automatic Upload}, in \l{WebEngine Demo - Browser Example}{Demo Browser} or \l{WebEngine Quick Nano Browser} + \l{HTML5 Demos - Drag and Drop, Automatic Upload}, in \l{WebEngine Widgets + Simple Browser Example}{Simple Browser} or \l{WebEngine Quick Nano Browser} {Nano Browser}. Dragging files into the browser is not actually part of HTML5, but it is @@ -108,7 +108,7 @@ QWebEnginePage::fullScreenRequested. This feature can be tested by playing a video from YouTube in \l{WebEngine - Demo Browser Example}{Demo Browser} or \l{WebEngine Quick Nano Browser} + Widgets Video Player Example}{Video Player} or \l{WebEngine Quick Nano Browser} {Nano Browser}, and clicking the full screen icon to go into fullscreen mode. @@ -123,8 +123,8 @@ proprietary audio and video codecs. For more information about enabling the codecs, see \l{Audio and Video Codecs}. - This feature can be tested by playing a video in \l{WebEngine Demo Browser - Example}{Demo Browser} or \l{WebEngine Quick Nano Browser}{Nano Browser} + This feature can be tested by playing a video in \l{WebEngine Widgets Simple Browser + Example}{Simple Browser} or \l{WebEngine Quick Nano Browser}{Nano Browser} from \l{castLabs}, \l{Swank Motion Pictures, Inc.}, or \l{Shaka Player}. Support for this feature was added in Qt 5.7.0. @@ -136,11 +136,11 @@ QWebEnginePage::Geolocation or \l{WebEngineView::Feature} {WebEngineView.Feature}. - This feature can be tested if Qt Location has been built before Qt WebEngine. - The \c http://html5demos.com/geo page can be opened in the \l{WebEngine Demo - Browser Example}{Demo Browser} and allowed to find the current position of - the user. Note that on Windows an external GPS receiver must be connected to - the application. For more information, see \l{Qt Positioning}. + If Qt Location has been built before Qt WebEngine then this feature can be + tested by using \l{WebEngine Widgets Maps Example}{Maps} and allowing it to + find the current position of the user. Note that on Windows an external GPS + receiver must be connected to the application. For more information, see + \l{Qt Positioning}. Support for this feature was added in Qt 5.5.0. @@ -253,7 +253,7 @@ --ppapi-flash-version=16.0.0.235 \endcode - This feature can be tested in \l{WebEngine Demo Browser Example}{Demo Browser} + This feature can be tested in \l{WebEngine Widgets Simple Browser Example}{Simple Browser} or \l{WebEngine Quick Nano Browser}{Nano Browser} if the Adobe Flash PPAPI plugin is installed and plugins are enabled in the browser. To test the feature, the \c https://helpx.adobe.com/flash-player.html page can be opened @@ -265,8 +265,8 @@ information, see QWebEnginePage::printToPdf() and \l{WebEngineView::printToPdf}{WebEngineView.printToPdf}. - This feature can be tested in \l{WebEngine Demo Browser Example} - {Demo Browser} by selecting \uicontrol File > \uicontrol {Print to PDF}. + This feature can be tested using \l{WebEngine Widgets Html2Pdf Example} + {Html2Pdf}. Support for this feature was added in Qt 5.7.0. diff --git a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc index e54c5d507..34a61ded3 100644 --- a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc @@ -77,7 +77,7 @@ new windows, such as pop-up windows, you can subclass QWebEngineView and reimplement the createWindow() function. - \sa {WebEngine Demo Browser Example}, {WebEngine Content Manipulation Example}, {WebEngine Markdown Editor Example} + \sa {WebEngine Widgets Simple Browser Example}, {WebEngine Content Manipulation Example}, {WebEngine Markdown Editor Example} */ -- GitLab