diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b1c8782c..8f1da02d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ include(ECMSetupVersion) set(KONQUEROR_LIB_VERSION "5.0.97") set(KONQUEROR_VERSION "${KONQUEROR_LIB_VERSION}") -find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Widgets WebEngineWidgets) +find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Widgets WebKitWidgets) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Parts KCMUtils KHtml KDELibs4Support Archive Crash) find_package(KF5 ${KF5_MIN_VERSION} COMPONENTS Activities DocTools) # Optional @@ -52,7 +52,7 @@ add_subdirectory( libkonq ) add_subdirectory( src ) add_subdirectory( client ) add_subdirectory( autotests ) -add_subdirectory( webenginepart ) +add_subdirectory( webkitpart ) add_subdirectory( about ) add_subdirectory( pics ) diff --git a/about/konq_aboutpage.cpp b/about/konq_aboutpage.cpp index 017875809..edfab3b64 100644 --- a/about/konq_aboutpage.cpp +++ b/about/konq_aboutpage.cpp @@ -219,13 +219,10 @@ QString KonqAboutPageSingleton::specs() QStringLiteral("http://www.ecma-international.org/publications/standards/ECMA-262.HTM"))) .arg(i18n("JavaScript disabled (globally). Enable JavaScript here.", QStringLiteral("exec:/kcmshell5 khtml_java_js"))) .arg(i18n("JavaScript enabled (globally). Configure JavaScript here.", QStringLiteral("exec:/kcmshell5 khtml_java_js"))) // leave the double backslashes here, they are necessary for javascript ! - .arg(i18n("Secure Java® support", QStringLiteral("http://www.oracle.com/technetwork/java/index.html"))) - .arg(i18n("JDK 1.2.0 (Java 2) compatible VM (IBM or Sun/Oracle)", - QStringLiteral("http://www.ibm.com"), QStringLiteral("http://www.oracle.com/technetwork/java/index.html"))) + .arg(i18n("Secure Java® support")) + .arg(i18n("JDK 1.2.0 (Java 2) compatible VM")) .arg(i18n("Enable Java (globally) here.", QStringLiteral("exec:/kcmshell5 khtml_java_js"))) // TODO Maybe test if Java is enabled ? - .arg(i18n("Netscape Communicator® plugins (for viewing Flash®, Real®Audio, Real®Video, etc.)", - QStringLiteral("http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"), - QStringLiteral("http://www.real.com"), QStringLiteral("http://www.real.com"), + .arg(i18n("NPAPI® plugins", QStringLiteral("about:plugins"))) .arg(i18n("built-in")) .arg(i18n("Secure Sockets Layer")) @@ -301,8 +298,8 @@ QString KonqAboutPageSingleton::tips() .arg(i18n("Tips")) .arg(i18n("Specifications")) .arg(i18n("Tips & Tricks")) - .arg(i18n("Use Web-Shortcuts: by typing \"gg: KDE\" one can search the Internet, " - "using Google, for the search phrase \"KDE\". There are a lot of " + .arg(i18n("Use Web-Shortcuts: by typing \"dd: KDE\" one can search the Internet, " + "using DuckDuckGo HTML, for the search phrase \"KDE\". There are a lot of " "Web-Shortcuts predefined to make searching for software or looking " "up certain words in an encyclopedia a breeze. You can even " "create your own Web-Shortcuts.", QStringLiteral("exec:/kcmshell5 webshortcuts"))) diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 09c1a28e9..590aea85d 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -12,7 +12,7 @@ add_test(konqviewmgrtest konqviewmgrtest) ecm_mark_as_test(konqviewmgrtest) target_link_libraries(konqviewmgrtest kdeinit_konqueror Qt5::Core Qt5::Gui # KF5::KHtml - kwebenginepartlib Qt5::WebEngineWidgets Qt5::Test) + kwebkitpartlib Qt5::WebKitWidgets Qt5::Test) ########### historymanagertest ############### @@ -33,7 +33,7 @@ target_link_libraries(undomanagertest kdeinit_konqueror Qt5::Core Qt5::Test) add_executable(konqhtmltest konqhtmltest.cpp) add_test(konqhtmltest konqhtmltest) ecm_mark_as_test(konqhtmltest) -target_link_libraries(konqhtmltest kdeinit_konqueror kwebenginepartlib Qt5::Core Qt5::Test) +target_link_libraries(konqhtmltest kdeinit_konqueror kwebkitpartlib Qt5::Core Qt5::Test) ########### konqviewtest ############### diff --git a/autotests/konqhtmltest.cpp b/autotests/konqhtmltest.cpp index b893e704e..e43b735d2 100644 --- a/autotests/konqhtmltest.cpp +++ b/autotests/konqhtmltest.cpp @@ -23,8 +23,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -50,14 +50,14 @@ private Q_SLOTS: KonqSessionManager::self()->disableAutosave(); //qRegisterMetaType("KonqView*"); - // Ensure the tests use webenginepart, not KHTML or kwebkitpart + // Ensure the tests use webkitpart, not KHTML or kwebkitpart // This code is inspired by settings/konqhtml/generalopts.cpp bool needsUpdate = false; KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::ApplicationsLocation); KConfigGroup addedServices(profile, "Added KDE Service Associations"); Q_FOREACH (const QString &mimeType, QStringList() << "text/html" << "application/xhtml+xml" << "application/xml") { QStringList services = addedServices.readXdgListEntry(mimeType); - const QString wanted = QStringLiteral("webenginepart.desktop"); + const QString wanted = QStringLiteral("webkitpart.desktop"); if (services.isEmpty() || services.at(0) != wanted) { services.removeAll(wanted); services.prepend(wanted); // make it the preferred one @@ -87,7 +87,7 @@ private Q_SLOTS: QSignalSpy spyCompleted(view, SIGNAL(viewCompleted(KonqView*))); QVERIFY(spyCompleted.wait(20000)); QCOMPARE(view->serviceType(), QString("text/html")); - WebEnginePart* part = qobject_cast(view->part()); + WebKitPart* part = qobject_cast(view->part()); QVERIFY(part); } @@ -105,7 +105,7 @@ private Q_SLOTS: QVERIFY(spyCompleted.wait(20000)); // which then opens the right part QCOMPARE(view->serviceType(), QString("inode/directory")); } else { - // WebEngine can actually list directories, no error. + // WebKit can actually list directories, no error. // To test this: konqueror --mimetype text/html $HOME QCOMPARE(view->url().adjusted(QUrl::StripTrailingSlash), url); } @@ -181,9 +181,9 @@ private Q_SLOTS: KonqFrame *frame = newWindow->currentView()->frame(); QVERIFY(frame); QVERIFY(!frame->childView()->isLoading()); - WebEnginePart *part = qobject_cast(frame->part()); + WebKitPart *part = qobject_cast(frame->part()); QVERIFY(part); - QTRY_VERIFY(!part->view()->url().isEmpty()); // hack to wait for webengine to load the page + QTRY_VERIFY(!part->view()->url().isEmpty()); // hack to wait for webkit to load the page QTRY_COMPARE(part->view()->title(), QString("Opener=[object Window]")); deleteAllMainWindows(); } @@ -210,14 +210,14 @@ private: static QWidget *partWidget(KonqView *view) { QWidget *widget = view->part()->widget(); - WebEnginePart *htmlPart = qobject_cast(view->part()); + WebKitPart *htmlPart = qobject_cast(view->part()); if (htmlPart) { widget = htmlPart->view(); // khtmlview != widget() nowadays, due to find bar } if (QScrollArea *scrollArea = qobject_cast(widget)) { widget = scrollArea->widget(); } - if (widget && widget->focusProxy()) { // for WebEngine's RenderWidgetHostViewQtDelegateWidget + if (widget && widget->focusProxy()) { // for WebKit's RenderWidgetHostViewQtDelegateWidget return widget->focusProxy(); } return widget; diff --git a/autotests/konqviewmgrtest.cpp b/autotests/konqviewmgrtest.cpp index c1ac0fc05..b68c21190 100644 --- a/autotests/konqviewmgrtest.cpp +++ b/autotests/konqviewmgrtest.cpp @@ -45,9 +45,9 @@ #include #include #else -#include -#include -#include "../webenginepart/autotests/webengine_testutils.h" +#include +#include +#include "../webkitpart/autotests/webkit_testutils.h" #endif #include @@ -81,7 +81,7 @@ static QWidget *partWidget(KonqView *view) #ifdef TEST_KHTML KHTMLPart *htmlPart = qobject_cast(view->part()); #else - WebEnginePart *htmlPart = qobject_cast(view->part()); + WebKitPart *htmlPart = qobject_cast(view->part()); #endif if (htmlPart) { widget = htmlPart->view(); // khtmlview != widget() nowadays, due to find bar @@ -89,7 +89,7 @@ static QWidget *partWidget(KonqView *view) if (QScrollArea *scrollArea = qobject_cast(widget)) { widget = scrollArea->widget(); } - if (widget && widget->focusProxy()) { // for WebEngine's RenderWidgetHostViewQtDelegateWidget + if (widget && widget->focusProxy()) { // for WebKit's RenderWidgetHostViewQtDelegateWidget return widget->focusProxy(); } return widget; @@ -192,7 +192,7 @@ void ViewMgrTest::initTestCase() QCOMPARE(KonqSettings::mmbOpensTab(), true); QCOMPARE(KonqSettings::popupsWithinTabs(), false); - // Ensure the tests use webenginepart (not khtml or webkit) + // Ensure the tests use webkitpart (not khtml or webkit) // This code is inspired by settings/konqhtml/generalopts.cpp KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::ApplicationsLocation); KConfigGroup addedServices(profile, "Added KDE Service Associations"); @@ -202,7 +202,7 @@ void ViewMgrTest::initTestCase() #ifdef TEST_KHTML const QString wanted = "khtml.desktop"; #else - const QString wanted = QStringLiteral("webenginepart.desktop"); + const QString wanted = QStringLiteral("webkitpart.desktop"); #endif if (services.isEmpty() || services.at(0) != wanted) { services.removeAll(wanted); @@ -434,7 +434,7 @@ void ViewMgrTest::testLinkedViews() MyKonqMainWindow mainWindow; openHtmlWithLink(mainWindow); KonqView *view = mainWindow.currentView(); - WebEnginePart *part = qobject_cast(view->part()); + WebKitPart *part = qobject_cast(view->part()); QVERIFY(part); // Split it qDebug() << "SPLITTING"; diff --git a/doc/konqueror/index.docbook b/doc/konqueror/index.docbook index 05bed1fc0..4f9313758 100644 --- a/doc/konqueror/index.docbook +++ b/doc/konqueror/index.docbook @@ -2244,7 +2244,7 @@ playground/utils Extensions... to open a dialog with all installed plugins and select the ones you need. All plugins are accessible in the Tools menu. -Only plugins appropriate for the current mode (file manager or browser in KHTML/WebEngine view) +Only plugins appropriate for the current mode (file manager or browser in KHTML/WebKit view) are listed in the dialog. @@ -2254,7 +2254,7 @@ FIXME 16.12 KHTML: Auto Refresh, HTML Settings, Minitools-Bookmarklets, Translate (disabled), DOM Tree Viewer, Document Relations, Web Archiver, Website Validators, Search Bar kwebkitpart for kf5 in extragear/base in branch frameworks WebKit only HTML Settings and Translate (disabled) -WebEngine -> no extensions +WebKit -> no extensions --> Web Page Translation @@ -3406,7 +3406,7 @@ in the text or &HTML; page. View Mode In browser mode this submenu holds items to select embedded -views like KHTML, WebEngine, Embedded Advanced +views like KHTML, WebKit, Embedded Advanced Text Editor and more embedded views. In file manager mode this submenu holds items to select Icon, Details, Compact, @@ -3495,7 +3495,7 @@ page. View Zoom In Zoom Out Actual Size Zoom Text Only -Zoom To DPI (Browser mode - WebEngine view) +Zoom To DPI (Browser mode - WebKit view) These menuitems offer different actions to modify the size of the items in the page. diff --git a/settings/konqhtml/generalopts.cpp b/settings/konqhtml/generalopts.cpp index 36cb14388..3298adc3d 100644 --- a/settings/konqhtml/generalopts.cpp +++ b/settings/konqhtml/generalopts.cpp @@ -126,12 +126,12 @@ void KKonqGeneralOptions::addHomeUrlWidgets(QVBoxLayout *lay) QLabel *webLabel = new QLabel(i18n("Default web browser engine:"), this); - m_webEngineCombo = new QComboBox(this); - m_webEngineCombo->setEditable(false); - m_webEngineCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); - formLayout->addRow(webLabel, m_webEngineCombo); - webLabel->setBuddy(m_webEngineCombo); - connect(m_webEngineCombo, SIGNAL(currentIndexChanged(int)), SLOT(slotChanged())); + m_webCombo = new QComboBox(this); + m_webCombo->setEditable(false); + m_webCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); + formLayout->addRow(webLabel, m_webCombo); + webLabel->setBuddy(m_webCombo); + connect(m_webCombo, SIGNAL(currentIndexChanged(int)), SLOT(slotChanged())); } KKonqGeneralOptions::~KKonqGeneralOptions() @@ -180,7 +180,7 @@ void KKonqGeneralOptions::load() Q_ASSERT(startComboIndex != -1); m_startCombo->setCurrentIndex(startComboIndex); - m_webEngineCombo->clear(); + m_webCombo->clear(); // ## Well, the problem with using the trader to find the available parts, is that if a user // removed a part in keditfiletype text/html, it won't be in the list anymore. Oh well. const KService::List partOfferList = KMimeTypeTrader::self()->query(QStringLiteral("text/html"), QStringLiteral("KParts/ReadOnlyPart"), QStringLiteral("not ('KParts/ReadWritePart' in ServiceTypes)")); @@ -189,7 +189,7 @@ void KKonqGeneralOptions::load() // We want only the HTML-capable parts, not any text/plain part (via inheritance) // This is a small "private inheritance" hack, pending a more general solution if (!partService->hasMimeType(QStringLiteral("text/plain"))) { - m_webEngineCombo->addItem(QIcon::fromTheme(partService->icon()), partService->name(), + m_webCombo->addItem(QIcon::fromTheme(partService->icon()), partService->name(), QVariant(partService->storageId())); } } @@ -234,17 +234,17 @@ void KKonqGeneralOptions::save() userSettings.writeEntry("StartURL", startUrl); userSettings.writeEntry("HomeURL", homeURL->text()); - if (m_webEngineCombo->currentIndex() > 0) { + if (m_webCombo->currentIndex() > 0) { // The user changed the preferred web engine, save into mimeapps.list. - const QString preferredWebEngine = m_webEngineCombo->itemData(m_webEngineCombo->currentIndex()).toString(); - //qDebug() << "preferredWebEngine=" << preferredWebEngine; + const QString preferredWebKit = m_webCombo->itemData(m_webCombo->currentIndex()).toString(); + //qDebug() << "preferredWebKit=" << preferredWebKit; KSharedConfig::Ptr profile = KSharedConfig::openConfig("mimeapps.list", KConfig::NoGlobals, QStandardPaths::ConfigLocation); KConfigGroup addedServices(profile, "Added KDE Service Associations"); Q_FOREACH (const QString &mimeType, QStringList() << "text/html" << "application/xhtml+xml" << "application/xml") { QStringList services = addedServices.readXdgListEntry(mimeType); - services.removeAll(preferredWebEngine); - services.prepend(preferredWebEngine); // make it the preferred one + services.removeAll(preferredWebKit); + services.prepend(preferredWebKit); // make it the preferred one addedServices.writeXdgListEntry(mimeType, services); } profile->sync(); diff --git a/settings/konqhtml/generalopts.h b/settings/konqhtml/generalopts.h index 066d02c81..838483c54 100644 --- a/settings/konqhtml/generalopts.h +++ b/settings/konqhtml/generalopts.h @@ -41,7 +41,7 @@ private: QComboBox *m_startCombo; QLineEdit *homeURL; QLineEdit *startURL; - QComboBox *m_webEngineCombo; + QComboBox *m_webCombo; Ui_advancedTabOptions *tabOptions; }; diff --git a/src/konqmain.cpp b/src/konqmain.cpp index 73c6a2f88..413bf5061 100644 --- a/src/konqmain.cpp +++ b/src/konqmain.cpp @@ -58,7 +58,7 @@ static KonqPreloadingHandler s_preloadingHandler; extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv) { - QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); // says QtWebEngine + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); // says QtWebKit KonquerorApplication app(argc, argv); KLocalizedString::setApplicationDomain("konqueror"); diff --git a/webenginepart/CMakeLists.txt a/webenginepart/CMakeLists.txt deleted file mode 100644 index b62735e8b..000000000 --- a/webenginepart/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_subdirectory(icons) -add_subdirectory(src) -add_subdirectory(tests) -add_subdirectory(autotests) diff --git a/webenginepart/COPYING.LIB a/webenginepart/COPYING.LIB deleted file mode 100644 index 01148ab6f..000000000 --- a/webenginepart/COPYING.LIB +++ /dev/null @@ -1,486 +0,0 @@ -NOTE! The LGPL below is copyrighted by the Free Software Foundation, but -the instance of code that it refers to (the kde libraries) are copyrighted -by the authors who actually wrote it. - ---------------------------------------------------------------------------- - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor - Boston, MA 02110-1301, USA. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - c) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - d) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Library General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/webenginepart/Mainpage.dox a/webenginepart/Mainpage.dox deleted file mode 100644 index 832196aef..000000000 --- a/webenginepart/Mainpage.dox +++ /dev/null @@ -1,4 +0,0 @@ -/** @mainpage -* -* Main Doxygen page for KWebKitPart. -*/ diff --git a/webenginepart/Messages.sh a/webenginepart/Messages.sh deleted file mode 100644 index 1fea7c2bb..000000000 --- a/webenginepart/Messages.sh +++ /dev/null @@ -1,4 +0,0 @@ -#! /usr/bin/env bash -$EXTRACTRC `find . -name '*.rc' -or -name '*.ui'` >> rc.cpp || exit 11 -$XGETTEXT `find . -name '*.cpp' | grep -v '/tests/'` -o $podir/webenginepart.pot -rm -f rc.cpp diff --git a/webenginepart/README a/webenginepart/README deleted file mode 100644 index f73bfc864..000000000 --- a/webenginepart/README +++ /dev/null @@ -1,40 +0,0 @@ -KWebKitPart -=========== - -KWebKitPart is a KDE component (KPart) wrapper for QtWebKit. It is intended to -allow KPart based KDE applications such as Konqueror to use it in place of other -browser engine, such as KHTML, to browse the web in Konqueror. - -Known limitations and unimplemented features are listed in the following -documents: - -* https://projects.kde.org/projects/kde/kdelibs/repository/revisions/master/entry/kdewebkit/ISSUES -* https://projects.kde.org/projects/extragear/base/kwebkitpart/repository/revisions/master/entry/TODO - -Please report any issues to: https://bugs.kde.org -IMPORTANT NOTE: Do not select "konqueror" as product, but "kwebkitpart"! - -There is also a public mailing list available for support: - - webkit-devel @ kde.org - -How to use KWebKitPart in Konqueror -=================================== - -You can switch between the different rendering engines: -View -> View Mode -> {KHTML, WebKit} (website needs to be open) -If WebKit does not show up in Konqueror, run 'kbuildsycoca4' and -restart Konqueror. Note that this change does not persist. If you -press the reload button or open a new website, it will fall back -to the default rendering engine. - -If you want to set KWebKitPart as default for any website, run: -'keditfiletype text/html' -and move "WebKit (kwebkitpart)" in the "Embedding" tab to the top. - -In KDE 4.6 and higher you can choose the default rendering engine -in Konqueror's configuration dialog under the "General" section. - -For more information about this project please see also: -http://techbase.kde.org/Projects/WebKit - diff --git a/webenginepart/TODO a/webenginepart/TODO deleted file mode 100644 index f6ba03459..000000000 --- a/webenginepart/TODO +++ /dev/null @@ -1,23 +0,0 @@ -* Proper support for KWebKitPart in the following Konqueror plugins: - - adblock This plugin's GUI needs to be changed to use the KPart plugin - extensions so that it is not khtml specific. Other than that - kwebkitpart supports the ad filtering functionalities supported - by khtml. - -* Add KPartStatusBarExtension support for the following plugins/features: - - Popup blocker (non-plugin) - -* Implement some means of showing information about the webkit rendering engine: - - KWebKitPart's version # - - QtWebKit's version # - - UserAgent string ??? - -* Look through all of Konqueror's web configuration options and make sure we - honor all those we possibly can. Here is a non-complete list of features - that are either partially implemented or not implemented at all: - - Change cursor over links (TODO, QtWebKit ???). - - Smooth scrolling support (TODO, QtWebKit ???). - - Underline links support (Partial, does not work as intended). - - Enable access key navigation with Ctrl key (TODO, QtWebKit ???). - - Animations (TODO, QtWebKit ???). - - Draw frames around not completely loaded images (TODO, QtWebKit ???). diff --git a/webenginepart/autotests/CMakeLists.txt a/webenginepart/autotests/CMakeLists.txt deleted file mode 100644 index 6c9f3b14f..000000000 --- a/webenginepart/autotests/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -include(ECMAddTests) - -find_package(Qt5Test ${QT_MIN_VERSION} CONFIG REQUIRED) - -macro(webenginepart_unit_tests) - foreach(_testname ${ARGN}) - ecm_add_test(${_testname}.cpp TEST_NAME ${_testname} - LINK_LIBRARIES kwebenginepartlib Qt5::Test) - endforeach() -endmacro(webenginepart_unit_tests) - -webenginepart_unit_tests( - webengine_partapi_test -) diff --git a/webenginepart/autotests/data/hello.html a/webenginepart/autotests/data/hello.html deleted file mode 100644 index e965047ad..000000000 --- a/webenginepart/autotests/data/hello.html +++ /dev/null @@ -1 +0,0 @@ -Hello diff --git a/webenginepart/autotests/data/page-with-link.html a/webenginepart/autotests/data/page-with-link.html deleted file mode 100644 index df85219d6..000000000 --- a/webenginepart/autotests/data/page-with-link.html +++ /dev/null @@ -1 +0,0 @@ -click me diff --git a/webenginepart/autotests/webengine_partapi_test.cpp a/webenginepart/autotests/webengine_partapi_test.cpp deleted file mode 100644 index c246536bf..000000000 --- a/webenginepart/autotests/webengine_partapi_test.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright (c) 2016 David Faure - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2 of the License or ( at - your option ) version 3 or, at the discretion of KDE e.V. ( which shall - act as a proxy as in section 14 of the GPLv3 ), any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include -#include "webengine_testutils.h" - -#include -#include - -#include -#include -#include -#include - -class WebEnginePartApiTest : public QObject -{ - Q_OBJECT -private Q_SLOTS: - void initTestCase(); - void shouldHaveBrowserExtension(); - void shouldEmitStartedAndCompleted(); - void shouldEmitSetWindowCaption(); - void shouldEmitOpenUrlNotifyOnClick(); - -}; - -void WebEnginePartApiTest::initTestCase() -{ - qRegisterMetaType(); // for the KParts started signal -} - -void WebEnginePartApiTest::shouldHaveBrowserExtension() -{ - // GIVEN - WebEnginePart part; - - // WHEN - KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject(&part); - - // THEN - QVERIFY(ext); -} - -void WebEnginePartApiTest::shouldEmitStartedAndCompleted() -{ - // GIVEN - WebEnginePart part; - QSignalSpy spyStarted(&part, &KParts::ReadOnlyPart::started); - QSignalSpy spyCompleted(&part, SIGNAL(completed(bool))); - QSignalSpy spySetWindowCaption(&part, &KParts::ReadOnlyPart::setWindowCaption); - KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject(&part); - QSignalSpy spyOpenUrlNotify(ext, &KParts::BrowserExtension::openUrlNotify); - const QUrl url(QStringLiteral("data:text/html,

Hello World

")); - - // WHEN - part.openUrl(url); - - // THEN - QVERIFY(spyStarted.wait()); - QVERIFY(spySetWindowCaption.wait()); - QCOMPARE(spySetWindowCaption.at(0).at(0).toUrl().toString(), url.toString()); - QVERIFY(spyCompleted.wait()); - QVERIFY(!spyCompleted.at(0).at(0).toBool()); - QVERIFY(spyOpenUrlNotify.isEmpty()); -} - -void WebEnginePartApiTest::shouldEmitSetWindowCaption() -{ - // GIVEN - WebEnginePart part; - QSignalSpy spyStarted(&part, &KParts::ReadOnlyPart::started); - QSignalSpy spyCompleted(&part, SIGNAL(completed(bool))); - QSignalSpy spySetWindowCaption(&part, &KParts::ReadOnlyPart::setWindowCaption); - - // WHEN opening a URL with a title tag - part.openUrl(QUrl(QStringLiteral("data:text/html, Custom Title

Hello World

"))); - - // THEN - QVERIFY(spyStarted.wait()); - QVERIFY(spyCompleted.wait()); - QVERIFY(!spyCompleted.at(0).at(0).toBool()); - QCOMPARE(spySetWindowCaption.count(), 2); - QCOMPARE(spySetWindowCaption.at(1).at(0).toUrl().toString(), QStringLiteral("Custom Title")); -} - -void WebEnginePartApiTest::shouldEmitOpenUrlNotifyOnClick() -{ - // GIVEN - WebEnginePart part; - QSignalSpy spyStarted(&part, &KParts::ReadOnlyPart::started); - QSignalSpy spyCompleted(&part, SIGNAL(completed(bool))); - QSignalSpy spySetWindowCaption(&part, &KParts::ReadOnlyPart::setWindowCaption); - KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject(&part); - QSignalSpy spyOpenUrlNotify(ext, &KParts::BrowserExtension::openUrlNotify); - const QString file = QFINDTESTDATA("data/page-with-link.html"); - QVERIFY(!file.isEmpty()); - const QUrl url = QUrl::fromLocalFile(file); - part.openUrl(url); - QVERIFY(spyCompleted.wait()); - QVERIFY(spyOpenUrlNotify.isEmpty()); - QWebEnginePage *page = part.view()->page(); - const QPoint pos = elementCenter(page, QStringLiteral("linkid")); // doesn't seem fully correct... - part.widget()->show(); - spyCompleted.clear(); - - // WHEN clicking on the link - QTest::mouseClick(part.view()->focusProxy(), Qt::LeftButton, Qt::KeyboardModifiers(), pos); - - // THEN - QVERIFY(spyCompleted.wait()); - QCOMPARE(spyOpenUrlNotify.count(), 1); - QCOMPARE(part.url().fileName(), QStringLiteral("hello.html")); -} - -QTEST_MAIN(WebEnginePartApiTest) -#include "webengine_partapi_test.moc" diff --git a/webenginepart/autotests/webengine_testutils.h a/webenginepart/autotests/webengine_testutils.h deleted file mode 100644 index 37489847b..000000000 --- a/webenginepart/autotests/webengine_testutils.h +++ /dev/null @@ -1,108 +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:GPL-EXCEPT$ - ** 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 General Public License Usage - ** Alternatively, this file may be used under the terms of the GNU - ** General Public License version 3 as published by the Free Software - ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT - ** included in the packaging of this file. Please review the following - ** information to ensure the GNU General Public License requirements will - ** be met: https://www.gnu.org/licenses/gpl-3.0.html. - ** - ** $QT_END_LICENSE$ - ** - ****************************************************************************/ - -#include -#include -#include - -template -struct RefWrapper { - R &ref; - void operator()(const T& result) { - ref(result); - } -}; - -template -class CallbackSpy { -public: - CallbackSpy() : called(false) { - timeoutTimer.setSingleShot(true); - QObject::connect(&timeoutTimer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); - } - - T waitForResult() { - if (!called) { - timeoutTimer.start(10000); - eventLoop.exec(); - } - return result; - } - - bool wasCalled() const { - return called; - } - - void operator()(const T &result) { - this->result = result; - called = true; - eventLoop.quit(); - } - - // Cheap rip-off of boost/std::ref - RefWrapper > ref() - { - RefWrapper > wrapper = {*this}; - return wrapper; - } - -private: - Q_DISABLE_COPY(CallbackSpy) - bool called; - QTimer timeoutTimer; - QEventLoop eventLoop; - T result; -}; - -// taken from the qwebengine unittests -static inline QVariant evaluateJavaScriptSync(QWebEnginePage *page, const QString &script) -{ - CallbackSpy spy; - page->runJavaScript(script, spy.ref()); - return spy.waitForResult(); -} - -// Taken from QtWebEngine's tst_qwebenginepage.cpp -static QPoint elementCenter(QWebEnginePage *page, const QString &id) -{ - QVariantList rectList = evaluateJavaScriptSync(page, - "(function(){" - "var elem = document.getElementById('" + id + "');" - "var rect = elem.getBoundingClientRect();" - "return [rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top];" - "})()").toList(); - - if (rectList.count() != 4) { - qWarning("elementCenter failed."); - return QPoint(); - } - const QRect rect(rectList.at(0).toInt(), rectList.at(1).toInt(), - rectList.at(2).toInt(), rectList.at(3).toInt()); - return rect.center(); -} - diff --git a/webenginepart/icons/CMakeLists.txt a/webenginepart/icons/CMakeLists.txt deleted file mode 100644 index 4b820aeb3..000000000 --- a/webenginepart/icons/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -include(ECMInstallIcons) -ecm_install_icons(${ICON_INSTALL_DIR}) diff --git a/webenginepart/icons/webengine.svg a/webenginepart/icons/webengine.svg deleted file mode 100644 index 148d955f9..000000000 --- a/webenginepart/icons/webengine.svg +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - W - E - E - B - - diff --git a/webenginepart/scripts/codingstyle.sh a/webenginepart/scripts/codingstyle.sh deleted file mode 100755 index 1761942d6..000000000 --- a/webenginepart/scripts/codingstyle.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -# -# Kdelibs coding style is defined in http://techbase.kde.org/Policies/Kdelibs_Coding_Style -# - -PWD=$(pwd) -cd $PWD - -echo "Applying astyle rules..." -astyle -v --indent=spaces=4 \ - --brackets=linux \ - --indent-labels \ - --pad=oper --unpad=paren \ - --one-line=keep-statements \ - --convert-tabs --indent-preprocessor \ - `find -type f -name '*.cpp' -or -name '*.h' -or -name '*.cc' | grep -Ev "\./.+/settings/"` - -echo "Done!" - diff --git a/webenginepart/scripts/create_release_package.sh a/webenginepart/scripts/create_release_package.sh deleted file mode 100755 index a8694c897..000000000 --- a/webenginepart/scripts/create_release_package.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -VERSION=${1} -GITREPO=${2} -OUTPUTDIR=${3} - -if [ -z ${VERSION} ] || [ -z {GITREPO} ]; then - echo "Usage: `basename ${0}` []" - exit 1 -fi - -if [ -z $OUTPUTDIR ] || [ ! -d $OUTPUTDIR ]; then - OUTPUTDIR="${PWD}" -fi - -git archive --format=tar --prefix=kwebkitpart-${VERSION}/ ${GITREPO} | bzip2 -9 > ${OUTPUTDIR}/kwebkitpart-${VERSION}.tar.bz2 diff --git a/webenginepart/src/CMakeLists.txt a/webenginepart/src/CMakeLists.txt deleted file mode 100644 index 1672c6038..000000000 --- a/webenginepart/src/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}) - -set(kwebenginepartlib_LIB_SRCS - webenginepart.cpp - webenginepart_ext.cpp - webengineview.cpp - webenginepage.cpp - websslinfo.cpp - webhistoryinterface.cpp - settings/webenginesettings.cpp - settings/webengine_filter.cpp - ui/searchbar.cpp - ui/passwordbar.cpp - ui/featurepermissionbar.cpp -) - -qt5_wrap_ui(kwebenginepartlib_LIB_SRCS - ui/searchbar.ui -) - -add_library(kwebenginepartlib ${kwebenginepartlib_LIB_SRCS}) - -generate_export_header(kwebenginepartlib) - -target_link_libraries(kwebenginepartlib Qt5::Core Qt5::DBus Qt5::Gui Qt5::Widgets Qt5::WebEngineWidgets Qt5::PrintSupport KF5::Parts KF5::SonnetCore) - -target_include_directories(kwebenginepartlib PUBLIC - "$" -) - -install(TARGETS kwebenginepartlib ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) - -add_library(webenginepart MODULE webenginepartfactory.cpp) - -target_link_libraries(webenginepart kwebenginepartlib) - -install(TARGETS webenginepart DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/parts) - -install(FILES webenginepart.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) - -install(FILES webenginepart.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/webenginepart) diff --git a/webenginepart/src/settings/webengine_filter.cpp a/webenginepart/src/settings/webengine_filter.cpp deleted file mode 100644 index 98f505d60..000000000 --- a/webenginepart/src/settings/webengine_filter.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/* This file is part of the KDE project - - Copyright (C) 2005 Ivor Hewitt - Copyright (C) 2008 Maksim Orlovich - Copyright (C) 2008 Vyacheslav Tokarev - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "webengine_filter.h" - -#include -#include - -// rolling hash parameters -#define HASH_P (1997) -#define HASH_Q (17509) -// HASH_MOD = (HASH_P^7) % HASH_Q -#define HASH_MOD (523) - - -using namespace KDEPrivate; - -// Updateable Multi-String Matcher based on Rabin-Karp's algorithm -class StringsMatcher { -public: - // add filter to matching set - void addString(const QString& pattern) - { - if (pattern.length() < 8) { - // handle short string differently - shortStringFilters.append(pattern); - } else { - // use modified Rabin-Karp's algorithm with 8-length string hash - // i.e. store hash of first 8 chars in the HashMap for fast look-up - stringFilters.append(pattern); - int ind = stringFilters.size() - 1; - int current = 0; - - // compute hash using rolling hash - // hash for string: x0,x1,x2...xn-1 will be: - // (p^(n-1)*x0 + p^(n-2)*x1 + ... + p * xn-2 + xn-1) % q - // where p and q some wisely-chosen integers - /*for (int k = 0; k < 8; ++k)*/ - int len = pattern.length(); - for (int k = len - 8; k < len; ++k) - current = (current * HASH_P + pattern[k].unicode()) % HASH_Q; - - // insert computed hash value into HashMap - QHash >::iterator it = stringFiltersHash.find(current + 1); - if (it == stringFiltersHash.end()) { - QVector list; - list.append(ind); - stringFiltersHash.insert(current + 1, list); - fastLookUp.setBit(current); - } else { - it->append(ind); - } - } - } - - - // check if string match at least one string from matching set - bool isMatched(const QString& str, QString *by = 0) const - { - // check short strings first - for (int i = 0; i < shortStringFilters.size(); ++i) { - if (str.contains(shortStringFilters[i])) - { - if (by != 0) *by = shortStringFilters[i]; - return true; - } - } - - int len = str.length(); - int k; - - int current = 0; - int next = 0; - // compute hash for first 8 characters - for (k = 0; k < 8 && k < len; ++k) - current = (current * HASH_P + str[k].unicode()) % HASH_Q; - - QHash >::const_iterator hashEnd = stringFiltersHash.end(); - // main Rabin-Karp's algorithm loop - for (k = 7; k < len; ++k, current = next) { - // roll the hash if not at the end - // (calculate hash for the next iteration) - if (k + 1 < len) - next = (HASH_P * ((current + HASH_Q - ((HASH_MOD * str[k - 7].unicode()) % HASH_Q)) % HASH_Q) + str[k + 1].unicode()) % HASH_Q; - - if (!fastLookUp.testBit(current)) - continue; - - // look-up the hash in the HashMap and check all strings - QHash >::const_iterator it = stringFiltersHash.find(current + 1); - - // check possible strings - if (it != hashEnd) { - for (int j = 0; j < it->size(); ++j) { - int index = it->value(j); - // check if we got simple string or REs prefix - if (index >= 0) { - int flen = stringFilters[index].length(); - if (k - flen + 1 >= 0 && stringFilters[index] == str.midRef(k - flen + 1 , flen)) - { - if (by != 0) *by = stringFilters[index]; - return true; - } - } else { - index = -index - 1; - int flen = rePrefixes[index].length(); - if (k - 8 + flen < len && rePrefixes[index] == str.midRef(k - 7, flen)) - { - int remStart = k - 7 + flen; - QString remainder = QString::fromRawData(str.unicode() + remStart, - str.length() - remStart); - if (reFilters[index].exactMatch(remainder)) { - if (by != 0) *by = rePrefixes[index]+reFilters[index].pattern(); - return true; - } - } - } - } - } - } - - return false; - } - - // add filter to matching set with wildcards (*,?) in it - void addWildedString(const QString& prefix, const QRegExp& rx) - { - rePrefixes.append(prefix); - reFilters.append(rx); - int index = -rePrefixes.size(); - - int current = 0; - for (int k = 0; k < 8; ++k) - current = (current * HASH_P + prefix[k].unicode()) % HASH_Q; - - // insert computed hash value into HashMap - QHash >::iterator it = stringFiltersHash.find(current + 1); - if (it == stringFiltersHash.end()) { - QVector list; - list.append(index); - stringFiltersHash.insert(current + 1, list); - fastLookUp.setBit(current); - } else { - it->append(index); - } - } - - void clear() - { - stringFilters.clear(); - shortStringFilters.clear(); - reFilters.clear(); - rePrefixes.clear(); - stringFiltersHash.clear(); - fastLookUp.resize(HASH_Q); - fastLookUp.fill(0, 0, HASH_Q); - } - -private: - QVector stringFilters; - QVector shortStringFilters; - QVector reFilters; - QVector rePrefixes; - QBitArray fastLookUp; - - QHash > stringFiltersHash; -}; - - -// We only want a subset of features of wildcards -- just the -// star, so we escape the rest before passing to QRegExp. -// The \ is escaped due to a QRegExp bug. -// ### we really should rather parse it ourselves, in order to -// handle adblock-special things like | and ^ properly. -static QRegExp fromAdBlockWildcard(const QString& wcStr) { - QRegExp rx; - rx.setPatternSyntax(QRegExp::Wildcard); - - QString out; - for (int p = 0; p < wcStr.length(); ++p) { - QChar c = wcStr[p]; - if (c == QLatin1Char('?')) - out += QLatin1String("[?]"); - else if (c == QLatin1Char('[')) - out += QLatin1String("[[]"); - else if (c == QLatin1Char('\\')) - out += QLatin1String("[\\]"); - else - out += c; - } - - rx.setPattern(out); - return rx; -} - -FilterSet::FilterSet() - :stringFiltersMatcher(new StringsMatcher) -{ -} - -FilterSet::~FilterSet() -{ - delete stringFiltersMatcher; -} - -void FilterSet::addFilter(const QString& filterStr) -{ - QString filter = filterStr; - - /** ignore special lines starting with "[", "!", "&", or "#" or contain "#" (comments or features are not supported by KHTML's AdBlock */ - QChar firstChar = filter.at(0); - if (firstChar == QLatin1Char('[') || firstChar == QLatin1Char('!') || firstChar == QLatin1Char('&') || firstChar == QLatin1Char('#') || filter.contains(QLatin1Char('#'))) - return; - - // Strip leading @@ - int first = 0; - int last = filter.length() - 1; - if (filter.startsWith(QLatin1String("@@"))) - first = 2; - - // Strip options, we ignore them for now. - // TODO: Add support for filters with options. See #310230. - int dollar = filter.lastIndexOf(QLatin1Char('$')); - if (dollar != -1) { - return; - } - - // Perhaps nothing left? - if (first > last) - return; - - filter = filter.mid(first, last - first + 1); - - // Is it a regexp filter? - if (filter.length()>2 && filter.startsWith(QLatin1Char('/')) && filter.endsWith(QLatin1Char('/'))) - { - QString inside = filter.mid(1, filter.length()-2); - QRegExp rx(inside); - reFilters.append(rx); -// qDebug() << "R:" << inside; - } - else - { - // Nope, a wildcard one. - // Note: For these, we also need to handle |. - - // Strip wildcards at the ends - first = 0; - last = filter.length() - 1; - - while (first < filter.length() && filter[first] == QLatin1Char('*')) - ++first; - - while (last >= 0 && filter[last] == QLatin1Char('*')) - --last; - - if (first > last) - filter = QStringLiteral("*"); // erm... Well, they asked for it. - else - filter = filter.mid(first, last - first + 1); - - // Now, do we still have any wildcard stuff left? - if (filter.contains(QLatin1String("*"))) - { - // check if we can use RK first (and then check full RE for the rest) for better performance - int aPos = filter.indexOf('*'); - if (aPos < 0) - aPos = filter.length(); - if (aPos > 7) { - QRegExp rx = fromAdBlockWildcard(filter.mid(aPos) + QLatin1Char('*')); - // We pad the final r.e. with * so we can check for an exact match - stringFiltersMatcher->addWildedString(filter.mid(0, aPos), rx); - } else { - QRegExp rx = fromAdBlockWildcard(filter); - reFilters.append(rx); - } - } - else - { - // Fast path - stringFiltersMatcher->addString(filter); - } - } -} - -bool FilterSet::isUrlMatched(const QString& url) -{ - if (stringFiltersMatcher->isMatched(url)) - return true; - - for (int c = 0; c < reFilters.size(); ++c) - { - if (url.contains(reFilters[c])) - return true; - } - - return false; -} - -QString FilterSet::urlMatchedBy(const QString& url) -{ - QString by; - - if (stringFiltersMatcher->isMatched(url, &by)) - return by; - - for (int c = 0; c < reFilters.size(); ++c) - { - if (url.contains(reFilters[c])) - { - by = reFilters[c].pattern(); - break; - } - } - - return by; -} - -void FilterSet::clear() -{ - reFilters.clear(); - stringFiltersMatcher->clear(); -} - -// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; diff --git a/webenginepart/src/settings/webengine_filter.h a/webenginepart/src/settings/webengine_filter.h deleted file mode 100644 index 2c908a478..000000000 --- a/webenginepart/src/settings/webengine_filter.h +++ /dev/null @@ -1,60 +0,0 @@ -/* This file is part of the KDE project - - Copyright (C) 2005 Ivor Hewitt - Copyright (C) 2008 Maksim Orlovich - Copyright (C) 2008 Vyacheslav Tokarev - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef WEBENGNINE_FILTER_P_H -#define WEBENGNINE_FILTER_P_H - -#include -#include -#include -#include - -class StringsMatcher; - -namespace KDEPrivate -{ -// This represents a set of filters that may match URLs. -// Currently it supports a subset of AddBlock Plus functionality. -class FilterSet { -public: - FilterSet(); - ~FilterSet(); - - // Parses and registers a filter. This will also strip @@ for exclusion rules, skip comments, etc. - // The user does have to split black and white lists into separate sets, however - void addFilter(const QString& filter); - - bool isUrlMatched(const QString& url); - QString urlMatchedBy(const QString& url); - - void clear(); - -private: - QVector reFilters; - StringsMatcher* stringFiltersMatcher; -}; - -} - -#endif // WEBENGINE_FILTER_P_H - -// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; diff --git a/webenginepart/src/settings/webenginesettings.cpp a/webenginepart/src/settings/webenginesettings.cpp deleted file mode 100644 index d159d29c0..000000000 --- a/webenginepart/src/settings/webenginesettings.cpp +++ /dev/null @@ -1,1276 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 1999 David Faure - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "webenginesettings.h" - -#include "webengine_filter.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -// browser window color defaults -- Bernd -#define HTML_DEFAULT_LNK_COLOR Qt::blue -#define HTML_DEFAULT_TXT_COLOR Qt::black -#define HTML_DEFAULT_VLNK_COLOR Qt::magenta -#define HTML_DEFAULT_BASE_COLOR Qt::white - -#define HTML_DEFAULT_VIEW_FONT "Sans Serif" -#define HTML_DEFAULT_VIEW_FIXED_FONT "Monospace" -#define HTML_DEFAULT_VIEW_SERIF_FONT "Serif" -#define HTML_DEFAULT_VIEW_SANSSERIF_FONT "Sans Serif" -#define HTML_DEFAULT_VIEW_CURSIVE_FONT "Sans Serif" -#define HTML_DEFAULT_VIEW_FANTASY_FONT "Sans Serif" -#define HTML_DEFAULT_MIN_FONT_SIZE 7 // everything smaller is usually unreadable. - -/** - * @internal - * Contains all settings which are both available globally and per-domain - */ -struct KPerDomainSettings { - bool m_bEnableJava : 1; - bool m_bEnableJavaScript : 1; - bool m_bEnablePlugins : 1; - // don't forget to maintain the bitfields as the enums grow - KParts::HtmlSettingsInterface::JSWindowOpenPolicy m_windowOpenPolicy : 2; - KParts::HtmlSettingsInterface::JSWindowStatusPolicy m_windowStatusPolicy : 1; - KParts::HtmlSettingsInterface::JSWindowFocusPolicy m_windowFocusPolicy : 1; - KParts::HtmlSettingsInterface::JSWindowMovePolicy m_windowMovePolicy : 1; - KParts::HtmlSettingsInterface::JSWindowResizePolicy m_windowResizePolicy : 1; - -#ifdef DEBUG_SETTINGS - void dump(const QString &infix = QString()) const { - kDebug() << "KPerDomainSettings " << infix << " @" << this << ":"; - kDebug() << " m_bEnableJava: " << m_bEnableJava; - kDebug() << " m_bEnableJavaScript: " << m_bEnableJavaScript; - kDebug() << " m_bEnablePlugins: " << m_bEnablePlugins; - kDebug() << " m_windowOpenPolicy: " << m_windowOpenPolicy; - kDebug() << " m_windowStatusPolicy: " << m_windowStatusPolicy; - kDebug() << " m_windowFocusPolicy: " << m_windowFocusPolicy; - kDebug() << " m_windowMovePolicy: " << m_windowMovePolicy; - kDebug() << " m_windowResizePolicy: " << m_windowResizePolicy; - } -#endif -}; - -typedef QMap PolicyMap; - -class WebEngineSettingsData -{ -public: - bool m_bChangeCursor : 1; - bool m_bOpenMiddleClick : 1; - bool m_underlineLink : 1; - bool m_hoverLink : 1; - bool m_bEnableJavaScriptDebug : 1; - bool m_bEnableJavaScriptErrorReporting : 1; - bool enforceCharset : 1; - bool m_bAutoLoadImages : 1; - bool m_bUnfinishedImageFrame : 1; - bool m_formCompletionEnabled : 1; - bool m_autoDelayedActionsEnabled : 1; - bool m_jsErrorsEnabled : 1; - bool m_follow_system_colors : 1; - bool m_allowTabulation : 1; - bool m_autoSpellCheck : 1; - bool m_adFilterEnabled : 1; - bool m_hideAdsEnabled : 1; - bool m_jsPopupBlockerPassivePopup : 1; - bool m_accessKeysEnabled : 1; - bool m_zoomTextOnly : 1; - bool m_useCookieJar : 1; - bool m_bAutoRefreshPage: 1; - bool m_bEnableFavicon:1; - bool m_disableInternalPluginHandling:1; - bool m_offerToSaveWebSitePassword:1; - bool m_loadPluginsOnDemand:1; - bool m_enableLocalStorage:1; - bool m_enableOfflineStorageDb:1; - bool m_enableOfflineWebAppCache:1; - bool m_enableWebGL:1; - bool m_zoomToDPI:1; - bool m_allowActiveMixedContent:1; - bool m_allowMixedContentDisplay:1; - - // the virtual global "domain" - KPerDomainSettings global; - - int m_fontSize; - int m_minFontSize; - int m_maxFormCompletionItems; - WebEngineSettings::KAnimationAdvice m_showAnimations; - WebEngineSettings::KSmoothScrollingMode m_smoothScrolling; - - QString m_encoding; - QString m_userSheet; - - QColor m_textColor; - QColor m_baseColor; - QColor m_linkColor; - QColor m_vLinkColor; - - PolicyMap domainPolicy; - QStringList fonts; - QStringList defaultFonts; - - KDEPrivate::FilterSet adBlackList; - KDEPrivate::FilterSet adWhiteList; - QList< QPair< QString, QChar > > m_fallbackAccessKeysAssignments; - - KSharedConfig::Ptr nonPasswordStorableSites; -}; - -class WebEngineSettingsPrivate : public QObject, public WebEngineSettingsData -{ - Q_OBJECT -public: - void adblockFilterLoadList(const QString& filename) - { - /** load list file and process each line */ - QFile file(filename); - if (file.open(QIODevice::ReadOnly)) { - QTextStream ts(&file); - QString line = ts.readLine(); - while (!line.isEmpty()) { - //kDebug() << "Adding filter:" << line; - /** white list lines start with "@@" */ - if (line.startsWith(QLatin1String("@@"))) - adWhiteList.addFilter(line); - else - adBlackList.addFilter(line); - line = ts.readLine(); - } - file.close(); - } - } - -public Q_SLOTS: - void adblockFilterResult(KJob *job) - { - KIO::StoredTransferJob *tJob = qobject_cast(job); - Q_ASSERT(tJob); - - if ( job->error() == KJob::NoError ) - { - const QByteArray byteArray = tJob->data(); - const QString localFileName = tJob->property( "webenginesettings_adBlock_filename" ).toString(); - - QFile file(localFileName); - if ( file.open(QFile::WriteOnly) ) - { - const bool success = (file.write(byteArray) == byteArray.size()); - if ( success ) - adblockFilterLoadList(localFileName); - else - qWarning() << "Could not write" << byteArray.size() << "to file" << localFileName; - file.close(); - } - else - qDebug() << "Cannot open file" << localFileName << "for filter list"; - } - else - qDebug() << "Downloading" << tJob->url() << "failed with message:" << job->errorText(); - } -}; - - -/** Returns a writeable per-domains settings instance for the given domain - * or a deep copy of the global settings if not existent. - */ -static KPerDomainSettings &setup_per_domain_policy(WebEngineSettingsPrivate* const d, const QString &domain) -{ - if (domain.isEmpty()) - qWarning() << "setup_per_domain_policy: domain is empty"; - - const QString ldomain = domain.toLower(); - PolicyMap::iterator it = d->domainPolicy.find(ldomain); - if (it == d->domainPolicy.end()) { - // simply copy global domain settings (they should have been initialized - // by this time) - it = d->domainPolicy.insert(ldomain,d->global); - } - return *it; -} - -template -static T readEntry(const KConfigGroup& config, const QString& key, int defaultValue) -{ - return static_cast(config.readEntry(key, defaultValue)); -} - -void WebEngineSettings::readDomainSettings(const KConfigGroup &config, bool reset, - bool global, KPerDomainSettings &pd_settings) -{ - const QString javaPrefix ((global ? QString() : QStringLiteral("java."))); - const QString jsPrefix ((global ? QString() : QStringLiteral("javascript."))); - const QString pluginsPrefix (global ? QString() : QStringLiteral("plugins.")); - - // The setting for Java - QString key = javaPrefix + QLatin1String("EnableJava"); - if ( (global && reset) || config.hasKey( key ) ) - pd_settings.m_bEnableJava = config.readEntry( key, false ); - else if ( !global ) - pd_settings.m_bEnableJava = d->global.m_bEnableJava; - - // The setting for Plugins - key = pluginsPrefix + QLatin1String("EnablePlugins"); - if ( (global && reset) || config.hasKey( key ) ) - pd_settings.m_bEnablePlugins = config.readEntry( key, true ); - else if ( !global ) - pd_settings.m_bEnablePlugins = d->global.m_bEnablePlugins; - - // The setting for JavaScript - key = jsPrefix + QLatin1String("EnableJavaScript"); - if ( (global && reset) || config.hasKey( key ) ) - pd_settings.m_bEnableJavaScript = config.readEntry( key, true ); - else if ( !global ) - pd_settings.m_bEnableJavaScript = d->global.m_bEnableJavaScript; - - // window property policies - key = jsPrefix + QLatin1String("WindowOpenPolicy"); - if ( (global && reset) || config.hasKey( key ) ) - pd_settings.m_windowOpenPolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowOpenSmart); - else if ( !global ) - pd_settings.m_windowOpenPolicy = d->global.m_windowOpenPolicy; - - key = jsPrefix + QLatin1String("WindowMovePolicy"); - if ( (global && reset) || config.hasKey( key ) ) - pd_settings.m_windowMovePolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowMoveAllow); - else if ( !global ) - pd_settings.m_windowMovePolicy = d->global.m_windowMovePolicy; - - key = jsPrefix + QLatin1String("WindowResizePolicy"); - if ( (global && reset) || config.hasKey( key ) ) - pd_settings.m_windowResizePolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowResizeAllow); - else if ( !global ) - pd_settings.m_windowResizePolicy = d->global.m_windowResizePolicy; - - key = jsPrefix + QLatin1String("WindowStatusPolicy"); - if ( (global && reset) || config.hasKey( key ) ) - pd_settings.m_windowStatusPolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowStatusAllow); - else if ( !global ) - pd_settings.m_windowStatusPolicy = d->global.m_windowStatusPolicy; - - key = jsPrefix + QLatin1String("WindowFocusPolicy"); - if ( (global && reset) || config.hasKey( key ) ) - pd_settings.m_windowFocusPolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowFocusAllow); - else if ( !global ) - pd_settings.m_windowFocusPolicy = d->global.m_windowFocusPolicy; -} - - -WebEngineSettings::WebEngineSettings() - :d (new WebEngineSettingsPrivate) -{ - init(); -} - -WebEngineSettings::~WebEngineSettings() -{ - delete d; -} - -bool WebEngineSettings::changeCursor() const -{ - return d->m_bChangeCursor; -} - -bool WebEngineSettings::underlineLink() const -{ - return d->m_underlineLink; -} - -bool WebEngineSettings::hoverLink() const -{ - return d->m_hoverLink; -} - -void WebEngineSettings::init() -{ - initWebEngineSettings(); - - KConfig global( QStringLiteral("khtmlrc"), KConfig::NoGlobals ); - init( &global, true ); - - KSharedConfig::Ptr local = KSharedConfig::openConfig(); - if ( local ) { - init( local.data(), false ); - } - - initNSPluginSettings(); - initCookieJarSettings(); -} - -void WebEngineSettings::init( KConfig * config, bool reset ) -{ - KConfigGroup cg( config, "MainView Settings" ); - if (reset || cg.exists() ) - { - if ( reset || cg.hasKey( "OpenMiddleClick" ) ) - d->m_bOpenMiddleClick = cg.readEntry( "OpenMiddleClick", true ); - } - - KConfigGroup cgAccess(config,"Access Keys" ); - if (reset || cgAccess.exists() ) { - d->m_accessKeysEnabled = cgAccess.readEntry( "Enabled", true ); - } - - KConfigGroup cgFilter( config, "Filter Settings" ); - - if ((reset || cgFilter.exists()) && (d->m_adFilterEnabled = cgFilter.readEntry("Enabled", false))) - { - d->m_hideAdsEnabled = cgFilter.readEntry("Shrink", false); - - d->adBlackList.clear(); - d->adWhiteList.clear(); - - /** read maximum age for filter list files, minimum is one day */ - int htmlFilterListMaxAgeDays = cgFilter.readEntry(QStringLiteral("HTMLFilterListMaxAgeDays")).toInt(); - if (htmlFilterListMaxAgeDays < 1) - htmlFilterListMaxAgeDays = 1; - - QMapIterator it (cgFilter.entryMap()); - while (it.hasNext()) - { - it.next(); - int id = -1; - const QString name = it.key(); - const QString url = it.value(); - - if (name.startsWith(QLatin1String("Filter"))) - { - if (url.startsWith(QLatin1String("@@"))) - d->adWhiteList.addFilter(url); - else - d->adBlackList.addFilter(url); - } - else if (name.startsWith(QLatin1String("HTMLFilterListName-")) && (id = name.midRef(19).toInt()) > 0) - { - /** check if entry is enabled */ - bool filterEnabled = cgFilter.readEntry(QStringLiteral("HTMLFilterListEnabled-").append(QString::number(id))) != QLatin1String("false"); - - /** get url for HTMLFilterList */ - QUrl url(cgFilter.readEntry(QStringLiteral("HTMLFilterListURL-").append(QString::number(id)))); - - if (filterEnabled && url.isValid()) { - /** determine where to cache HTMLFilterList file */ - QString localFile = cgFilter.readEntry(QStringLiteral("HTMLFilterListLocalFilename-").append(QString::number(id))); - localFile = QStandardPaths::locate(QStandardPaths::ConfigLocation, "khtml/" + localFile); - - /** determine existence and age of cache file */ - QFileInfo fileInfo(localFile); - - /** load cached file if it exists, irrespective of age */ - if (fileInfo.exists()) - d->adblockFilterLoadList( localFile ); - - /** if no cache list file exists or if it is too old ... */ - if (!fileInfo.exists() || fileInfo.lastModified().daysTo(QDateTime::currentDateTime()) > htmlFilterListMaxAgeDays) - { - /** ... in this case, refetch list asynchronously */ - // kDebug() << "Fetching filter list from" << url << "to" << localFile; - KIO::StoredTransferJob *job = KIO::storedGet( url, KIO::Reload, KIO::HideProgressInfo ); - QObject::connect( job, SIGNAL(result(KJob*)), d, SLOT(adblockFilterResult(KJob*)) ); - /** for later reference, store name of cache file */ - job->setProperty("webenginesettings_adBlock_filename", localFile); - } - } - } - } - } - - KConfigGroup cgHtml( config, "HTML Settings" ); - if (reset || cgHtml.exists() ) - { - // Fonts and colors - if( reset ) { - d->defaultFonts = QStringList(); - d->defaultFonts.append( cgHtml.readEntry( "StandardFont", QFontDatabase::systemFont(QFontDatabase::GeneralFont).family() ) ); - d->defaultFonts.append( cgHtml.readEntry( "FixedFont", QFontDatabase::systemFont(QFontDatabase::FixedFont).family() )); - d->defaultFonts.append( cgHtml.readEntry( "SerifFont", HTML_DEFAULT_VIEW_SERIF_FONT ) ); - d->defaultFonts.append( cgHtml.readEntry( "SansSerifFont", HTML_DEFAULT_VIEW_SANSSERIF_FONT ) ); - d->defaultFonts.append( cgHtml.readEntry( "CursiveFont", HTML_DEFAULT_VIEW_CURSIVE_FONT ) ); - d->defaultFonts.append( cgHtml.readEntry( "FantasyFont", HTML_DEFAULT_VIEW_FANTASY_FONT ) ); - d->defaultFonts.append( QStringLiteral( "0" ) ); // font size adjustment - } - - if ( reset || cgHtml.hasKey( "MinimumFontSize" ) ) - d->m_minFontSize = cgHtml.readEntry( "MinimumFontSize", HTML_DEFAULT_MIN_FONT_SIZE ); - - if ( reset || cgHtml.hasKey( "MediumFontSize" ) ) - d->m_fontSize = cgHtml.readEntry( "MediumFontSize", 12 ); - - d->fonts = cgHtml.readEntry( "Fonts", QStringList() ); - - if ( reset || cgHtml.hasKey( "DefaultEncoding" ) ) - d->m_encoding = cgHtml.readEntry( "DefaultEncoding", "" ); - - if ( reset || cgHtml.hasKey( "EnforceDefaultCharset" ) ) - d->enforceCharset = cgHtml.readEntry( "EnforceDefaultCharset", false ); - - // Behavior - - if ( reset || cgHtml.hasKey("UnderlineLinks") ) - d->m_underlineLink = cgHtml.readEntry( "UnderlineLinks", true ); - - if ( reset || cgHtml.hasKey( "HoverLinks" ) ) - { - if ( (d->m_hoverLink = cgHtml.readEntry( "HoverLinks", false ))) - d->m_underlineLink = false; - } - - if ( reset || cgHtml.hasKey( "AllowTabulation" ) ) - d->m_allowTabulation = cgHtml.readEntry( "AllowTabulation", false ); - - if ( reset || cgHtml.hasKey( "AutoSpellCheck" ) ) - d->m_autoSpellCheck = cgHtml.readEntry( "AutoSpellCheck", true ); - - // Other - if ( reset || cgHtml.hasKey( "AutoLoadImages" ) ) - d->m_bAutoLoadImages = cgHtml.readEntry( "AutoLoadImages", true ); - - if ( reset || cgHtml.hasKey( "AutoDelayedActions" ) ) - d->m_bAutoRefreshPage = cgHtml.readEntry( "AutoDelayedActions", true ); - - if ( reset || cgHtml.hasKey( "UnfinishedImageFrame" ) ) - d->m_bUnfinishedImageFrame = cgHtml.readEntry( "UnfinishedImageFrame", true ); - - if ( reset || cgHtml.hasKey( "ShowAnimations" ) ) - { - QString value = cgHtml.readEntry( "ShowAnimations").toLower(); - if (value == QLatin1String("disabled")) - d->m_showAnimations = KAnimationDisabled; - else if (value == QLatin1String("looponce")) - d->m_showAnimations = KAnimationLoopOnce; - else - d->m_showAnimations = KAnimationEnabled; - } - - if ( reset || cgHtml.hasKey( "SmoothScrolling" ) ) - { - QString value = cgHtml.readEntry( "SmoothScrolling", "whenefficient" ).toLower(); - if (value == QLatin1String("disabled")) - d->m_smoothScrolling = KSmoothScrollingDisabled; - else if (value == QLatin1String("whenefficient")) - d->m_smoothScrolling = KSmoothScrollingWhenEfficient; - else - d->m_smoothScrolling = KSmoothScrollingEnabled; - } - - if ( reset || cgHtml.hasKey( "ZoomTextOnly" ) ) { - d->m_zoomTextOnly = cgHtml.readEntry( "ZoomTextOnly", false ); - } - - if ( reset || cgHtml.hasKey( "ZoomToDPI" ) ) { - d->m_zoomToDPI = cgHtml.readEntry( "ZoomToDPI", false ); - } - - if (cgHtml.readEntry("UserStyleSheetEnabled", false)) { - if (reset || cgHtml.hasKey("UserStyleSheet")) - d->m_userSheet = cgHtml.readEntry("UserStyleSheet", QString()); - } else { - d->m_userSheet.clear(); - } - - d->m_formCompletionEnabled = cgHtml.readEntry("FormCompletion", true); - d->m_maxFormCompletionItems = cgHtml.readEntry("MaxFormCompletionItems", 10); - d->m_autoDelayedActionsEnabled = cgHtml.readEntry ("AutoDelayedActions", true); - d->m_jsErrorsEnabled = cgHtml.readEntry("ReportJSErrors", true); - const QStringList accesskeys = cgHtml.readEntry("FallbackAccessKeysAssignments", QStringList()); - d->m_fallbackAccessKeysAssignments.clear(); - for( QStringList::ConstIterator it = accesskeys.begin(); it != accesskeys.end(); ++it ) - if( (*it).length() > 2 && (*it)[ 1 ] == ':' ) - d->m_fallbackAccessKeysAssignments.append( qMakePair( (*it).mid( 2 ), (*it)[ 0 ] )); - - d->m_bEnableFavicon = cgHtml.readEntry("EnableFavicon", true); - d->m_offerToSaveWebSitePassword = cgHtml.readEntry("OfferToSaveWebsitePassword", true); - } - - // Colors - //In which group ????? - if ( reset || cg.hasKey( "FollowSystemColors" ) ) - d->m_follow_system_colors = cg.readEntry( "FollowSystemColors", false ); - - KConfigGroup cgGeneral( config, "General" ); - if ( reset || cgGeneral.exists( ) ) - { - if ( reset || cgGeneral.hasKey( "foreground" ) ) { - QColor def(HTML_DEFAULT_TXT_COLOR); - d->m_textColor = cgGeneral.readEntry( "foreground", def ); - } - - if ( reset || cgGeneral.hasKey( "linkColor" ) ) { - QColor def(HTML_DEFAULT_LNK_COLOR); - d->m_linkColor = cgGeneral.readEntry( "linkColor", def ); - } - - if ( reset || cgGeneral.hasKey( "visitedLinkColor" ) ) { - QColor def(HTML_DEFAULT_VLNK_COLOR); - d->m_vLinkColor = cgGeneral.readEntry( "visitedLinkColor", def); - } - - if ( reset || cgGeneral.hasKey( "background" ) ) { - QColor def(HTML_DEFAULT_BASE_COLOR); - d->m_baseColor = cgGeneral.readEntry( "background", def); - } - } - - KConfigGroup cgJava( config, "Java/JavaScript Settings" ); - if( reset || cgJava.exists() ) - { - // The global setting for JavaScript debugging - // This is currently always enabled by default - if ( reset || cgJava.hasKey( "EnableJavaScriptDebug" ) ) - d->m_bEnableJavaScriptDebug = cgJava.readEntry( "EnableJavaScriptDebug", false ); - - // The global setting for JavaScript error reporting - if ( reset || cgJava.hasKey( "ReportJavaScriptErrors" ) ) - d->m_bEnableJavaScriptErrorReporting = cgJava.readEntry( "ReportJavaScriptErrors", false ); - - // The global setting for popup block passive popup - if ( reset || cgJava.hasKey( "PopupBlockerPassivePopup" ) ) - d->m_jsPopupBlockerPassivePopup = cgJava.readEntry("PopupBlockerPassivePopup", true ); - - // Read options from the global "domain" - readDomainSettings(cgJava,reset,true,d->global); -#ifdef DEBUG_SETTINGS - d->global.dump("init global"); -#endif - - // The domain-specific settings. - - static const char *const domain_keys[] = { // always keep order of keys - "ECMADomains", "JavaDomains", "PluginDomains" - }; - bool check_old_ecma_settings = true; - bool check_old_java_settings = true; - // merge all domains into one list - QSet domainList; - for (unsigned i = 0; i < sizeof domain_keys/sizeof domain_keys[0]; ++i) { - if (reset || cgJava.hasKey(domain_keys[i])) { - if (i == 0) check_old_ecma_settings = false; - else if (i == 1) check_old_java_settings = false; - const QStringList dl = cgJava.readEntry( domain_keys[i], QStringList() ); - const QSet::Iterator notfound = domainList.end(); - QStringList::ConstIterator it = dl.begin(); - const QStringList::ConstIterator itEnd = dl.end(); - for (; it != itEnd; ++it) { - const QString domain = (*it).toLower(); - QSet::Iterator pos = domainList.find(domain); - if (pos == notfound) domainList.insert(domain); - }/*next it*/ - } - }/*next i*/ - - if (reset) - d->domainPolicy.clear(); - - { - QSet::ConstIterator it = domainList.constBegin(); - const QSet::ConstIterator itEnd = domainList.constEnd(); - for ( ; it != itEnd; ++it) - { - const QString domain = *it; - KConfigGroup cg( config, domain ); - readDomainSettings(cg,reset,false,d->domainPolicy[domain]); -#ifdef DEBUG_SETTINGS - d->domainPolicy[domain].dump("init "+domain); -#endif - } - } - - bool check_old_java = true; - if( (reset || cgJava.hasKey("JavaDomainSettings")) && check_old_java_settings) - { - check_old_java = false; - const QStringList domainList = cgJava.readEntry( "JavaDomainSettings", QStringList() ); - QStringList::ConstIterator it = domainList.constBegin(); - const QStringList::ConstIterator itEnd = domainList.constEnd(); - for ( ; it != itEnd; ++it) - { - QString domain; - KParts::HtmlSettingsInterface::JavaScriptAdvice javaAdvice; - KParts::HtmlSettingsInterface::JavaScriptAdvice javaScriptAdvice; - KParts::HtmlSettingsInterface::splitDomainAdvice(*it, domain, javaAdvice, javaScriptAdvice); - setup_per_domain_policy(d,domain).m_bEnableJava = javaAdvice == KParts::HtmlSettingsInterface::JavaScriptAccept; -#ifdef DEBUG_SETTINGS - setup_per_domain_policy(d,domain).dump("JavaDomainSettings 4 "+domain); -#endif - } - } - - bool check_old_ecma = true; - if( ( reset || cgJava.hasKey( "ECMADomainSettings" ) ) && check_old_ecma_settings ) - { - check_old_ecma = false; - const QStringList domainList = cgJava.readEntry( "ECMADomainSettings", QStringList() ); - QStringList::ConstIterator it = domainList.constBegin(); - const QStringList::ConstIterator itEnd = domainList.constEnd(); - for ( ; it != itEnd; ++it) - { - QString domain; - KParts::HtmlSettingsInterface::JavaScriptAdvice javaAdvice; - KParts::HtmlSettingsInterface::JavaScriptAdvice javaScriptAdvice; - KParts::HtmlSettingsInterface::splitDomainAdvice(*it, domain, javaAdvice, javaScriptAdvice); - setup_per_domain_policy(d,domain).m_bEnableJavaScript = javaScriptAdvice == KParts::HtmlSettingsInterface::JavaScriptAccept; -#ifdef DEBUG_SETTINGS - setup_per_domain_policy(d,domain).dump("ECMADomainSettings 4 "+domain); -#endif - } - } - - if( ( reset || cgJava.hasKey( "JavaScriptDomainAdvice" ) ) - && ( check_old_java || check_old_ecma ) - && ( check_old_ecma_settings || check_old_java_settings ) ) - { - const QStringList domainList = cgJava.readEntry( "JavaScriptDomainAdvice", QStringList() ); - QStringList::ConstIterator it = domainList.constBegin(); - const QStringList::ConstIterator itEnd = domainList.constEnd(); - for ( ; it != itEnd; ++it) - { - QString domain; - KParts::HtmlSettingsInterface::JavaScriptAdvice javaAdvice; - KParts::HtmlSettingsInterface::JavaScriptAdvice javaScriptAdvice; - KParts::HtmlSettingsInterface::splitDomainAdvice(*it, domain, javaAdvice, javaScriptAdvice); - if( check_old_java ) - setup_per_domain_policy(d,domain).m_bEnableJava = javaAdvice == KParts::HtmlSettingsInterface::JavaScriptAccept; - if( check_old_ecma ) - setup_per_domain_policy(d,domain).m_bEnableJavaScript = javaScriptAdvice == KParts::HtmlSettingsInterface::JavaScriptAccept; -#ifdef DEBUG_SETTINGS - setup_per_domain_policy(d,domain).dump("JavaScriptDomainAdvice 4 "+domain); -#endif - } - } - } - -#if 0 - // DNS Prefect support... - if ( reset || cgHtml.hasKey( "DNSPrefetch" ) ) - { - // Enabled, Disabled, OnlyWWWAndSLD - QString value = cgHtml.readEntry( "DNSPrefetch", "Enabled" ).toLower(); - - if (value == "enabled") - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::DnsPrefetchEnabled, true); - else - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::DnsPrefetchEnabled, false); - } - - // Sync with QWebEngineSettings. - if (!d->m_encoding.isEmpty()) - QWebEngineSettings::globalSettings()->setDefaultTextEncoding(d->m_encoding); - QWebEngineSettings::globalSettings()->setUserStyleSheetUrl(QUrl::fromUserInput(userStyleSheet())); -#endif - - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::AutoLoadImages, autoLoadImages()); - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::JavascriptEnabled, isJavaScriptEnabled()); - // QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::JavaEnabled, isJavaEnabled()); - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::PluginsEnabled, isPluginsEnabled()); - - // By default disable JS window.open when policy is deny or smart. - const KParts::HtmlSettingsInterface::JSWindowOpenPolicy policy = windowOpenPolicy(); - if (policy == KParts::HtmlSettingsInterface::JSWindowOpenDeny || policy == KParts::HtmlSettingsInterface::JSWindowOpenSmart) - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false); - else - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); - -// QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::ZoomTextOnly, zoomTextOnly()); -// QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, isJavaScriptDebugEnabled()); - QWebEngineSettings::globalSettings()->setFontFamily(QWebEngineSettings::StandardFont, stdFontName()); - QWebEngineSettings::globalSettings()->setFontFamily(QWebEngineSettings::FixedFont, fixedFontName()); - QWebEngineSettings::globalSettings()->setFontFamily(QWebEngineSettings::SerifFont, serifFontName()); - QWebEngineSettings::globalSettings()->setFontFamily(QWebEngineSettings::SansSerifFont, sansSerifFontName()); - QWebEngineSettings::globalSettings()->setFontFamily(QWebEngineSettings::CursiveFont, cursiveFontName()); - QWebEngineSettings::globalSettings()->setFontFamily(QWebEngineSettings::FantasyFont, fantasyFontName()); - - // TODO: Create a webengine config module that gets embeded into Konqueror's kcm. - // Turn on WebGL support -// QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::WebGLEnabled, d->m_enableWebGL); - // Turn on HTML 5 local and offline storage capabilities... -// QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::OfflineStorageDatabaseEnabled, d->m_enableOfflineStorageDb); -// QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::OfflineWebApplicationCacheEnabled, d->m_enableOfflineWebAppCache); - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, d->m_enableLocalStorage); - - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, smoothScrolling() != KSmoothScrollingDisabled); - - // These numbers should be calculated from real "logical" DPI/72, using a default dpi of 96 for now - computeFontSizes(96); -} - - -void WebEngineSettings::computeFontSizes( int logicalDpi ) -{ - if (zoomToDPI()) - logicalDpi = 96; - - float toPix = logicalDpi/72.0; - - if (toPix < 96.0/72.0) - toPix = 96.0/72.0; - - QWebEngineSettings::globalSettings()->setFontSize(QWebEngineSettings::MinimumFontSize, qRound(minFontSize() * toPix)); - QWebEngineSettings::globalSettings()->setFontSize(QWebEngineSettings::DefaultFontSize, qRound(mediumFontSize() * toPix)); -} - -bool WebEngineSettings::zoomToDPI() const -{ - return d->m_zoomToDPI; -} - -void WebEngineSettings::setZoomToDPI(bool enabled) -{ - d->m_zoomToDPI = enabled; - // save it - KConfigGroup cg( KSharedConfig::openConfig(), "HTML Settings"); - cg.writeEntry("ZoomToDPI", enabled); - cg.sync(); -} - -/** Local helper for retrieving per-domain settings. - * - * In case of doubt, the global domain is returned. - */ -static const KPerDomainSettings& lookup_hostname_policy(const WebEngineSettingsPrivate* const d, - const QString& hostname) -{ -#ifdef DEBUG_SETTINGS - kDebug() << "lookup_hostname_policy(" << hostname << ")"; -#endif - if (hostname.isEmpty()) { -#ifdef DEBUG_SETTINGS - d->global.dump("global"); -#endif - return d->global; - } - - const PolicyMap::const_iterator notfound = d->domainPolicy.constEnd(); - - // First check whether there is a perfect match. - PolicyMap::const_iterator it = d->domainPolicy.find(hostname); - if( it != notfound ) { -#ifdef DEBUG_SETTINGS - kDebug() << "perfect match"; - (*it).dump(hostname); -#endif - // yes, use it (unless dunno) - return *it; - } - - // Now, check for partial match. Chop host from the left until - // there's no dots left. - QString host_part = hostname; - int dot_idx = -1; - while( (dot_idx = host_part.indexOf(QChar('.'))) >= 0 ) { - host_part.remove(0,dot_idx); - it = d->domainPolicy.find(host_part); - Q_ASSERT(notfound == d->domainPolicy.end()); - if( it != notfound ) { -#ifdef DEBUG_SETTINGS - kDebug() << "partial match"; - (*it).dump(host_part); -#endif - return *it; - } - // assert(host_part[0] == QChar('.')); - host_part.remove(0,1); // Chop off the dot. - } - - // No domain-specific entry: use global domain -#ifdef DEBUG_SETTINGS - kDebug() << "no match"; - d->global.dump("global"); -#endif - return d->global; -} - -bool WebEngineSettings::isOpenMiddleClickEnabled() -{ - return d->m_bOpenMiddleClick; -} - -bool WebEngineSettings::accessKeysEnabled() const -{ - return d->m_accessKeysEnabled; -} - -bool WebEngineSettings::favIconsEnabled() const -{ - return d->m_bEnableFavicon; -} - -bool WebEngineSettings::isAdFilterEnabled() const -{ - return d->m_adFilterEnabled; -} - -bool WebEngineSettings::isHideAdsEnabled() const -{ - return d->m_hideAdsEnabled; -} - -bool WebEngineSettings::isAdFiltered( const QString &url ) const -{ - if (!d->m_adFilterEnabled) - return false; - - if (url.startsWith(QLatin1String("data:"))) - return false; - - return d->adBlackList.isUrlMatched(url) && !d->adWhiteList.isUrlMatched(url); -} - -QString WebEngineSettings::adFilteredBy( const QString &url, bool *isWhiteListed ) const -{ - QString m = d->adWhiteList.urlMatchedBy(url); - - if (!m.isEmpty()) { - if (isWhiteListed != 0) - *isWhiteListed = true; - return m; - } - - m = d->adBlackList.urlMatchedBy(url); - if (m.isEmpty()) - return QString(); - - if (isWhiteListed != 0) - *isWhiteListed = false; - return m; -} - -void WebEngineSettings::addAdFilter( const QString &url ) -{ - KConfigGroup config = KSharedConfig::openConfig( QStringLiteral("khtmlrc"), KConfig::NoGlobals )->group( "Filter Settings" ); - - QRegExp rx; - - // Try compiling to avoid invalid stuff. Only support the basic syntax here... - // ### refactor somewhat - if (url.length()>2 && url[0]=='/' && url[url.length()-1] == '/') - { - const QString inside = url.mid(1, url.length()-2); - rx.setPattern(inside); - } - else - { - rx.setPatternSyntax(QRegExp::Wildcard); - rx.setPattern(url); - } - - if (rx.isValid()) - { - int last=config.readEntry("Count", 0); - const QString key = "Filter-" + QString::number(last); - config.writeEntry(key, url); - config.writeEntry("Count",last+1); - config.sync(); - - if (url.startsWith(QLatin1String("@@"))) - d->adWhiteList.addFilter(url); - else - d->adBlackList.addFilter(url); - } - else - { - KMessageBox::error(0, - rx.errorString(), - i18n("Filter error")); - } -} - -bool WebEngineSettings::isJavaEnabled( const QString& hostname ) const -{ - return lookup_hostname_policy(d,hostname.toLower()).m_bEnableJava; -} - -bool WebEngineSettings::isJavaScriptEnabled( const QString& hostname ) const -{ - return lookup_hostname_policy(d,hostname.toLower()).m_bEnableJavaScript; -} - -bool WebEngineSettings::isJavaScriptDebugEnabled( const QString& /*hostname*/ ) const -{ - // debug setting is global for now, but could change in the future - return d->m_bEnableJavaScriptDebug; -} - -bool WebEngineSettings::isJavaScriptErrorReportingEnabled( const QString& /*hostname*/ ) const -{ - // error reporting setting is global for now, but could change in the future - return d->m_bEnableJavaScriptErrorReporting; -} - -bool WebEngineSettings::isPluginsEnabled( const QString& hostname ) const -{ - return lookup_hostname_policy(d,hostname.toLower()).m_bEnablePlugins; -} - -KParts::HtmlSettingsInterface::JSWindowOpenPolicy WebEngineSettings::windowOpenPolicy(const QString& hostname) const { - return lookup_hostname_policy(d,hostname.toLower()).m_windowOpenPolicy; -} - -KParts::HtmlSettingsInterface::JSWindowMovePolicy WebEngineSettings::windowMovePolicy(const QString& hostname) const { - return lookup_hostname_policy(d,hostname.toLower()).m_windowMovePolicy; -} - -KParts::HtmlSettingsInterface::JSWindowResizePolicy WebEngineSettings::windowResizePolicy(const QString& hostname) const { - return lookup_hostname_policy(d,hostname.toLower()).m_windowResizePolicy; -} - -KParts::HtmlSettingsInterface::JSWindowStatusPolicy WebEngineSettings::windowStatusPolicy(const QString& hostname) const { - return lookup_hostname_policy(d,hostname.toLower()).m_windowStatusPolicy; -} - -KParts::HtmlSettingsInterface::JSWindowFocusPolicy WebEngineSettings::windowFocusPolicy(const QString& hostname) const { - return lookup_hostname_policy(d,hostname.toLower()).m_windowFocusPolicy; -} - -int WebEngineSettings::mediumFontSize() const -{ - return d->m_fontSize; -} - -int WebEngineSettings::minFontSize() const -{ - return d->m_minFontSize; -} - -QString WebEngineSettings::settingsToCSS() const -{ - // lets start with the link properties - QString str = QStringLiteral("a:link {\ncolor: "); - str += d->m_linkColor.name(); - str += ';'; - if(d->m_underlineLink) - str += QLatin1String("\ntext-decoration: underline;"); - - if( d->m_bChangeCursor ) - { - str += QLatin1String("\ncursor: pointer;"); - str += QLatin1String("\n}\ninput[type=image] { cursor: pointer;"); - } - str += QLatin1String("\n}\n"); - str += QLatin1String("a:visited {\ncolor: "); - str += d->m_vLinkColor.name(); - str += ';'; - if(d->m_underlineLink) - str += QLatin1String("\ntext-decoration: underline;"); - - if( d->m_bChangeCursor ) - str += QLatin1String("\ncursor: pointer;"); - str += QLatin1String("\n}\n"); - - if(d->m_hoverLink) - str += QLatin1String("a:link:hover, a:visited:hover { text-decoration: underline; }\n"); - - return str; -} - -QString WebEngineSettings::lookupFont(int i) const -{ - if (d->fonts.count() > i) { - return d->fonts.at(i); - } - - if (d->defaultFonts.count() > i) { - return d->defaultFonts.at(i); - } - - return QString(); -} - -QString WebEngineSettings::stdFontName() const -{ - return lookupFont(0); -} - -QString WebEngineSettings::fixedFontName() const -{ - return lookupFont(1); -} - -QString WebEngineSettings::serifFontName() const -{ - return lookupFont(2); -} - -QString WebEngineSettings::sansSerifFontName() const -{ - return lookupFont(3); -} - -QString WebEngineSettings::cursiveFontName() const -{ - return lookupFont(4); -} - -QString WebEngineSettings::fantasyFontName() const -{ - return lookupFont(5); -} - -void WebEngineSettings::setStdFontName(const QString &n) -{ - while(d->fonts.count() <= 0) - d->fonts.append(QString()); - d->fonts[0] = n; -} - -void WebEngineSettings::setFixedFontName(const QString &n) -{ - while(d->fonts.count() <= 1) - d->fonts.append(QString()); - d->fonts[1] = n; -} - -QString WebEngineSettings::userStyleSheet() const -{ - return d->m_userSheet; -} - -bool WebEngineSettings::isFormCompletionEnabled() const -{ - return d->m_formCompletionEnabled; -} - -int WebEngineSettings::maxFormCompletionItems() const -{ - return d->m_maxFormCompletionItems; -} - -const QString &WebEngineSettings::encoding() const -{ - return d->m_encoding; -} - -bool WebEngineSettings::followSystemColors() const -{ - return d->m_follow_system_colors; -} - -const QColor& WebEngineSettings::textColor() const -{ - return d->m_textColor; -} - -const QColor& WebEngineSettings::baseColor() const -{ - return d->m_baseColor; -} - -const QColor& WebEngineSettings::linkColor() const -{ - return d->m_linkColor; -} - -const QColor& WebEngineSettings::vLinkColor() const -{ - return d->m_vLinkColor; -} - -bool WebEngineSettings::autoPageRefresh() const -{ - return d->m_bAutoRefreshPage; -} - -bool WebEngineSettings::autoLoadImages() const -{ - return d->m_bAutoLoadImages; -} - -bool WebEngineSettings::unfinishedImageFrame() const -{ - return d->m_bUnfinishedImageFrame; -} - -WebEngineSettings::KAnimationAdvice WebEngineSettings::showAnimations() const -{ - return d->m_showAnimations; -} - -WebEngineSettings::KSmoothScrollingMode WebEngineSettings::smoothScrolling() const -{ - return d->m_smoothScrolling; -} - -bool WebEngineSettings::zoomTextOnly() const -{ - return d->m_zoomTextOnly; -} - -bool WebEngineSettings::isAutoDelayedActionsEnabled() const -{ - return d->m_autoDelayedActionsEnabled; -} - -bool WebEngineSettings::jsErrorsEnabled() const -{ - return d->m_jsErrorsEnabled; -} - -void WebEngineSettings::setJSErrorsEnabled(bool enabled) -{ - d->m_jsErrorsEnabled = enabled; - // save it - KConfigGroup cg( KSharedConfig::openConfig(), "HTML Settings"); - cg.writeEntry("ReportJSErrors", enabled); - cg.sync(); -} - -bool WebEngineSettings::allowTabulation() const -{ - return d->m_allowTabulation; -} - -bool WebEngineSettings::autoSpellCheck() const -{ - return d->m_autoSpellCheck; -} - -QList< QPair< QString, QChar > > WebEngineSettings::fallbackAccessKeysAssignments() const -{ - return d->m_fallbackAccessKeysAssignments; -} - -void WebEngineSettings::setJSPopupBlockerPassivePopup(bool enabled) -{ - d->m_jsPopupBlockerPassivePopup = enabled; - // save it - KConfigGroup cg( KSharedConfig::openConfig(), "Java/JavaScript Settings"); - cg.writeEntry("PopupBlockerPassivePopup", enabled); - cg.sync(); -} - -bool WebEngineSettings::jsPopupBlockerPassivePopup() const -{ - return d->m_jsPopupBlockerPassivePopup; -} - -bool WebEngineSettings::isCookieJarEnabled() const -{ - return d->m_useCookieJar; -} - -// Password storage... -static KConfigGroup nonPasswordStorableSitesCg(KSharedConfig::Ptr& configPtr) -{ - if (!configPtr) { - configPtr = KSharedConfig::openConfig(QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("khtml/formcompletions")), KConfig::NoGlobals); - } - - return KConfigGroup(configPtr, "NonPasswordStorableSites"); -} - -bool WebEngineSettings::isNonPasswordStorableSite(const QString &host) const -{ - KConfigGroup cg = nonPasswordStorableSitesCg(d->nonPasswordStorableSites); - const QStringList sites = cg.readEntry("Sites", QStringList()); - return sites.contains(host); -} - -void WebEngineSettings::addNonPasswordStorableSite(const QString &host) -{ - KConfigGroup cg = nonPasswordStorableSitesCg(d->nonPasswordStorableSites); - QStringList sites = cg.readEntry("Sites", QStringList()); - sites.append(host); - cg.writeEntry("Sites", sites); - cg.sync(); -} - -void WebEngineSettings::removeNonPasswordStorableSite(const QString &host) -{ - KConfigGroup cg = nonPasswordStorableSitesCg(d->nonPasswordStorableSites); - QStringList sites = cg.readEntry("Sites", QStringList()); - sites.removeOne(host); - cg.writeEntry("Sites", sites); - cg.sync(); -} - -bool WebEngineSettings::askToSaveSitePassword() const -{ - return d->m_offerToSaveWebSitePassword; -} - -bool WebEngineSettings::isInternalPluginHandlingDisabled() const -{ - return d->m_disableInternalPluginHandling; -} - -bool WebEngineSettings::isLoadPluginsOnDemandEnabled() const -{ - return d->m_loadPluginsOnDemand; -} - -bool WebEngineSettings::allowMixedContentDisplay() const -{ - return d->m_allowMixedContentDisplay; -} - -bool WebEngineSettings::alowActiveMixedContent() const -{ - return d->m_allowActiveMixedContent; -} - - -void WebEngineSettings::initWebEngineSettings() -{ - KConfig cfg (QStringLiteral("webenginepartrc"), KConfig::NoGlobals); - KConfigGroup generalCfg (&cfg, "General"); - d->m_disableInternalPluginHandling = generalCfg.readEntry("DisableInternalPluginHandling", false); - d->m_enableLocalStorage = generalCfg.readEntry("EnableLocalStorage", true); - d->m_enableOfflineStorageDb = generalCfg.readEntry("EnableOfflineStorageDatabase", true); - d->m_enableOfflineWebAppCache = generalCfg.readEntry("EnableOfflineWebApplicationCache", true); - d->m_enableWebGL = generalCfg.readEntry("EnableWebGL", true); - d->m_allowActiveMixedContent = generalCfg.readEntry("AllowActiveMixedContent", false); - d->m_allowMixedContentDisplay = generalCfg.readEntry("AllowMixedContentDisplay", true); - - // Force the reloading of the non password storable sites settings. - d->nonPasswordStorableSites.reset(); -} - -void WebEngineSettings::initCookieJarSettings() -{ - KSharedConfig::Ptr cookieCfgPtr = KSharedConfig::openConfig(QStringLiteral("kcookiejarrc"), KConfig::NoGlobals); - KConfigGroup cookieCfg ( cookieCfgPtr, "Cookie Policy"); - d->m_useCookieJar = cookieCfg.readEntry("Cookies", false); -} - -void WebEngineSettings::initNSPluginSettings() -{ - KSharedConfig::Ptr cookieCfgPtr = KSharedConfig::openConfig(QStringLiteral("kcmnspluginrc"), KConfig::NoGlobals); - KConfigGroup cookieCfg ( cookieCfgPtr, "Misc"); - d->m_loadPluginsOnDemand = cookieCfg.readEntry("demandLoad", false); -} - - -WebEngineSettings* WebEngineSettings::self() -{ - static WebEngineSettings s_webEngineSettings; - return &s_webEngineSettings; -} - -#include "webenginesettings.moc" diff --git a/webenginepart/src/settings/webenginesettings.h a/webenginepart/src/settings/webenginesettings.h deleted file mode 100644 index 6b2baa101..000000000 --- a/webenginepart/src/settings/webenginesettings.h +++ /dev/null @@ -1,213 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 1999 David Faure - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef WEBENGINESETTINGS_H -#define WEBENGINESETTINGS_H - -class KConfig; -class KConfigGroup; - -#include -#include -#include - -#include -#include - -struct KPerDomainSettings; -class WebEngineSettingsPrivate; - -/** - * Settings for the HTML view. - */ -class WebEngineSettings -{ -public: - - enum KAnimationAdvice { - KAnimationDisabled=0, - KAnimationLoopOnce, - KAnimationEnabled - }; - - enum KSmoothScrollingMode { - KSmoothScrollingDisabled=0, - KSmoothScrollingWhenEfficient, - KSmoothScrollingEnabled - }; - - /** - * Called by constructor and reparseConfiguration - */ - void init(); - - /** - * Destructor. Don't delete any instance by yourself. - */ - virtual ~WebEngineSettings(); - - void computeFontSizes(int logicalDpi); - bool zoomToDPI() const; - void setZoomToDPI(bool b); - - // Automatic page reload/refresh... - bool autoPageRefresh() const; - - bool isOpenMiddleClickEnabled(); - - // Java and JavaScript - bool isJavaEnabled( const QString& hostname = QString() ) const; - bool isJavaScriptEnabled( const QString& hostname = QString() ) const; - bool isJavaScriptDebugEnabled( const QString& hostname = QString() ) const; - bool isJavaScriptErrorReportingEnabled( const QString& hostname = QString() ) const; - bool isPluginsEnabled( const QString& hostname = QString() ) const; - bool isLoadPluginsOnDemandEnabled() const; - bool isInternalPluginHandlingDisabled() const; - - // AdBlocK Filtering - bool isAdFiltered( const QString &url ) const; - bool isAdFilterEnabled() const; - bool isHideAdsEnabled() const; - void addAdFilter( const QString &url ); - QString adFilteredBy( const QString &url, bool *isWhiteListed = 0 ) const; - - // Access Keys - bool accessKeysEnabled() const; - - // Favicons - bool favIconsEnabled() const; - - KParts::HtmlSettingsInterface::JSWindowOpenPolicy windowOpenPolicy( const QString& hostname = QString() ) const; - KParts::HtmlSettingsInterface::JSWindowMovePolicy windowMovePolicy( const QString& hostname = QString() ) const; - KParts::HtmlSettingsInterface::JSWindowResizePolicy windowResizePolicy( const QString& hostname = QString() ) const; - KParts::HtmlSettingsInterface::JSWindowStatusPolicy windowStatusPolicy( const QString& hostname = QString() ) const; - KParts::HtmlSettingsInterface::JSWindowFocusPolicy windowFocusPolicy( const QString& hostname = QString() ) const; - - QString settingsToCSS() const; - QString userStyleSheet() const; - - // Form completion - bool isFormCompletionEnabled() const; - int maxFormCompletionItems() const; - - // Meta refresh/redirect (http-equiv) - bool isAutoDelayedActionsEnabled () const; - - // CookieJar... - bool isCookieJarEnabled() const; - - // Password storage... - bool isNonPasswordStorableSite(const QString &host) const; - void addNonPasswordStorableSite(const QString &host); - void removeNonPasswordStorableSite(const QString &host); - bool askToSaveSitePassword() const; - - // Mixed content - bool alowActiveMixedContent() const; - bool allowMixedContentDisplay() const; - - // Global config object stuff. - static WebEngineSettings* self(); - -private: - /** - * Read settings from @p config. - * @param config is a pointer to KConfig object. - * @param reset if true, settings are always set; if false, - * settings are only set if the config file has a corresponding key. - */ - void init( KConfig * config, bool reset = true ); - - // Behavior settings - bool changeCursor() const; - bool underlineLink() const; - bool hoverLink() const; - bool allowTabulation() const; - bool autoSpellCheck() const; - KAnimationAdvice showAnimations() const; - KSmoothScrollingMode smoothScrolling() const; - bool zoomTextOnly() const; - - // Font settings - QString stdFontName() const; - QString fixedFontName() const; - QString serifFontName() const; - QString sansSerifFontName() const; - QString cursiveFontName() const; - QString fantasyFontName() const; - - // these two can be set. Mainly for historical reasons (the method in KHTMLPart exists...) - void setStdFontName(const QString &n); - void setFixedFontName(const QString &n); - - int minFontSize() const; - int mediumFontSize() const; - - bool jsErrorsEnabled() const; - void setJSErrorsEnabled(bool enabled); - - const QString &encoding() const; - - bool followSystemColors() const; - - // Color settings - const QColor& textColor() const; - const QColor& baseColor() const; - const QColor& linkColor() const; - const QColor& vLinkColor() const; - - // Autoload images - bool autoLoadImages() const; - bool unfinishedImageFrame() const; - - /** - * reads from @p config's current group, forcing initialization - * if @p reset is true. - * @param config is a pointer to KConfig object. - * @param reset true if initialization is to be forced. - * @param global true if the global domain is to be read. - * @param pd_settings will be initialised with the computed (inherited) - * settings. - */ - void readDomainSettings(const KConfigGroup &config, bool reset, - bool global, KPerDomainSettings &pd_settings); - - - QList< QPair< QString, QChar > > fallbackAccessKeysAssignments() const; - - // Whether to show passive popup when windows are blocked - void setJSPopupBlockerPassivePopup(bool enabled); - bool jsPopupBlockerPassivePopup() const; - - - QString lookupFont(int i) const; - - void initWebEngineSettings(); - void initCookieJarSettings(); - void initNSPluginSettings(); - - /** - * @internal Constructor - */ - WebEngineSettings(); - - WebEngineSettingsPrivate* const d; -}; - -#endif diff --git a/webenginepart/src/ui/featurepermissionbar.cpp a/webenginepart/src/ui/featurepermissionbar.cpp deleted file mode 100644 index e13351a16..000000000 --- a/webenginepart/src/ui/featurepermissionbar.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2009 Dawit Alemayehu - * Copyright (C) 2013 Allan Sandfeld Jensen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "featurepermissionbar.h" - -#include - -#include - - -FeaturePermissionBar::FeaturePermissionBar(QWidget *parent) - :KMessageWidget(parent) -{ - setCloseButtonVisible(false); - setMessageType(KMessageWidget::Information); - - QAction* action = new QAction(i18nc("@action:deny access", "&Deny access"), this); - connect(action, SIGNAL(triggered()), this, SLOT(onDeniedButtonClicked())); - addAction(action); - - action = new QAction(i18nc("@action:grant access", "&Grant access"), this); - connect(action, SIGNAL(triggered()), this, SLOT(onGrantedButtonClicked())); - addAction(action); - - // FIXME: Add option to allow and remember for this site. -} - -FeaturePermissionBar::~FeaturePermissionBar() -{ -} - -QWebEnginePage::Feature FeaturePermissionBar::feature() const -{ - return m_feature; -} - -void FeaturePermissionBar::setFeature (QWebEnginePage::Feature feature) -{ - m_feature = feature; -} - -void FeaturePermissionBar::onDeniedButtonClicked() -{ - animatedHide(); - emit permissionDenied(m_feature); - emit done(); -} - -void FeaturePermissionBar::onGrantedButtonClicked() -{ - animatedHide(); - emit permissionGranted(m_feature); - emit done(); -} - -#include "featurepermissionbar.moc" diff --git a/webenginepart/src/ui/featurepermissionbar.h a/webenginepart/src/ui/featurepermissionbar.h deleted file mode 100644 index d988ad36f..000000000 --- a/webenginepart/src/ui/featurepermissionbar.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2013 Allan Sandfeld Jensen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef FEATUREPERMISSIONBAR_H -#define FEATUREPERMISSIONBAR_H - -#include - -#include - - -class FeaturePermissionBar : public KMessageWidget -{ - Q_OBJECT -public: - explicit FeaturePermissionBar(QWidget *parent = Q_NULLPTR); - ~FeaturePermissionBar(); - - QWebEnginePage::Feature feature() const; - - void setFeature(QWebEnginePage::Feature); - -Q_SIGNALS: - void permissionGranted(QWebEnginePage::Feature); - void permissionDenied(QWebEnginePage::Feature); - void done(); - -private Q_SLOTS: - void onDeniedButtonClicked(); - void onGrantedButtonClicked(); - -private: - QWebEnginePage::Feature m_feature; -}; - -#endif // FEATUREPERMISSIONBAR_H diff --git a/webenginepart/src/ui/passwordbar.cpp a/webenginepart/src/ui/passwordbar.cpp deleted file mode 100644 index 328d5d4b2..000000000 --- a/webenginepart/src/ui/passwordbar.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2009 Dawit Alemayehu - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "passwordbar.h" - -#include "settings/webenginesettings.h" - -#include -#include - -#include -#include -#include - - -PasswordBar::PasswordBar(QWidget *parent) - :KMessageWidget(parent) -{ - setCloseButtonVisible(false); - setMessageType(KMessageWidget::Information); - - QAction* action = new QAction(i18nc("@action:remember password", "&Remember"), this); - connect(action, SIGNAL(triggered()), this, SLOT(onRememberButtonClicked())); - addAction(action); - - action = new QAction(i18nc("@action:never for this site", "Ne&ver for this site"), this); - connect(action, SIGNAL(triggered()), this, SLOT(onNeverButtonClicked())); - addAction(action); - - action = new QAction(i18nc("@action:not now", "N&ot now"), this); - connect(action, SIGNAL(triggered()), this, SLOT(onNotNowButtonClicked())); - addAction(action); -} - -PasswordBar::~PasswordBar() -{ -} - -QUrl PasswordBar::url() const -{ - return m_url; -} - -QString PasswordBar::requestKey() const -{ - return m_requestKey; -} - -void PasswordBar::setUrl (const QUrl& url) -{ - m_url = url; -} - -void PasswordBar::setRequestKey (const QString& key) -{ - m_requestKey = key; -} - -void PasswordBar::onNotNowButtonClicked() -{ - animatedHide(); - emit saveFormDataRejected (m_requestKey); - emit done(); - clear(); -} - -void PasswordBar::onNeverButtonClicked() -{ - WebEngineSettings::self()->addNonPasswordStorableSite(m_url.host()); - onNotNowButtonClicked(); -} - -void PasswordBar::onRememberButtonClicked() -{ - animatedHide(); - emit saveFormDataAccepted(m_requestKey); - emit done(); - clear(); -} - -void PasswordBar::clear() -{ - m_requestKey.clear(); - m_url.clear(); -} - -#include "passwordbar.moc" diff --git a/webenginepart/src/ui/passwordbar.h a/webenginepart/src/ui/passwordbar.h deleted file mode 100644 index 9f641a625..000000000 --- a/webenginepart/src/ui/passwordbar.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2009 Dawit Alemayehu - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef PASSWORDBAR_H -#define PASSWORDBAR_H - -#include - -#include - - -class PasswordBar : public KMessageWidget -{ - Q_OBJECT -public: - explicit PasswordBar(QWidget *parent = Q_NULLPTR); - ~PasswordBar(); - - QUrl url() const; - QString requestKey() const; - - void setUrl(const QUrl&); - void setRequestKey(const QString&); - -Q_SIGNALS: - void saveFormDataRejected(const QString &key); - void saveFormDataAccepted(const QString &key); - void done(); - -private Q_SLOTS: - void onNotNowButtonClicked(); - void onNeverButtonClicked(); - void onRememberButtonClicked(); - -private: - void clear(); - - QUrl m_url; - QString m_requestKey; -}; - -#endif // PASSWORDBAR_H diff --git a/webenginepart/src/ui/searchbar.cpp a/webenginepart/src/ui/searchbar.cpp deleted file mode 100644 index aca133ff6..000000000 --- a/webenginepart/src/ui/searchbar.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2008 Laurent Montel - * Copyright (C) 2008 Benjamin C. Meyer - * Copyright (C) 2008 Urs Wolfer - * Copyright (C) 2009 Dawit Alemayehu - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "searchbar.h" - -#include -#include -#include -#include - -#include - - -SearchBar::SearchBar(QWidget *parent) - :QWidget(parent) -{ - - // Get the widget that currently has the focus so we can properly - // restore it when the filter bar is closed. - QWidget* widgetWindow = (parent ? parent->window() : 0); - m_focusWidget = (widgetWindow ? widgetWindow->focusWidget() : 0); - - // Initialize the user interface... - m_ui.setupUi(this); - m_ui.optionsButton->addAction(m_ui.actionMatchCase); - m_ui.optionsButton->addAction(m_ui.actionHighlightMatch); - m_ui.optionsButton->addAction(m_ui.actionSearchAutomatically); - m_ui.closeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); - m_ui.previousButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up-search"))); - m_ui.nextButton->setIcon(QIcon::fromTheme(QStringLiteral("go-down-search"))); - m_ui.previousButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - m_ui.nextButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - m_ui.searchInfo->setText(i18nc("label for input line to find text", "&Find:")); - - setFocusProxy(m_ui.searchComboBox); - - connect(m_ui.nextButton, SIGNAL(clicked()), - this, SLOT(findNext())); - connect(m_ui.previousButton, SIGNAL(clicked()), - this, SLOT(findPrevious())); - connect(m_ui.searchComboBox, SIGNAL(returnPressed()), - this, SLOT(findNext())); - connect(m_ui.searchComboBox, SIGNAL(editTextChanged(QString)), - this, SLOT(textChanged(QString))); - - // Start off hidden by default... - setVisible(false); -} - -SearchBar::~SearchBar() -{ - // NOTE: For some reason, if we do not clear the focus from the line edit - // widget before we delete this object, it seems to cause a crash!! - m_ui.searchComboBox->clearFocus(); -} - -void SearchBar::clear() -{ - m_ui.searchComboBox->clear(); -} - -void SearchBar::setVisible (bool visible) -{ - if (visible) { - m_ui.searchComboBox->setFocus(Qt::ActiveWindowFocusReason); - m_ui.searchComboBox->lineEdit()->selectAll(); - } else { - m_ui.searchComboBox->setPalette(QPalette()); - emit searchTextChanged(QString()); - } - - QWidget::setVisible(visible); -} - -QString SearchBar::searchText() const -{ - return m_ui.searchComboBox->currentText(); -} - -bool SearchBar::caseSensitive() const -{ - return m_ui.actionMatchCase->isChecked(); -} - -bool SearchBar::highlightMatches() const -{ - return m_ui.actionHighlightMatch->isChecked(); -} - -void SearchBar::setSearchText(const QString& text) -{ - show(); - m_ui.searchComboBox->setEditText(text); -} - -void SearchBar::setFoundMatch(bool match) -{ - //kDebug() << match; - if (m_ui.searchComboBox->currentText().isEmpty()) { - m_ui.searchComboBox->setPalette(QPalette()); - return; - } - - KColorScheme::BackgroundRole role = (match ? KColorScheme::PositiveBackground : KColorScheme::NegativeBackground); - QPalette newPal(m_ui.searchComboBox->palette()); - KColorScheme::adjustBackground(newPal, role); - m_ui.searchComboBox->setPalette(newPal); -} - -void SearchBar::findNext() -{ - if (!isVisible()) - return; - - const QString text (m_ui.searchComboBox->currentText()); - if (m_ui.searchComboBox->findText(text) == -1) { - m_ui.searchComboBox->addItem(text); - } - - emit searchTextChanged(text); -} - -void SearchBar::findPrevious() -{ - if (!isVisible()) - return; - - const QString text (m_ui.searchComboBox->currentText()); - if (m_ui.searchComboBox->findText(text) == -1) { - m_ui.searchComboBox->addItem(text); - } - - emit searchTextChanged(m_ui.searchComboBox->currentText(), true); -} - -void SearchBar::textChanged(const QString &text) -{ - if (text.isEmpty()) { - m_ui.searchComboBox->setPalette(QPalette()); - m_ui.nextButton->setEnabled(false); - m_ui.previousButton->setEnabled(false); - } else { - m_ui.nextButton->setEnabled(true); - m_ui.previousButton->setEnabled(true); - } - - if (m_ui.actionSearchAutomatically->isChecked()) { - emit searchTextChanged(m_ui.searchComboBox->currentText()); - } -} - -bool SearchBar::event(QEvent* e) -{ - // Close the bar when Escape is pressed. Note we cannot - // assign Escape as a shortcut key because it would cause - // a conflict with the Stop button. - if (e->type() == QEvent::ShortcutOverride) { - QKeyEvent* kev = static_cast(e); - if (kev->key() == Qt::Key_Escape) { - e->accept(); - close(); - if (m_focusWidget) { - m_focusWidget->setFocus(); - m_focusWidget = 0; - } - return true; - } - } - return QWidget::event(e); -} - -#include "searchbar.moc" diff --git a/webenginepart/src/ui/searchbar.h a/webenginepart/src/ui/searchbar.h deleted file mode 100644 index 598fe69ff..000000000 --- a/webenginepart/src/ui/searchbar.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2008 Laurent Montel - * Copyright 2008 Benjamin C. Meyer - * Copyright (C) 2008 Urs Wolfer - * Copyright (C) 2009 Dawit Alemayehu - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef SEARCHBAR_P_H -#define SEARCHBAR_P_H - -#include - -#include "ui_searchbar.h" - -class QEvent; - -/** - * This is the widget that shows up when the search is initiated. - */ -class SearchBar : public QWidget -{ - Q_OBJECT - -public: - SearchBar(QWidget *parent = Q_NULLPTR); - ~SearchBar(); - - QString searchText() const; - bool caseSensitive() const; - bool highlightMatches() const; - void setFoundMatch(bool match); - void setSearchText(const QString&); - - bool event(QEvent* e) Q_DECL_OVERRIDE; - -public Q_SLOTS: - void setVisible(bool visible) Q_DECL_OVERRIDE; - void clear(); - void findNext(); - void findPrevious(); - void textChanged(const QString&); - -Q_SIGNALS: - void searchTextChanged(const QString& text, bool backward = false); - -private: - Ui::SearchBar m_ui; - QPointer m_focusWidget; -}; - -#endif // SEARCHBAR_P_H diff --git a/webenginepart/src/ui/searchbar.ui a/webenginepart/src/ui/searchbar.ui deleted file mode 100644 index 0ed50bdda..000000000 --- a/webenginepart/src/ui/searchbar.ui +++ /dev/null @@ -1,168 +0,0 @@ - - - SearchBar - - - - 0 - 0 - 564 - 34 - - - - - 0 - 0 - - - - - - - Close the search bar - - - true - - - - - - - &Find: - - - searchComboBox - - - - - - - - 0 - 0 - - - - - - - - false - - - Find the next match for the current search phrase - - - &Next - - - - - - - false - - - Find the previous match for the current search phrase - - - &Previous - - - - - - - Find the previous match for the current search phrase - - - &Options - - - QToolButton::InstantPopup - - - - - - - Qt::Horizontal - - - QSizePolicy::MinimumExpanding - - - - 20 - 20 - - - - - - - - true - - - &Match Case - - - - - true - - - true - - - &Search As You Type - - - - - true - - - &Highlight All Matches - - - Highlight Matches - - - - - - KComboBox - QComboBox -
kcombobox.h
-
- - KHistoryComboBox - KComboBox -
khistorycombobox.h
-
-
- - - - closeButton - clicked() - SearchBar - close() - - - 16 - 16 - - - 290 - 16 - - - - -
diff --git a/webenginepart/src/utils.h a/webenginepart/src/utils.h deleted file mode 100644 index c3b33267c..000000000 --- a/webenginepart/src/utils.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef WEBENGINEPART_UTILS_H -#define WEBENGINEPART_UTILS_H - -namespace Utils -{ - -#define QL1S(x) QLatin1String(x) -#define QL1C(x) QLatin1Char(x) - -inline bool isBlankUrl(const QUrl& url) -{ - return (url.isEmpty() || url.url() == QL1S("about:blank")); -} - -} -#endif // WEBENGINEPART_UTILS_H diff --git a/webenginepart/src/webenginepage.cpp a/webenginepart/src/webenginepage.cpp deleted file mode 100644 index cde853641..000000000 --- a/webenginepart/src/webenginepage.cpp +++ /dev/null @@ -1,888 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2008 Dirk Mueller - * Copyright (C) 2008 - 2010 Urs Wolfer - * Copyright (C) 2009 Dawit Alemayehu - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - */ - -#include "webenginepage.h" - -#include "webenginepart.h" -#include "websslinfo.h" -#include "webengineview.h" -#include "settings/webenginesettings.h" -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include // Qt::escape -#include -#include -#include -#include -#include -#include -//#include -#include "utils.h" - - -WebEnginePage::WebEnginePage(WebEnginePart *part, QWidget *parent) - : QWebEnginePage(parent), - m_kioErrorCode(0), - m_ignoreError(false), - m_part(part) -{ - if (view()) - WebEngineSettings::self()->computeFontSizes(view()->logicalDpiY()); - - //setForwardUnsupportedContent(true); - - connect(this, &QWebEnginePage::geometryChangeRequested, - this, &WebEnginePage::slotGeometryChangeRequested); -// connect(this, SIGNAL(unsupportedContent(QNetworkReply*)), -// this, SLOT(slotUnsupportedContent(QNetworkReply*))); - connect(this, &QWebEnginePage::featurePermissionRequested, - this, &WebEnginePage::slotFeaturePermissionRequested); - connect(this, &QWebEnginePage::loadFinished, - this, &WebEnginePage::slotLoadFinished); - connect(this->profile(), &QWebEngineProfile::downloadRequested, this, &WebEnginePage::downloadRequest); - if(!this->profile()->httpUserAgent().contains(QLatin1String("Konqueror"))) - { - this->profile()->setHttpUserAgent(this->profile()->httpUserAgent() + " Konqueror (WebEnginePart)"); - } -} - -WebEnginePage::~WebEnginePage() -{ - //kDebug() << this; -} - -const WebSslInfo& WebEnginePage::sslInfo() const -{ - return m_sslInfo; -} - -void WebEnginePage::setSslInfo (const WebSslInfo& info) -{ - m_sslInfo = info; -} - -static void checkForDownloadManager(QWidget* widget, QString& cmd) -{ - cmd.clear(); - KConfigGroup cfg (KSharedConfig::openConfig(QStringLiteral("konquerorrc"), KConfig::NoGlobals), "HTML Settings"); - const QString fileName (cfg.readPathEntry("DownloadManager", QString())); - if (fileName.isEmpty()) - return; - - const QString exeName = QStandardPaths::findExecutable(fileName); - if (exeName.isEmpty()) { - KMessageBox::detailedSorry(widget, - i18n("The download manager (%1) could not be found in your installation.", fileName), - i18n("Try to reinstall it and make sure that it is available in $PATH. \n\nThe integration will be disabled.")); - cfg.writePathEntry("DownloadManager", QString()); - cfg.sync(); - return; - } - - cmd = exeName; -} - -void WebEnginePage::downloadRequest(QWebEngineDownloadItem* request) -{ - const QUrl url(request->url()); - - // Integration with a download manager... - if (!url.isLocalFile()) { - QString managerExe; - checkForDownloadManager(view(), managerExe); - if (!managerExe.isEmpty()) { - //kDebug() << "Calling command" << cmd; - KRun::runCommand((managerExe + QLatin1Char(' ') + KShell::quoteArg(url.url())), view()); - return; - } - } - request->accept(); - -} - -QWebEnginePage *WebEnginePage::createWindow(WebWindowType type) -{ - //qDebug() << "window type:" << type; - // Crete an instance of NewWindowPage class to capture all the - // information we need to create a new window. See documentation of - // the class for more information... - NewWindowPage* page = new NewWindowPage(type, part()); - return page; -} - -// Returns true if the scheme and domain of the two urls match... -static bool domainSchemeMatch(const QUrl& u1, const QUrl& u2) -{ - if (u1.scheme() != u2.scheme()) - return false; - - QStringList u1List = u1.host().split(QL1C('.'), QString::SkipEmptyParts); - QStringList u2List = u2.host().split(QL1C('.'), QString::SkipEmptyParts); - - if (qMin(u1List.count(), u2List.count()) < 2) - return false; // better safe than sorry... - - while (u1List.count() > 2) - u1List.removeFirst(); - - while (u2List.count() > 2) - u2List.removeFirst(); - - return (u1List == u2List); -} - -bool WebEnginePage::acceptNavigationRequest(const QUrl& url, NavigationType type, bool isMainFrame) -{ - qDebug() << url << "type=" << type; - QUrl reqUrl(url); - - // Handle "mailto:" url here... - if (handleMailToUrl(reqUrl, type)) - return false; - - const bool isTypedUrl = property("NavigationTypeUrlEntered").toBool(); - - /* - NOTE: We use a dynamic QObject property called "NavigationTypeUrlEntered" - to distinguish between requests generated by user entering a url vs those - that were generated programatically through javascript (AJAX requests). - */ - if (isMainFrame && isTypedUrl) - setProperty("NavigationTypeUrlEntered", QVariant()); - - // inPage requests are those generarted within the current page through - // link clicks, javascript queries, and button clicks (form submission). - bool inPageRequest = true; - switch (type) { - case QWebEnginePage::NavigationTypeFormSubmitted: - //if (!checkFormData(request)) - // return false; - break; -#if 0 - case QWebEnginePage::NavigationTypeFormResubmitted: - if (!checkFormData(request)) - return false; - if (KMessageBox::warningContinueCancel(view(), - i18n("

To display the requested web page again, " - "the browser needs to resend information you have " - "previously submitted.

" - "

If you were shopping online and made a purchase, " - "click the Cancel button to prevent a duplicate purchase." - "Otherwise, click the Continue button to display the web" - "page again.

"), - i18n("Resubmit Information")) == KMessageBox::Cancel) { - return false; - } - break; -#endif - case QWebEnginePage::NavigationTypeBackForward: - // If history navigation is locked, ignore all such requests... - if (property("HistoryNavigationLocked").toBool()) { - setProperty("HistoryNavigationLocked", QVariant()); - qDebug() << "Rejected history navigation because 'HistoryNavigationLocked' property is set!"; - return false; - } - //kDebug() << "Navigating to item (" << history()->currentItemIndex() - // << "of" << history()->count() << "):" << history()->currentItem().url(); - inPageRequest = false; - break; - case QWebEnginePage::NavigationTypeReload: -// setRequestMetaData(QL1S("cache"), QL1S("reload")); - inPageRequest = false; - break; - case QWebEnginePage::NavigationTypeOther: // triggered by javascript - qDebug() << "Triggered by javascript"; - inPageRequest = !isTypedUrl; - break; - default: - break; - } - - if (inPageRequest) { - // if (!checkLinkSecurity(request, type)) - // return false; - - // if (m_sslInfo.isValid()) - // setRequestMetaData(QL1S("ssl_was_in_use"), QL1S("TRUE")); - } - - - // Honor the enabling/disabling of plugins per host. - settings()->setAttribute(QWebEngineSettings::PluginsEnabled, WebEngineSettings::self()->isPluginsEnabled(reqUrl.host())); - // Insert the request into the queue... - return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame); -} - -#if 0 -static int errorCodeFromReply(QNetworkReply* reply) -{ - // First check if there is a KIO error code sent back and use that, - // if not attempt to convert QNetworkReply's NetworkError to KIO::Error. - QVariant attr = reply->attribute(static_cast(KIO::AccessManager::KioError)); - if (attr.isValid() && attr.type() == QVariant::Int) - return attr.toInt(); - - switch (reply->error()) { - case QNetworkReply::ConnectionRefusedError: - return KIO::ERR_COULD_NOT_CONNECT; - case QNetworkReply::HostNotFoundError: - return KIO::ERR_UNKNOWN_HOST; - case QNetworkReply::TimeoutError: - return KIO::ERR_SERVER_TIMEOUT; - case QNetworkReply::OperationCanceledError: - return KIO::ERR_USER_CANCELED; - case QNetworkReply::ProxyNotFoundError: - return KIO::ERR_UNKNOWN_PROXY_HOST; - case QNetworkReply::ContentAccessDenied: - return KIO::ERR_ACCESS_DENIED; - case QNetworkReply::ContentOperationNotPermittedError: - return KIO::ERR_WRITE_ACCESS_DENIED; - case QNetworkReply::ContentNotFoundError: - return KIO::ERR_NO_CONTENT; - case QNetworkReply::AuthenticationRequiredError: - return KIO::ERR_COULD_NOT_AUTHENTICATE; - case QNetworkReply::ProtocolUnknownError: - return KIO::ERR_UNSUPPORTED_PROTOCOL; - case QNetworkReply::ProtocolInvalidOperationError: - return KIO::ERR_UNSUPPORTED_ACTION; - case QNetworkReply::UnknownNetworkError: - return KIO::ERR_UNKNOWN; - case QNetworkReply::NoError: - default: - break; - } - - return 0; -} -#endif - -WebEnginePart* WebEnginePage::part() const -{ - return m_part.data(); -} - -void WebEnginePage::setPart(WebEnginePart* part) -{ - m_part = part; -} - -void WebEnginePage::slotLoadFinished(bool ok) -{ - QUrl requestUrl = url(); - requestUrl.setUserInfo(QString()); - const bool shouldResetSslInfo = (m_sslInfo.isValid() && !domainSchemeMatch(requestUrl, m_sslInfo.url())); -#if 0 - QWebFrame* frame = qobject_cast(reply->request().originatingObject()); - if (!frame) - return; - const bool isMainFrameRequest = (frame == mainFrame()); -#else - // PORTING_TODO - const bool isMainFrameRequest = true; -#endif - -#if 0 - // Only deal with non-redirect responses... - const QVariant redirectVar = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - - if (isMainFrameRequest && redirectVar.isValid()) { - m_sslInfo.restoreFrom(reply->attribute(static_cast(KIO::AccessManager::MetaData)), - reply->url(), shouldResetSslInfo); - return; - } - - const int errCode = errorCodeFromReply(reply); - kDebug() << frame << "is main frame request?" << isMainFrameRequest << requestUrl; -#endif - - if (ok) { - if (isMainFrameRequest) { -#if 0 - m_sslInfo.restoreFrom(reply->attribute(static_cast(KIO::AccessManager::MetaData)), - reply->url(), shouldResetSslInfo); -#endif - setPageJScriptPolicy(url()); - } - } else { - // Handle any error... -#if 0 - switch (errCode) { - case 0: - case KIO::ERR_NO_CONTENT: - break; - case KIO::ERR_ABORTED: - case KIO::ERR_USER_CANCELED: // Do nothing if request is cancelled/aborted - //kDebug() << "User aborted request!"; - m_ignoreError = true; - emit loadAborted(QUrl()); - return; - // Handle the user clicking on a link that refers to a directory - // Since KIO cannot automatically convert a GET request to a LISTDIR one. - case KIO::ERR_IS_DIRECTORY: - m_ignoreError = true; - emit loadAborted(reply->url()); - return; - default: - // Make sure the saveFrameStateRequested signal is emitted so - // the page can restored properly. - if (isMainFrameRequest) - emit saveFrameStateRequested(frame, 0); - - m_ignoreError = (reply->attribute(QNetworkRequest::User).toInt() == QNetworkReply::ContentAccessDenied); - m_kioErrorCode = errCode; - break; -#endif - } - - if (isMainFrameRequest) { - const WebEnginePageSecurity security = (m_sslInfo.isValid() ? PageEncrypted : PageUnencrypted); - emit m_part->browserExtension()->setPageSecurity(security); - } -} - -void WebEnginePage::slotUnsupportedContent(QNetworkReply* reply) -{ -#if 0 - //kDebug() << reply->url(); - QString mimeType; - KIO::MetaData metaData; - - KIO::AccessManager::putReplyOnHold(reply); - QString downloadCmd; - checkForDownloadManager(view(), downloadCmd); - if (!downloadCmd.isEmpty()) { - reply->setProperty("DownloadManagerExe", downloadCmd); - } - - if (QWePage::handleReply(reply, &mimeType, &metaData)) { - reply->deleteLater(); - if (qobject_cast(this) && isBlankUrl(m_part->url())) { - m_part->closeUrl(); - if (m_part->arguments().metaData().contains(QL1S("new-window"))) { - m_part->widget()->topLevelWidget()->close(); - } else { - delete m_part; - } - } - return; - } - - //kDebug() << "mimetype=" << mimeType << "metadata:" << metaData; - - if (reply->request().originatingObject() == this->mainFrame()) { - KParts::OpenUrlArguments args; - args.setMimeType(mimeType); - args.metaData() = metaData; - emit m_part->browserExtension()->openUrlRequest(reply->url(), args, KParts::BrowserArguments()); - return; - } -#endif - reply->deleteLater(); - -} -void WebEnginePage::slotFeaturePermissionRequested(const QUrl& url, QWebEnginePage::Feature feature) -{ - if (url == this->url()) { - part()->slotShowFeaturePermissionBar(feature); - return; - } - switch(feature) { - case QWebEnginePage::Notifications: - // FIXME: We should have a setting to tell if this is enabled, but so far it is always enabled. - setFeaturePermission(url, feature, QWebEnginePage::PermissionGrantedByUser); - break; - case QWebEnginePage::Geolocation: - if (KMessageBox::warningContinueCancel(0, i18n("This site is attempting to " - "access information about your " - "physical location.\n" - "Do you want to allow it access?"), - i18n("Network Transmission"), - KGuiItem(i18n("Allow access")), - KStandardGuiItem::cancel(), - QStringLiteral("WarnGeolocation")) == KMessageBox::Cancel) { - setFeaturePermission(url, feature, QWebEnginePage::PermissionDeniedByUser); - } else { - setFeaturePermission(url, feature, QWebEnginePage::PermissionGrantedByUser); - } - break; - default: - setFeaturePermission(url, feature, QWebEnginePage::PermissionUnknown); - break; - } -} - -void WebEnginePage::slotGeometryChangeRequested(const QRect & rect) -{ - const QString host = url().host(); - - // NOTE: If a new window was created from another window which is in - // maximized mode and its width and/or height were not specified at the - // time of its creation, which is always the case in QWebEnginePage::createWindow, - // then any move operation will seem not to work. That is because the new - // window will be in maximized mode where moving it will not be possible... - if (WebEngineSettings::self()->windowMovePolicy(host) == KParts::HtmlSettingsInterface::JSWindowMoveAllow && - (view()->x() != rect.x() || view()->y() != rect.y())) - emit m_part->browserExtension()->moveTopLevelWidget(rect.x(), rect.y()); - - const int height = rect.height(); - const int width = rect.width(); - - // parts of following code are based on kjs_window.cpp - // Security check: within desktop limits and bigger than 100x100 (per spec) - if (width < 100 || height < 100) { - qWarning() << "Window resize refused, window would be too small (" << width << "," << height << ")"; - return; - } - - QRect sg = QApplication::desktop()->screenGeometry(view()); - - if (width > sg.width() || height > sg.height()) { - qWarning() << "Window resize refused, window would be too big (" << width << "," << height << ")"; - return; - } - - if (WebEngineSettings::self()->windowResizePolicy(host) == KParts::HtmlSettingsInterface::JSWindowResizeAllow) { - //kDebug() << "resizing to " << width << "x" << height; - emit m_part->browserExtension()->resizeTopLevelWidget(width, height); - } - - // If the window is out of the desktop, move it up/left - // (maybe we should use workarea instead of sg, otherwise the window ends up below kicker) - const int right = view()->x() + view()->frameGeometry().width(); - const int bottom = view()->y() + view()->frameGeometry().height(); - int moveByX = 0, moveByY = 0; - if (right > sg.right()) - moveByX = - right + sg.right(); // always <0 - if (bottom > sg.bottom()) - moveByY = - bottom + sg.bottom(); // always <0 - - if ((moveByX || moveByY) && WebEngineSettings::self()->windowMovePolicy(host) == KParts::HtmlSettingsInterface::JSWindowMoveAllow) - emit m_part->browserExtension()->moveTopLevelWidget(view()->x() + moveByX, view()->y() + moveByY); -} - -bool WebEnginePage::checkLinkSecurity(const QNetworkRequest &req, NavigationType type) const -{ - // Check whether the request is authorized or not... - if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("redirect"), url(), req.url())) { - - //kDebug() << "*** Failed security check: base-url=" << mainFrame()->url() << ", dest-url=" << req.url(); - QString buttonText, title, message; - - int response = KMessageBox::Cancel; - QUrl linkUrl (req.url()); - - if (type == QWebEnginePage::NavigationTypeLinkClicked) { - message = i18n("This untrusted page links to
%1." - "
Do you want to follow the link?
", linkUrl.url()); - title = i18n("Security Warning"); - buttonText = i18nc("follow link despite of security warning", "Follow"); - } else { - title = i18n("Security Alert"); - message = i18n("Access by untrusted page to
%1
denied.
", - linkUrl.toDisplayString().toHtmlEscaped()); - } - - if (buttonText.isEmpty()) { - KMessageBox::error( 0, message, title); - } else { - // Dangerous flag makes the Cancel button the default - response = KMessageBox::warningContinueCancel(0, message, title, - KGuiItem(buttonText), - KStandardGuiItem::cancel(), - QString(), // no don't ask again info - KMessageBox::Notify | KMessageBox::Dangerous); - } - - return (response == KMessageBox::Continue); - } - - return true; -} - -bool WebEnginePage::checkFormData(const QNetworkRequest &req) const -{ - const QString scheme (req.url().scheme()); - - if (m_sslInfo.isValid() && - !scheme.compare(QL1S("https")) && !scheme.compare(QL1S("mailto")) && - (KMessageBox::warningContinueCancel(0, - i18n("Warning: This is a secure form " - "but it is attempting to send " - "your data back unencrypted.\n" - "A third party may be able to " - "intercept and view this " - "information.\nAre you sure you " - "want to send the data unencrypted?"), - i18n("Network Transmission"), - KGuiItem(i18n("&Send Unencrypted"))) == KMessageBox::Cancel)) { - - return false; - } - - - if (scheme.compare(QL1S("mailto")) == 0 && - (KMessageBox::warningContinueCancel(0, i18n("This site is attempting to " - "submit form data via email.\n" - "Do you want to continue?"), - i18n("Network Transmission"), - KGuiItem(i18n("&Send Email")), - KStandardGuiItem::cancel(), - QStringLiteral("WarnTriedEmailSubmit")) == KMessageBox::Cancel)) { - return false; - } - - return true; -} - -// Sanitizes the "mailto:" url, e.g. strips out any "attach" parameters. -static QUrl sanitizeMailToUrl(const QUrl &url, QStringList& files) { - QUrl sanitizedUrl; - - // NOTE: This is necessary to ensure we can properly use QUrl's query - // related APIs to process 'mailto:' urls of form 'mailto:foo@bar.com'. - if (url.hasQuery()) - sanitizedUrl = url; - else - sanitizedUrl = QUrl(url.scheme() + QL1S(":?") + url.path()); - - QUrlQuery query(sanitizedUrl); - const QList > items (query.queryItems()); - - QUrlQuery sanitizedQuery; - for(auto queryItem : items) { - if (queryItem.first.contains(QL1C('@')) && queryItem.second.isEmpty()) { - // ### DF: this hack breaks mailto:faure@kde.org, kmail doesn't expect mailto:?to=faure@kde.org - queryItem.second = queryItem.first; - queryItem.first = QStringLiteral("to"); - } else if (QString::compare(queryItem.first, QL1S("attach"), Qt::CaseInsensitive) == 0) { - files << queryItem.second; - continue; - } - sanitizedQuery.addQueryItem(queryItem.first, queryItem.second); - } - - sanitizedUrl.setQuery(sanitizedQuery); - return sanitizedUrl; -} - -bool WebEnginePage::handleMailToUrl (const QUrl &url, NavigationType type) const -{ - if (QString::compare(url.scheme(), QL1S("mailto"), Qt::CaseInsensitive) == 0) { - QStringList files; - QUrl mailtoUrl (sanitizeMailToUrl(url, files)); - - switch (type) { - case QWebEnginePage::NavigationTypeLinkClicked: - if (!files.isEmpty() && KMessageBox::warningContinueCancelList(0, - i18n("Do you want to allow this site to attach " - "the following files to the email message?"), - files, i18n("Email Attachment Confirmation"), - KGuiItem(i18n("&Allow attachments")), - KGuiItem(i18n("&Ignore attachments")), QL1S("WarnEmailAttachment")) == KMessageBox::Continue) { - - // Re-add the attachments... - QStringListIterator filesIt (files); - QUrlQuery query(mailtoUrl); - while (filesIt.hasNext()) { - query.addQueryItem(QL1S("attach"), filesIt.next()); - } - mailtoUrl.setQuery(query); - } - break; - case QWebEnginePage::NavigationTypeFormSubmitted: - //case QWebEnginePage::NavigationTypeFormResubmitted: - if (!files.isEmpty()) { - KMessageBox::information(0, i18n("This site attempted to attach a file from your " - "computer in the form submission. The attachment " - "was removed for your protection."), - i18n("Attachment Removed"), QStringLiteral("InfoTriedAttach")); - } - break; - default: - break; - } - - //kDebug() << "Emitting openUrlRequest with " << mailtoUrl; - emit m_part->browserExtension()->openUrlRequest(mailtoUrl); - return true; - } - - return false; -} - -void WebEnginePage::setPageJScriptPolicy(const QUrl &url) -{ - const QString hostname (url.host()); - settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, - WebEngineSettings::self()->isJavaScriptEnabled(hostname)); - - const KParts::HtmlSettingsInterface::JSWindowOpenPolicy policy = WebEngineSettings::self()->windowOpenPolicy(hostname); - settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, - (policy != KParts::HtmlSettingsInterface::JSWindowOpenDeny && - policy != KParts::HtmlSettingsInterface::JSWindowOpenSmart)); -} - - - - - -/************************************* Begin NewWindowPage ******************************************/ - -NewWindowPage::NewWindowPage(WebWindowType type, WebEnginePart* part, QWidget* parent) - :WebEnginePage(part, parent) , m_type(type) , m_createNewWindow(true) -{ - Q_ASSERT_X (part, "NewWindowPage", "Must specify a valid KPart"); - - connect(this, SIGNAL(menuBarVisibilityChangeRequested(bool)), - this, SLOT(slotMenuBarVisibilityChangeRequested(bool))); - connect(this, SIGNAL(toolBarVisibilityChangeRequested(bool)), - this, SLOT(slotToolBarVisibilityChangeRequested(bool))); - connect(this, SIGNAL(statusBarVisibilityChangeRequested(bool)), - this, SLOT(slotStatusBarVisibilityChangeRequested(bool))); - connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool))); -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (m_type == WebBrowserBackgroundTab) { - m_windowArgs.setLowerWindow(true); - } -#endif -} - -NewWindowPage::~NewWindowPage() -{ -} - -static KParts::BrowserArguments browserArgs(WebEnginePage::WebWindowType type) -{ - KParts::BrowserArguments bargs; - switch (type) { - case WebEnginePage::WebDialog: - case WebEnginePage::WebBrowserWindow: - bargs.setForcesNewWindow(true); - break; - case WebEnginePage::WebBrowserTab: -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - case WebEnginePage::WebBrowserBackgroundTab: -#endif - // let konq decide, based on user configuration - //bargs.setNewTab(true); - break; - } - return bargs; -} - -bool NewWindowPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) -{ - //qDebug() << "url:" << url << ", type:" << type << ", isMainFrame:" << isMainFrame << "m_createNewWindow=" << m_createNewWindow; - if (m_createNewWindow) { - const QUrl reqUrl (url); - - const bool actionRequestedByUser = type != QWebEnginePage::NavigationTypeOther; - - if (actionRequestedByUser) { - if (!part() && !isMainFrame) { - return false; - } - const KParts::HtmlSettingsInterface::JSWindowOpenPolicy policy = WebEngineSettings::self()->windowOpenPolicy(reqUrl.host()); - switch (policy) { - case KParts::HtmlSettingsInterface::JSWindowOpenDeny: - // TODO: Implement support for dealing with blocked pop up windows. - this->deleteLater(); - return false; - case KParts::HtmlSettingsInterface::JSWindowOpenAsk: { - const QString message = (reqUrl.isEmpty() ? - i18n("This site is requesting to open a new popup window.\n" - "Do you want to allow this?") : - i18n("This site is requesting to open a popup window to" - "

%1


Do you want to allow this?
", - KStringHandler::rsqueeze(reqUrl.toDisplayString().toHtmlEscaped(), 100))); - if (KMessageBox::questionYesNo(view(), message, - i18n("Javascript Popup Confirmation"), - KGuiItem(i18n("Allow")), - KGuiItem(i18n("Do Not Allow"))) == KMessageBox::No) { - // TODO: Implement support for dealing with blocked pop up windows. - this->deleteLater(); - return false; - } - break; - } - default: - break; - } - } - - // Browser args... - KParts::BrowserArguments bargs = browserArgs(m_type); - - // OpenUrl args... - KParts::OpenUrlArguments uargs; - uargs.setMimeType(QL1S("text/html")); - uargs.setActionRequestedByUser(actionRequestedByUser); - - // Window args... - KParts::WindowArgs wargs (m_windowArgs); - - KParts::ReadOnlyPart* newWindowPart =0; - part()->browserExtension()->createNewWindow(QUrl(), uargs, bargs, wargs, &newWindowPart); - qDebug() << "Created new window" << newWindowPart; - - if (!newWindowPart) { - return false; - } else if (newWindowPart->widget()->topLevelWidget() != part()->widget()->topLevelWidget()) { - KParts::OpenUrlArguments args; - args.metaData().insert(QL1S("new-window"), QL1S("true")); - newWindowPart->setArguments(args); - } - - // Get the webview... - WebEnginePart* webenginePart = qobject_cast(newWindowPart); - WebEngineView* webView = webenginePart ? qobject_cast(webenginePart->view()) : 0; - - // If the newly created window is NOT a webenginepart... - if (!webView) { - qDebug() << "Opening URL on" << newWindowPart; - newWindowPart->openUrl(reqUrl); - this->deleteLater(); - return false; - } - // Reparent this page to the new webview to prevent memory leaks. - setParent(webView); - // Replace the webpage of the new webview with this one. Nice trick... - webView->setPage(this); - // Set the new part as the one this page will use going forward. - setPart(webenginePart); - // Connect all the signals from this page to the slots in the new part. - webenginePart->connectWebEnginePageSignals(this); - //Set the create new window flag to false... - m_createNewWindow = false; - } - - return WebEnginePage::acceptNavigationRequest(url, type, isMainFrame); -} - -void NewWindowPage::slotGeometryChangeRequested(const QRect & rect) -{ - if (!rect.isValid()) - return; - - if (!m_createNewWindow) { - WebEnginePage::slotGeometryChangeRequested(rect); - return; - } - - m_windowArgs.setX(rect.x()); - m_windowArgs.setY(rect.y()); - m_windowArgs.setWidth(qMax(rect.width(), 100)); - m_windowArgs.setHeight(qMax(rect.height(), 100)); -} - -void NewWindowPage::slotMenuBarVisibilityChangeRequested(bool visible) -{ - //kDebug() << visible; - m_windowArgs.setMenuBarVisible(visible); -} - -void NewWindowPage::slotStatusBarVisibilityChangeRequested(bool visible) -{ - //kDebug() << visible; - m_windowArgs.setStatusBarVisible(visible); -} - -void NewWindowPage::slotToolBarVisibilityChangeRequested(bool visible) -{ - //kDebug() << visible; - m_windowArgs.setToolBarsVisible(visible); -} - -// When is this called? (and acceptNavigationRequest is not called?) -// The only case I found is Ctrl+click on link to data URL (like in konqviewmgrtest), that's quite specific... -// Everything else seems to work with this method being commented out... -void NewWindowPage::slotLoadFinished(bool ok) -{ - Q_UNUSED(ok) - qDebug() << ok; - if (!m_createNewWindow) - return; - - const bool actionRequestedByUser = true; // ### we don't have the information here, unlike in acceptNavigationRequest - - // Browser args... - KParts::BrowserArguments bargs = browserArgs(m_type); - //bargs.frameName = mainFrame()->frameName(); - - // OpenUrl args... - KParts::OpenUrlArguments uargs; - uargs.setMimeType(QL1S("text/html")); - uargs.setActionRequestedByUser(actionRequestedByUser); - - // Window args... - KParts::WindowArgs wargs (m_windowArgs); - - KParts::ReadOnlyPart* newWindowPart =0; - part()->browserExtension()->createNewWindow(QUrl(), uargs, bargs, wargs, &newWindowPart); - - qDebug() << "Created new window or tab" << newWindowPart; - - // Get the webview... - WebEnginePart* webenginePart = newWindowPart ? qobject_cast(newWindowPart) : 0; - WebEngineView* webView = webenginePart ? qobject_cast(webenginePart->view()) : 0; - - if (webView) { - // if a new window is created, set a new window meta-data flag. - if (newWindowPart->widget()->topLevelWidget() != part()->widget()->topLevelWidget()) { - KParts::OpenUrlArguments args; - args.metaData().insert(QL1S("new-window"), QL1S("true")); - newWindowPart->setArguments(args); - } - // Reparent this page to the new webview to prevent memory leaks. - setParent(webView); - // Replace the webpage of the new webview with this one. Nice trick... - webView->setPage(this); - // Set the new part as the one this page will use going forward. - setPart(webenginePart); - // Connect all the signals from this page to the slots in the new part. - webenginePart->connectWebEnginePageSignals(this); - } - - //Set the create new window flag to false... - m_createNewWindow = false; -} - -/****************************** End NewWindowPage *************************************************/ - diff --git a/webenginepart/src/webenginepage.h a/webenginepart/src/webenginepage.h deleted file mode 100644 index 0cd74ac1b..000000000 --- a/webenginepart/src/webenginepage.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2008 Dirk Mueller - * Copyright (C) 2008 Urs Wolfer - * Copyright (C) 2009 Dawit Alemayehu - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - */ - -#ifndef WEBENGINEPAGE_H -#define WEBENGINEPAGE_H - -#include "websslinfo.h" - -#include -#include - -#include -#include -#include -#include - -class QUrl; -class WebSslInfo; -class WebEnginePart; -class QWebEngineDownloadItem; - - -class WebEnginePage : public QWebEnginePage -{ - Q_OBJECT -public: - explicit WebEnginePage(WebEnginePart *wpart, QWidget *parent = Q_NULLPTR); - ~WebEnginePage(); - - /** - * Returns the SSL information for the current page. - * - * @see WebSslInfo. - */ - const WebSslInfo& sslInfo() const; - - /** - * Sets the page's SSL information to @p other. - * - * @see WebSslInfo - */ - void setSslInfo (const WebSslInfo &other); - - /** - * Reimplemented for internal reasons. The API is not affected. - * - * @internal - * @see KWebEnginePage::downloadRequest. - */ - void downloadRequest(QWebEngineDownloadItem* request); - -Q_SIGNALS: - /** - * This signal is emitted whenever a user cancels/aborts a load resource - * request. - */ - void loadAborted(const QUrl &url); - -protected: - /** - * Returns the webengine part in use by this object. - * @internal - */ - WebEnginePart* part() const; - - /** - * Sets the webengine part to be used by this object. - * @internal - */ - void setPart(WebEnginePart*); - - /** - * Reimplemented for internal reasons, the API is not affected. - * @internal - */ - QWebEnginePage* createWindow(WebWindowType type) Q_DECL_OVERRIDE; - - /** - * Reimplemented for internal reasons, the API is not affected. - * @internal - */ - bool acceptNavigationRequest(const QUrl& request, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE; - -protected Q_SLOTS: - void slotLoadFinished(bool ok); - void slotUnsupportedContent(QNetworkReply* reply); - virtual void slotGeometryChangeRequested(const QRect& rect); - void slotFeaturePermissionRequested(const QUrl& url, QWebEnginePage::Feature feature); - -private: - bool checkLinkSecurity(const QNetworkRequest& req, NavigationType type) const; - bool checkFormData(const QNetworkRequest& req) const; - bool handleMailToUrl (const QUrl& , NavigationType type) const; - void setPageJScriptPolicy(const QUrl& url); - -private: - enum WebEnginePageSecurity { PageUnencrypted, PageEncrypted, PageMixed }; - - int m_kioErrorCode; - bool m_ignoreError; - - WebSslInfo m_sslInfo; - QPointer m_part; -}; - - -/** - * This is a fake implementation of WebEnginePage to workaround the ugly API used - * to request for the creation of a new window from javascript in QtWebEngine. PORTING_TODO - * - * The KPart API for creating new windows requires all the information about the - * new window up front. Unfortunately QWebEnginePage::createWindow function does not - * provide any of these necessary information except for the window type. All - * the other necessary information is emitted as signals instead! Hence, the - * need for this class to collect all of the necessary information, such as - * window name, size and position, before calling KPart's createNewWindow - * function. - */ -class NewWindowPage : public WebEnginePage -{ - Q_OBJECT -public: - NewWindowPage(WebWindowType windowType, WebEnginePart* part, - QWidget* parent = Q_NULLPTR); - virtual ~NewWindowPage(); - -protected: - bool acceptNavigationRequest(const QUrl& request, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE; - -private Q_SLOTS: - void slotGeometryChangeRequested(const QRect& rect) override; - void slotMenuBarVisibilityChangeRequested(bool visible); - void slotStatusBarVisibilityChangeRequested(bool visible); - void slotToolBarVisibilityChangeRequested(bool visible); - void slotLoadFinished(bool); - -private: - KParts::WindowArgs m_windowArgs; - WebWindowType m_type; - bool m_createNewWindow; -}; - -#endif // WEBENGINEPAGE_H diff --git a/webenginepart/src/webenginepart.cpp a/webenginepart/src/webenginepart.cpp deleted file mode 100644 index 10bbffc15..000000000 --- a/webenginepart/src/webenginepart.cpp +++ /dev/null @@ -1,926 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2007 Trolltech ASA - * Copyright (C) 2008 - 2010 Urs Wolfer - * Copyright (C) 2008 Laurent Montel - * Copyright (C) 2009 Dawit Alemayehu - * Copyright (C) 2013 Allan Sandfeld Jensen - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - */ - -#include "webenginepart.h" - -//#include -#include -#include -#include - -#include "webenginepart_ext.h" -#include "webengineview.h" -#include "webenginepage.h" -#include "websslinfo.h" -#include "webhistoryinterface.h" - -#include "ui/searchbar.h" -#include "ui/passwordbar.h" -#include "ui/featurepermissionbar.h" -#include "settings/webenginesettings.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "utils.h" - -WebEnginePart::WebEnginePart(QWidget *parentWidget, QObject *parent, - const QByteArray& cachedHistory, const QStringList& /*args*/) - :KParts::ReadOnlyPart(parent), - m_emitOpenUrlNotify(true), - m_hasCachedFormData(false), - m_doLoadFinishedActions(false), - m_statusBarWalletLabel(0), - m_searchBar(0), - m_passwordBar(0), - m_featurePermissionBar(0) -{ - KAboutData about = KAboutData(QStringLiteral("webenginepart"), - i18nc("Program Name", "WebEnginePart"), - /*version*/ QStringLiteral("1.3.0"), - i18nc("Short Description", "QtWebEngine Browser Engine Component"), - KAboutLicense::LGPL, - i18n("(C) 2009-2010 Dawit Alemayehu\n" - "(C) 2008-2010 Urs Wolfer\n" - "(C) 2007 Trolltech ASA")); - - about.addAuthor(i18n("Sune Vuorela"), i18n("Maintainer, Developer"), QStringLiteral("sune@kde.org")); - about.addAuthor(i18n("Dawit Alemayehu"), i18n("Developer"), QStringLiteral("adawit@kde.org")); - about.addAuthor(i18n("Urs Wolfer"), i18n("Maintainer, Developer"), QStringLiteral("uwolfer@kde.org")); - about.addAuthor(i18n("Michael Howell"), i18n("Developer"), QStringLiteral("mhowell123@gmail.com")); - about.addAuthor(i18n("Laurent Montel"), i18n("Developer"), QStringLiteral("montel@kde.org")); - about.addAuthor(i18n("Dirk Mueller"), i18n("Developer"), QStringLiteral("mueller@kde.org")); - about.setProductName("webenginepart/general"); -// KComponentData componentData(&about); - setComponentData(about, false /*don't load plugins yet*/); - -#if 0 - // NOTE: If the application does not set its version number, we automatically - // set it to KDE's version number so that the default user-agent string contains - // proper application version number information. See QWebEnginePage::userAgentForUrl... - if (QCoreApplication::applicationVersion().isEmpty()) - QCoreApplication::setApplicationVersion(QString("%1.%2.%3") - .arg(KDE::versionMajor()) - .arg(KDE::versionMinor()) - .arg(KDE::versionRelease())); -#endif - setXMLFile(QL1S("webenginepart.rc")); - - // Create this KPart's widget - QWidget *mainWidget = new QWidget (parentWidget); - mainWidget->setObjectName(QStringLiteral("webenginepart")); - - // Create the WebEngineView... - m_webView = new WebEngineView (this, parentWidget); - - // Create the browser extension. - m_browserExtension = new WebEngineBrowserExtension(this, cachedHistory); - - // Add status bar extension... - m_statusBarExtension = new KParts::StatusBarExtension(this); - - // Add a web history interface for storing visited links. -// if (!QWebEngineHistoryInterface::defaultInterface()) -// QWebHistoryInterface::setDefaultInterface(new WebHistoryInterface(this)); - - // Add text and html extensions... - new WebEngineTextExtension(this); - new WebEngineHtmlExtension(this); - new WebEngineScriptableExtension(this); - - - // Layout the GUI... - QVBoxLayout* l = new QVBoxLayout(mainWidget); - l->setContentsMargins(0, 0, 0, 0); - l->setSpacing(0); - l->addWidget(m_webView); - - // Set the part's widget - setWidget(mainWidget); - - // Set the web view as the the focus object - mainWidget->setFocusProxy(m_webView); - - // Connect the signals from the webview - connect(m_webView, &QWebEngineView::titleChanged, - this, &Part::setWindowCaption); - connect(m_webView, &QWebEngineView::urlChanged, - this, &WebEnginePart::slotUrlChanged); -// connect(m_webView, SIGNAL(linkMiddleOrCtrlClicked(QUrl)), -// this, SLOT(slotLinkMiddleOrCtrlClicked(QUrl))); -// connect(m_webView, SIGNAL(selectionClipboardUrlPasted(QUrl,QString)), -// this, SLOT(slotSelectionClipboardUrlPasted(QUrl,QString))); - connect(m_webView, &QWebEngineView::loadFinished, - this, &WebEnginePart::slotLoadFinished); - - // Connect the signals from the page... - connectWebEnginePageSignals(page()); - - // Init the QAction we are going to use... - initActions(); - - // Load plugins once we are fully ready - loadPlugins(); -} - -WebEnginePart::~WebEnginePart() -{ -} - -WebEnginePage* WebEnginePart::page() -{ - if (m_webView) - return qobject_cast(m_webView->page()); - return Q_NULLPTR; -} - -const WebEnginePage* WebEnginePart::page() const -{ - if (m_webView) - return qobject_cast(m_webView->page()); - return Q_NULLPTR; -} - -void WebEnginePart::initActions() -{ - actionCollection()->addAction(KStandardAction::SaveAs, QStringLiteral("saveDocument"), - m_browserExtension, SLOT(slotSaveDocument())); - - QAction* action = new QAction(i18n("Save &Frame As..."), this); - actionCollection()->addAction(QStringLiteral("saveFrame"), action); - connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::slotSaveFrame); - - action = new QAction(QIcon::fromTheme(QStringLiteral("document-print-preview")), i18n("Print Preview"), this); - actionCollection()->addAction(QStringLiteral("printPreview"), action); - connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::slotPrintPreview); - - action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-in")), i18nc("zoom in action", "Zoom In"), this); - actionCollection()->addAction(QStringLiteral("zoomIn"), action); - actionCollection()->setDefaultShortcuts(action, QList () << QKeySequence(QStringLiteral("CTRL++")) << QKeySequence(QStringLiteral("CTRL+="))); - connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::zoomIn); - - action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-out")), i18nc("zoom out action", "Zoom Out"), this); - actionCollection()->addAction(QStringLiteral("zoomOut"), action); - actionCollection()->setDefaultShortcuts(action, QList () << QKeySequence(QStringLiteral("CTRL+-")) << QKeySequence(QStringLiteral("CTRL+_"))); - connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::zoomOut); - - action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-original")), i18nc("reset zoom action", "Actual Size"), this); - actionCollection()->addAction(QStringLiteral("zoomNormal"), action); - actionCollection()->setDefaultShortcut(action, QKeySequence(QStringLiteral("CTRL+0"))); - connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::zoomNormal); - - action = new QAction(i18n("Zoom Text Only"), this); - action->setCheckable(true); - KConfigGroup cgHtml(KSharedConfig::openConfig(), "HTML Settings"); - bool zoomTextOnly = cgHtml.readEntry("ZoomTextOnly", false); - action->setChecked(zoomTextOnly); - actionCollection()->addAction(QStringLiteral("zoomTextOnly"), action); - connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::toogleZoomTextOnly); - - action = new QAction(i18n("Zoom To DPI"), this); - action->setCheckable(true); - bool zoomToDPI = cgHtml.readEntry("ZoomToDPI", false); - action->setChecked(zoomToDPI); - actionCollection()->addAction(QStringLiteral("zoomToDPI"), action); - connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::toogleZoomToDPI); - - action = actionCollection()->addAction(KStandardAction::SelectAll, QStringLiteral("selectAll"), - m_browserExtension, SLOT(slotSelectAll())); - action->setShortcutContext(Qt::WidgetShortcut); - m_webView->addAction(action); - - KCodecAction *codecAction = new KCodecAction( QIcon::fromTheme(QStringLiteral("character-set")), i18n( "Set &Encoding" ), this, true ); - actionCollection()->addAction( QStringLiteral("setEncoding"), codecAction ); - connect(codecAction, SIGNAL(triggered(QTextCodec*)), SLOT(slotSetTextEncoding(QTextCodec*))); - - action = new QAction(i18n("View Do&cument Source"), this); - actionCollection()->addAction(QStringLiteral("viewDocumentSource"), action); - actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_U)); - connect(action, &QAction::triggered, m_browserExtension, &WebEngineBrowserExtension::slotViewDocumentSource); - - action = new QAction(i18nc("Secure Sockets Layer", "SSL"), this); - actionCollection()->addAction(QStringLiteral("security"), action); - connect(action, &QAction::triggered, this, &WebEnginePart::slotShowSecurity); - - action = actionCollection()->addAction(KStandardAction::Find, QStringLiteral("find"), this, SLOT(slotShowSearchBar())); - action->setWhatsThis(i18nc("find action \"whats this\" text", "

Find text

" - "Shows a dialog that allows you to find text on the displayed page.")); -} - -void WebEnginePart::updateActions() -{ - m_browserExtension->updateActions(); - - QAction* action = actionCollection()->action(QL1S("saveDocument")); - if (action) { - const QString protocol (url().scheme()); - action->setEnabled(protocol != QL1S("about") && protocol != QL1S("error")); - } - - action = actionCollection()->action(QL1S("printPreview")); - if (action) { - action->setEnabled(m_browserExtension->isActionEnabled("print")); - } - -} - -void WebEnginePart::connectWebEnginePageSignals(WebEnginePage* page) -{ - if (!page) - return; - - connect(page, SIGNAL(loadStarted()), - this, SLOT(slotLoadStarted())); - connect(page, SIGNAL(loadAborted(QUrl)), - this, SLOT(slotLoadAborted(QUrl))); - connect(page, &QWebEnginePage::linkHovered, - this, &WebEnginePart::slotLinkHovered); -// connect(page, SIGNAL(saveFrameStateRequested(QWebFrame*,QWebHistoryItem*)), -// this, SLOT(slotSaveFrameState(QWebFrame*,QWebHistoryItem*))); -// connect(page, SIGNAL(restoreFrameStateRequested(QWebFrame*)), -// this, SLOT(slotRestoreFrameState(QWebFrame*))); -// connect(page, SIGNAL(statusBarMessage(QString)), -// this, SLOT(slotSetStatusBarText(QString))); - connect(page, SIGNAL(windowCloseRequested()), - this, SLOT(slotWindowCloseRequested())); -// connect(page, SIGNAL(printRequested(QWebFrame*)), -// m_browserExtension, SLOT(slotPrintRequested(QWebFrame*))); - // connect(page, SIGNAL(frameCreated(QWebFrame*)), - // this, SLOT(slotFrameCreated(QWebFrame*))); - -// connect(m_webView, SIGNAL(linkShiftClicked(QUrl)), -// page, SLOT(downloadUrl(QUrl))); - - connect(page, SIGNAL(loadProgress(int)), - m_browserExtension, SIGNAL(loadingProgress(int))); - connect(page, SIGNAL(selectionChanged()), - m_browserExtension, SLOT(updateEditActions())); -// connect(m_browserExtension, SIGNAL(saveUrl(QUrl)), -// page, SLOT(downloadUrl(QUrl))); - - connect(page, &QWebEnginePage::iconUrlChanged, [page, this](const QUrl& url) { - if (WebEngineSettings::self()->favIconsEnabled() - && !page->profile()->isOffTheRecord()){ - m_browserExtension->setIconUrl(url); - } - }); - -#if 0 - KWebWallet *wallet = page->wallet(); - if (wallet) { - connect(wallet, SIGNAL(saveFormDataRequested(QString,QUrl)), - this, SLOT(slotSaveFormDataRequested(QString,QUrl))); - connect(wallet, SIGNAL(fillFormRequestCompleted(bool)), - this, SLOT(slotFillFormRequestCompleted(bool))); - connect(wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed())); - } -#endif -} - -bool WebEnginePart::openUrl(const QUrl &_u) -{ - QUrl u (_u); - - qDebug() << u; - - // Ignore empty requests... - if (u.isEmpty()) - return false; - - // If the URL given is a supported local protocol, e.g. "bookmark" but lacks - // a path component, we set the path to "/" here so that the security context - // will properly allow access to local resources. - if (u.host().isEmpty() && u.path().isEmpty() - && KProtocolInfo::protocolClass(u.scheme()) == QL1S(":local")) { - u.setPath(QL1S("/")); - } - - // Do not emit update history when url is typed in since the host - // should handle that automatically itself. - m_emitOpenUrlNotify = false; - - // Pointer to the page object... - WebEnginePage* p = page(); - Q_ASSERT(p); - - KParts::BrowserArguments bargs (m_browserExtension->browserArguments()); - KParts::OpenUrlArguments args (arguments()); - - if (!Utils::isBlankUrl(u)) { - // Get the SSL information sent, if any... - if (args.metaData().contains(QL1S("ssl_in_use"))) { - WebSslInfo sslInfo; - sslInfo.restoreFrom(KIO::MetaData(args.metaData()).toVariant()); - sslInfo.setUrl(u); - p->setSslInfo(sslInfo); - } - } - - // Set URL in KParts before emitting started; konq plugins rely on that. - setUrl(u); - m_doLoadFinishedActions = true; - m_webView->loadUrl(u, args, bargs); - return true; -} - -bool WebEnginePart::closeUrl() -{ - m_webView->triggerPageAction(QWebEnginePage::Stop); - m_webView->stop(); - return true; -} - -QWebEngineView* WebEnginePart::view() -{ - return m_webView; -} - -bool WebEnginePart::isModified() const -{ - //return m_webView->isModified(); - return false; -} - -void WebEnginePart::guiActivateEvent(KParts::GUIActivateEvent *event) -{ - if (event && event->activated() && m_webView) { - emit setWindowCaption(m_webView->title()); - } -} - -bool WebEnginePart::openFile() -{ - // never reached - return false; -} - - -/// slots... - -void WebEnginePart::slotLoadStarted() -{ - if(!Utils::isBlankUrl(url())) - { - emit started(0); - } - updateActions(); - - // If "NoEmitOpenUrlNotification" property is set to true, do not - // emit the open url notification. Property is set by this part's - // extension to prevent openUrl notification being sent when - // handling history navigation requests (back/forward). - const bool doNotEmitOpenUrl = property("NoEmitOpenUrlNotification").toBool(); - if (doNotEmitOpenUrl) { - setProperty("NoEmitOpenUrlNotification", QVariant()); - } else { - if (m_emitOpenUrlNotify) { - emit m_browserExtension->openUrlNotify(); - } - } - // Unless we go via openUrl again, the next time we are here we emit (e.g. after clicking on a link) - m_emitOpenUrlNotify = true; -} - -void WebEnginePart::slotLoadFinished (bool ok) -{ - if (!ok || !m_doLoadFinishedActions) - return; - - slotWalletClosed(); - m_doLoadFinishedActions = false; - - // If the document contains no tag, then set it to the current url. - if (m_webView->title().trimmed().isEmpty()) { - // If the document title is empty, then set it to the current url - const QUrl url (m_webView->url()); - const QString caption (url.toString((QUrl::RemoveQuery|QUrl::RemoveFragment))); - emit setWindowCaption(caption); - - // The urlChanged signal is emitted if and only if the main frame - // receives the title of the page so we manually invoke the slot as a - // work around here for pages that do not contain it, such as text - // documents... - slotUrlChanged(url); - } - if (!Utils::isBlankUrl(url())) { - m_hasCachedFormData = false; - - if (WebEngineSettings::self()->isNonPasswordStorableSite(url().host())) { - addWalletStatusBarIcon(); - } else { -// Attempt to fill the web form... -// KWebWallet *webWallet = page() ? page()->wallet() : 0; -// if (webWallet) { -// webWallet->fillFormData(frame, false); -// } - } - } - - bool pending = false; - // QWebFrame* frame = (page() ? page()->currentFrame() : 0); - // if (ok && - // frame == page()->mainFrame() && - // !frame->findFirstElement(QL1S("head>meta[http-equiv=refresh]")).isNull()) { - // if (WebEngineSettings::self()->autoPageRefresh()) { - // pending = true; - // } else { - // frame->page()->triggerAction(QWebEnginePage::Stop); - // } - // } - emit completed ((ok && pending)); - - updateActions(); -} - -void WebEnginePart::slotLoadAborted(const QUrl & url) -{ - closeUrl(); - m_doLoadFinishedActions = false; - if (url.isValid()) - emit m_browserExtension->openUrlRequest(url); - else - setUrl(m_webView->url()); -} - -void WebEnginePart::slotUrlChanged(const QUrl& url) -{ - // Ignore if empty - if (url.isEmpty()) - return; - - // Ignore if error url - if (url.scheme() == QL1S("error")) - return; - - const QUrl u (url); - - // Ignore if url has not changed! - if (this->url() == u) - return; - - m_doLoadFinishedActions = true; - setUrl(u); - - // Do not update the location bar with about:blank - if (!Utils::isBlankUrl(url)) { - //kDebug() << "Setting location bar to" << u.prettyUrl() << "current URL:" << this->url(); - emit m_browserExtension->setLocationBarUrl(u.toDisplayString()); - } -} - -void WebEnginePart::slotShowSecurity() -{ - if (!page()) - return; - - const WebSslInfo& sslInfo = page()->sslInfo(); - if (!sslInfo.isValid()) { - KMessageBox::information(0, i18n("The SSL information for this site " - "appears to be corrupt."), - i18nc("Secure Sockets Layer", "SSL")); - return; - } - - KSslInfoDialog *dlg = new KSslInfoDialog (widget()); - dlg->setSslInfo(sslInfo.certificateChain(), - sslInfo.peerAddress().toString(), - url().host(), - sslInfo.protocol(), - sslInfo.ciphers(), - sslInfo.usedChiperBits(), - sslInfo.supportedChiperBits(), - KSslInfoDialog::errorsFromString(sslInfo.certificateErrors())); - - dlg->open(); -} - -#if 0 -void WebEnginePart::slotSaveFrameState(QWebFrame *frame, QWebHistoryItem *item) -{ - if (!frame || !item) { - return; - } - - // Handle actions that apply only to the mainframe... - if (frame == view()->page()->mainFrame()) { - } - - // For some reason, QtWebEngine PORTING_TODO does not restore scroll position when - // QWebHistory is restored from persistent storage. Therefore, we - // preserve that information and restore it as needed. See - // slotRestoreFrameState. - const QPoint scrollPos (frame->scrollPosition()); - if (!scrollPos.isNull()) { - // kDebug() << "Saving scroll position:" << scrollPos; - item->setUserData(scrollPos); - } -} -#endif - -#if 0 -void WebEnginePart::slotRestoreFrameState(QWebFrame *frame) -{ - QWebEnginePage* page = (frame ? frame->page() : 0); - QWebHistory* history = (page ? page->history() : 0); - - // No history item... - if (!history || history->count() < 1) - return; - - QWebHistoryItem currentHistoryItem (history->currentItem()); - - // Update the scroll position if needed. See comment in slotSaveFrameState above. - if (frame->baseUrl().resolved(frame->url()) == currentHistoryItem.url()) { - const QPoint currentPos (frame->scrollPosition()); - const QPoint desiredPos (currentHistoryItem.userData().toPoint()); - if (currentPos.isNull() && !desiredPos.isNull()) { - frame->setScrollPosition(desiredPos); - } - } -} -#endif - -void WebEnginePart::slotLinkHovered(const QString& _link) -{ - QString message; - - if (_link.isEmpty()) { - message = QL1S(""); - emit m_browserExtension->mouseOverInfo(KFileItem()); - } else { - QUrl linkUrl (_link); - const QString scheme = linkUrl.scheme(); - - // Protect the user against URL spoofing! - linkUrl.setUserName(QString()); - const QString link (linkUrl.toString()); - - if (QString::compare(scheme, QL1S("mailto"), Qt::CaseInsensitive) == 0) { - message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", "Email: "); - - // Workaround: for QUrl's parsing deficiencies of "mailto:foo@bar.com". - if (!linkUrl.hasQuery()) - linkUrl = QUrl(scheme + '?' + linkUrl.path()); - - QMap<QString, QStringList> fields; - QUrlQuery query(linkUrl); - QList<QPair<QString, QString> > queryItems = query.queryItems(); - const int count = queryItems.count(); - - for(int i = 0; i < count; ++i) { - const QPair<QString, QString> queryItem (queryItems.at(i)); - //kDebug() << "query: " << queryItem.first << queryItem.second; - if (queryItem.first.contains(QL1C('@')) && queryItem.second.isEmpty()) - fields[QStringLiteral("to")] << queryItem.first; - if (QString::compare(queryItem.first, QL1S("to"), Qt::CaseInsensitive) == 0) - fields[QStringLiteral("to")] << queryItem.second; - if (QString::compare(queryItem.first, QL1S("cc"), Qt::CaseInsensitive) == 0) - fields[QStringLiteral("cc")] << queryItem.second; - if (QString::compare(queryItem.first, QL1S("bcc"), Qt::CaseInsensitive) == 0) - fields[QStringLiteral("bcc")] << queryItem.second; - if (QString::compare(queryItem.first, QL1S("subject"), Qt::CaseInsensitive) == 0) - fields[QStringLiteral("subject")] << queryItem.second; - } - - if (fields.contains(QL1S("to"))) - message += fields.value(QL1S("to")).join(QL1S(", ")); - if (fields.contains(QL1S("cc"))) - message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - CC: ") + fields.value(QL1S("cc")).join(QL1S(", ")); - if (fields.contains(QL1S("bcc"))) - message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - BCC: ") + fields.value(QL1S("bcc")).join(QL1S(", ")); - if (fields.contains(QL1S("subject"))) - message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - Subject: ") + fields.value(QL1S("subject")).join(QL1S(" ")); - } else if (scheme == QL1S("javascript")) { - message = KStringHandler::rsqueeze(link, 150); - if (link.startsWith(QL1S("javascript:window.open"))) - message += i18n(" (In new window)"); - } else { - message = link; -#if 0 - QWebFrame* frame = page() ? page()->currentFrame() : 0; - if (frame) { - QWebHitTestResult result = frame->hitTestContent(page()->view()->mapFromGlobal(QCursor::pos())); - QWebFrame* target = result.linkTargetFrame(); - if (frame->parentFrame() && target == frame->parentFrame()) { - message += i18n(" (In parent frame)"); - } else if (!target || target != frame) { - message += i18n(" (In new window)"); - } - } -#endif - KFileItem item (linkUrl, QString(), KFileItem::Unknown); - emit m_browserExtension->mouseOverInfo(item); - } - } - - emit setStatusBarText(message); -} - -void WebEnginePart::slotSearchForText(const QString &text, bool backward) -{ - QWebEnginePage::FindFlags flags; // = QWebEnginePage::FindWrapsAroundDocument; - - if (backward) - flags |= QWebEnginePage::FindBackward; - - if (m_searchBar->caseSensitive()) - flags |= QWebEnginePage::FindCaseSensitively; - - //kDebug() << "search for text:" << text << ", backward ?" << backward; - page()->findText(text, flags, [this](bool found) { - m_searchBar->setFoundMatch(found); - }); -} - -void WebEnginePart::slotShowSearchBar() -{ - if (!m_searchBar) { - // Create the search bar... - m_searchBar = new SearchBar(widget()); - connect(m_searchBar, SIGNAL(searchTextChanged(QString,bool)), - this, SLOT(slotSearchForText(QString,bool))); - - actionCollection()->addAction(KStandardAction::FindNext, QStringLiteral("findnext"), - m_searchBar, SLOT(findNext())); - actionCollection()->addAction(KStandardAction::FindPrev, QStringLiteral("findprev"), - m_searchBar, SLOT(findPrevious())); - - QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); - if (lay) { - lay->addWidget(m_searchBar); - } - } - const QString text = m_webView->selectedText(); - m_searchBar->setSearchText(text.left(150)); -} - -void WebEnginePart::slotLinkMiddleOrCtrlClicked(const QUrl& linkUrl) -{ - emit m_browserExtension->createNewWindow(linkUrl); -} - -void WebEnginePart::slotSelectionClipboardUrlPasted(const QUrl& selectedUrl, const QString& searchText) -{ - if (!WebEngineSettings::self()->isOpenMiddleClickEnabled()) - return; - - if (!searchText.isEmpty() && - KMessageBox::questionYesNo(m_webView, - i18n("<qt>Do you want to search for <b>%1</b>?</qt>", searchText), - i18n("Internet Search"), KGuiItem(i18n("&Search"), QStringLiteral("edit-find")), - KStandardGuiItem::cancel(), QStringLiteral("MiddleClickSearch")) != KMessageBox::Yes) - return; - - emit m_browserExtension->openUrlRequest(selectedUrl); -} - -void WebEnginePart::slotWalletClosed() -{ - if (!m_statusBarWalletLabel) - return; - - m_statusBarExtension->removeStatusBarItem(m_statusBarWalletLabel); - delete m_statusBarWalletLabel; - m_statusBarWalletLabel = 0; - m_hasCachedFormData = false; -} - -void WebEnginePart::slotShowWalletMenu() -{ - QMenu *menu = new QMenu(0); - - if (m_webView && WebEngineSettings::self()->isNonPasswordStorableSite(m_webView->url().host())) - menu->addAction(i18n("&Allow password caching for this site"), this, SLOT(slotDeleteNonPasswordStorableSite())); - - if (m_hasCachedFormData) - menu->addAction(i18n("Remove all cached passwords for this site"), this, SLOT(slotRemoveCachedPasswords())); - - menu->addSeparator(); - menu->addAction(i18n("&Close Wallet"), this, SLOT(slotWalletClosed())); - - KAcceleratorManager::manage(menu); - menu->popup(QCursor::pos()); -} - -void WebEnginePart::slotLaunchWalletManager() -{ - QDBusInterface r(QStringLiteral("org.kde.kwalletmanager"), QStringLiteral("/kwalletmanager/MainWindow_1")); - if (r.isValid()) - r.call(QDBus::NoBlock, QStringLiteral("show")); - else - KToolInvocation::startServiceByDesktopName(QStringLiteral("kwalletmanager_show")); -} - -void WebEnginePart::slotDeleteNonPasswordStorableSite() -{ - if (m_webView) - WebEngineSettings::self()->removeNonPasswordStorableSite(m_webView->url().host()); -} - -void WebEnginePart::slotRemoveCachedPasswords() -{ - if (!page()) // || !page()->wallet()) - return; - -// page()->wallet()->removeFormData(page()->mainFrame(), true); - m_hasCachedFormData = false; -} - -void WebEnginePart::slotSetTextEncoding(QTextCodec * codec) -{ - // FIXME: The code below that sets the text encoding has been reported not to work. - if (!page()) - return; - - QWebEngineSettings *localSettings = page()->settings(); - if (!localSettings) - return; - - qDebug() << "Encoding: new=>" << localSettings->defaultTextEncoding() << ", old=>" << codec->name(); - - localSettings->setDefaultTextEncoding(codec->name()); - page()->triggerAction(QWebEnginePage::Reload); -} - -void WebEnginePart::slotSetStatusBarText(const QString& text) -{ - const QString host (page() ? page()->url().host() : QString()); - if (WebEngineSettings::self()->windowStatusPolicy(host) == KParts::HtmlSettingsInterface::JSWindowStatusAllow) - emit setStatusBarText(text); -} - -void WebEnginePart::slotWindowCloseRequested() -{ - emit m_browserExtension->requestFocus(this); -#if 0 - if (KMessageBox::questionYesNo(m_webView, - i18n("Close window?"), i18n("Confirmation Required"), - KStandardGuiItem::close(), KStandardGuiItem::cancel()) - != KMessageBox::Yes) - return; -#endif - this->deleteLater(); -} - -void WebEnginePart::slotShowFeaturePermissionBar(QWebEnginePage::Feature feature) -{ - // FIXME: Allow multiple concurrent feature permission requests. - if (m_featurePermissionBar && m_featurePermissionBar->isVisible()) - return; - - if (!m_featurePermissionBar) { - m_featurePermissionBar = new FeaturePermissionBar(widget()); - - connect(m_featurePermissionBar, SIGNAL(permissionGranted(QWebEnginePage::Feature)), - this, SLOT(slotFeaturePermissionGranted(QWebEnginePage::Feature))); - connect(m_featurePermissionBar, SIGNAL(permissionDenied(QWebEnginePage::Feature)), - this, SLOT(slotFeaturePermissionDenied(QWebEnginePage::Feature))); -// connect(m_passwordBar, SIGNAL(done()), -// this, SLOT(slotSaveFormDataDone())); - QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); - if (lay) - lay->insertWidget(0, m_featurePermissionBar); - } - m_featurePermissionBar->setFeature(feature); -// m_featurePermissionBar->setText(i18n("<html>Do you want to grant the site <b>%1</b> " -// "access to information about your current physical location?", -// url.host())); - m_featurePermissionBar->setText(i18n("<html>Do you want to grant the site " - "access to information about your current physical location?")); - m_featurePermissionBar->animatedShow(); -} - -void WebEnginePart::slotFeaturePermissionGranted(QWebEnginePage::Feature feature) -{ - Q_ASSERT(m_featurePermissionBar && m_featurePermissionBar->feature() == feature); - page()->setFeaturePermission(page()->url(), feature, QWebEnginePage::PermissionGrantedByUser); -} - -void WebEnginePart::slotFeaturePermissionDenied(QWebEnginePage::Feature feature) -{ - Q_ASSERT(m_featurePermissionBar && m_featurePermissionBar->feature() == feature); - page()->setFeaturePermission(page()->url(), feature, QWebEnginePage::PermissionDeniedByUser); -} - -void WebEnginePart::slotSaveFormDataRequested (const QString& key, const QUrl& url) -{ - if (WebEngineSettings::self()->isNonPasswordStorableSite(url.host())) - return; - - if (!WebEngineSettings::self()->askToSaveSitePassword()) - return; - - if (m_passwordBar && m_passwordBar->isVisible()) - return; - - if (!m_passwordBar) { - m_passwordBar = new PasswordBar(widget()); -#if 0 - KWebWallet* wallet = page()->wallet(); - if (!wallet) { - kWarning() << "No wallet instance found! This should never happen!"; - return; - } - connect(m_passwordBar, SIGNAL(saveFormDataAccepted(QString)), - wallet, SLOT(acceptSaveFormDataRequest(QString))); - connect(m_passwordBar, SIGNAL(saveFormDataRejected(QString)), - wallet, SLOT(rejectSaveFormDataRequest(QString))); - connect(m_passwordBar, SIGNAL(done()), - this, SLOT(slotSaveFormDataDone())); -#endif - } - - Q_ASSERT(m_passwordBar); - - m_passwordBar->setUrl(url); - m_passwordBar->setRequestKey(key); - m_passwordBar->setText(i18n("<html>Do you want %1 to remember the login " - "information for <b>%2</b>?</html>", - QCoreApplication::applicationName(), - url.host())); - - QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); - if (lay) - lay->insertWidget(0, m_passwordBar); - - m_passwordBar->animatedShow(); -} - -void WebEnginePart::slotSaveFormDataDone() -{ - if (!m_passwordBar) - return; - - QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); - if (lay) - lay->removeWidget(m_passwordBar); -} - -void WebEnginePart::addWalletStatusBarIcon () -{ - if (m_statusBarWalletLabel) { - m_statusBarExtension->removeStatusBarItem(m_statusBarWalletLabel); - } else { - m_statusBarWalletLabel = new KUrlLabel(m_statusBarExtension->statusBar()); - m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); - m_statusBarWalletLabel->setUseCursor(false); - m_statusBarWalletLabel->setPixmap(QIcon::fromTheme(QStringLiteral("wallet-open")).pixmap(QSize(16,16))); - connect(m_statusBarWalletLabel, SIGNAL(leftClickedUrl()), SLOT(slotLaunchWalletManager())); - connect(m_statusBarWalletLabel, SIGNAL(rightClickedUrl()), SLOT(slotShowWalletMenu())); - } - m_statusBarExtension->addStatusBarItem(m_statusBarWalletLabel, 0, false); -} - -void WebEnginePart::slotFillFormRequestCompleted (bool ok) -{ - if ((m_hasCachedFormData = ok)) - addWalletStatusBarIcon(); -} - diff --git a/webenginepart/src/webenginepart.desktop a/webenginepart/src/webenginepart.desktop deleted file mode 100644 index 5d6085773..000000000 --- a/webenginepart/src/webenginepart.desktop +++ /dev/null @@ -1,65 +0,0 @@ -[Desktop Entry] -Type=Service -Comment=Embeddable HTML component -Comment[ca]=Component HTML incrustable -Comment[ca@valencia]=Component HTML incrustable -Comment[cs]=Zapouzdřitelná HTML komponenta -Comment[da]=HTML-komponent som kan indlejres -Comment[de]=Einbettungsfähige HTML-Komponente -Comment[en_GB]=Embeddable HTML component -Comment[es]=Componente HTML empotrable -Comment[et]=Põimitav HTML-komponent -Comment[fi]=Upotettava HTML-osa -Comment[it]=Componente HTML incorporabile -Comment[ko]=끼워넣을 수 있는 HTML 구성 요소 -Comment[nb]=Innebyggbar HTML-komponent -Comment[nl]=In te bedden HTML-component -Comment[nn]=Innebyggbar HTML-komponent -Comment[pl]=Osadzalny składnik HTML -Comment[pt]=Componente incorporada de HTML -Comment[pt_BR]=Componete HTML embutido -Comment[sk]=Vložiteľný HTML komponent -Comment[sl]=Vgradljiv sestavni del HTML -Comment[sr]=Угнездива ХТМЛ компонента -Comment[sr@ijekavian]=Угњездива ХТМЛ компонента -Comment[sr@ijekavianlatin]=Ugnjezdiva HTML komponenta -Comment[sr@latin]=Ugnezdiva HTML komponenta -Comment[sv]=Inbäddningsbar HTML-komponent -Comment[uk]=Придатний до вбудовування компонент HTML -Comment[x-test]=xxEmbeddable HTML componentxx -Comment[zh_CN]=可嵌入的 HTML 组件 -Comment[zh_TW]=可內嵌的 HTML 元件 -Icon=webengine -MimeType=text/html;application/xml;application/xhtml+xml; -Name=WebEngine -Name[ca]=WebEngine -Name[ca@valencia]=WebEngine -Name[cs]=WebEngine -Name[da]=WebEngine -Name[de]=Webengine -Name[en_GB]=WebEngine -Name[es]=Motor Web -Name[et]=WebEngine -Name[fi]=WebEngine -Name[it]=WebEngine -Name[ko]=WebEngine -Name[nl]=WebEngine -Name[nn]=Vevmotor -Name[pl]=SilnikSieciowy -Name[pt]=Motor Web -Name[pt_BR]=WebEngine -Name[sk]=WebEngine -Name[sl]=Spletni pogon -Name[sr]=КуТ‑вебенџин -Name[sr@ijekavian]=КуТ‑вебенџин -Name[sr@ijekavianlatin]=QtWebEngine -Name[sr@latin]=QtWebEngine -Name[sv]=Webbgränssnitt -Name[uk]=Вебрушій -Name[x-test]=xxWebEnginexx -Name[zh_CN]=WebEngine -Name[zh_TW]=WebEngine -X-KDE-Default-UserAgent=Mozilla/5.0 (%PLATFORM%; %SECURITY%; %OSNAME% %OSVERSION% %SYSTYPE%; %LANGUAGE%) AppleWebKit/534.34 (KHTML, like Gecko) %APPVERSION% Safari/534.34 -X-KDE-ServiceTypes=KParts/ReadOnlyPart,Browser/View -X-KDE-Library=kf5/parts/webenginepart -InitialPreference=12 diff --git a/webenginepart/src/webenginepart.h a/webenginepart/src/webenginepart.h deleted file mode 100644 index 6889e6d7f..000000000 --- a/webenginepart/src/webenginepart.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2007 Trolltech ASA - * Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org> - * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ -#ifndef WEBENGINEPART_H -#define WEBENGINEPART_H - -#include "kwebenginepartlib_export.h" - -#include <QtWebEngineWidgets/QWebEnginePage> - -#include <KParts/ReadOnlyPart> -#include <QUrl> - -namespace KParts { - class BrowserExtension; - class StatusBarExtension; -} - -class QWebEngineView; -class WebEngineView; -class WebEnginePage; -class SearchBar; -class PasswordBar; -class FeaturePermissionBar; -class KUrlLabel; -class WebEngineBrowserExtension; - -/** - * A KPart wrapper for the QtWebEngine's browser rendering engine. - * - * This class attempts to provide the same type of integration into KPart - * plugin applications, such as Konqueror, in much the same way as KHTML. - * - * Unlink the KHTML part however, access into the internals of the rendering - * engine are provided through existing QtWebEngine class ; @see QWebEngineView. - * - */ -class KWEBENGINEPARTLIB_EXPORT WebEnginePart : public KParts::ReadOnlyPart -{ - Q_OBJECT - Q_PROPERTY( bool modified READ isModified ) -public: - explicit WebEnginePart(QWidget* parentWidget = 0, QObject* parent = Q_NULLPTR, - const QByteArray& cachedHistory = QByteArray(), - const QStringList& = QStringList()); - ~WebEnginePart(); - - /** - * Re-implemented for internal reasons. API remains unaffected. - * - * @see KParts::ReadOnlyPart::openUrl - */ - bool openUrl(const QUrl &) Q_DECL_OVERRIDE; - - /** - * Re-implemented for internal reasons. API remains unaffected. - * - * @see KParts::ReadOnlyPart::closeUrl - */ - bool closeUrl() Q_DECL_OVERRIDE; - - /** - * Returns a pointer to the render widget used to display a web page. - * - * @see QWebEngineView. - */ - virtual QWebEngineView *view(); - - /** - * Checks whether the page contains unsubmitted form changes. - * - * @return @p true if form changes exist. - */ - bool isModified() const; - - /** - * Connects the appropriate signals from the given page to the slots - * in this class. - */ - void connectWebEnginePageSignals(WebEnginePage* page); - - void slotShowFeaturePermissionBar(QWebEnginePage::Feature); -protected: - /** - * Re-implemented for internal reasons. API remains unaffected. - * - * @see KParts::ReadOnlyPart::guiActivateEvent - */ - void guiActivateEvent(KParts::GUIActivateEvent *) Q_DECL_OVERRIDE; - - /** - * Re-implemented for internal reasons. API remains unaffected. - * - * @see KParts::ReadOnlyPart::openFile - */ - bool openFile() Q_DECL_OVERRIDE; - -private Q_SLOTS: - void slotShowSecurity(); - void slotShowSearchBar(); - void slotLoadStarted(); - void slotLoadAborted(const QUrl &); - void slotLoadFinished(bool); - - void slotSearchForText(const QString &text, bool backward); - void slotLinkHovered(const QString &); - //void slotSaveFrameState(QWebFrame *frame, QWebHistoryItem *item); - //void slotRestoreFrameState(QWebFrame *frame); - void slotLinkMiddleOrCtrlClicked(const QUrl&); - void slotSelectionClipboardUrlPasted(const QUrl&, const QString&); - - void slotUrlChanged(const QUrl &); - void slotWalletClosed(); - void slotShowWalletMenu(); - void slotLaunchWalletManager(); - void slotDeleteNonPasswordStorableSite(); - void slotRemoveCachedPasswords(); - void slotSetTextEncoding(QTextCodec*); - void slotSetStatusBarText(const QString& text); - void slotWindowCloseRequested(); - void slotSaveFormDataRequested(const QString &, const QUrl &); - void slotSaveFormDataDone(); - void slotFillFormRequestCompleted(bool); - - void slotFeaturePermissionGranted(QWebEnginePage::Feature); - void slotFeaturePermissionDenied(QWebEnginePage::Feature); - -private: - WebEnginePage* page(); - const WebEnginePage* page() const; - void initActions(); - void updateActions(); - void addWalletStatusBarIcon(); - - bool m_emitOpenUrlNotify; - bool m_hasCachedFormData; - bool m_doLoadFinishedActions; - KUrlLabel* m_statusBarWalletLabel; - SearchBar* m_searchBar; - PasswordBar* m_passwordBar; - FeaturePermissionBar* m_featurePermissionBar; - WebEngineBrowserExtension* m_browserExtension; - KParts::StatusBarExtension* m_statusBarExtension; - WebEngineView* m_webView; -}; - -#endif // WEBENGINEPART_H diff --git a/webenginepart/src/webenginepart.rc a/webenginepart/src/webenginepart.rc deleted file mode 100644 index 2b564ca97..000000000 --- a/webenginepart/src/webenginepart.rc +++ /dev/null @@ -1,32 +0,0 @@ -<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> -<kpartgui name="kwebkitpart" version="8"> -<MenuBar> - <Menu name="file"> - <Action name="saveDocument" /> - <Action name="saveFrame" /> - <Separator /> - <Action name="printPreview" group="print" /> - </Menu> - <Menu name="edit"> - <Action name="selectAll" /> - <Separator /> - <Action name="find" /> - </Menu> - <Menu name="view"> - <Action name="zoomIn" /> - <Action name="zoomOut" /> - <Action name="zoomNormal" /> - <Action name="zoomTextOnly" /> - <Action name="zoomToDPI" /> - <Separator /> - <Action name="setEncoding" /> - <Action name="viewDocumentSource" /> - <ActionList name="debugScriptList" /> - </Menu> -</MenuBar> -<ToolBar name="htmlToolBar" iconText="icononly" iconSize="22" hidden="true"><text>HTML Toolbar</text> - <Action name="zoomIn" /> - <Action name="zoomOut" /> - <Action name="zoomNormal" /> -</ToolBar> -</kpartgui> diff --git a/webenginepart/src/webenginepart_ext.cpp a/webenginepart/src/webenginepart_ext.cpp deleted file mode 100644 index b80de84ad..000000000 --- a/webenginepart/src/webenginepart_ext.cpp +++ /dev/null @@ -1,1237 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <QtWebEngine/QtWebEngineVersion> -#include "webenginepart_ext.h" - -#include "webenginepart.h" -#include "webengineview.h" -#include "webenginepage.h" -#include "settings/webenginesettings.h" -#include <QtWebEngineWidgets/QWebEngineSettings> - -#include <KDesktopFile> -#include <KConfigGroup> -#include <KToolInvocation> -#include <KSharedConfig> -#include <KRun> -#include <KProtocolInfo> -#include <QInputDialog> -#include <KLocalizedString> -#include <QTemporaryFile> -#include <KUriFilter> -#include <Sonnet/Dialog> -#include <sonnet/backgroundchecker.h> - -#include <QBuffer> -#include <QVariant> -#include <QClipboard> -#include <QApplication> -#include <QAction> -#include <QPrinter> -#include <QPrintDialog> -#include <QPrintPreviewDialog> -#include <QInputDialog> -#include <QWebEngineHistory> -#include <QMimeData> -#define QL1S(x) QLatin1String(x) -#define QL1C(x) QLatin1Char(x) - -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; -} - -WebEngineBrowserExtension::WebEngineBrowserExtension(WebEnginePart *parent, const QByteArray& cachedHistoryData) - :KParts::BrowserExtension(parent), - m_part(parent), - mCurrentPrinter(Q_NULLPTR) -{ - enableAction("cut", false); - enableAction("copy", false); - enableAction("paste", false); - enableAction("print", true); - - if (cachedHistoryData.isEmpty()) { - return; - } - - QBuffer buffer; - buffer.setData(cachedHistoryData); - if (!buffer.open(QIODevice::ReadOnly)) { - return; - } - - // NOTE: When restoring history, webengine PORTING_TODO automatically navigates to - // the previous "currentItem". Since we do not want that to happen, - // we set a property on the WebEnginePage object that is used to allow or - // disallow history navigation in WebEnginePage::acceptNavigationRequest. - view()->page()->setProperty("HistoryNavigationLocked", true); - QDataStream s (&buffer); - s >> *(view()->history()); -} - -WebEngineBrowserExtension::~WebEngineBrowserExtension() -{ -} - -WebEngineView* WebEngineBrowserExtension::view() -{ - if (!m_view && m_part) { - m_view = qobject_cast<WebEngineView*>(m_part->view()); - } - - return m_view; -} - -int WebEngineBrowserExtension::xOffset() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (view()) - return view()->page()->scrollPosition().x(); -#endif - - return KParts::BrowserExtension::xOffset(); -} - -int WebEngineBrowserExtension::yOffset() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (view()) - return view()->page()->scrollPosition().y(); -#endif - - return KParts::BrowserExtension::yOffset(); -} - -void WebEngineBrowserExtension::saveState(QDataStream &stream) -{ - // TODO: Save information such as form data from the current page. - QWebEngineHistory* history = (view() ? view()->history() : 0); - const int historyIndex = (history ? history->currentItemIndex() : -1); - const QUrl historyUrl = (history && historyIndex > -1) ? QUrl(history->currentItem().url()) : m_part->url(); - - stream << historyUrl - << static_cast<qint32>(xOffset()) - << static_cast<qint32>(yOffset()) - << historyIndex - << m_historyData; -} - -void WebEngineBrowserExtension::restoreState(QDataStream &stream) -{ - QUrl u; - QByteArray historyData; - qint32 xOfs = -1, yOfs = -1, historyItemIndex = -1; - stream >> u >> xOfs >> yOfs >> historyItemIndex >> historyData; - - QWebEngineHistory* history = (view() ? view()->page()->history() : 0); - if (history) { - bool success = false; - if (history->count() == 0) { // Handle restoration: crash recovery, tab close undo, session restore - if (!historyData.isEmpty()) { - historyData = qUncompress(historyData); // uncompress the history data... - QBuffer buffer (&historyData); - if (buffer.open(QIODevice::ReadOnly)) { - QDataStream stream (&buffer); - view()->page()->setProperty("HistoryNavigationLocked", true); - stream >> *history; - QWebEngineHistoryItem currentItem (history->currentItem()); - if (currentItem.isValid()) { - if (currentItem.isValid() && (xOfs != -1 || yOfs != -1)) { - const QPoint scrollPos (xOfs, yOfs); -// currentItem.setUserData(scrollPos); - } - // NOTE 1: The following Konqueror specific workaround is necessary - // because Konqueror only preserves information for the last visited - // page. However, we save the entire history content in saveState and - // and hence need to elimiate all but the current item here. - // NOTE 2: This condition only applies when Konqueror is restored from - // abnormal termination ; a crash and/or a session restoration. - if (QCoreApplication::applicationName() == QLatin1String("konqueror")) { - history->clear(); - } - //kDebug() << "Restoring URL:" << currentItem.url(); - m_part->setProperty("NoEmitOpenUrlNotification", true); - history->goToItem(currentItem); - } - } - } - success = (history->count() > 0); - } else { // Handle navigation: back and forward button navigation. - //kDebug() << "history count:" << history->count() << "request index:" << historyItemIndex; - if (history->count() > historyItemIndex && historyItemIndex > -1) { - QWebEngineHistoryItem item (history->itemAt(historyItemIndex)); - //kDebug() << "URL:" << u << "Item URL:" << item.url(); - if (u == item.url()) { - if (item.isValid() && (xOfs != -1 || yOfs != -1)) { - const QPoint scrollPos (xOfs, yOfs); -// item.setUserData(scrollPos); - } - m_part->setProperty("NoEmitOpenUrlNotification", true); - history->goToItem(item); - success = true; - } - } - } - - if (success) { - return; - } - } - - // As a last resort, in case the history restoration logic above fails, - // attempt to open the requested URL directly. - qDebug() << "Normal history navgation logic failed! Falling back to opening url directly."; - m_part->openUrl(u); -} - - -void WebEngineBrowserExtension::cut() -{ - if (view()) - view()->triggerPageAction(QWebEnginePage::Cut); -} - -void WebEngineBrowserExtension::copy() -{ - if (view()) - view()->triggerPageAction(QWebEnginePage::Copy); -} - -void WebEngineBrowserExtension::paste() -{ - if (view()) - view()->triggerPageAction(QWebEnginePage::Paste); -} - -void WebEngineBrowserExtension::slotSaveDocument() -{ - if (view()) - emit saveUrl(view()->url()); -} - -void WebEngineBrowserExtension::slotSaveFrame() -{ - if (view()) - emit saveUrl(view()->page()->url()); // TODO lol -} - -void WebEngineBrowserExtension::print() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 8, 0) - if (view()) { - mCurrentPrinter = new QPrinter(); - QPointer<QPrintDialog> dialog = new QPrintDialog(mCurrentPrinter, Q_NULLPTR); - dialog->setWindowTitle(i18n("Print Document")); - if (dialog->exec() != QDialog::Accepted) { - slotHandlePagePrinted(false); - delete dialog; - return; - } - delete dialog; - view()->page()->print(mCurrentPrinter, invoke(this, &WebEngineBrowserExtension::slotHandlePagePrinted)); - } -#endif -} - -void WebEngineBrowserExtension::slotHandlePagePrinted(bool result) -{ - Q_UNUSED(result); - delete mCurrentPrinter; - mCurrentPrinter = Q_NULLPTR; -} - - -void WebEngineBrowserExtension::updateEditActions() -{ - if (!view()) - return; - - enableAction("cut", view()->pageAction(QWebEnginePage::Cut)->isEnabled()); - enableAction("copy", view()->pageAction(QWebEnginePage::Copy)->isEnabled()); - enableAction("paste", view()->pageAction(QWebEnginePage::Paste)->isEnabled()); -} - -void WebEngineBrowserExtension::updateActions() -{ - const QString protocol (m_part->url().scheme()); - const bool isValidDocument = (protocol != QL1S("about") && protocol != QL1S("error")); - enableAction("print", isValidDocument); -} - -void WebEngineBrowserExtension::searchProvider() -{ - if (!view()) - return; - - QAction *action = qobject_cast<QAction*>(sender()); - if (!action) - return; - - QUrl url = action->data().toUrl(); - - if (url.host().isEmpty()) { - KUriFilterData data; - data.setData(action->data().toString()); - if (KUriFilter::self()->filterSearchUri(data, KUriFilter::WebShortcutFilter)) - url = data.uri(); - } - - if (!url.isValid()) - return; - - KParts::BrowserArguments bargs; - bargs.frameName = QL1S("_blank"); - emit openUrlRequest(url, KParts::OpenUrlArguments(), bargs); -} - -void WebEngineBrowserExtension::reparseConfiguration() -{ - // Force the configuration stuff to reparse... - WebEngineSettings::self()->init(); -} - -void WebEngineBrowserExtension::disableScrolling() -{ - QWebEngineView* currentView = view(); - QWebEnginePage* page = currentView ? currentView->page() : 0; - - if (!page) - return; - - page->runJavaScript(QStringLiteral("document.documentElement.style.overflow = 'hidden';")); -} - -void WebEngineBrowserExtension::zoomIn() -{ - if (view()) - view()->setZoomFactor(view()->zoomFactor() + 0.1); -} - -void WebEngineBrowserExtension::zoomOut() -{ - if (view()) - view()->setZoomFactor(view()->zoomFactor() - 0.1); -} - -void WebEngineBrowserExtension::zoomNormal() -{ - if (view()) { - if (WebEngineSettings::self()->zoomToDPI()) - view()->setZoomFactor(view()->logicalDpiY() / 96.0f); - else - view()->setZoomFactor(1); - } -} - -void WebEngineBrowserExtension::toogleZoomTextOnly() -{ - if (!view()) - return; - - KConfigGroup cgHtml(KSharedConfig::openConfig(), "HTML Settings"); - bool zoomTextOnly = cgHtml.readEntry( "ZoomTextOnly", false ); - cgHtml.writeEntry("ZoomTextOnly", !zoomTextOnly); - cgHtml.sync(); - - // view()->settings()->setAttribute(QWebEngineSettings::ZoomTextOnly, !zoomTextOnly); -} - -void WebEngineBrowserExtension::toogleZoomToDPI() -{ - if (!view()) - return; - - bool zoomToDPI = !WebEngineSettings::self()->zoomToDPI(); - WebEngineSettings::self()->setZoomToDPI(zoomToDPI); - - if (zoomToDPI) - view()->setZoomFactor(view()->zoomFactor() * view()->logicalDpiY() / 96.0f); - else - view()->setZoomFactor(view()->zoomFactor() * 96.0f / view()->logicalDpiY()); - - // Recompute default font-sizes since they are only DPI dependent when zoomToDPI is false. - WebEngineSettings::self()->computeFontSizes(view()->logicalDpiY()); -} - -void WebEngineBrowserExtension::slotSelectAll() -{ - if (view()) - view()->triggerPageAction(QWebEnginePage::SelectAll); -} - -void WebEngineBrowserExtension::slotSaveImageAs() -{ - if (view()) - view()->triggerPageAction(QWebEnginePage::DownloadImageToDisk); -} - -void WebEngineBrowserExtension::slotSendImage() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - QStringList urls; - urls.append(view()->contextMenuResult().mediaUrl().path()); - const QString subject = view()->contextMenuResult().mediaUrl().path(); - KToolInvocation::invokeMailer(QString(), QString(), QString(), subject, - QString(), //body - QString(), - urls); // attachments -#endif -} - -void WebEngineBrowserExtension::slotCopyImageURL() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - QUrl safeURL = view()->contextMenuResult().mediaUrl(); - safeURL.setPassword(QString()); - // Set it in both the mouse selection and in the clipboard - QMimeData* mimeData = new QMimeData; -//TODO: Porting: test - QList<QUrl> safeURLList; - safeURLList.append(safeURL); - mimeData->setUrls(safeURLList); - QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); - - mimeData = new QMimeData; - mimeData->setUrls(safeURLList); - QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection); -#endif -} - - -void WebEngineBrowserExtension::slotCopyImage() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - QUrl safeURL; //(view()->contextMenuResult().imageUrl()); - safeURL.setPassword(QString()); - - // Set it in both the mouse selection and in the clipboard - QMimeData* mimeData = new QMimeData; -// mimeData->setImageData(view()->contextMenuResult().pixmap()); -//TODO: Porting: test - QList<QUrl> safeURLList; - safeURLList.append(safeURL); - mimeData->setUrls(safeURLList); - QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); - - mimeData = new QMimeData; -// mimeData->setImageData(view()->contextMenuResult().pixmap()); - mimeData->setUrls(safeURLList); - QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection); -#endif -} - -void WebEngineBrowserExtension::slotViewImage() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (view()) - emit createNewWindow(view()->contextMenuResult().mediaUrl()); -#endif -} - -void WebEngineBrowserExtension::slotBlockImage() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - bool ok = false; - const QString url = QInputDialog::getText(view(), i18n("Add URL to Filter"), - i18n("Enter the URL:"), QLineEdit::Normal, - view()->contextMenuResult().mediaUrl().toString(), - &ok); - if (ok) { - WebEngineSettings::self()->addAdFilter(url); - reparseConfiguration(); - } -#endif -} - -void WebEngineBrowserExtension::slotBlockHost() -{ - if (!view()) - return; - - QUrl url; // (view()->contextMenuResult().imageUrl()); - url.setPath(QL1S("/*")); - WebEngineSettings::self()->addAdFilter(url.toString(QUrl::RemoveUserInfo | QUrl::RemovePort)); - reparseConfiguration(); -} - -void WebEngineBrowserExtension::slotCopyLinkURL() -{ - if (view()) - view()->triggerPageAction(QWebEnginePage::CopyLinkToClipboard); -} - -void WebEngineBrowserExtension::slotCopyLinkText() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (view()) { - QMimeData* data = new QMimeData; - data->setText(view()->contextMenuResult().linkText()); - QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard); - } -#endif -} - -void WebEngineBrowserExtension::slotCopyEmailAddress() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (view()) { - QMimeData* data = new QMimeData; - const QUrl url(view()->contextMenuResult().linkUrl()); - data->setText(url.path()); - QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard); - } -#endif -} - -void WebEngineBrowserExtension::slotSaveLinkAs() -{ - if (view()) - view()->triggerPageAction(QWebEnginePage::DownloadLinkToDisk); -} - -void WebEngineBrowserExtension::slotViewDocumentSource() -{ - if (!view()) - return; - - const QUrl pageUrl (view()->url()); - if (pageUrl.isLocalFile()) { - KRun::runUrl(pageUrl, QL1S("text/plain"), view(), false); - } else { - view()->page()->toHtml([this](const QString& html) { - QTemporaryFile tempFile; - tempFile.setFileTemplate(tempFile.fileTemplate() + QL1S(".html")); - tempFile.setAutoRemove(false); - if (tempFile.open()) { - tempFile.write(html.toUtf8()); - KRun::runUrl(QUrl::fromLocalFile(tempFile.fileName()), QL1S("text/plain"), view(), true, false); - } - }); - } -} - -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) -static bool isMultimediaElement(QWebEngineContextMenuData::MediaType mediaType) -{ - switch(mediaType) - { - case QWebEngineContextMenuData::MediaTypeVideo: - case QWebEngineContextMenuData::MediaTypeAudio: - return true; - default: - return false; - } -} -#endif - -void WebEngineBrowserExtension::slotLoopMedia() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - QWebEngineContextMenuData data = view()->contextMenuResult(); - if (!isMultimediaElement( data.mediaType())) - return; - view()->page()->triggerAction(QWebEnginePage::ToggleMediaLoop); -#endif -} - -void WebEngineBrowserExtension::slotMuteMedia() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - QWebEngineContextMenuData data = view()->contextMenuResult(); - if (!isMultimediaElement( data.mediaType())) - return; - view()->page()->triggerAction(QWebEnginePage::ToggleMediaMute); -#endif -} - -void WebEngineBrowserExtension::slotPlayMedia() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - QWebEngineContextMenuData data = view()->contextMenuResult(); - if (!isMultimediaElement( data.mediaType())) - return; - view()->page()->triggerAction(QWebEnginePage::ToggleMediaPlayPause); -#endif -} - -void WebEngineBrowserExtension::slotShowMediaControls() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - QWebEngineContextMenuData data = view()->contextMenuResult(); - if (!isMultimediaElement( data.mediaType())) - return; - view()->page()->triggerAction(QWebEnginePage::ToggleMediaControls); -#endif -} - -#if 0 -static QUrl mediaUrlFrom(QWebElement& element) -{ - QWebFrame* frame = element.webFrame(); - QString src = frame ? element.attribute(QL1S("src")) : QString(); - if (src.isEmpty()) - src = frame ? element.evaluateJavaScript(QL1S("this.src")).toString() : QString(); - - if (src.isEmpty()) - return QUrl(); - - return QUrl(frame->baseUrl().resolved(QUrl::fromEncoded(QUrl::toPercentEncoding(src), QUrl::StrictMode))); -} -#endif - -void WebEngineBrowserExtension::slotSaveMedia() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - QWebEngineContextMenuData data = view()->contextMenuResult(); - if (!isMultimediaElement( data.mediaType())) - return; - emit saveUrl(data.mediaUrl()); -#endif -} - -void WebEngineBrowserExtension::slotCopyMedia() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - QWebEngineContextMenuData data = view()->contextMenuResult(); - if (!isMultimediaElement( data.mediaType())) - return; - - QUrl safeURL(data.mediaUrl()); - if (!safeURL.isValid()) - return; - - safeURL.setPassword(QString()); - // Set it in both the mouse selection and in the clipboard - QMimeData* mimeData = new QMimeData; -//TODO: Porting: test - QList<QUrl> safeURLList; - safeURLList.append(safeURL); - mimeData->setUrls(safeURLList); - QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); - - mimeData = new QMimeData; - mimeData->setUrls(safeURLList); - QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection); -#endif -} - -void WebEngineBrowserExtension::slotTextDirectionChanged() -{ - QAction* action = qobject_cast<QAction*>(sender()); - if (action) { - bool ok = false; - const int value = action->data().toInt(&ok); - if (ok) { - view()->triggerPageAction(static_cast<QWebEnginePage::WebAction>(value)); - } - } -} - -static QVariant execJScript(WebEngineView* view, const QString& script) -{ -#if 0 - QWebElement element (view->contextMenuResult().element()); - if (element.isNull()) - return QVariant(); - return element.evaluateJavaScript(script); -#endif - return QVariant(); -} - -void WebEngineBrowserExtension::slotCheckSpelling() -{ - const QString text (execJScript(view(), QL1S("this.value")).toString()); - - if ( text.isEmpty() ) { - return; - } - - m_spellTextSelectionStart = 0; - m_spellTextSelectionEnd = 0; - - Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker; - Sonnet::Dialog* spellDialog = new Sonnet::Dialog(backgroundSpellCheck, view()); - backgroundSpellCheck->setParent(spellDialog); - spellDialog->setAttribute(Qt::WA_DeleteOnClose, true); - spellDialog->showSpellCheckCompletionMessage(true); - connect(spellDialog, SIGNAL(replace(QString,int,QString)), this, SLOT(spellCheckerCorrected(QString,int,QString))); - connect(spellDialog, SIGNAL(misspelling(QString,int)), this, SLOT(spellCheckerMisspelling(QString,int))); - spellDialog->setBuffer(text); - spellDialog->show(); -} - -void WebEngineBrowserExtension::slotSpellCheckSelection() -{ - QString text (execJScript(view(), QL1S("this.value")).toString()); - - if ( text.isEmpty() ) { - return; - } - - m_spellTextSelectionStart = qMax(0, execJScript(view(), QL1S("this.selectionStart")).toInt()); - m_spellTextSelectionEnd = qMax(0, execJScript(view(), QL1S("this.selectionEnd")).toInt()); - // kDebug() << "selection start:" << m_spellTextSelectionStart << "end:" << m_spellTextSelectionEnd; - - Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker; - Sonnet::Dialog* spellDialog = new Sonnet::Dialog(backgroundSpellCheck, view()); - backgroundSpellCheck->setParent(spellDialog); - spellDialog->setAttribute(Qt::WA_DeleteOnClose, true); - spellDialog->showSpellCheckCompletionMessage(true); - connect(spellDialog, SIGNAL(replace(QString,int,QString)), this, SLOT(spellCheckerCorrected(QString,int,QString))); - connect(spellDialog, SIGNAL(misspelling(QString,int)), this, SLOT(spellCheckerMisspelling(QString,int))); - connect(spellDialog, SIGNAL(done(QString)), this, SLOT(slotSpellCheckDone(QString))); - spellDialog->setBuffer(text.mid(m_spellTextSelectionStart, (m_spellTextSelectionEnd - m_spellTextSelectionStart))); - spellDialog->show(); -} - -void WebEngineBrowserExtension::spellCheckerCorrected(const QString& original, int pos, const QString& replacement) -{ - // Adjust the selection end... - if (m_spellTextSelectionEnd > 0) { - m_spellTextSelectionEnd += qMax (0, (replacement.length() - original.length())); - } - - const int index = pos + m_spellTextSelectionStart; - QString script(QL1S("this.value=this.value.substring(0,")); - script += QString::number(index); - script += QL1S(") + \""); - script += replacement; - script += QL1S("\" + this.value.substring("); - script += QString::number(index + original.length()); - script += QL1S(")"); - - //kDebug() << "**** script:" << script; - execJScript(view(), script); -} - -void WebEngineBrowserExtension::spellCheckerMisspelling(const QString& text, int pos) -{ - // kDebug() << text << pos; - QString selectionScript (QL1S("this.setSelectionRange(")); - selectionScript += QString::number(pos + m_spellTextSelectionStart); - selectionScript += QL1C(','); - selectionScript += QString::number(pos + text.length() + m_spellTextSelectionStart); - selectionScript += QL1C(')'); - execJScript(view(), selectionScript); -} - -void WebEngineBrowserExtension::slotSpellCheckDone(const QString&) -{ - // Restore the text selection if one was present before we started the - // spell check. - if (m_spellTextSelectionStart > 0 || m_spellTextSelectionEnd > 0) { - QString script (QL1S("; this.setSelectionRange(")); - script += QString::number(m_spellTextSelectionStart); - script += QL1C(','); - script += QString::number(m_spellTextSelectionEnd); - script += QL1C(')'); - execJScript(view(), script); - } -} - - -void WebEngineBrowserExtension::saveHistory() -{ - QWebEngineHistory* history = (view() ? view()->history() : 0); - - if (history && history->count() > 0) { - //kDebug() << "Current history: index=" << history->currentItemIndex() << "url=" << history->currentItem().url(); - QByteArray histData; - QBuffer buff (&histData); - m_historyData.clear(); - if (buff.open(QIODevice::WriteOnly)) { - QDataStream stream (&buff); - stream << *history; - m_historyData = qCompress(histData, 9); - } - QWidget* mainWidget = m_part ? m_part->widget() : 0; - QWidget* frameWidget = mainWidget ? mainWidget->parentWidget() : 0; - if (frameWidget) { - emit saveHistory(frameWidget, m_historyData); - // kDebug() << "# of items:" << history->count() << "current item:" << history->currentItemIndex() << "url:" << history->currentItem().url(); - } - } else { - Q_ASSERT(false); // should never happen!!! - } -} - -void WebEngineBrowserExtension::slotPrintPreview() -{ -#if 0 - // Make it non-modal, in case a redirection deletes the part - QPointer<QPrintPreviewDialog> dlg (new QPrintPreviewDialog(view())); - connect(dlg.data(), SIGNAL(paintRequested(QPrinter*)), - view()->page()->currentFrame(), SLOT(print(QPrinter*))); - dlg->exec(); - delete dlg; -#endif -} - -void WebEngineBrowserExtension::slotOpenSelection() -{ - QAction *action = qobject_cast<QAction*>(sender()); - if (action) { - KParts::BrowserArguments browserArgs; - browserArgs.frameName = QStringLiteral("_blank"); - emit openUrlRequest(QUrl(action->data().toUrl()), KParts::OpenUrlArguments(), browserArgs); - } -} - -void WebEngineBrowserExtension::slotLinkInTop() -{ -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) - if (!view()) - return; - - KParts::OpenUrlArguments uargs; - uargs.setActionRequestedByUser(true); - - KParts::BrowserArguments bargs; - bargs.frameName = QL1S("_top"); - - const QUrl url(view()->contextMenuResult().linkUrl()); - - emit openUrlRequest(url, uargs, bargs); -#endif -} - -//// - -WebEngineTextExtension::WebEngineTextExtension(WebEnginePart* part) - : KParts::TextExtension(part) -{ - connect(part->view(), SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged())); -} - -WebEnginePart* WebEngineTextExtension::part() const -{ - return static_cast<WebEnginePart*>(parent()); -} - -bool WebEngineTextExtension::hasSelection() const -{ - return part()->view()->hasSelection(); -} - -QString WebEngineTextExtension::selectedText(Format format) const -{ - switch(format) { - case PlainText: - return part()->view()->selectedText(); - case HTML: - // PORTING_TODO selectedText might not be html - return part()->view()->selectedText(); - } - return QString(); -} - -QString WebEngineTextExtension::completeText(Format format) const -{ - // TODO David will hunt me down with a rusty spork if he sees this - QEventLoop ev; - QString str; - switch(format) { - case PlainText: - part()->view()->page()->toPlainText([&ev,&str](const QString& data) { - str = data; - ev.quit(); - }); - case HTML: - part()->view()->page()->toHtml([&ev,&str](const QString& data) { - str = data; - ev.quit(); - }); - } - ev.exec(); - return QString(); -} - -//// - -WebEngineHtmlExtension::WebEngineHtmlExtension(WebEnginePart* part) - : KParts::HtmlExtension(part) -{ -} - - -QUrl WebEngineHtmlExtension::baseUrl() const -{ - return part()->view()->page()->url(); -} - -bool WebEngineHtmlExtension::hasSelection() const -{ - return part()->view()->hasSelection(); -} - -KParts::SelectorInterface::QueryMethods WebEngineHtmlExtension::supportedQueryMethods() const -{ - return (KParts::SelectorInterface::EntireContent - | KParts::SelectorInterface::SelectedContent); -} - -#if 0 -static KParts::SelectorInterface::Element convertWebElement(const QWebElement& webElem) -{ - KParts::SelectorInterface::Element element; - element.setTagName(webElem.tagName()); - Q_FOREACH(const QString &attr, webElem.attributeNames()) { - element.setAttribute(attr, webElem.attribute(attr)); - } - return element; -} -#endif - -static QString queryOne(const QString& query) -{ - QString jsQuery = QL1S("(function(query) { var element; var selectedElement = window.getSelection().getRangeAt(0).cloneContents().querySelector(\""); - jsQuery += query; - jsQuery += QL1S("\"); if (selectedElement && selectedElement.length > 0) { element = new Object; " - "element.tagName = String(selectedElements[0].tagName); element.href = String(selectedElements[0].href); } " - "return element; }())"); - return jsQuery; -} - -static QString queryAll(const QString& query) -{ - QString jsQuery = QL1S("(function(query) { var elements = []; var selectedElements = window.getSelection().getRangeAt(0).cloneContents().querySelectorAll(\""); - jsQuery += query; - jsQuery += QL1S("\"); var numSelectedElements = (selectedElements ? selectedElements.length : 0);" - "for (var i = 0; i < numSelectedElements; ++i) { var element = new Object; " - "element.tagName = String(selectedElements[i].tagName); element.href = String(selectedElements[i].href);" - "elements.push(element); } return elements; } ())"); - return jsQuery; -} - -static KParts::SelectorInterface::Element convertSelectionElement(const QVariant& variant) -{ - KParts::SelectorInterface::Element element; - if (!variant.isNull() && variant.type() == QVariant::Map) { - const QVariantMap elementMap (variant.toMap()); - element.setTagName(elementMap.value(QL1S("tagName")).toString()); - element.setAttribute(QL1S("href"), elementMap.value(QL1S("href")).toString()); - } - return element; -} - -static QList<KParts::SelectorInterface::Element> convertSelectionElements(const QVariant& variant) -{ - QList<KParts::SelectorInterface::Element> elements; - const QVariantList resultList (variant.toList()); - Q_FOREACH(const QVariant& result, resultList) { - const QVariantMap elementMap = result.toMap(); - KParts::SelectorInterface::Element element; - element.setTagName(elementMap.value(QL1S("tagName")).toString()); - element.setAttribute(QL1S("href"), elementMap.value(QL1S("href")).toString()); - elements.append(element); - } - return elements; -} - -KParts::SelectorInterface::Element WebEngineHtmlExtension::querySelector(const QString& query, KParts::SelectorInterface::QueryMethod method) const -{ - KParts::SelectorInterface::Element element; - - // If the specified method is None, return an empty list... - if (method == KParts::SelectorInterface::None) - return element; - - // If the specified method is not supported, return an empty list... - if (!(supportedQueryMethods() & method)) - return element; - -#if 0 - switch (method) { - case KParts::SelectorInterface::EntireContent: { - const QWebFrame* webFrame = part()->view()->page()->mainFrame(); - element = convertWebElement(webFrame->findFirstElement(query)); - break; - } - case KParts::SelectorInterface::SelectedContent: { - QWebFrame* webFrame = part()->view()->page()->mainFrame(); - element = convertSelectionElement(webFrame->evaluateJavaScript(queryOne(query))); - break; - } - default: - break; - } -#endif - - return element; -} - -QList<KParts::SelectorInterface::Element> WebEngineHtmlExtension::querySelectorAll(const QString& query, KParts::SelectorInterface::QueryMethod method) const -{ - QList<KParts::SelectorInterface::Element> elements; - - // If the specified method is None, return an empty list... - if (method == KParts::SelectorInterface::None) - return elements; - - // If the specified method is not supported, return an empty list... - if (!(supportedQueryMethods() & method)) - return elements; -#if 0 - switch (method) { - case KParts::SelectorInterface::EntireContent: { - const QWebFrame* webFrame = part()->view()->page()->mainFrame(); - const QWebElementCollection collection = webFrame->findAllElements(query); - elements.reserve(collection.count()); - Q_FOREACH(const QWebElement& element, collection) - elements.append(convertWebElement(element)); - break; - } - case KParts::SelectorInterface::SelectedContent: { - QWebFrame* webFrame = part()->view()->page()->mainFrame(); - elements = convertSelectionElements(webFrame->evaluateJavaScript(queryAll(query))); - break; - } - default: - break; - } -#endif - return elements; -} - -QVariant WebEngineHtmlExtension::htmlSettingsProperty(KParts::HtmlSettingsInterface::HtmlSettingsType type) const -{ - QWebEngineView* view = part() ? part()->view() : 0; - QWebEnginePage* page = view ? view->page() : 0; - QWebEngineSettings* settings = page ? page->settings() : 0; - - if (settings) { - switch (type) { - case KParts::HtmlSettingsInterface::AutoLoadImages: - return settings->testAttribute(QWebEngineSettings::AutoLoadImages); - case KParts::HtmlSettingsInterface::JavaEnabled: - return false; // settings->testAttribute(QWebEngineSettings::JavaEnabled); - case KParts::HtmlSettingsInterface::JavascriptEnabled: - return settings->testAttribute(QWebEngineSettings::JavascriptEnabled); - case KParts::HtmlSettingsInterface::PluginsEnabled: - return settings->testAttribute(QWebEngineSettings::PluginsEnabled); - case KParts::HtmlSettingsInterface::DnsPrefetchEnabled: - return false; //settings->testAttribute(QWebEngineSettings::DnsPrefetchEnabled); - case KParts::HtmlSettingsInterface::MetaRefreshEnabled: - return view->pageAction(QWebEnginePage::Stop)->isEnabled(); - case KParts::HtmlSettingsInterface::LocalStorageEnabled: - return settings->testAttribute(QWebEngineSettings::LocalStorageEnabled); - case KParts::HtmlSettingsInterface::OfflineStorageDatabaseEnabled: - return false; //settings->testAttribute(QWebEngineSettings::OfflineStorageDatabaseEnabled); - case KParts::HtmlSettingsInterface::OfflineWebApplicationCacheEnabled: - return false ;//settings->testAttribute(QWebEngineSettings::OfflineWebApplicationCacheEnabled); - case KParts::HtmlSettingsInterface::PrivateBrowsingEnabled: - return false; //settings->testAttribute(QWebEngineSettings::PrivateBrowsingEnabled); - case KParts::HtmlSettingsInterface::UserDefinedStyleSheetURL: - return false; //settings->userStyleSheetUrl(); - default: - break; - } - } - - return QVariant(); -} - -bool WebEngineHtmlExtension::setHtmlSettingsProperty(KParts::HtmlSettingsInterface::HtmlSettingsType type, const QVariant& value) -{ - QWebEngineView* view = part() ? part()->view() : 0; - QWebEnginePage* page = view ? view->page() : 0; - QWebEngineSettings* settings = page ? page->settings() : 0; - - if (settings) { - switch (type) { - case KParts::HtmlSettingsInterface::AutoLoadImages: - settings->setAttribute(QWebEngineSettings::AutoLoadImages, value.toBool()); - return true; - case KParts::HtmlSettingsInterface::JavaEnabled: - //settings->setAttribute(QWebESettings::JavaEnabled, value.toBool()); - return false; - case KParts::HtmlSettingsInterface::JavascriptEnabled: - settings->setAttribute(QWebEngineSettings::JavascriptEnabled, value.toBool()); - return true; - case KParts::HtmlSettingsInterface::PluginsEnabled: - settings->setAttribute(QWebEngineSettings::PluginsEnabled, value.toBool()); - return true; - case KParts::HtmlSettingsInterface::DnsPrefetchEnabled: -// settings->setAttribute(QWebEngineSettings::DnsPrefetchEnabled, value.toBool()); - return false; - case KParts::HtmlSettingsInterface::MetaRefreshEnabled: - view->triggerPageAction(QWebEnginePage::Stop); - return true; - case KParts::HtmlSettingsInterface::LocalStorageEnabled: - settings->setAttribute(QWebEngineSettings::LocalStorageEnabled, value.toBool()); - return false; - case KParts::HtmlSettingsInterface::OfflineStorageDatabaseEnabled: - //settings->setAttribute(QWebEngineSettings::OfflineStorageDatabaseEnabled, value.toBool()); - return false; - case KParts::HtmlSettingsInterface::OfflineWebApplicationCacheEnabled: - //settings->setAttribute(QWebEngineSettings::OfflineWebApplicationCacheEnabled, value.toBool()); - return false; - case KParts::HtmlSettingsInterface::PrivateBrowsingEnabled: - //settings->setAttribute(QWebEnngineSettings::PrivateBrowsingEnabled, value.toBool()); - return false; - case KParts::HtmlSettingsInterface::UserDefinedStyleSheetURL: - //kDebug() << "Setting user style sheet for" << page << "to" << value.toUrl(); - // settings->setUserStyleSheetUrl(value.toUrl()); - return false; - default: - break; - } - } - - return false; -} - -WebEnginePart* WebEngineHtmlExtension::part() const -{ - return static_cast<WebEnginePart*>(parent()); -} - -WebEngineScriptableExtension::WebEngineScriptableExtension(WebEnginePart* part) - : ScriptableExtension(part) -{ -} - -QVariant WebEngineScriptableExtension::rootObject() -{ - return QVariant::fromValue(KParts::ScriptableExtension::Object(this, reinterpret_cast<quint64>(this))); -} - -bool WebEngineScriptableExtension::setException (KParts::ScriptableExtension* callerPrincipal, const QString& message) -{ - return KParts::ScriptableExtension::setException (callerPrincipal, message); -} - -QVariant WebEngineScriptableExtension::get (KParts::ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName) -{ - //kDebug() << "caller:" << callerPrincipal << "id:" << objId << "propName:" << propName; - return callerPrincipal->get (0, objId, propName); -} - -bool WebEngineScriptableExtension::put (KParts::ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName, const QVariant& value) -{ - return KParts::ScriptableExtension::put (callerPrincipal, objId, propName, value); -} - -static QVariant exception(const char* msg) -{ - qWarning() << msg; - return QVariant::fromValue(KParts::ScriptableExtension::Exception(QString::fromLatin1(msg))); -} - -QVariant WebEngineScriptableExtension::evaluateScript (KParts::ScriptableExtension* callerPrincipal, - quint64 contextObjectId, - const QString& code, - KParts::ScriptableExtension::ScriptLanguage lang) -{ - Q_UNUSED(contextObjectId); - Q_UNUSED(code) - //kDebug() << "principal:" << callerPrincipal << "id:" << contextObjectId << "language:" << lang << "code:" << code; - - if (lang != ECMAScript) - return exception("unsupported language"); - - - KParts::ReadOnlyPart* part = callerPrincipal ? qobject_cast<KParts::ReadOnlyPart*>(callerPrincipal->parent()) : 0; - // QWebFrame* frame = part ? qobject_cast<QWebFrame*>(part->parent()) : 0; - // if (!frame) - return exception("failed to resolve principal"); -#if 0 - QVariant result (frame->evaluateJavaScript(code)); - - if (result.type() == QVariant::Map) { - const QVariantMap map (result.toMap()); - for (QVariantMap::const_iterator it = map.constBegin(), itEnd = map.constEnd(); it != itEnd; ++it) { - callerPrincipal->put(callerPrincipal, 0, it.key(), it.value()); - } - } else { - const QString propName(code.contains(QLatin1String("__nsplugin")) ? QLatin1String("__nsplugin") : QString()); - callerPrincipal->put(callerPrincipal, 0, propName, result.toString()); - } - - return QVariant::fromValue(ScriptableExtension::Null()); -#endif -} - -bool WebEngineScriptableExtension::isScriptLanguageSupported (KParts::ScriptableExtension::ScriptLanguage lang) const -{ - return (lang == KParts::ScriptableExtension::ECMAScript); -} - -QVariant WebEngineScriptableExtension::encloserForKid (KParts::ScriptableExtension* kid) -{ -#if 0 - KParts::ReadOnlyPart* part = kid ? qobject_cast<KParts::ReadOnlyPart*>(kid->parent()) : 0; - QWebFrame* frame = part ? qobject_cast<QWebFrame*>(part->parent()) : 0; - if (frame) { - return QVariant::fromValue(KParts::ScriptableExtension::Object(kid, reinterpret_cast<quint64>(kid))); - } -#endif - - return QVariant::fromValue(ScriptableExtension::Null()); -} - -WebEnginePart* WebEngineScriptableExtension::part() -{ - return qobject_cast<WebEnginePart*>(parent()); -} - diff --git a/webenginepart/src/webenginepart_ext.h a/webenginepart/src/webenginepart_ext.h deleted file mode 100644 index 550daa7d8..000000000 --- a/webenginepart/src/webenginepart_ext.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#ifndef WEBENGINEPART_EXT_H -#define WEBENGINEPART_EXT_H - -#include "kwebenginepartlib_export.h" - -#include <QPointer> - -#include <KParts/BrowserExtension> -#include <KParts/TextExtension> -#include <KParts/HtmlExtension> -#include <KParts/HtmlSettingsInterface> -#include <KParts/ScriptableExtension> -#include <KParts/SelectorInterface> - -class QUrl; -class WebEnginePart; -class WebEngineView; -class QPrinter; -class KWEBENGINEPARTLIB_EXPORT WebEngineBrowserExtension : public KParts::BrowserExtension -{ - Q_OBJECT - -public: - WebEngineBrowserExtension(WebEnginePart *parent, const QByteArray& cachedHistoryData); - ~WebEngineBrowserExtension(); - - virtual int xOffset() override; - virtual int yOffset() override; - virtual void saveState(QDataStream &) override; - virtual void restoreState(QDataStream &) override; - void saveHistory(); - -Q_SIGNALS: - void saveUrl(const QUrl &); - void saveHistory(QObject*, const QByteArray&); - -public Q_SLOTS: - void cut(); - void copy(); - void paste(); - void print(); - - void slotSaveDocument(); - void slotSaveFrame(); - void searchProvider(); - void reparseConfiguration(); - void disableScrolling(); - - void zoomIn(); - void zoomOut(); - void zoomNormal(); - void toogleZoomTextOnly(); - void toogleZoomToDPI(); - void slotSelectAll(); - - void slotSaveImageAs(); - void slotSendImage(); - void slotCopyImageURL(); - void slotCopyImage(); - void slotViewImage(); - void slotBlockImage(); - void slotBlockHost(); - - void slotCopyLinkURL(); - void slotCopyLinkText(); - void slotSaveLinkAs(); - void slotCopyEmailAddress(); - - void slotViewDocumentSource(); - - void updateEditActions(); - void updateActions(); - - void slotPlayMedia(); - void slotMuteMedia(); - void slotLoopMedia(); - void slotShowMediaControls(); - void slotSaveMedia(); - void slotCopyMedia(); - void slotTextDirectionChanged(); - void slotCheckSpelling(); - void slotSpellCheckSelection(); - void slotSpellCheckDone(const QString&); - void spellCheckerCorrected(const QString&, int, const QString&); - void spellCheckerMisspelling(const QString&, int); - //void slotPrintRequested(QWebFrame*); - void slotPrintPreview(); - - void slotOpenSelection(); - void slotLinkInTop(); - -private Q_SLOTS: - void slotHandlePagePrinted(bool result); -private: - WebEngineView* view(); - QPointer<WebEnginePart> m_part; - QPointer<WebEngineView> m_view; - quint32 m_spellTextSelectionStart; - quint32 m_spellTextSelectionEnd; - QByteArray m_historyData; - QPrinter *mCurrentPrinter; -}; - -/** - * @internal - * Implements the TextExtension interface - */ -class WebEngineTextExtension : public KParts::TextExtension -{ - Q_OBJECT -public: - WebEngineTextExtension(WebEnginePart* part); - - bool hasSelection() const Q_DECL_OVERRIDE; - QString selectedText(Format format) const Q_DECL_OVERRIDE; - QString completeText(Format format) const Q_DECL_OVERRIDE; - -private: - WebEnginePart* part() const; -}; - -/** - * @internal - * Implements the HtmlExtension interface - */ -class WebEngineHtmlExtension : public KParts::HtmlExtension, - public KParts::SelectorInterface, - public KParts::HtmlSettingsInterface -{ - Q_OBJECT - Q_INTERFACES(KParts::SelectorInterface) - Q_INTERFACES(KParts::HtmlSettingsInterface) - -public: - WebEngineHtmlExtension(WebEnginePart* part); - - // HtmlExtension - QUrl baseUrl() const Q_DECL_OVERRIDE; - bool hasSelection() const Q_DECL_OVERRIDE; - - // SelectorInterface - QueryMethods supportedQueryMethods() const Q_DECL_OVERRIDE; - Element querySelector(const QString& query, KParts::SelectorInterface::QueryMethod method) const Q_DECL_OVERRIDE; - QList<Element> querySelectorAll(const QString& query, KParts::SelectorInterface::QueryMethod method) const Q_DECL_OVERRIDE; - - // HtmlSettingsInterface - QVariant htmlSettingsProperty(HtmlSettingsType type) const Q_DECL_OVERRIDE; - bool setHtmlSettingsProperty(HtmlSettingsType type, const QVariant& value) Q_DECL_OVERRIDE; - -private: - WebEnginePart* part() const; -}; - -class WebEngineScriptableExtension : public KParts::ScriptableExtension -{ - Q_OBJECT - -public: - WebEngineScriptableExtension(WebEnginePart* part); - - QVariant rootObject() Q_DECL_OVERRIDE; - - QVariant get(ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName) Q_DECL_OVERRIDE; - - bool put(ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName, const QVariant& value) Q_DECL_OVERRIDE; - - bool setException(ScriptableExtension* callerPrincipal, const QString& message) Q_DECL_OVERRIDE; - - QVariant evaluateScript(ScriptableExtension* callerPrincipal, - quint64 contextObjectId, - const QString& code, - ScriptLanguage language = ECMAScript) Q_DECL_OVERRIDE; - - bool isScriptLanguageSupported(ScriptLanguage lang) const Q_DECL_OVERRIDE; - -private: - QVariant encloserForKid(KParts::ScriptableExtension* kid) Q_DECL_OVERRIDE; - WebEnginePart* part(); -}; - -#endif // WEBENGINEPART_EXT_H diff --git a/webenginepart/src/webenginepartfactory.cpp a/webenginepart/src/webenginepartfactory.cpp deleted file mode 100644 index 04853bd27..000000000 --- a/webenginepart/src/webenginepartfactory.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2008 Laurent Montel <montel@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "webenginepartfactory.h" -#include "webenginepart_ext.h" -#include "webenginepart.h" - -#include <QWidget> - -WebEngineFactory::~WebEngineFactory() -{ - // kDebug() << this; -} - -QObject *WebEngineFactory::create(const char* iface, QWidget *parentWidget, QObject *parent, const QVariantList &args, const QString& keyword) -{ - Q_UNUSED(iface); - Q_UNUSED(keyword); - Q_UNUSED(args); - - qDebug() << parentWidget << parent; - connect(parentWidget, SIGNAL(destroyed(QObject*)), this, SLOT(slotDestroyed(QObject*))); - - // NOTE: The code below is what makes it possible to properly integrate QtWebEngine's PORTING_TODO - // history management with any KParts based application. - QByteArray histData (m_historyBufContainer.value(parentWidget)); - if (!histData.isEmpty()) histData = qUncompress(histData); - WebEnginePart* part = new WebEnginePart(parentWidget, parent, histData); - WebEngineBrowserExtension* ext = qobject_cast<WebEngineBrowserExtension*>(part->browserExtension()); - if (ext) { - connect(ext, SIGNAL(saveHistory(QObject*,QByteArray)), this, SLOT(slotSaveHistory(QObject*,QByteArray))); - } - return part; -} - -void WebEngineFactory::slotSaveHistory(QObject* widget, const QByteArray& buffer) -{ - // kDebug() << "Caching history data from" << widget; - m_historyBufContainer.insert(widget, buffer); -} - -void WebEngineFactory::slotDestroyed(QObject* object) -{ - // kDebug() << "Removing cached history data of" << object; - m_historyBufContainer.remove(object); -} - -K_EXPORT_PLUGIN(WebEngineFactory) diff --git a/webenginepart/src/webenginepartfactory.h a/webenginepart/src/webenginepartfactory.h deleted file mode 100644 index 1eaaf42ba..000000000 --- a/webenginepart/src/webenginepartfactory.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2008 Laurent Montel <montel@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#ifndef WEBENGINEPARTFACTORY -#define WEBENGINEPARTFACTORY - -#include <kpluginfactory.h> - -#include <QHash> - -class QWidget; - -class WebEngineFactory : public KPluginFactory -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.kde.KPluginFactory" FILE "") - Q_INTERFACES(KPluginFactory) -public: - virtual ~WebEngineFactory(); - QObject *create(const char* iface, QWidget *parentWidget, QObject *parent, const QVariantList& args, const QString &keyword) Q_DECL_OVERRIDE; - -private Q_SLOTS: - void slotDestroyed(QObject* object); - void slotSaveHistory(QObject* widget, const QByteArray&); - -private: - QHash<QObject*, QByteArray> m_historyBufContainer; -}; - -#endif // WEBENGINEPARTFACTORY diff --git a/webenginepart/src/webengineview.cpp a/webenginepart/src/webengineview.cpp deleted file mode 100644 index 1bed6110f..000000000 --- a/webenginepart/src/webengineview.cpp +++ /dev/null @@ -1,594 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2007 Trolltech ASA - * Copyright (C) 2008 - 2010 Urs Wolfer <uwolfer @ kde.org> - * Copyright (C) 2008 Laurent Montel <montel@kde.org> - * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "webengineview.h" -#include "webenginepage.h" -#include "webenginepart.h" -#include "settings/webenginesettings.h" - -#include <kio/global.h> -#include <KAboutData> -#include <KActionCollection> -#include <KConfigGroup> -#include <KService> -#include <KUriFilter> -#include <KActionMenu> -#include <KIO/AccessManager> -#include <KStringHandler> -#include <KLocalizedString> - -#include <QTimer> -#include <QMimeData> -#include <QDropEvent> -#include <QLabel> -#include <QNetworkRequest> -#include <QToolTip> -#include <QCoreApplication> -#include <unistd.h> -#include <QMimeType> -#include <QMimeDatabase> - -#define QL1S(x) QLatin1String(x) -#define QL1C(x) QLatin1Char(x) - -#define ALTERNATE_DEFAULT_WEB_SHORTCUT QL1S("google") -#define ALTERNATE_WEB_SHORTCUTS QStringList() << QL1S("google") << QL1S("wikipedia") << QL1S("webster") << QL1S("dmoz") - -WebEngineView::WebEngineView(WebEnginePart* part, QWidget* parent) - :QWebEngineView(parent), - m_actionCollection(new KActionCollection(this)), - m_part(part), - m_autoScrollTimerId(-1), - m_verticalAutoScrollSpeed(0), - m_horizontalAutoScrollSpeed(0) -{ - setAcceptDrops(true); - - // Create the custom page... - setPage(new WebEnginePage(part, this)); - - connect(this, SIGNAL(loadStarted()), this, SLOT(slotStopAutoScroll())); - - if (WebEngineSettings::self()->zoomToDPI()) - setZoomFactor(logicalDpiY() / 96.0f); - -#ifndef HAVE_WEBENGINECONTEXTMENUDATA - m_result = 0; -#endif -} - -WebEngineView::~WebEngineView() -{ - //kDebug(); -} - -void WebEngineView::loadUrl(const QUrl& url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments& bargs) -{ - page()->setProperty("NavigationTypeUrlEntered", true); - - if (args.reload() && url == this->url()) { - reload(); - return; - } - - QNetworkRequest request(url); - if (args.reload()) { - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - } - - if (bargs.postData.isEmpty()) { - QWebEngineView::load(url); - } else { - // QWebEngineView::load(url, QNetworkAccessManager::PostOperation, bargs.postData); - } -} - -QWebEngineContextMenuData WebEngineView::contextMenuResult() const -{ - return m_result; -} - -static void extractMimeTypeFor(const QUrl& url, QString& mimeType) -{ - const QString fname(url.fileName()); - - if (fname.isEmpty() || url.hasFragment() || url.hasQuery()) - return; - - QMimeType pmt = QMimeDatabase().mimeTypeForFile(fname); - - // Further check for mime types guessed from the extension which, - // on a web page, are more likely to be a script delivering content - // of undecidable type. If the mime type from the extension is one - // of these, don't use it. Retain the original type 'text/html'. - if (pmt.isDefault() || - pmt.inherits(QL1S("application/x-perl")) || - pmt.inherits(QL1S("application/x-perl-module")) || - pmt.inherits(QL1S("application/x-php")) || - pmt.inherits(QL1S("application/x-python-bytecode")) || - pmt.inherits(QL1S("application/x-python")) || - pmt.inherits(QL1S("application/x-shellscript"))) - return; - - mimeType = pmt.name(); -} - -void WebEngineView::contextMenuEvent(QContextMenuEvent* e) -{ -#ifdef HAVE_WEBENGINECONTEXTMENUDATA - m_result = page()->contextMenuData(); - - // Clear the previous collection entries first... - m_actionCollection->clear(); - - KParts::BrowserExtension::PopupFlags flags = KParts::BrowserExtension::DefaultPopupItems; - KParts::BrowserExtension::ActionGroupMap mapAction; - QString mimeType (QL1S("text/html")); - bool forcesNewWindow = false; - - QUrl emitUrl; - - if (m_result.isContentEditable()) { - flags |= KParts::BrowserExtension::ShowTextSelectionItems; - editableContentActionPopupMenu(mapAction); - } else if (m_result.mediaType() == QWebEngineContextMenuData::MediaTypeVideo || m_result.mediaType() == QWebEngineContextMenuData::MediaTypeAudio) { - multimediaActionPopupMenu(mapAction); - } else if (!m_result.linkUrl().isValid()) { - if (m_result.mediaType() == QWebEngineContextMenuData::MediaTypeImage) { - emitUrl = m_result.mediaUrl(); - extractMimeTypeFor(emitUrl, mimeType); - } else { - flags |= KParts::BrowserExtension::ShowBookmark; - emitUrl = m_part->url(); - - if (!m_result.selectedText().isEmpty()) { - flags |= KParts::BrowserExtension::ShowTextSelectionItems; - selectActionPopupMenu(mapAction); - } - } - partActionPopupMenu(mapAction); - } else { - flags |= KParts::BrowserExtension::ShowBookmark; - flags |= KParts::BrowserExtension::IsLink; - emitUrl = m_result.linkUrl(); - linkActionPopupMenu(mapAction); - if (emitUrl.isLocalFile()) - mimeType = QMimeDatabase().mimeTypeForUrl(emitUrl).name(); - else - extractMimeTypeFor(emitUrl, mimeType); - partActionPopupMenu(mapAction); - - // Show the OpenInThisWindow context menu item -// forcesNewWindow = (page()->currentFrame() != m_result.linkTargetFrame()); - } - - if (!mapAction.isEmpty()) { - KParts::OpenUrlArguments args; - KParts::BrowserArguments bargs; - args.setMimeType(mimeType); - bargs.setForcesNewWindow(forcesNewWindow); - e->accept(); - emit m_part->browserExtension()->popupMenu(e->globalPos(), emitUrl, static_cast<mode_t>(-1), args, bargs, flags, mapAction); - return; - } - -#endif - QWebEngineView::contextMenuEvent(e); -} - -void WebEngineView::keyPressEvent(QKeyEvent* e) -{ - if (e && hasFocus()) { - const int key = e->key(); - if (e->modifiers() & Qt::ShiftModifier) { - switch (key) { - case Qt::Key_Up: - /* if (!isEditableElement(page()))*/ { - m_verticalAutoScrollSpeed--; - if (m_autoScrollTimerId == -1) - m_autoScrollTimerId = startTimer(100); - e->accept(); - return; - } - break; - case Qt::Key_Down: - /*if (!isEditableElement(page()))*/ { - m_verticalAutoScrollSpeed++; - if (m_autoScrollTimerId == -1) - m_autoScrollTimerId = startTimer(100); - e->accept(); - return; - } - break; - case Qt::Key_Left: - /*if (!isEditableElement(page()))*/ { - m_horizontalAutoScrollSpeed--; - if (m_autoScrollTimerId == -1) - m_autoScrollTimerId = startTimer(100); - e->accept(); - return; - } - break; - case Qt::Key_Right: - /*if (!isEditableElement(page()))*/ { - m_horizontalAutoScrollSpeed--; - if (m_autoScrollTimerId == -1) - m_autoScrollTimerId = startTimer(100); - e->accept(); - return; - } - break; - default: - break; - } - } else if (m_autoScrollTimerId != -1) { - // kDebug() << "scroll timer id:" << m_autoScrollTimerId; - slotStopAutoScroll(); - e->accept(); - return; - } - } - QWebEngineView::keyPressEvent(e); -} - -void WebEngineView::keyReleaseEvent(QKeyEvent *e) -{ - QWebEngineView::keyReleaseEvent(e); -} - -void WebEngineView::mouseReleaseEvent(QMouseEvent* e) -{ - QWebEngineView::mouseReleaseEvent(e); -} - -void WebEngineView::wheelEvent (QWheelEvent* e) -{ - QWebEngineView::wheelEvent(e); -} - - -void WebEngineView::timerEvent(QTimerEvent* e) -{ -#if 0 - if (e && e->timerId() == m_autoScrollTimerId) { - // do the scrolling - scroll(m_horizontalAutoScrollSpeed, m_verticalAutoScrollSpeed); - // check if we reached the end - const int y = page()->scrollPosition().y(); - if (y == page()->currentFrame()->scrollBarMinimum(Qt::Vertical) || - y == page()->currentFrame()->scrollBarMaximum(Qt::Vertical)) { - m_verticalAutoScrollSpeed = 0; - } - - const int x = page()->scrollPosition().x(); - if (x == page()->currentFrame()->scrollBarMinimum(Qt::Horizontal) || - x == page()->currentFrame()->scrollBarMaximum(Qt::Horizontal)) { - m_horizontalAutoScrollSpeed = 0; - } - - // Kill the timer once the max/min scroll limit is reached. - if (m_horizontalAutoScrollSpeed == 0 && m_verticalAutoScrollSpeed == 0) { - killTimer(m_autoScrollTimerId); - m_autoScrollTimerId = -1; - } - e->accept(); - return; - } -#endif - QWebEngineView::timerEvent(e); -} - -void WebEngineView::editableContentActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& partGroupMap) -{ - QList<QAction*> editableContentActions; - - QActionGroup* group = new QActionGroup(this); - group->setExclusive(true); - - QAction* action = new QAction(m_actionCollection); - action->setSeparator(true); - editableContentActions.append(action); - - action = m_actionCollection->addAction(KStandardAction::Copy, QL1S("copy"), m_part->browserExtension(), SLOT(copy())); - action->setEnabled(pageAction(QWebEnginePage::Copy)->isEnabled()); - editableContentActions.append(action); - - action = m_actionCollection->addAction(KStandardAction::Cut, QL1S("cut"), m_part->browserExtension(), SLOT(cut())); - action->setEnabled(pageAction(QWebEnginePage::Cut)->isEnabled()); - editableContentActions.append(action); - - action = m_actionCollection->addAction(KStandardAction::Paste, QL1S("paste"), m_part->browserExtension(), SLOT(paste())); - action->setEnabled(pageAction(QWebEnginePage::Paste)->isEnabled()); - editableContentActions.append(action); - - action = new QAction(m_actionCollection); - action->setSeparator(true); - editableContentActions.append(action); - - editableContentActions.append(pageAction(QWebEnginePage::SelectAll)); - editableContentActions.append(pageAction(QWebEnginePage::InspectElement)); - - partGroupMap.insert(QStringLiteral("editactions") , editableContentActions); -} - - -void WebEngineView::partActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& partGroupMap) -{ - QList<QAction*> partActions; - -#ifdef HAVE_WEBENGINECONTEXTMENUDATA - if (m_result.mediaUrl().isValid()) { - QAction *action; - action = new QAction(i18n("Save Image As..."), this); - m_actionCollection->addAction(QL1S("saveimageas"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotSaveImageAs())); - partActions.append(action); - - action = new QAction(i18n("Send Image..."), this); - m_actionCollection->addAction(QL1S("sendimage"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotSendImage())); - partActions.append(action); - - action = new QAction(i18n("Copy Image URL"), this); - m_actionCollection->addAction(QL1S("copyimageurl"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyImageURL())); - partActions.append(action); - -#if 0 - action = new QAction(i18n("Copy Image"), this); - m_actionCollection->addAction(QL1S("copyimage"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyImage())); - action->setEnabled(!m_result.pixmap().isNull()); - partActions.append(action); -#endif - - action = new QAction(i18n("View Image (%1)", QUrl(m_result.mediaUrl()).fileName()), this); - m_actionCollection->addAction(QL1S("viewimage"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotViewImage())); - partActions.append(action); - - if (WebEngineSettings::self()->isAdFilterEnabled()) { - action = new QAction(i18n("Block Image..."), this); - m_actionCollection->addAction(QL1S("blockimage"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotBlockImage())); - partActions.append(action); - - if (!m_result.mediaUrl().host().isEmpty() && - !m_result.mediaUrl().scheme().isEmpty()) - { - action = new QAction(i18n("Block Images From %1" , m_result.mediaUrl().host()), this); - m_actionCollection->addAction(QL1S("blockhost"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotBlockHost())); - partActions.append(action); - } - } - } -#endif - - { - QAction *separatorAction = new QAction(m_actionCollection); - separatorAction->setSeparator(true); - partActions.append(separatorAction); - } - - partActions.append(m_part->actionCollection()->action(QStringLiteral("viewDocumentSource"))); - - partActions.append(pageAction(QWebEnginePage::InspectElement)); - - partGroupMap.insert(QStringLiteral("partactions"), partActions); -} - -void WebEngineView::selectActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& selectGroupMap) -{ - QList<QAction*> selectActions; - - QAction* copyAction = m_actionCollection->addAction(KStandardAction::Copy, QL1S("copy"), m_part->browserExtension(), SLOT(copy())); - copyAction->setText(i18n("&Copy Text")); - copyAction->setEnabled(m_part->browserExtension()->isActionEnabled("copy")); - selectActions.append(copyAction); - - addSearchActions(selectActions, this); - - KUriFilterData data (selectedText().simplified().left(256)); - data.setCheckForExecutables(false); - if (KUriFilter::self()->filterUri(data, QStringList() << QStringLiteral("kshorturifilter") << QStringLiteral("fixhosturifilter")) && - data.uri().isValid() && data.uriType() == KUriFilterData::NetProtocol) { - QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("window-new")), i18nc("open selected url", "Open '%1'", - KStringHandler::rsqueeze(data.uri().url(), 18)), this); - m_actionCollection->addAction(QL1S("openSelection"), action); - action->setData(QUrl(data.uri())); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotOpenSelection())); - selectActions.append(action); - } - - selectGroupMap.insert(QStringLiteral("editactions"), selectActions); -} - -void WebEngineView::linkActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& linkGroupMap) -{ -#ifdef HAVE_WEBENGINECONTEXTMENUDATA - Q_ASSERT(!m_result.linkUrl().isEmpty()); - - const QUrl url(m_result.linkUrl()); -#else - const QUrl url; -#endif - - QList<QAction*> linkActions; - - QAction* action; - -#ifdef HAVE_WEBENGINECONTEXTMENUDATA - if (!m_result.selectedText().isEmpty()) { - action = m_actionCollection->addAction(KStandardAction::Copy, QL1S("copy"), m_part->browserExtension(), SLOT(copy())); - action->setText(i18n("&Copy Text")); - action->setEnabled(m_part->browserExtension()->isActionEnabled("copy")); - linkActions.append(action); - } -#endif - - if (url.scheme() == QLatin1String("mailto")) { -#ifdef HAVE_WEBENGINECONTEXTMENUDATA - action = new QAction(i18n("&Copy Email Address"), this); - m_actionCollection->addAction(QL1S("copylinklocation"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyEmailAddress())); - linkActions.append(action); -#endif - } else { -#ifdef HAVE_WEBENGINECONTEXTMENUDATA - if (!m_result.linkText().isEmpty()) { - action = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy Link &Text"), this); - m_actionCollection->addAction(QL1S("copylinktext"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyLinkText())); - linkActions.append(action); - } -#endif - - action = new QAction(i18n("Copy Link &URL"), this); - m_actionCollection->addAction(QL1S("copylinkurl"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyLinkURL())); - linkActions.append(action); - - action = new QAction(i18n("&Save Link As..."), this); - m_actionCollection->addAction(QL1S("savelinkas"), action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotSaveLinkAs())); - linkActions.append(action); - } - - linkGroupMap.insert(QStringLiteral("linkactions"), linkActions); -} - -void WebEngineView::multimediaActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& mmGroupMap) -{ -#ifdef HAVE_WEBENGINECONTEXTMENUDATA - QList<QAction*> multimediaActions; - - const bool isVideoElement = m_result.mediaType() == QWebEngineContextMenuData::MediaTypeVideo; - const bool isAudioElement = m_result.mediaType() == QWebEngineContextMenuData::MediaTypeAudio; - - QAction* action = new QAction(i18n("&Play/Pause"), this); - m_actionCollection->addAction(QL1S("playmultimedia"), action); - connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotPlayMedia())); - multimediaActions.append(action); - - action = new QAction(i18n("Un&mute/&Mute"), this); - m_actionCollection->addAction(QL1S("mutemultimedia"), action); - connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotMuteMedia())); - multimediaActions.append(action); - - action = new QAction(i18n("Toggle &Loop"), this); - m_actionCollection->addAction(QL1S("loopmultimedia"), action); - connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotLoopMedia())); - multimediaActions.append(action); - - action = new QAction(i18n("Toggle &Controls"), this); - m_actionCollection->addAction(QL1S("showmultimediacontrols"), action); - connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotShowMediaControls())); - multimediaActions.append(action); - - action = new QAction(m_actionCollection); - action->setSeparator(true); - multimediaActions.append(action); - - QString saveMediaText, copyMediaText; - if (isVideoElement) { - saveMediaText = i18n("Sa&ve Video As..."); - copyMediaText = i18n("C&opy Video URL"); - } else if (isAudioElement) { - saveMediaText = i18n("Sa&ve Audio As..."); - copyMediaText = i18n("C&opy Audio URL"); - } else { - saveMediaText = i18n("Sa&ve Media As..."); - copyMediaText = i18n("C&opy Media URL"); - } - - action = new QAction(saveMediaText, this); - m_actionCollection->addAction(QL1S("savemultimedia"), action); - connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotSaveMedia())); - multimediaActions.append(action); - - action = new QAction(copyMediaText, this); - m_actionCollection->addAction(QL1S("copymultimediaurl"), action); - connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotCopyMedia())); - multimediaActions.append(action); - - mmGroupMap.insert(QStringLiteral("partactions"), multimediaActions); -#endif -} - -void WebEngineView::slotStopAutoScroll() -{ - if (m_autoScrollTimerId == -1) { - return; - } - - killTimer(m_autoScrollTimerId); - m_autoScrollTimerId = -1; - m_verticalAutoScrollSpeed = 0; - m_horizontalAutoScrollSpeed = 0; - -} - -void WebEngineView::addSearchActions(QList<QAction*>& selectActions, QWebEngineView* view) -{ - // search text - const QString selectedText = view->selectedText().simplified(); - if (selectedText.isEmpty()) - return; - - KUriFilterData data; - data.setData(selectedText); - data.setAlternateDefaultSearchProvider(ALTERNATE_DEFAULT_WEB_SHORTCUT); - data.setAlternateSearchProviders(ALTERNATE_WEB_SHORTCUTS); - - if (KUriFilter::self()->filterSearchUri(data, KUriFilter::NormalTextFilter)) { - const QString squeezedText = KStringHandler::rsqueeze(selectedText, 20); - QAction *action = new QAction(QIcon::fromTheme(data.iconName()), - i18nc("Search \"search provider\" for \"text\"", "Search %1 for '%2'", - data.searchProvider(), squeezedText), view); - action->setData(QUrl(data.uri())); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(searchProvider())); - m_actionCollection->addAction(QL1S("defaultSearchProvider"), action); - selectActions.append(action); - - - const QStringList preferredSearchProviders = data.preferredSearchProviders(); - if (!preferredSearchProviders.isEmpty()) { - KActionMenu* providerList = new KActionMenu(i18nc("Search for \"text\" with", - "Search for '%1' with", squeezedText), view); - Q_FOREACH(const QString &searchProvider, preferredSearchProviders) { - if (searchProvider == data.searchProvider()) - continue; - - QAction *action = new QAction(QIcon::fromTheme(data.iconNameForPreferredSearchProvider(searchProvider)), searchProvider, view); - action->setData(data.queryForPreferredSearchProvider(searchProvider)); - m_actionCollection->addAction(searchProvider, action); - connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(searchProvider())); - - providerList->addAction(action); - } - m_actionCollection->addAction(QL1S("searchProviderList"), providerList); - selectActions.append(providerList); - } - } -} diff --git a/webenginepart/src/webengineview.h a/webenginepart/src/webengineview.h deleted file mode 100644 index 25b13eae9..000000000 --- a/webenginepart/src/webengineview.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2007 Trolltech ASA - * Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org> - * Copyright (C) 2008 Laurent Montel <montel@kde.org> - * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ -#ifndef WEBENGINEVIEW_H -#define WEBENGINEVIEW_H - -#include <QPointer> -#include <KParts/BrowserExtension> - -#include <QWebEngineView> -#include <QtWebEngine/QtWebEngineVersion> -#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 7, 0) -#define HAVE_WEBENGINECONTEXTMENUDATA -#include <QWebEngineContextMenuData> -#else -typedef void* QWebEngineContextMenuData; -#endif - -class QUrl; -class WebEnginePart; - -class WebEngineView : public QWebEngineView -{ - Q_OBJECT -public: - WebEngineView(WebEnginePart* part, QWidget* parent); - ~WebEngineView(); - - /** - * Same as QWebEnginePage::load, but with KParts style arguments instead. - * - * @see KParts::OpenUrlArguments, KParts::BrowserArguments. - * - * @param url the url to load. - * @param args reference to a OpenUrlArguments object. - * @param bargs reference to a BrowserArguments object. - */ - void loadUrl(const QUrl& url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments& bargs); - - QWebEngineContextMenuData contextMenuResult() const; - -protected: - /** - * Reimplemented for internal reasons, the API is not affected. - * - * @see QWidget::contextMenuEvent - * @internal - */ - void contextMenuEvent(QContextMenuEvent*) Q_DECL_OVERRIDE; - - /** - * Reimplemented for internal reasons, the API is not affected. - * - * @see QWidget::keyPressEvent - * @internal - */ - void keyPressEvent(QKeyEvent*) Q_DECL_OVERRIDE; - - /** - * Reimplemented for internal reasons, the API is not affected. - * - * @see QWidget::keyReleaseEvent - * @internal - */ - void keyReleaseEvent(QKeyEvent*) Q_DECL_OVERRIDE; - - /** - * Reimplemented for internal reasons, the API is not affected. - * - * @see QWidget::mouseReleaseEvent - * @internal - */ - void mouseReleaseEvent(QMouseEvent*) Q_DECL_OVERRIDE; - - /** - * Reimplemented for internal reasons, the API is not affected. - * - * @see QObject::timerEvent - * @internal - */ - void timerEvent(QTimerEvent*) Q_DECL_OVERRIDE; - - /** - * Reimplemented for internal reasons, the API is not affected. - * - * @see QWidget::wheelEvent - * @internal - */ - void wheelEvent(QWheelEvent*) Q_DECL_OVERRIDE; - -private Q_SLOTS: - void slotStopAutoScroll(); - -private: - void editableContentActionPopupMenu(KParts::BrowserExtension::ActionGroupMap&); - void selectActionPopupMenu(KParts::BrowserExtension::ActionGroupMap&); - void linkActionPopupMenu(KParts::BrowserExtension::ActionGroupMap&); - void partActionPopupMenu(KParts::BrowserExtension::ActionGroupMap &); - void multimediaActionPopupMenu(KParts::BrowserExtension::ActionGroupMap&); - void addSearchActions(QList<QAction*>& selectActions, QWebEngineView*); - - KActionCollection* m_actionCollection; - QWebEngineContextMenuData m_result; - QPointer<WebEnginePart> m_part; - - qint32 m_autoScrollTimerId; - qint32 m_verticalAutoScrollSpeed; - qint32 m_horizontalAutoScrollSpeed; - - QHash<QString, QChar> m_duplicateLinkElements; -}; - -#endif // WEBENGINEVIEW_H diff --git a/webenginepart/src/webhistoryinterface.cpp a/webenginepart/src/webhistoryinterface.cpp deleted file mode 100644 index 74e2c096e..000000000 --- a/webenginepart/src/webhistoryinterface.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2011 Dawit Alemayehu <adawit@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "webhistoryinterface.h" - -#include <KParts/HistoryProvider> - - -WebHistoryInterface::WebHistoryInterface(QObject* parent) -{ -} - -void WebHistoryInterface::addHistoryEntry(const QString& url) -{ - KParts::HistoryProvider::self()->insert(url); -} - -bool WebHistoryInterface::historyContains(const QString& url) const -{ - return KParts::HistoryProvider::self()->contains(url); -} diff --git a/webenginepart/src/webhistoryinterface.h a/webenginepart/src/webhistoryinterface.h deleted file mode 100644 index fbc6d6f8b..000000000 --- a/webenginepart/src/webhistoryinterface.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2011 Dawit Alemayehu <adawit@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ -#ifndef WEBHISTORYINTERFACE_H -#define WEBHISTORYINTERFACE_H - -#include <QObject> - - -class WebHistoryInterface -{ -public: - WebHistoryInterface(QObject* parent = Q_NULLPTR); - void addHistoryEntry (const QString & url); - bool historyContains (const QString & url) const; -}; - -#endif //WEBHISTORYINTERFACE_H diff --git a/webenginepart/src/websslinfo.cpp a/webenginepart/src/websslinfo.cpp deleted file mode 100644 index 7960007d0..000000000 --- a/webenginepart/src/websslinfo.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "websslinfo.h" - -#include <QVariant> - - -class WebSslInfo::WebSslInfoPrivate -{ -public: - WebSslInfoPrivate() - : usedCipherBits(0), supportedCipherBits(0) {} - - QUrl url; - QString ciphers; - QString protocol; - QString certErrors; - QHostAddress peerAddress; - QHostAddress parentAddress; - QList<QSslCertificate> certificateChain; - - int usedCipherBits; - int supportedCipherBits; -}; - -WebSslInfo::WebSslInfo() - :d(new WebSslInfo::WebSslInfoPrivate) -{ -} - -WebSslInfo::WebSslInfo(const WebSslInfo& other) - :d(new WebSslInfo::WebSslInfoPrivate) -{ - *this = other; -} - -WebSslInfo::~WebSslInfo() -{ - delete d; - d = 0; -} - -bool WebSslInfo::isValid() const -{ - return (d ? !d->peerAddress.isNull() : false); -} - -QUrl WebSslInfo::url() const -{ - return (d ? d->url : QUrl()); -} - -QHostAddress WebSslInfo::parentAddress() const -{ - return (d ? d->parentAddress : QHostAddress()); -} - -QHostAddress WebSslInfo::peerAddress() const -{ - return (d ? d->peerAddress : QHostAddress()); -} - -QString WebSslInfo::protocol() const -{ - return (d ? d->protocol : QString()); -} - -QString WebSslInfo::ciphers() const -{ - return (d ? d->ciphers : QString()); -} - -QString WebSslInfo::certificateErrors() const -{ - return (d ? d->certErrors : QString()); -} - -int WebSslInfo::supportedChiperBits () const -{ - return (d ? d->supportedCipherBits : 0); -} - -int WebSslInfo::usedChiperBits () const -{ - return (d ? d->usedCipherBits : 0); -} - -QList<QSslCertificate> WebSslInfo::certificateChain() const -{ - return (d ? d->certificateChain : QList<QSslCertificate>()); -} - -WebSslInfo& WebSslInfo::operator=(const WebSslInfo& other) -{ - if (d) { - d->ciphers = other.d->ciphers; - d->protocol = other.d->protocol; - d->certErrors = other.d->certErrors; - d->peerAddress = other.d->peerAddress; - d->parentAddress = other.d->parentAddress; - d->certificateChain = other.d->certificateChain; - - d->usedCipherBits = other.d->usedCipherBits; - d->supportedCipherBits = other.d->supportedCipherBits; - d->url = other.d->url; - } - - return *this; -} - -bool WebSslInfo::saveTo(QMap<QString, QVariant>& data) const -{ - const bool ok = isValid(); - if (ok) { - data.insert(QStringLiteral("ssl_in_use"), true); - data.insert(QStringLiteral("ssl_peer_ip"), d->peerAddress.toString()); - data.insert(QStringLiteral("ssl_parent_ip"), d->parentAddress.toString()); - data.insert(QStringLiteral("ssl_protocol_version"), d->protocol); - data.insert(QStringLiteral("ssl_cipher"), d->ciphers); - data.insert(QStringLiteral("ssl_cert_errors"), d->certErrors); - data.insert(QStringLiteral("ssl_cipher_used_bits"), d->usedCipherBits); - data.insert(QStringLiteral("ssl_cipher_bits"), d->supportedCipherBits); - QByteArray certChain; - Q_FOREACH(const QSslCertificate& cert, d->certificateChain) - certChain += cert.toPem(); - data.insert(QStringLiteral("ssl_peer_chain"), certChain); - } - - return ok; -} - -void WebSslInfo::restoreFrom(const QVariant& value, const QUrl& url, bool reset) -{ - if (reset) { - *this = WebSslInfo(); - } - - if (value.isValid() && value.type() == QVariant::Map) { - QMap<QString,QVariant> metaData = value.toMap(); - if (metaData.value(QStringLiteral("ssl_in_use"), false).toBool()) { - setCertificateChain(metaData.value(QStringLiteral("ssl_peer_chain")).toByteArray()); - setPeerAddress(metaData.value(QStringLiteral("ssl_peer_ip")).toString()); - setParentAddress(metaData.value(QStringLiteral("ssl_parent_ip")).toString()); - setProtocol(metaData.value(QStringLiteral("ssl_protocol_version")).toString()); - setCiphers(metaData.value(QStringLiteral("ssl_cipher")).toString()); - setCertificateErrors(metaData.value(QStringLiteral("ssl_cert_errors")).toString()); - setUsedCipherBits(metaData.value(QStringLiteral("ssl_cipher_used_bits")).toString()); - setSupportedCipherBits(metaData.value(QStringLiteral("ssl_cipher_bits")).toString()); - setUrl(url); - } - } -} - -void WebSslInfo::setUrl (const QUrl &url) -{ - if (d) - d->url = url; -} - -void WebSslInfo::setPeerAddress(const QString& address) -{ - if (d) - d->peerAddress = address; -} - -void WebSslInfo::setParentAddress(const QString& address) -{ - if (d) - d->parentAddress = address; -} - -void WebSslInfo::setProtocol(const QString& protocol) -{ - if (d) - d->protocol = protocol; -} - -void WebSslInfo::setCertificateChain(const QByteArray& chain) -{ - if (d) - d->certificateChain = QSslCertificate::fromData(chain); -} - -void WebSslInfo::setCiphers(const QString& ciphers) -{ - if (d) - d->ciphers = ciphers; -} - -void WebSslInfo::setUsedCipherBits(const QString& bits) -{ - if (d) - d->usedCipherBits = bits.toInt(); -} - -void WebSslInfo::setSupportedCipherBits(const QString& bits) -{ - if (d) - d->supportedCipherBits = bits.toInt(); -} - -void WebSslInfo::setCertificateErrors(const QString& certErrors) -{ - if (d) - d->certErrors = certErrors; -} diff --git a/webenginepart/src/websslinfo.h a/webenginepart/src/websslinfo.h deleted file mode 100644 index 7c7d09ca7..000000000 --- a/webenginepart/src/websslinfo.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the KDE project. - * - * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ -#ifndef WEBSSLINFO_H -#define WEBSSLINFO_H - -//#include <kdemacros.h> - -#include <QUrl> -#include <QList> -#include <QString> -#include <QHostAddress> -#include <QSslCertificate> - -class WebSslInfo -{ -public: - WebSslInfo(); - WebSslInfo(const WebSslInfo&); - virtual ~WebSslInfo(); - - bool isValid() const; - QUrl url() const; - QHostAddress peerAddress() const; - QHostAddress parentAddress() const; - QString ciphers() const; - QString protocol() const; - QString certificateErrors() const; - int supportedChiperBits () const; - int usedChiperBits () const; - QList<QSslCertificate> certificateChain() const; - - bool saveTo(QMap<QString, QVariant>&) const; - void restoreFrom(const QVariant &, const QUrl& = QUrl(), bool reset = false); - - void setUrl (const QUrl &url); - WebSslInfo& operator = (const WebSslInfo&); - -protected: - void setCiphers(const QString& ciphers); - void setProtocol(const QString& protocol); - void setPeerAddress(const QString& address); - void setParentAddress(const QString& address); - void setCertificateChain(const QByteArray& chain); - void setCertificateErrors(const QString& certErrors); - void setUsedCipherBits(const QString& bits); - void setSupportedCipherBits(const QString& bits); - -private: - class WebSslInfoPrivate; - WebSslInfoPrivate* d; -}; - -#endif // WEBSSLINFO_H diff --git a/webenginepart/testfiles/embed_tag_test.html a/webenginepart/testfiles/embed_tag_test.html deleted file mode 100644 index 8afe2d611..000000000 --- a/webenginepart/testfiles/embed_tag_test.html +++ /dev/null @@ -1,20 +0,0 @@ -<html> -<head> - <title> <EMBED> tests - - -

KDE e.V. Report 2011 Q2

-
- -
-

-

KDE e.V. Report 2011 Q1

-
- -
-

-

-
- - diff --git a/webenginepart/testfiles/form_save_restore_test.html a/webenginepart/testfiles/form_save_restore_test.html deleted file mode 100644 index d1adaeb76..000000000 --- a/webenginepart/testfiles/form_save_restore_test.html +++ /dev/null @@ -1,68 +0,0 @@ - - - Form save restore test - - - -
- - -
- - -
- - -
-One -
-Two -
-Three -
-
- -

-Enter some text in the box below:
- -

- -

-Disabled text area:
- -

- -

-Read only text area:
- -

- -

-Text area with spell check disabled:
- -

- -

-Choose one: - -

- -

-Select one or more items:
- -

- - - diff --git a/webenginepart/testfiles/frameset_test.html a/webenginepart/testfiles/frameset_test.html deleted file mode 100644 index 25a295937..000000000 --- a/webenginepart/testfiles/frameset_test.html +++ /dev/null @@ -1,9 +0,0 @@ - - -<FRAMESET> test - - - - - - diff --git a/webenginepart/testfiles/frametest/frame_a.html a/webenginepart/testfiles/frametest/frame_a.html deleted file mode 100644 index 0ea08f3f6..000000000 --- a/webenginepart/testfiles/frametest/frame_a.html +++ /dev/null @@ -1,7 +0,0 @@ - - - -

Frame A

- - - diff --git a/webenginepart/testfiles/frametest/frame_b.html a/webenginepart/testfiles/frametest/frame_b.html deleted file mode 100644 index fe36a8d98..000000000 --- a/webenginepart/testfiles/frametest/frame_b.html +++ /dev/null @@ -1,7 +0,0 @@ - - - -

Frame B

- - - \ No newline at end of file diff --git a/webenginepart/testfiles/frametest/frame_c.html a/webenginepart/testfiles/frametest/frame_c.html deleted file mode 100644 index 3ed0e0e67..000000000 --- a/webenginepart/testfiles/frametest/frame_c.html +++ /dev/null @@ -1,7 +0,0 @@ - - - -

Frame C

-Go to KDE website - - \ No newline at end of file diff --git a/webenginepart/testfiles/frametest/frame_navigation.html a/webenginepart/testfiles/frametest/frame_navigation.html deleted file mode 100644 index 3632a0d8b..000000000 --- a/webenginepart/testfiles/frametest/frame_navigation.html +++ /dev/null @@ -1,9 +0,0 @@ - - -Frame a
-Frame b
-Frame c
-Invalid frame
-bugs.kde.org - - \ No newline at end of file diff --git a/webenginepart/testfiles/js.html a/webenginepart/testfiles/js.html deleted file mode 100644 index 4c03c3473..000000000 --- a/webenginepart/testfiles/js.html +++ /dev/null @@ -1,52 +0,0 @@ - - -Javascript Link Tests - - - - -

Javascript Link Tests

-resizeTo
-moveTo
-promptAndAlertMessage
-status
-JS open new window
-JS open new frameset
- - diff --git a/webenginepart/testfiles/link_tests.html a/webenginepart/testfiles/link_tests.html deleted file mode 100644 index f2d73007a..000000000 --- a/webenginepart/testfiles/link_tests.html +++ /dev/null @@ -1,136 +0,0 @@ - - - Link Tests - - - -

MAILTO Link Tests

- Email link #1 -
- Email link #2 -
-

FTP Link Tests

- FTP link #1 (new window) -
- FTP link #2 (new window) -
- FTP link #3 -
- Text File Link -
- Anchor test -
- Anchor test (new window) -
-

HTTP Link Tests

- Web site link (new window) -
- Web site link with bogus username -
- Web site link with different bogus username -
- PDF link -
- PDF link (new window) -
- Duplicate PDF link (new window) -
- Movie link -
- Movie link (new window) -
- Text Document Link -
- Bogus link -
-

Javascript Link Tests

- Open dialog like window link #1 -
- Open dialog like window link #2 -
- Open new window link #2 (might be opened as Tab) -
- Open PDF Document (new window) -
- Javscript + Target test -
- Close window -
- On mouse over open window test -
- Redirect test -
-

KDE specific URL Tests

- Text Document Link -
-

Form Tests

-
- Choose file to upload:
-
- - -
-
-

URL Fragment Test

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - diff --git a/webenginepart/testfiles/meta_tag_refresh_test.html a/webenginepart/testfiles/meta_tag_refresh_test.html deleted file mode 100644 index 4ea95a59c..000000000 --- a/webenginepart/testfiles/meta_tag_refresh_test.html +++ /dev/null @@ -1,14 +0,0 @@ - - - Meta redirect test - - - -You will be redirected to kde.org in 10 seconds.
-

-If the stop button is active (not disabled) after the page has completely loaded, it -means the rendering engine allows you to cancel <META> based redirect requests. -Otherwise, you are not able to stop redirects or refresh requests set by web pages. -

- - \ No newline at end of file diff --git a/webenginepart/tests/CMakeLists.txt a/webenginepart/tests/CMakeLists.txt deleted file mode 100644 index 5589c1b18..000000000 --- a/webenginepart/tests/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_executable(webenginepart_tester webenginepart_tester.cpp) -target_link_libraries(webenginepart_tester kwebenginepartlib Qt5::Core Qt5::Gui Qt5::Widgets Qt5::WebEngineWidgets KF5::I18n KF5::KDELibs4Support) diff --git a/webenginepart/tests/webenginepart_tester.cpp a/webenginepart/tests/webenginepart_tester.cpp deleted file mode 100644 index 069a4323f..000000000 --- a/webenginepart/tests/webenginepart_tester.cpp +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) - * Copyright (C) 2006 George Staikos - * Copyright (C) 2006 Dirk Mueller - * Copyright (C) 2006 Zack Rusin - * Copyright (C) 2006 Simon Hausmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -//#include -//#include -#include -//#include -#include -//#include -//#include - -#if !defined(QT_NO_PRINTER) -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -class MainWindow : public QMainWindow -{ - Q_OBJECT -public: - MainWindow(const QString& url = QString()): currentZoom(100) { - view = new WebEnginePart(this); - setCentralWidget(view->widget()); - - connect(view->view(), &QWebEngineView::loadFinished, - this, &MainWindow::loadFinished); - connect(view->view(), SIGNAL(titleChanged(QString)), - this, SLOT(setWindowTitle(QString))); - connect(view->view()->page(), SIGNAL(linkHovered(QString)), - this, SLOT(showLinkHover(QString))); - connect(view->view()->page(), SIGNAL(windowCloseRequested()), this, SLOT(deleteLater())); - - setupUI(); - - QUrl qurl(KUriFilter::self()->filteredUri(url, QStringList() << QStringLiteral("kshorturifilter"))); - if (qurl.isValid()) { - urlEdit->setText(qurl.toEncoded()); - view->openUrl(qurl); - - // the zoom values are chosen to be like in Mozilla Firefox 3 - zoomLevels << 30 << 50 << 67 << 80 << 90; - zoomLevels << 100; - zoomLevels << 110 << 120 << 133 << 150 << 170 << 200 << 240 << 300; - } - } - - QWebEnginePage* webPage() const { - return view->view()->page(); - } - - QWebEngineView* webView() const { - return view->view(); - } - -protected slots: - - void changeLocation() { - QUrl url (KUriFilter::self()->filteredUri(urlEdit->text(), QStringList() << QStringLiteral("kshorturifilter"))); - view->openUrl(url); - view->view()->setFocus(Qt::OtherFocusReason); - } - - void loadFinished() { - urlEdit->setText(view->url().toString()); - - QUrl::FormattingOptions opts; - opts |= QUrl::RemoveScheme; - opts |= QUrl::RemoveUserInfo; - opts |= QUrl::StripTrailingSlash; - QString s = view->url().toString(opts); - s = s.mid(2); - if (s.isEmpty()) - return; - - if (!urlList.contains(s)) - urlList += s; - urlModel.setStringList(urlList); - } - - void showLinkHover(const QString &link) { - statusBar()->showMessage(link); - } - - void zoomIn() { - int i = zoomLevels.indexOf(currentZoom); - Q_ASSERT(i >= 0); - if (i < zoomLevels.count() - 1) - currentZoom = zoomLevels[i + 1]; - - view->view()->setZoomFactor(qreal(currentZoom)/100.0); - } - - void zoomOut() { - int i = zoomLevels.indexOf(currentZoom); - Q_ASSERT(i >= 0); - if (i > 0) - currentZoom = zoomLevels[i - 1]; - - view->view()->setZoomFactor(qreal(currentZoom)/100.0); - } - - void resetZoom() - { - currentZoom = 100; - view->view()->setZoomFactor(1.0); - } - - void toggleZoomTextOnly(bool b) - { -// view->view()->page()->settings()->setAttribute(QWebEngineSettings::ZoomTextOnly, b); - } - - void print() { -#if !defined(QT_NO_PRINTER) - QScopedPointer dlg (new QPrintPreviewDialog(this)); - connect(dlg.data(), SIGNAL(paintRequested(QPrinter*)), - view, SLOT(print(QPrinter*))); - dlg->exec(); -#endif - } - - void setEditable(bool on) { -// view->view()->page()->setContentEditable(on); - formatMenuAction->setVisible(on); - } - - void dumpHtml() { - view->view()->page()->toHtml([](const QString& text) { - kDebug() << "HTML: " << text; - }); - } - - void selectElements() { - bool ok; - QString str = QInputDialog::getText(this, i18nc("input dialog window title for selecting html elements", "Select elements"), - i18nc("input dialog text for selecting html elements", "Choose elements"), QLineEdit::Normal, - QStringLiteral("a"), &ok); - if (ok && !str.isEmpty()) { - //QWebElementCollection collection = view->page()->mainFrame()->findAllElements(str); - //const int count = collection.count(); - //for (int i=0; i < count; i++) - // collection.at(i).setStyleProperty("background-color", "yellow"); - //statusBar()->showMessage(i18np("%1 element selected", "%1 elements selected", count), 5000); - } - } - -public slots: - - void newWindow(const QString &url = QString()) { - MainWindow *mw = new MainWindow(url); - mw->show(); - } - -private: - - QVector zoomLevels; - int currentZoom; - - // create the status bar, tool bar & menu - void setupUI() { - progress = new QProgressBar(this); - progress->setRange(0, 100); - progress->setMinimumSize(100, 20); - progress->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - progress->hide(); - statusBar()->addPermanentWidget(progress); - - connect(view->view(), SIGNAL(loadProgress(int)), progress, SLOT(show())); - connect(view->view(), SIGNAL(loadProgress(int)), progress, SLOT(setValue(int))); - connect(view->view(), SIGNAL(loadFinished(bool)), progress, SLOT(hide())); - - urlEdit = new KLineEdit(this); - urlEdit->setSizePolicy(QSizePolicy::Expanding, urlEdit->sizePolicy().verticalPolicy()); - connect(urlEdit, SIGNAL(returnPressed()), - SLOT(changeLocation())); - QCompleter *completer = new QCompleter(this); - urlEdit->setCompleter(completer); - completer->setModel(&urlModel); - - QToolBar *bar = addToolBar(QStringLiteral("Navigation")); - bar->addAction(view->view()->pageAction(QWebEnginePage::Back)); - bar->addAction(view->view()->pageAction(QWebEnginePage::Forward)); - bar->addAction(view->view()->pageAction(QWebEnginePage::Reload)); - bar->addAction(view->view()->pageAction(QWebEnginePage::Stop)); - bar->addWidget(urlEdit); - - QMenu *fileMenu = menuBar()->addMenu(i18n("&File")); - QAction *newWindow = fileMenu->addAction(i18n("New Window"), this, SLOT(newWindow())); - - fileMenu->addAction(i18n("Print"), this, SLOT(print())); - fileMenu->addAction(i18n("Close"), this, SLOT(close())); - - QMenu *editMenu = menuBar()->addMenu(i18n("&Edit")); - editMenu->addAction(view->view()->pageAction(QWebEnginePage::Undo)); - editMenu->addAction(view->view()->pageAction(QWebEnginePage::Redo)); - editMenu->addSeparator(); - editMenu->addAction(view->view()->pageAction(QWebEnginePage::Cut)); - editMenu->addAction(view->view()->pageAction(QWebEnginePage::Copy)); - editMenu->addAction(view->view()->pageAction(QWebEnginePage::Paste)); - editMenu->addSeparator(); - QAction *setEditable = editMenu->addAction(i18n("Set Editable"), this, SLOT(setEditable(bool))); - setEditable->setCheckable(true); - - QMenu *viewMenu = menuBar()->addMenu(i18n("&View")); - viewMenu->addAction(view->view()->pageAction(QWebEnginePage::Stop)); - viewMenu->addAction(view->view()->pageAction(QWebEnginePage::Reload)); - viewMenu->addSeparator(); - QAction *zoomIn = viewMenu->addAction(i18n("Zoom &In"), this, SLOT(zoomIn())); - QAction *zoomOut = viewMenu->addAction(i18n("Zoom &Out"), this, SLOT(zoomOut())); - QAction *resetZoom = viewMenu->addAction(i18n("Reset Zoom"), this, SLOT(resetZoom())); - QAction *zoomTextOnly = viewMenu->addAction(i18n("Zoom Text Only"), this, SLOT(toggleZoomTextOnly(bool))); - zoomTextOnly->setCheckable(true); - zoomTextOnly->setChecked(false); - viewMenu->addSeparator(); - viewMenu->addAction(i18n("Dump HTML"), this, SLOT(dumpHtml())); - -#if 0 - QMenu *formatMenu = new QMenu(i18n("F&ormat")); - formatMenuAction = menuBar()->addMenu(formatMenu); - formatMenuAction->setVisible(false); - formatMenu->addAction(view->view()->pageAction(QWebEnginePage::ToggleBold)); - formatMenu->addAction(view->view()->pageAction(QWebEnginePage::ToggleItalic)); - formatMenu->addAction(view->view()->pageAction(QWebEnginePage::ToggleUnderline)); - QMenu *writingMenu = formatMenu->addMenu(i18n("Writing Direction")); - writingMenu->addAction(view->view()->pageAction(QWebEnginePage::SetTextDirectionDefault)); - writingMenu->addAction(view->view()->pageAction(QWebEnginePage::SetTextDirectionLeftToRight)); - writingMenu->addAction(view->view()->pageAction(QWebEnginePage::SetTextDirectionRightToLeft)); -#endif - newWindow->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_N)); - view->view()->pageAction(QWebEnginePage::Back)->setShortcut(QKeySequence::Back); - view->view()->pageAction(QWebEnginePage::Stop)->setShortcut(Qt::Key_Escape); - view->view()->pageAction(QWebEnginePage::Forward)->setShortcut(QKeySequence::Forward); - view->view()->pageAction(QWebEnginePage::Reload)->setShortcut(QKeySequence::Refresh); - view->view()->pageAction(QWebEnginePage::Undo)->setShortcut(QKeySequence::Undo); - view->view()->pageAction(QWebEnginePage::Redo)->setShortcut(QKeySequence::Redo); - view->view()->pageAction(QWebEnginePage::Cut)->setShortcut(QKeySequence::Cut); - view->view()->pageAction(QWebEnginePage::Copy)->setShortcut(QKeySequence::Copy); - view->view()->pageAction(QWebEnginePage::Paste)->setShortcut(QKeySequence::Paste); - zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus)); - zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus)); - resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0)); -// view->view()->pageAction(QWebEnginePage::ToggleBold)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_B)); -// view->view()->pageAction(QWebEnginePage::ToggleItalic)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_I)); -// view->view()->pageAction(QWebEnginePage::ToggleUnderline)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_U)); - - QMenu *toolsMenu = menuBar()->addMenu(i18n("&Tools")); - toolsMenu->addAction(i18n("Select elements..."), this, SLOT(selectElements())); - - } - - WebEnginePart *view; - KLineEdit *urlEdit; - QProgressBar *progress; - - QAction *formatMenuAction; - - QStringList urlList; - QStringListModel urlModel; -}; - -class URLLoader : public QObject -{ - Q_OBJECT -public: - URLLoader(QWebEngineView* view, const QString& inputFileName) - : m_view(view) - , m_stdOut(stdout) - { - init(inputFileName); - } - -public slots: - void loadNext() - { - QString qstr; - if (getUrl(qstr)) { - QUrl url(qstr, QUrl::StrictMode); - if (url.isValid()) { - m_stdOut << "Loading " << qstr << " ......" << endl; - m_view->load(url); - } else - loadNext(); - } else - disconnect(m_view, 0, this, 0); - } - -private: - void init(const QString& inputFileName) - { - QFile inputFile(inputFileName); - if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream stream(&inputFile); - QString line; - while (true) { - line = stream.readLine(); - if (line.isNull()) - break; - m_urls.append(line); - } - } else { - kDebug() << "Can't open list file"; - exit(0); - } - m_index = 0; - inputFile.close(); - } - - bool getUrl(QString& qstr) - { - if (m_index == m_urls.size()) - return false; - - qstr = m_urls[m_index++]; - return true; - } - -private: - QVector m_urls; - int m_index; - QWebEngineView* m_view; - QTextStream m_stdOut; -}; - - -int main(int argc, char **argv) -{ - KAboutData about(QStringLiteral("KDELauncher"), i18n("KDELauncher"), QStringLiteral("0.0000013")); - QApplication app(argc, argv); - QCommandLineParser parser; - KAboutData::setApplicationData(about); - parser.addVersionOption(); - parser.addHelpOption(); - //PORTING SCRIPT: adapt aboutdata variable if necessary - about.setupCommandLine(&parser); - parser.process(app); - about.processCommandLine(&parser); - - QString url = QStringLiteral("%1/%2").arg(QDir::homePath()).arg(QStringLiteral("index.html")); - -// QWebEngineSettings::globalSettings()->setMaximumPagesInCache(4); - -// QWebEngineSettings::setObjectCacheCapacities((16*1024*1024) / 8, (16*1024*1024) / 8, 16*1024*1024); - - QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); -// QWebEngineSettings::globalSettings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); - - const QStringList args = app.arguments(); - - if (args.contains(QStringLiteral("-r"))) { - // robotized - QString listFile = args.at(2); - if (!(args.count() == 3) && QFile::exists(listFile)) { - kDebug() << "Usage: KDELauncher -r listfile"; - exit(0); - } - MainWindow window; - QWebEngineView *view = window.webView(); - URLLoader loader(view, listFile); - QObject::connect(view, SIGNAL(loadFinished(bool)), &loader, SLOT(loadNext())); - loader.loadNext(); - window.show(); - return app.exec(); - } else { - if (args.count() > 1) - url = args.at(1); - - MainWindow window(url); - - // Opens every given urls in new windows - for (int i = 2; i < args.count(); i++) - window.newWindow(args.at(i)); - - window.show(); - return app.exec(); - } -} - -#include "webenginepart_tester.moc" diff --git a/webenginepart/webenginepart.lsm a/webenginepart/webenginepart.lsm deleted file mode 100644 index 99b4fbe5a..000000000 --- a/webenginepart/webenginepart.lsm +++ /dev/null @@ -1,18 +0,0 @@ -Begin3 -Title: webenginepart -Version: 1.2.0 -Entered-date: 06APR2011 -Description: A WebEngine browser component for KDE (KPart) -Keywords: webengine, webenginepart -Author: Trolltech ASA - Urs Wolfer - Laurent Montel - Dawit Alemayehu - Sune Vuorela -Maintained-by: Sune Vuorela -Primary-site: -Home-Page: -Original-site: None -Platforms: KF5 and higher -Copying-policy: LGPL -End diff --git b/webkitpart/CMakeLists.txt b/webkitpart/CMakeLists.txt new file mode 100644 index 000000000..b62735e8b --- /dev/null +++ b/webkitpart/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(icons) +add_subdirectory(src) +add_subdirectory(tests) +add_subdirectory(autotests) diff --git b/webkitpart/COPYING.LIB b/webkitpart/COPYING.LIB new file mode 100644 index 000000000..01148ab6f --- /dev/null +++ b/webkitpart/COPYING.LIB @@ -0,0 +1,486 @@ +NOTE! The LGPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the kde libraries) are copyrighted +by the authors who actually wrote it. + +--------------------------------------------------------------------------- + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor + Boston, MA 02110-1301, USA. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git b/webkitpart/Mainpage.dox b/webkitpart/Mainpage.dox new file mode 100644 index 000000000..832196aef --- /dev/null +++ b/webkitpart/Mainpage.dox @@ -0,0 +1,4 @@ +/** @mainpage +* +* Main Doxygen page for KWebKitPart. +*/ diff --git b/webkitpart/Messages.sh b/webkitpart/Messages.sh new file mode 100644 index 000000000..ce16bc912 --- /dev/null +++ b/webkitpart/Messages.sh @@ -0,0 +1,4 @@ +#! /usr/bin/env bash +$EXTRACTRC `find . -name '*.rc' -or -name '*.ui'` >> rc.cpp || exit 11 +$XGETTEXT `find . -name '*.cpp' | grep -v '/tests/'` -o $podir/webkitpart.pot +rm -f rc.cpp diff --git b/webkitpart/README b/webkitpart/README new file mode 100644 index 000000000..f73bfc864 --- /dev/null +++ b/webkitpart/README @@ -0,0 +1,40 @@ +KWebKitPart +=========== + +KWebKitPart is a KDE component (KPart) wrapper for QtWebKit. It is intended to +allow KPart based KDE applications such as Konqueror to use it in place of other +browser engine, such as KHTML, to browse the web in Konqueror. + +Known limitations and unimplemented features are listed in the following +documents: + +* https://projects.kde.org/projects/kde/kdelibs/repository/revisions/master/entry/kdewebkit/ISSUES +* https://projects.kde.org/projects/extragear/base/kwebkitpart/repository/revisions/master/entry/TODO + +Please report any issues to: https://bugs.kde.org +IMPORTANT NOTE: Do not select "konqueror" as product, but "kwebkitpart"! + +There is also a public mailing list available for support: + + webkit-devel @ kde.org + +How to use KWebKitPart in Konqueror +=================================== + +You can switch between the different rendering engines: +View -> View Mode -> {KHTML, WebKit} (website needs to be open) +If WebKit does not show up in Konqueror, run 'kbuildsycoca4' and +restart Konqueror. Note that this change does not persist. If you +press the reload button or open a new website, it will fall back +to the default rendering engine. + +If you want to set KWebKitPart as default for any website, run: +'keditfiletype text/html' +and move "WebKit (kwebkitpart)" in the "Embedding" tab to the top. + +In KDE 4.6 and higher you can choose the default rendering engine +in Konqueror's configuration dialog under the "General" section. + +For more information about this project please see also: +http://techbase.kde.org/Projects/WebKit + diff --git b/webkitpart/TODO b/webkitpart/TODO new file mode 100644 index 000000000..f6ba03459 --- /dev/null +++ b/webkitpart/TODO @@ -0,0 +1,23 @@ +* Proper support for KWebKitPart in the following Konqueror plugins: + - adblock This plugin's GUI needs to be changed to use the KPart plugin + extensions so that it is not khtml specific. Other than that + kwebkitpart supports the ad filtering functionalities supported + by khtml. + +* Add KPartStatusBarExtension support for the following plugins/features: + - Popup blocker (non-plugin) + +* Implement some means of showing information about the webkit rendering engine: + - KWebKitPart's version # + - QtWebKit's version # + - UserAgent string ??? + +* Look through all of Konqueror's web configuration options and make sure we + honor all those we possibly can. Here is a non-complete list of features + that are either partially implemented or not implemented at all: + - Change cursor over links (TODO, QtWebKit ???). + - Smooth scrolling support (TODO, QtWebKit ???). + - Underline links support (Partial, does not work as intended). + - Enable access key navigation with Ctrl key (TODO, QtWebKit ???). + - Animations (TODO, QtWebKit ???). + - Draw frames around not completely loaded images (TODO, QtWebKit ???). diff --git b/webkitpart/autotests/CMakeLists.txt b/webkitpart/autotests/CMakeLists.txt new file mode 100644 index 000000000..69a14a1a1 --- /dev/null +++ b/webkitpart/autotests/CMakeLists.txt @@ -0,0 +1,14 @@ +include(ECMAddTests) + +find_package(Qt5Test ${QT_MIN_VERSION} CONFIG REQUIRED) + +macro(webkitpart_unit_tests) + foreach(_testname ${ARGN}) + ecm_add_test(${_testname}.cpp TEST_NAME ${_testname} + LINK_LIBRARIES kwebkitpartlib Qt5::Test) + endforeach() +endmacro(webkitpart_unit_tests) + +webkitpart_unit_tests( + webkit_partapi_test +) diff --git b/webkitpart/autotests/data/hello.html b/webkitpart/autotests/data/hello.html new file mode 100644 index 000000000..e965047ad --- /dev/null +++ b/webkitpart/autotests/data/hello.html @@ -0,0 +1 @@ +Hello diff --git b/webkitpart/autotests/data/page-with-link.html b/webkitpart/autotests/data/page-with-link.html new file mode 100644 index 000000000..df85219d6 --- /dev/null +++ b/webkitpart/autotests/data/page-with-link.html @@ -0,0 +1 @@ +click me diff --git b/webkitpart/autotests/webkit_partapi_test.cpp b/webkitpart/autotests/webkit_partapi_test.cpp new file mode 100644 index 000000000..107677692 --- /dev/null +++ b/webkitpart/autotests/webkit_partapi_test.cpp @@ -0,0 +1,133 @@ +/* + Copyright (c) 2016 David Faure + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License or ( at + your option ) version 3 or, at the discretion of KDE e.V. ( which shall + act as a proxy as in section 14 of the GPLv3 ), any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include "webkit_testutils.h" + +#include +#include + +#include +#include +#include +#include + +class WebKitPartApiTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void shouldHaveBrowserExtension(); + void shouldEmitStartedAndCompleted(); + void shouldEmitSetWindowCaption(); + void shouldEmitOpenUrlNotifyOnClick(); + +}; + +void WebKitPartApiTest::initTestCase() +{ + qRegisterMetaType(); // for the KParts started signal +} + +void WebKitPartApiTest::shouldHaveBrowserExtension() +{ + // GIVEN + WebKitPart part; + + // WHEN + KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject(&part); + + // THEN + QVERIFY(ext); +} + +void WebKitPartApiTest::shouldEmitStartedAndCompleted() +{ + // GIVEN + WebKitPart part; + QSignalSpy spyStarted(&part, &KParts::ReadOnlyPart::started); + QSignalSpy spyCompleted(&part, SIGNAL(completed(bool))); + QSignalSpy spySetWindowCaption(&part, &KParts::ReadOnlyPart::setWindowCaption); + KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject(&part); + QSignalSpy spyOpenUrlNotify(ext, &KParts::BrowserExtension::openUrlNotify); + const QUrl url(QStringLiteral("data:text/html,

Hello World

")); + + // WHEN + part.openUrl(url); + + // THEN + QVERIFY(spyStarted.wait()); + QVERIFY(spySetWindowCaption.wait()); + QCOMPARE(spySetWindowCaption.at(0).at(0).toUrl().toString(), url.toString()); + QVERIFY(spyCompleted.wait()); + QVERIFY(!spyCompleted.at(0).at(0).toBool()); + QVERIFY(spyOpenUrlNotify.isEmpty()); +} + +void WebKitPartApiTest::shouldEmitSetWindowCaption() +{ + // GIVEN + WebKitPart part; + QSignalSpy spyStarted(&part, &KParts::ReadOnlyPart::started); + QSignalSpy spyCompleted(&part, SIGNAL(completed(bool))); + QSignalSpy spySetWindowCaption(&part, &KParts::ReadOnlyPart::setWindowCaption); + + // WHEN opening a URL with a title tag + part.openUrl(QUrl(QStringLiteral("data:text/html, Custom Title

Hello World

"))); + + // THEN + QVERIFY(spyStarted.wait()); + QVERIFY(spyCompleted.wait()); + QVERIFY(!spyCompleted.at(0).at(0).toBool()); + QCOMPARE(spySetWindowCaption.count(), 2); + QCOMPARE(spySetWindowCaption.at(1).at(0).toUrl().toString(), QStringLiteral("Custom Title")); +} + +void WebKitPartApiTest::shouldEmitOpenUrlNotifyOnClick() +{ + // GIVEN + WebKitPart part; + QSignalSpy spyStarted(&part, &KParts::ReadOnlyPart::started); + QSignalSpy spyCompleted(&part, SIGNAL(completed(bool))); + QSignalSpy spySetWindowCaption(&part, &KParts::ReadOnlyPart::setWindowCaption); + KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject(&part); + QSignalSpy spyOpenUrlNotify(ext, &KParts::BrowserExtension::openUrlNotify); + const QString file = QFINDTESTDATA("data/page-with-link.html"); + QVERIFY(!file.isEmpty()); + const QUrl url = QUrl::fromLocalFile(file); + part.openUrl(url); + QVERIFY(spyCompleted.wait()); + QVERIFY(spyOpenUrlNotify.isEmpty()); + QWebPage *page = part.view()->page(); + const QPoint pos = elementCenter(page, QStringLiteral("linkid")); // doesn't seem fully correct... + part.widget()->show(); + spyCompleted.clear(); + + // WHEN clicking on the link + QTest::mouseClick(part.view()->focusProxy(), Qt::LeftButton, Qt::KeyboardModifiers(), pos); + + // THEN + QVERIFY(spyCompleted.wait()); + QCOMPARE(spyOpenUrlNotify.count(), 1); + QCOMPARE(part.url().fileName(), QStringLiteral("hello.html")); +} + +QTEST_MAIN(WebKitPartApiTest) +#include "webkit_partapi_test.moc" diff --git b/webkitpart/autotests/webkit_testutils.h b/webkitpart/autotests/webkit_testutils.h new file mode 100644 index 000000000..73ac53d85 --- /dev/null +++ b/webkitpart/autotests/webkit_testutils.h @@ -0,0 +1,108 @@ +/**************************************************************************** + ** + ** Copyright (C) 2016 The Qt Company Ltd. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the QtWebKit module of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ + ** 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 General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3 as published by the Free Software + ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT + ** included in the packaging of this file. Please review the following + ** information to ensure the GNU General Public License requirements will + ** be met: https://www.gnu.org/licenses/gpl-3.0.html. + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +#include +#include +#include + +template +struct RefWrapper { + R &ref; + void operator()(const T& result) { + ref(result); + } +}; + +template +class CallbackSpy { +public: + CallbackSpy() : called(false) { + timeoutTimer.setSingleShot(true); + QObject::connect(&timeoutTimer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); + } + + T waitForResult() { + if (!called) { + timeoutTimer.start(10000); + eventLoop.exec(); + } + return result; + } + + bool wasCalled() const { + return called; + } + + void operator()(const T &result) { + this->result = result; + called = true; + eventLoop.quit(); + } + + // Cheap rip-off of boost/std::ref + RefWrapper > ref() + { + RefWrapper > wrapper = {*this}; + return wrapper; + } + +private: + Q_DISABLE_COPY(CallbackSpy) + bool called; + QTimer timeoutTimer; + QEventLoop eventLoop; + T result; +}; + +// taken from the qwebkit unittests +static inline QVariant evaluateJavaScriptSync(QWebPage *page, const QString &script) +{ + CallbackSpy spy; + page->runJavaScript(script, spy.ref()); + return spy.waitForResult(); +} + +// Taken from QtWebKit's tst_qwebkitpage.cpp +static QPoint elementCenter(QWebPage *page, const QString &id) +{ + QVariantList rectList = evaluateJavaScriptSync(page, + "(function(){" + "var elem = document.getElementById('" + id + "');" + "var rect = elem.getBoundingClientRect();" + "return [rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top];" + "})()").toList(); + + if (rectList.count() != 4) { + qWarning("elementCenter failed."); + return QPoint(); + } + const QRect rect(rectList.at(0).toInt(), rectList.at(1).toInt(), + rectList.at(2).toInt(), rectList.at(3).toInt()); + return rect.center(); +} + diff --git b/webkitpart/icons/CMakeLists.txt b/webkitpart/icons/CMakeLists.txt new file mode 100644 index 000000000..4b820aeb3 --- /dev/null +++ b/webkitpart/icons/CMakeLists.txt @@ -0,0 +1,2 @@ +include(ECMInstallIcons) +ecm_install_icons(${ICON_INSTALL_DIR}) diff --git b/webkitpart/icons/hi128-apps-webkit.png b/webkitpart/icons/hi128-apps-webkit.png new file mode 100644 index 000000000..f6580be51 Binary files /dev/null and b/webkitpart/icons/hi128-apps-webkit.png differ diff --git b/webkitpart/icons/hi16-apps-webkit.png b/webkitpart/icons/hi16-apps-webkit.png new file mode 100644 index 000000000..17c14d129 Binary files /dev/null and b/webkitpart/icons/hi16-apps-webkit.png differ diff --git b/webkitpart/icons/hi22-apps-webkit.png b/webkitpart/icons/hi22-apps-webkit.png new file mode 100644 index 000000000..03f0a4f38 Binary files /dev/null and b/webkitpart/icons/hi22-apps-webkit.png differ diff --git b/webkitpart/icons/hi32-apps-webkit.png b/webkitpart/icons/hi32-apps-webkit.png new file mode 100644 index 000000000..4325d32a0 Binary files /dev/null and b/webkitpart/icons/hi32-apps-webkit.png differ diff --git b/webkitpart/icons/hi48-apps-webkit.png b/webkitpart/icons/hi48-apps-webkit.png new file mode 100644 index 000000000..3d9c79853 Binary files /dev/null and b/webkitpart/icons/hi48-apps-webkit.png differ diff --git b/webkitpart/icons/hi64-apps-webkit.png b/webkitpart/icons/hi64-apps-webkit.png new file mode 100644 index 000000000..e915bfa0d Binary files /dev/null and b/webkitpart/icons/hi64-apps-webkit.png differ diff --git b/webkitpart/icons/webkit.svg b/webkitpart/icons/webkit.svg new file mode 100644 index 000000000..ac2e6b9af --- /dev/null +++ b/webkitpart/icons/webkit.svg @@ -0,0 +1,104 @@ + + + + + + + + + + image/svg+xml + + + + + + + W + E + E + B + + diff --git b/webkitpart/scripts/codingstyle.sh b/webkitpart/scripts/codingstyle.sh new file mode 100755 index 000000000..1761942d6 --- /dev/null +++ b/webkitpart/scripts/codingstyle.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# +# Kdelibs coding style is defined in http://techbase.kde.org/Policies/Kdelibs_Coding_Style +# + +PWD=$(pwd) +cd $PWD + +echo "Applying astyle rules..." +astyle -v --indent=spaces=4 \ + --brackets=linux \ + --indent-labels \ + --pad=oper --unpad=paren \ + --one-line=keep-statements \ + --convert-tabs --indent-preprocessor \ + `find -type f -name '*.cpp' -or -name '*.h' -or -name '*.cc' | grep -Ev "\./.+/settings/"` + +echo "Done!" + diff --git b/webkitpart/scripts/create_release_package.sh b/webkitpart/scripts/create_release_package.sh new file mode 100755 index 000000000..a8694c897 --- /dev/null +++ b/webkitpart/scripts/create_release_package.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +VERSION=${1} +GITREPO=${2} +OUTPUTDIR=${3} + +if [ -z ${VERSION} ] || [ -z {GITREPO} ]; then + echo "Usage: `basename ${0}` []" + exit 1 +fi + +if [ -z $OUTPUTDIR ] || [ ! -d $OUTPUTDIR ]; then + OUTPUTDIR="${PWD}" +fi + +git archive --format=tar --prefix=kwebkitpart-${VERSION}/ ${GITREPO} | bzip2 -9 > ${OUTPUTDIR}/kwebkitpart-${VERSION}.tar.bz2 diff --git b/webkitpart/src/CMakeLists.txt b/webkitpart/src/CMakeLists.txt new file mode 100644 index 000000000..9685b28e6 --- /dev/null +++ b/webkitpart/src/CMakeLists.txt @@ -0,0 +1,41 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}) + +set(kwebkitpartlib_LIB_SRCS + webkitpart.cpp + webkitpart_ext.cpp + webkitview.cpp + webkitpage.cpp + websslinfo.cpp + webhistoryinterface.cpp + settings/webkitsettings.cpp + settings/webkit_filter.cpp + ui/searchbar.cpp + ui/passwordbar.cpp + ui/featurepermissionbar.cpp +) + +qt5_wrap_ui(kwebkitpartlib_LIB_SRCS + ui/searchbar.ui +) + +add_library(kwebkitpartlib ${kwebkitpartlib_LIB_SRCS}) + +generate_export_header(kwebkitpartlib) + +target_link_libraries(kwebkitpartlib Qt5::Core Qt5::DBus Qt5::Gui Qt5::Widgets Qt5::WebKitWidgets Qt5::PrintSupport KF5::Parts KF5::SonnetCore) + +target_include_directories(kwebkitpartlib PUBLIC + "$" +) + +install(TARGETS kwebkitpartlib ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) + +add_library(webkitpart MODULE webkitpartfactory.cpp) + +target_link_libraries(webkitpart kwebkitpartlib) + +install(TARGETS webkitpart DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/parts) + +install(FILES webkitpart.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) + +install(FILES webkitpart.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/webkitpart) diff --git b/webkitpart/src/settings/webkit_filter.cpp b/webkitpart/src/settings/webkit_filter.cpp new file mode 100644 index 000000000..f70620053 --- /dev/null +++ b/webkitpart/src/settings/webkit_filter.cpp @@ -0,0 +1,344 @@ +/* This file is part of the KDE project + + Copyright (C) 2005 Ivor Hewitt + Copyright (C) 2008 Maksim Orlovich + Copyright (C) 2008 Vyacheslav Tokarev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "webkit_filter.h" + +#include +#include + +// rolling hash parameters +#define HASH_P (1997) +#define HASH_Q (17509) +// HASH_MOD = (HASH_P^7) % HASH_Q +#define HASH_MOD (523) + + +using namespace KDEPrivate; + +// Updateable Multi-String Matcher based on Rabin-Karp's algorithm +class StringsMatcher { +public: + // add filter to matching set + void addString(const QString& pattern) + { + if (pattern.length() < 8) { + // handle short string differently + shortStringFilters.append(pattern); + } else { + // use modified Rabin-Karp's algorithm with 8-length string hash + // i.e. store hash of first 8 chars in the HashMap for fast look-up + stringFilters.append(pattern); + int ind = stringFilters.size() - 1; + int current = 0; + + // compute hash using rolling hash + // hash for string: x0,x1,x2...xn-1 will be: + // (p^(n-1)*x0 + p^(n-2)*x1 + ... + p * xn-2 + xn-1) % q + // where p and q some wisely-chosen integers + /*for (int k = 0; k < 8; ++k)*/ + int len = pattern.length(); + for (int k = len - 8; k < len; ++k) + current = (current * HASH_P + pattern[k].unicode()) % HASH_Q; + + // insert computed hash value into HashMap + QHash >::iterator it = stringFiltersHash.find(current + 1); + if (it == stringFiltersHash.end()) { + QVector list; + list.append(ind); + stringFiltersHash.insert(current + 1, list); + fastLookUp.setBit(current); + } else { + it->append(ind); + } + } + } + + + // check if string match at least one string from matching set + bool isMatched(const QString& str, QString *by = 0) const + { + // check short strings first + for (int i = 0; i < shortStringFilters.size(); ++i) { + if (str.contains(shortStringFilters[i])) + { + if (by != 0) *by = shortStringFilters[i]; + return true; + } + } + + int len = str.length(); + int k; + + int current = 0; + int next = 0; + // compute hash for first 8 characters + for (k = 0; k < 8 && k < len; ++k) + current = (current * HASH_P + str[k].unicode()) % HASH_Q; + + QHash >::const_iterator hashEnd = stringFiltersHash.end(); + // main Rabin-Karp's algorithm loop + for (k = 7; k < len; ++k, current = next) { + // roll the hash if not at the end + // (calculate hash for the next iteration) + if (k + 1 < len) + next = (HASH_P * ((current + HASH_Q - ((HASH_MOD * str[k - 7].unicode()) % HASH_Q)) % HASH_Q) + str[k + 1].unicode()) % HASH_Q; + + if (!fastLookUp.testBit(current)) + continue; + + // look-up the hash in the HashMap and check all strings + QHash >::const_iterator it = stringFiltersHash.find(current + 1); + + // check possible strings + if (it != hashEnd) { + for (int j = 0; j < it->size(); ++j) { + int index = it->value(j); + // check if we got simple string or REs prefix + if (index >= 0) { + int flen = stringFilters[index].length(); + if (k - flen + 1 >= 0 && stringFilters[index] == str.midRef(k - flen + 1 , flen)) + { + if (by != 0) *by = stringFilters[index]; + return true; + } + } else { + index = -index - 1; + int flen = rePrefixes[index].length(); + if (k - 8 + flen < len && rePrefixes[index] == str.midRef(k - 7, flen)) + { + int remStart = k - 7 + flen; + QString remainder = QString::fromRawData(str.unicode() + remStart, + str.length() - remStart); + if (reFilters[index].exactMatch(remainder)) { + if (by != 0) *by = rePrefixes[index]+reFilters[index].pattern(); + return true; + } + } + } + } + } + } + + return false; + } + + // add filter to matching set with wildcards (*,?) in it + void addWildedString(const QString& prefix, const QRegExp& rx) + { + rePrefixes.append(prefix); + reFilters.append(rx); + int index = -rePrefixes.size(); + + int current = 0; + for (int k = 0; k < 8; ++k) + current = (current * HASH_P + prefix[k].unicode()) % HASH_Q; + + // insert computed hash value into HashMap + QHash >::iterator it = stringFiltersHash.find(current + 1); + if (it == stringFiltersHash.end()) { + QVector list; + list.append(index); + stringFiltersHash.insert(current + 1, list); + fastLookUp.setBit(current); + } else { + it->append(index); + } + } + + void clear() + { + stringFilters.clear(); + shortStringFilters.clear(); + reFilters.clear(); + rePrefixes.clear(); + stringFiltersHash.clear(); + fastLookUp.resize(HASH_Q); + fastLookUp.fill(0, 0, HASH_Q); + } + +private: + QVector stringFilters; + QVector shortStringFilters; + QVector reFilters; + QVector rePrefixes; + QBitArray fastLookUp; + + QHash > stringFiltersHash; +}; + + +// We only want a subset of features of wildcards -- just the +// star, so we escape the rest before passing to QRegExp. +// The \ is escaped due to a QRegExp bug. +// ### we really should rather parse it ourselves, in order to +// handle adblock-special things like | and ^ properly. +static QRegExp fromAdBlockWildcard(const QString& wcStr) { + QRegExp rx; + rx.setPatternSyntax(QRegExp::Wildcard); + + QString out; + for (int p = 0; p < wcStr.length(); ++p) { + QChar c = wcStr[p]; + if (c == QLatin1Char('?')) + out += QLatin1String("[?]"); + else if (c == QLatin1Char('[')) + out += QLatin1String("[[]"); + else if (c == QLatin1Char('\\')) + out += QLatin1String("[\\]"); + else + out += c; + } + + rx.setPattern(out); + return rx; +} + +FilterSet::FilterSet() + :stringFiltersMatcher(new StringsMatcher) +{ +} + +FilterSet::~FilterSet() +{ + delete stringFiltersMatcher; +} + +void FilterSet::addFilter(const QString& filterStr) +{ + QString filter = filterStr; + + /** ignore special lines starting with "[", "!", "&", or "#" or contain "#" (comments or features are not supported by KHTML's AdBlock */ + QChar firstChar = filter.at(0); + if (firstChar == QLatin1Char('[') || firstChar == QLatin1Char('!') || firstChar == QLatin1Char('&') || firstChar == QLatin1Char('#') || filter.contains(QLatin1Char('#'))) + return; + + // Strip leading @@ + int first = 0; + int last = filter.length() - 1; + if (filter.startsWith(QLatin1String("@@"))) + first = 2; + + // Strip options, we ignore them for now. + // TODO: Add support for filters with options. See #310230. + int dollar = filter.lastIndexOf(QLatin1Char('$')); + if (dollar != -1) { + return; + } + + // Perhaps nothing left? + if (first > last) + return; + + filter = filter.mid(first, last - first + 1); + + // Is it a regexp filter? + if (filter.length()>2 && filter.startsWith(QLatin1Char('/')) && filter.endsWith(QLatin1Char('/'))) + { + QString inside = filter.mid(1, filter.length()-2); + QRegExp rx(inside); + reFilters.append(rx); +// qDebug() << "R:" << inside; + } + else + { + // Nope, a wildcard one. + // Note: For these, we also need to handle |. + + // Strip wildcards at the ends + first = 0; + last = filter.length() - 1; + + while (first < filter.length() && filter[first] == QLatin1Char('*')) + ++first; + + while (last >= 0 && filter[last] == QLatin1Char('*')) + --last; + + if (first > last) + filter = QStringLiteral("*"); // erm... Well, they asked for it. + else + filter = filter.mid(first, last - first + 1); + + // Now, do we still have any wildcard stuff left? + if (filter.contains(QLatin1String("*"))) + { + // check if we can use RK first (and then check full RE for the rest) for better performance + int aPos = filter.indexOf('*'); + if (aPos < 0) + aPos = filter.length(); + if (aPos > 7) { + QRegExp rx = fromAdBlockWildcard(filter.mid(aPos) + QLatin1Char('*')); + // We pad the final r.e. with * so we can check for an exact match + stringFiltersMatcher->addWildedString(filter.mid(0, aPos), rx); + } else { + QRegExp rx = fromAdBlockWildcard(filter); + reFilters.append(rx); + } + } + else + { + // Fast path + stringFiltersMatcher->addString(filter); + } + } +} + +bool FilterSet::isUrlMatched(const QString& url) +{ + if (stringFiltersMatcher->isMatched(url)) + return true; + + for (int c = 0; c < reFilters.size(); ++c) + { + if (url.contains(reFilters[c])) + return true; + } + + return false; +} + +QString FilterSet::urlMatchedBy(const QString& url) +{ + QString by; + + if (stringFiltersMatcher->isMatched(url, &by)) + return by; + + for (int c = 0; c < reFilters.size(); ++c) + { + if (url.contains(reFilters[c])) + { + by = reFilters[c].pattern(); + break; + } + } + + return by; +} + +void FilterSet::clear() +{ + reFilters.clear(); + stringFiltersMatcher->clear(); +} + +// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; diff --git b/webkitpart/src/settings/webkit_filter.h b/webkitpart/src/settings/webkit_filter.h new file mode 100644 index 000000000..732cf1538 --- /dev/null +++ b/webkitpart/src/settings/webkit_filter.h @@ -0,0 +1,60 @@ +/* This file is part of the KDE project + + Copyright (C) 2005 Ivor Hewitt + Copyright (C) 2008 Maksim Orlovich + Copyright (C) 2008 Vyacheslav Tokarev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef WEBENGNINE_FILTER_P_H +#define WEBENGNINE_FILTER_P_H + +#include +#include +#include +#include + +class StringsMatcher; + +namespace KDEPrivate +{ +// This represents a set of filters that may match URLs. +// Currently it supports a subset of AddBlock Plus functionality. +class FilterSet { +public: + FilterSet(); + ~FilterSet(); + + // Parses and registers a filter. This will also strip @@ for exclusion rules, skip comments, etc. + // The user does have to split black and white lists into separate sets, however + void addFilter(const QString& filter); + + bool isUrlMatched(const QString& url); + QString urlMatchedBy(const QString& url); + + void clear(); + +private: + QVector reFilters; + StringsMatcher* stringFiltersMatcher; +}; + +} + +#endif // WEBKIT_FILTER_P_H + +// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; diff --git b/webkitpart/src/settings/webkitsettings.cpp b/webkitpart/src/settings/webkitsettings.cpp new file mode 100644 index 000000000..d20e320b5 --- /dev/null +++ b/webkitpart/src/settings/webkitsettings.cpp @@ -0,0 +1,1276 @@ +/* This file is part of the KDE project + Copyright (C) 1999 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "webkitsettings.h" + +#include "webkit_filter.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// browser window color defaults -- Bernd +#define HTML_DEFAULT_LNK_COLOR Qt::blue +#define HTML_DEFAULT_TXT_COLOR Qt::black +#define HTML_DEFAULT_VLNK_COLOR Qt::magenta +#define HTML_DEFAULT_BASE_COLOR Qt::white + +#define HTML_DEFAULT_VIEW_FONT "Sans Serif" +#define HTML_DEFAULT_VIEW_FIXED_FONT "Monospace" +#define HTML_DEFAULT_VIEW_SERIF_FONT "Serif" +#define HTML_DEFAULT_VIEW_SANSSERIF_FONT "Sans Serif" +#define HTML_DEFAULT_VIEW_CURSIVE_FONT "Sans Serif" +#define HTML_DEFAULT_VIEW_FANTASY_FONT "Sans Serif" +#define HTML_DEFAULT_MIN_FONT_SIZE 7 // everything smaller is usually unreadable. + +/** + * @internal + * Contains all settings which are both available globally and per-domain + */ +struct KPerDomainSettings { + bool m_bEnableJava : 1; + bool m_bEnableJavaScript : 1; + bool m_bEnablePlugins : 1; + // don't forget to maintain the bitfields as the enums grow + KParts::HtmlSettingsInterface::JSWindowOpenPolicy m_windowOpenPolicy : 2; + KParts::HtmlSettingsInterface::JSWindowStatusPolicy m_windowStatusPolicy : 1; + KParts::HtmlSettingsInterface::JSWindowFocusPolicy m_windowFocusPolicy : 1; + KParts::HtmlSettingsInterface::JSWindowMovePolicy m_windowMovePolicy : 1; + KParts::HtmlSettingsInterface::JSWindowResizePolicy m_windowResizePolicy : 1; + +#ifdef DEBUG_SETTINGS + void dump(const QString &infix = QString()) const { + kDebug() << "KPerDomainSettings " << infix << " @" << this << ":"; + kDebug() << " m_bEnableJava: " << m_bEnableJava; + kDebug() << " m_bEnableJavaScript: " << m_bEnableJavaScript; + kDebug() << " m_bEnablePlugins: " << m_bEnablePlugins; + kDebug() << " m_windowOpenPolicy: " << m_windowOpenPolicy; + kDebug() << " m_windowStatusPolicy: " << m_windowStatusPolicy; + kDebug() << " m_windowFocusPolicy: " << m_windowFocusPolicy; + kDebug() << " m_windowMovePolicy: " << m_windowMovePolicy; + kDebug() << " m_windowResizePolicy: " << m_windowResizePolicy; + } +#endif +}; + +typedef QMap PolicyMap; + +class WebSettingsData +{ +public: + bool m_bChangeCursor : 1; + bool m_bOpenMiddleClick : 1; + bool m_underlineLink : 1; + bool m_hoverLink : 1; + bool m_bEnableJavaScriptDebug : 1; + bool m_bEnableJavaScriptErrorReporting : 1; + bool enforceCharset : 1; + bool m_bAutoLoadImages : 1; + bool m_bUnfinishedImageFrame : 1; + bool m_formCompletionEnabled : 1; + bool m_autoDelayedActionsEnabled : 1; + bool m_jsErrorsEnabled : 1; + bool m_follow_system_colors : 1; + bool m_allowTabulation : 1; + bool m_autoSpellCheck : 1; + bool m_adFilterEnabled : 1; + bool m_hideAdsEnabled : 1; + bool m_jsPopupBlockerPassivePopup : 1; + bool m_accessKeysEnabled : 1; + bool m_zoomTextOnly : 1; + bool m_useCookieJar : 1; + bool m_bAutoRefreshPage: 1; + bool m_bEnableFavicon:1; + bool m_disableInternalPluginHandling:1; + bool m_offerToSaveWebSitePassword:1; + bool m_loadPluginsOnDemand:1; + bool m_enableLocalStorage:1; + bool m_enableOfflineStorageDb:1; + bool m_enableOfflineWebAppCache:1; + bool m_enableWebGL:1; + bool m_zoomToDPI:1; + bool m_allowActiveMixedContent:1; + bool m_allowMixedContentDisplay:1; + + // the virtual global "domain" + KPerDomainSettings global; + + int m_fontSize; + int m_minFontSize; + int m_maxFormCompletionItems; + WebSettings::KAnimationAdvice m_showAnimations; + WebSettings::KSmoothScrollingMode m_smoothScrolling; + + QString m_encoding; + QString m_userSheet; + + QColor m_textColor; + QColor m_baseColor; + QColor m_linkColor; + QColor m_vLinkColor; + + PolicyMap domainPolicy; + QStringList fonts; + QStringList defaultFonts; + + KDEPrivate::FilterSet adBlackList; + KDEPrivate::FilterSet adWhiteList; + QList< QPair< QString, QChar > > m_fallbackAccessKeysAssignments; + + KSharedConfig::Ptr nonPasswordStorableSites; +}; + +class WebSettingsPrivate : public QObject, public WebSettingsData +{ + Q_OBJECT +public: + void adblockFilterLoadList(const QString& filename) + { + /** load list file and process each line */ + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) { + QTextStream ts(&file); + QString line = ts.readLine(); + while (!line.isEmpty()) { + //kDebug() << "Adding filter:" << line; + /** white list lines start with "@@" */ + if (line.startsWith(QLatin1String("@@"))) + adWhiteList.addFilter(line); + else + adBlackList.addFilter(line); + line = ts.readLine(); + } + file.close(); + } + } + +public Q_SLOTS: + void adblockFilterResult(KJob *job) + { + KIO::StoredTransferJob *tJob = qobject_cast(job); + Q_ASSERT(tJob); + + if ( job->error() == KJob::NoError ) + { + const QByteArray byteArray = tJob->data(); + const QString localFileName = tJob->property( "websettings_adBlock_filename" ).toString(); + + QFile file(localFileName); + if ( file.open(QFile::WriteOnly) ) + { + const bool success = (file.write(byteArray) == byteArray.size()); + if ( success ) + adblockFilterLoadList(localFileName); + else + qWarning() << "Could not write" << byteArray.size() << "to file" << localFileName; + file.close(); + } + else + qDebug() << "Cannot open file" << localFileName << "for filter list"; + } + else + qDebug() << "Downloading" << tJob->url() << "failed with message:" << job->errorText(); + } +}; + + +/** Returns a writeable per-domains settings instance for the given domain + * or a deep copy of the global settings if not existent. + */ +static KPerDomainSettings &setup_per_domain_policy(WebSettingsPrivate* const d, const QString &domain) +{ + if (domain.isEmpty()) + qWarning() << "setup_per_domain_policy: domain is empty"; + + const QString ldomain = domain.toLower(); + PolicyMap::iterator it = d->domainPolicy.find(ldomain); + if (it == d->domainPolicy.end()) { + // simply copy global domain settings (they should have been initialized + // by this time) + it = d->domainPolicy.insert(ldomain,d->global); + } + return *it; +} + +template +static T readEntry(const KConfigGroup& config, const QString& key, int defaultValue) +{ + return static_cast(config.readEntry(key, defaultValue)); +} + +void WebSettings::readDomainSettings(const KConfigGroup &config, bool reset, + bool global, KPerDomainSettings &pd_settings) +{ + const QString javaPrefix ((global ? QString() : QStringLiteral("java."))); + const QString jsPrefix ((global ? QString() : QStringLiteral("javascript."))); + const QString pluginsPrefix (global ? QString() : QStringLiteral("plugins.")); + + // The setting for Java + QString key = javaPrefix + QLatin1String("EnableJava"); + if ( (global && reset) || config.hasKey( key ) ) + pd_settings.m_bEnableJava = config.readEntry( key, false ); + else if ( !global ) + pd_settings.m_bEnableJava = d->global.m_bEnableJava; + + // The setting for Plugins + key = pluginsPrefix + QLatin1String("EnablePlugins"); + if ( (global && reset) || config.hasKey( key ) ) + pd_settings.m_bEnablePlugins = config.readEntry( key, true ); + else if ( !global ) + pd_settings.m_bEnablePlugins = d->global.m_bEnablePlugins; + + // The setting for JavaScript + key = jsPrefix + QLatin1String("EnableJavaScript"); + if ( (global && reset) || config.hasKey( key ) ) + pd_settings.m_bEnableJavaScript = config.readEntry( key, true ); + else if ( !global ) + pd_settings.m_bEnableJavaScript = d->global.m_bEnableJavaScript; + + // window property policies + key = jsPrefix + QLatin1String("WindowOpenPolicy"); + if ( (global && reset) || config.hasKey( key ) ) + pd_settings.m_windowOpenPolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowOpenSmart); + else if ( !global ) + pd_settings.m_windowOpenPolicy = d->global.m_windowOpenPolicy; + + key = jsPrefix + QLatin1String("WindowMovePolicy"); + if ( (global && reset) || config.hasKey( key ) ) + pd_settings.m_windowMovePolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowMoveAllow); + else if ( !global ) + pd_settings.m_windowMovePolicy = d->global.m_windowMovePolicy; + + key = jsPrefix + QLatin1String("WindowResizePolicy"); + if ( (global && reset) || config.hasKey( key ) ) + pd_settings.m_windowResizePolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowResizeAllow); + else if ( !global ) + pd_settings.m_windowResizePolicy = d->global.m_windowResizePolicy; + + key = jsPrefix + QLatin1String("WindowStatusPolicy"); + if ( (global && reset) || config.hasKey( key ) ) + pd_settings.m_windowStatusPolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowStatusAllow); + else if ( !global ) + pd_settings.m_windowStatusPolicy = d->global.m_windowStatusPolicy; + + key = jsPrefix + QLatin1String("WindowFocusPolicy"); + if ( (global && reset) || config.hasKey( key ) ) + pd_settings.m_windowFocusPolicy = readEntry(config, key, KParts::HtmlSettingsInterface::JSWindowFocusAllow); + else if ( !global ) + pd_settings.m_windowFocusPolicy = d->global.m_windowFocusPolicy; +} + + +WebSettings::WebSettings() + :d (new WebSettingsPrivate) +{ + init(); +} + +WebSettings::~WebSettings() +{ + delete d; +} + +bool WebSettings::changeCursor() const +{ + return d->m_bChangeCursor; +} + +bool WebSettings::underlineLink() const +{ + return d->m_underlineLink; +} + +bool WebSettings::hoverLink() const +{ + return d->m_hoverLink; +} + +void WebSettings::init() +{ + initWebSettings(); + + KConfig global( QStringLiteral("khtmlrc"), KConfig::NoGlobals ); + init( &global, true ); + + KSharedConfig::Ptr local = KSharedConfig::openConfig(); + if ( local ) { + init( local.data(), false ); + } + + initNSPluginSettings(); + initCookieJarSettings(); +} + +void WebSettings::init( KConfig * config, bool reset ) +{ + KConfigGroup cg( config, "MainView Settings" ); + if (reset || cg.exists() ) + { + if ( reset || cg.hasKey( "OpenMiddleClick" ) ) + d->m_bOpenMiddleClick = cg.readEntry( "OpenMiddleClick", true ); + } + + KConfigGroup cgAccess(config,"Access Keys" ); + if (reset || cgAccess.exists() ) { + d->m_accessKeysEnabled = cgAccess.readEntry( "Enabled", true ); + } + + KConfigGroup cgFilter( config, "Filter Settings" ); + + if ((reset || cgFilter.exists()) && (d->m_adFilterEnabled = cgFilter.readEntry("Enabled", false))) + { + d->m_hideAdsEnabled = cgFilter.readEntry("Shrink", false); + + d->adBlackList.clear(); + d->adWhiteList.clear(); + + /** read maximum age for filter list files, minimum is one day */ + int htmlFilterListMaxAgeDays = cgFilter.readEntry(QStringLiteral("HTMLFilterListMaxAgeDays")).toInt(); + if (htmlFilterListMaxAgeDays < 1) + htmlFilterListMaxAgeDays = 1; + + QMapIterator it (cgFilter.entryMap()); + while (it.hasNext()) + { + it.next(); + int id = -1; + const QString name = it.key(); + const QString url = it.value(); + + if (name.startsWith(QLatin1String("Filter"))) + { + if (url.startsWith(QLatin1String("@@"))) + d->adWhiteList.addFilter(url); + else + d->adBlackList.addFilter(url); + } + else if (name.startsWith(QLatin1String("HTMLFilterListName-")) && (id = name.midRef(19).toInt()) > 0) + { + /** check if entry is enabled */ + bool filterEnabled = cgFilter.readEntry(QStringLiteral("HTMLFilterListEnabled-").append(QString::number(id))) != QLatin1String("false"); + + /** get url for HTMLFilterList */ + QUrl url(cgFilter.readEntry(QStringLiteral("HTMLFilterListURL-").append(QString::number(id)))); + + if (filterEnabled && url.isValid()) { + /** determine where to cache HTMLFilterList file */ + QString localFile = cgFilter.readEntry(QStringLiteral("HTMLFilterListLocalFilename-").append(QString::number(id))); + localFile = QStandardPaths::locate(QStandardPaths::ConfigLocation, "khtml/" + localFile); + + /** determine existence and age of cache file */ + QFileInfo fileInfo(localFile); + + /** load cached file if it exists, irrespective of age */ + if (fileInfo.exists()) + d->adblockFilterLoadList( localFile ); + + /** if no cache list file exists or if it is too old ... */ + if (!fileInfo.exists() || fileInfo.lastModified().daysTo(QDateTime::currentDateTime()) > htmlFilterListMaxAgeDays) + { + /** ... in this case, refetch list asynchronously */ + // kDebug() << "Fetching filter list from" << url << "to" << localFile; + KIO::StoredTransferJob *job = KIO::storedGet( url, KIO::Reload, KIO::HideProgressInfo ); + QObject::connect( job, SIGNAL(result(KJob*)), d, SLOT(adblockFilterResult(KJob*)) ); + /** for later reference, store name of cache file */ + job->setProperty("websettings_adBlock_filename", localFile); + } + } + } + } + } + + KConfigGroup cgHtml( config, "HTML Settings" ); + if (reset || cgHtml.exists() ) + { + // Fonts and colors + if( reset ) { + d->defaultFonts = QStringList(); + d->defaultFonts.append( cgHtml.readEntry( "StandardFont", QFontDatabase::systemFont(QFontDatabase::GeneralFont).family() ) ); + d->defaultFonts.append( cgHtml.readEntry( "FixedFont", QFontDatabase::systemFont(QFontDatabase::FixedFont).family() )); + d->defaultFonts.append( cgHtml.readEntry( "SerifFont", HTML_DEFAULT_VIEW_SERIF_FONT ) ); + d->defaultFonts.append( cgHtml.readEntry( "SansSerifFont", HTML_DEFAULT_VIEW_SANSSERIF_FONT ) ); + d->defaultFonts.append( cgHtml.readEntry( "CursiveFont", HTML_DEFAULT_VIEW_CURSIVE_FONT ) ); + d->defaultFonts.append( cgHtml.readEntry( "FantasyFont", HTML_DEFAULT_VIEW_FANTASY_FONT ) ); + d->defaultFonts.append( QStringLiteral( "0" ) ); // font size adjustment + } + + if ( reset || cgHtml.hasKey( "MinimumFontSize" ) ) + d->m_minFontSize = cgHtml.readEntry( "MinimumFontSize", HTML_DEFAULT_MIN_FONT_SIZE ); + + if ( reset || cgHtml.hasKey( "MediumFontSize" ) ) + d->m_fontSize = cgHtml.readEntry( "MediumFontSize", 12 ); + + d->fonts = cgHtml.readEntry( "Fonts", QStringList() ); + + if ( reset || cgHtml.hasKey( "DefaultEncoding" ) ) + d->m_encoding = cgHtml.readEntry( "DefaultEncoding", "" ); + + if ( reset || cgHtml.hasKey( "EnforceDefaultCharset" ) ) + d->enforceCharset = cgHtml.readEntry( "EnforceDefaultCharset", false ); + + // Behavior + + if ( reset || cgHtml.hasKey("UnderlineLinks") ) + d->m_underlineLink = cgHtml.readEntry( "UnderlineLinks", true ); + + if ( reset || cgHtml.hasKey( "HoverLinks" ) ) + { + if ( (d->m_hoverLink = cgHtml.readEntry( "HoverLinks", false ))) + d->m_underlineLink = false; + } + + if ( reset || cgHtml.hasKey( "AllowTabulation" ) ) + d->m_allowTabulation = cgHtml.readEntry( "AllowTabulation", false ); + + if ( reset || cgHtml.hasKey( "AutoSpellCheck" ) ) + d->m_autoSpellCheck = cgHtml.readEntry( "AutoSpellCheck", true ); + + // Other + if ( reset || cgHtml.hasKey( "AutoLoadImages" ) ) + d->m_bAutoLoadImages = cgHtml.readEntry( "AutoLoadImages", true ); + + if ( reset || cgHtml.hasKey( "AutoDelayedActions" ) ) + d->m_bAutoRefreshPage = cgHtml.readEntry( "AutoDelayedActions", true ); + + if ( reset || cgHtml.hasKey( "UnfinishedImageFrame" ) ) + d->m_bUnfinishedImageFrame = cgHtml.readEntry( "UnfinishedImageFrame", true ); + + if ( reset || cgHtml.hasKey( "ShowAnimations" ) ) + { + QString value = cgHtml.readEntry( "ShowAnimations").toLower(); + if (value == QLatin1String("disabled")) + d->m_showAnimations = KAnimationDisabled; + else if (value == QLatin1String("looponce")) + d->m_showAnimations = KAnimationLoopOnce; + else + d->m_showAnimations = KAnimationEnabled; + } + + if ( reset || cgHtml.hasKey( "SmoothScrolling" ) ) + { + QString value = cgHtml.readEntry( "SmoothScrolling", "whenefficient" ).toLower(); + if (value == QLatin1String("disabled")) + d->m_smoothScrolling = KSmoothScrollingDisabled; + else if (value == QLatin1String("whenefficient")) + d->m_smoothScrolling = KSmoothScrollingWhenEfficient; + else + d->m_smoothScrolling = KSmoothScrollingEnabled; + } + + if ( reset || cgHtml.hasKey( "ZoomTextOnly" ) ) { + d->m_zoomTextOnly = cgHtml.readEntry( "ZoomTextOnly", false ); + } + + if ( reset || cgHtml.hasKey( "ZoomToDPI" ) ) { + d->m_zoomToDPI = cgHtml.readEntry( "ZoomToDPI", false ); + } + + if (cgHtml.readEntry("UserStyleSheetEnabled", false)) { + if (reset || cgHtml.hasKey("UserStyleSheet")) + d->m_userSheet = cgHtml.readEntry("UserStyleSheet", QString()); + } else { + d->m_userSheet.clear(); + } + + d->m_formCompletionEnabled = cgHtml.readEntry("FormCompletion", true); + d->m_maxFormCompletionItems = cgHtml.readEntry("MaxFormCompletionItems", 10); + d->m_autoDelayedActionsEnabled = cgHtml.readEntry ("AutoDelayedActions", true); + d->m_jsErrorsEnabled = cgHtml.readEntry("ReportJSErrors", true); + const QStringList accesskeys = cgHtml.readEntry("FallbackAccessKeysAssignments", QStringList()); + d->m_fallbackAccessKeysAssignments.clear(); + for( QStringList::ConstIterator it = accesskeys.begin(); it != accesskeys.end(); ++it ) + if( (*it).length() > 2 && (*it)[ 1 ] == ':' ) + d->m_fallbackAccessKeysAssignments.append( qMakePair( (*it).mid( 2 ), (*it)[ 0 ] )); + + d->m_bEnableFavicon = cgHtml.readEntry("EnableFavicon", true); + d->m_offerToSaveWebSitePassword = cgHtml.readEntry("OfferToSaveWebsitePassword", true); + } + + // Colors + //In which group ????? + if ( reset || cg.hasKey( "FollowSystemColors" ) ) + d->m_follow_system_colors = cg.readEntry( "FollowSystemColors", false ); + + KConfigGroup cgGeneral( config, "General" ); + if ( reset || cgGeneral.exists( ) ) + { + if ( reset || cgGeneral.hasKey( "foreground" ) ) { + QColor def(HTML_DEFAULT_TXT_COLOR); + d->m_textColor = cgGeneral.readEntry( "foreground", def ); + } + + if ( reset || cgGeneral.hasKey( "linkColor" ) ) { + QColor def(HTML_DEFAULT_LNK_COLOR); + d->m_linkColor = cgGeneral.readEntry( "linkColor", def ); + } + + if ( reset || cgGeneral.hasKey( "visitedLinkColor" ) ) { + QColor def(HTML_DEFAULT_VLNK_COLOR); + d->m_vLinkColor = cgGeneral.readEntry( "visitedLinkColor", def); + } + + if ( reset || cgGeneral.hasKey( "background" ) ) { + QColor def(HTML_DEFAULT_BASE_COLOR); + d->m_baseColor = cgGeneral.readEntry( "background", def); + } + } + + KConfigGroup cgJava( config, "Java/JavaScript Settings" ); + if( reset || cgJava.exists() ) + { + // The global setting for JavaScript debugging + // This is currently always enabled by default + if ( reset || cgJava.hasKey( "EnableJavaScriptDebug" ) ) + d->m_bEnableJavaScriptDebug = cgJava.readEntry( "EnableJavaScriptDebug", false ); + + // The global setting for JavaScript error reporting + if ( reset || cgJava.hasKey( "ReportJavaScriptErrors" ) ) + d->m_bEnableJavaScriptErrorReporting = cgJava.readEntry( "ReportJavaScriptErrors", false ); + + // The global setting for popup block passive popup + if ( reset || cgJava.hasKey( "PopupBlockerPassivePopup" ) ) + d->m_jsPopupBlockerPassivePopup = cgJava.readEntry("PopupBlockerPassivePopup", true ); + + // Read options from the global "domain" + readDomainSettings(cgJava,reset,true,d->global); +#ifdef DEBUG_SETTINGS + d->global.dump("init global"); +#endif + + // The domain-specific settings. + + static const char *const domain_keys[] = { // always keep order of keys + "ECMADomains", "JavaDomains", "PluginDomains" + }; + bool check_old_ecma_settings = true; + bool check_old_java_settings = true; + // merge all domains into one list + QSet domainList; + for (unsigned i = 0; i < sizeof domain_keys/sizeof domain_keys[0]; ++i) { + if (reset || cgJava.hasKey(domain_keys[i])) { + if (i == 0) check_old_ecma_settings = false; + else if (i == 1) check_old_java_settings = false; + const QStringList dl = cgJava.readEntry( domain_keys[i], QStringList() ); + const QSet::Iterator notfound = domainList.end(); + QStringList::ConstIterator it = dl.begin(); + const QStringList::ConstIterator itEnd = dl.end(); + for (; it != itEnd; ++it) { + const QString domain = (*it).toLower(); + QSet::Iterator pos = domainList.find(domain); + if (pos == notfound) domainList.insert(domain); + }/*next it*/ + } + }/*next i*/ + + if (reset) + d->domainPolicy.clear(); + + { + QSet::ConstIterator it = domainList.constBegin(); + const QSet::ConstIterator itEnd = domainList.constEnd(); + for ( ; it != itEnd; ++it) + { + const QString domain = *it; + KConfigGroup cg( config, domain ); + readDomainSettings(cg,reset,false,d->domainPolicy[domain]); +#ifdef DEBUG_SETTINGS + d->domainPolicy[domain].dump("init "+domain); +#endif + } + } + + bool check_old_java = true; + if( (reset || cgJava.hasKey("JavaDomainSettings")) && check_old_java_settings) + { + check_old_java = false; + const QStringList domainList = cgJava.readEntry( "JavaDomainSettings", QStringList() ); + QStringList::ConstIterator it = domainList.constBegin(); + const QStringList::ConstIterator itEnd = domainList.constEnd(); + for ( ; it != itEnd; ++it) + { + QString domain; + KParts::HtmlSettingsInterface::JavaScriptAdvice javaAdvice; + KParts::HtmlSettingsInterface::JavaScriptAdvice javaScriptAdvice; + KParts::HtmlSettingsInterface::splitDomainAdvice(*it, domain, javaAdvice, javaScriptAdvice); + setup_per_domain_policy(d,domain).m_bEnableJava = javaAdvice == KParts::HtmlSettingsInterface::JavaScriptAccept; +#ifdef DEBUG_SETTINGS + setup_per_domain_policy(d,domain).dump("JavaDomainSettings 4 "+domain); +#endif + } + } + + bool check_old_ecma = true; + if( ( reset || cgJava.hasKey( "ECMADomainSettings" ) ) && check_old_ecma_settings ) + { + check_old_ecma = false; + const QStringList domainList = cgJava.readEntry( "ECMADomainSettings", QStringList() ); + QStringList::ConstIterator it = domainList.constBegin(); + const QStringList::ConstIterator itEnd = domainList.constEnd(); + for ( ; it != itEnd; ++it) + { + QString domain; + KParts::HtmlSettingsInterface::JavaScriptAdvice javaAdvice; + KParts::HtmlSettingsInterface::JavaScriptAdvice javaScriptAdvice; + KParts::HtmlSettingsInterface::splitDomainAdvice(*it, domain, javaAdvice, javaScriptAdvice); + setup_per_domain_policy(d,domain).m_bEnableJavaScript = javaScriptAdvice == KParts::HtmlSettingsInterface::JavaScriptAccept; +#ifdef DEBUG_SETTINGS + setup_per_domain_policy(d,domain).dump("ECMADomainSettings 4 "+domain); +#endif + } + } + + if( ( reset || cgJava.hasKey( "JavaScriptDomainAdvice" ) ) + && ( check_old_java || check_old_ecma ) + && ( check_old_ecma_settings || check_old_java_settings ) ) + { + const QStringList domainList = cgJava.readEntry( "JavaScriptDomainAdvice", QStringList() ); + QStringList::ConstIterator it = domainList.constBegin(); + const QStringList::ConstIterator itEnd = domainList.constEnd(); + for ( ; it != itEnd; ++it) + { + QString domain; + KParts::HtmlSettingsInterface::JavaScriptAdvice javaAdvice; + KParts::HtmlSettingsInterface::JavaScriptAdvice javaScriptAdvice; + KParts::HtmlSettingsInterface::splitDomainAdvice(*it, domain, javaAdvice, javaScriptAdvice); + if( check_old_java ) + setup_per_domain_policy(d,domain).m_bEnableJava = javaAdvice == KParts::HtmlSettingsInterface::JavaScriptAccept; + if( check_old_ecma ) + setup_per_domain_policy(d,domain).m_bEnableJavaScript = javaScriptAdvice == KParts::HtmlSettingsInterface::JavaScriptAccept; +#ifdef DEBUG_SETTINGS + setup_per_domain_policy(d,domain).dump("JavaScriptDomainAdvice 4 "+domain); +#endif + } + } + } + +#if 0 + // DNS Prefect support... + if ( reset || cgHtml.hasKey( "DNSPrefetch" ) ) + { + // Enabled, Disabled, OnlyWWWAndSLD + QString value = cgHtml.readEntry( "DNSPrefetch", "Enabled" ).toLower(); + + if (value == "enabled") + QWebSettings::globalSettings()->setAttribute(QWebSettings::DnsPrefetchEnabled, true); + else + QWebSettings::globalSettings()->setAttribute(QWebSettings::DnsPrefetchEnabled, false); + } + + // Sync with QWebSettings. + if (!d->m_encoding.isEmpty()) + QWebSettings::globalSettings()->setDefaultTextEncoding(d->m_encoding); + QWebSettings::globalSettings()->setUserStyleSheetUrl(QUrl::fromUserInput(userStyleSheet())); +#endif + + QWebSettings::globalSettings()->setAttribute(QWebSettings::AutoLoadImages, autoLoadImages()); + QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptEnabled, isJavaScriptEnabled()); +// QWebSettings::globalSettings()->setAttribute(QWebSettings::JavaEnabled, isJavaEnabled()); + QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, isPluginsEnabled()); + + // By default disable JS window.open when policy is deny or smart. + const KParts::HtmlSettingsInterface::JSWindowOpenPolicy policy = windowOpenPolicy(); + if (policy == KParts::HtmlSettingsInterface::JSWindowOpenDeny || policy == KParts::HtmlSettingsInterface::JSWindowOpenSmart) + QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, false); + else + QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, true); + +// QWebSettings::globalSettings()->setAttribute(QWebSettings::ZoomTextOnly, zoomTextOnly()); +// QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, isJavaScriptDebugEnabled()); + QWebSettings::globalSettings()->setFontFamily(QWebSettings::StandardFont, stdFontName()); + QWebSettings::globalSettings()->setFontFamily(QWebSettings::FixedFont, fixedFontName()); + QWebSettings::globalSettings()->setFontFamily(QWebSettings::SerifFont, serifFontName()); + QWebSettings::globalSettings()->setFontFamily(QWebSettings::SansSerifFont, sansSerifFontName()); + QWebSettings::globalSettings()->setFontFamily(QWebSettings::CursiveFont, cursiveFontName()); + QWebSettings::globalSettings()->setFontFamily(QWebSettings::FantasyFont, fantasyFontName()); + + // TODO: Create a webkit config module that gets embeded into Konqueror's kcm. + // Turn on WebGL support +// QWebSettings::globalSettings()->setAttribute(QWebSettings::WebGLEnabled, d->m_enableWebGL); + // Turn on HTML 5 local and offline storage capabilities... +// QWebSettings::globalSettings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, d->m_enableOfflineStorageDb); +// QWebSettings::globalSettings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, d->m_enableOfflineWebAppCache); + QWebSettings::globalSettings()->setAttribute(QWebSettings::LocalStorageEnabled, d->m_enableLocalStorage); + + QWebSettings::globalSettings()->setAttribute(QWebSettings::ScrollAnimatorEnabled, smoothScrolling() != KSmoothScrollingDisabled); + + // These numbers should be calculated from real "logical" DPI/72, using a default dpi of 96 for now + computeFontSizes(96); +} + + +void WebSettings::computeFontSizes( int logicalDpi ) +{ + if (zoomToDPI()) + logicalDpi = 96; + + float toPix = logicalDpi/72.0; + + if (toPix < 96.0/72.0) + toPix = 96.0/72.0; + + QWebSettings::globalSettings()->setFontSize(QWebSettings::MinimumFontSize, qRound(minFontSize() * toPix)); + QWebSettings::globalSettings()->setFontSize(QWebSettings::DefaultFontSize, qRound(mediumFontSize() * toPix)); +} + +bool WebSettings::zoomToDPI() const +{ + return d->m_zoomToDPI; +} + +void WebSettings::setZoomToDPI(bool enabled) +{ + d->m_zoomToDPI = enabled; + // save it + KConfigGroup cg( KSharedConfig::openConfig(), "HTML Settings"); + cg.writeEntry("ZoomToDPI", enabled); + cg.sync(); +} + +/** Local helper for retrieving per-domain settings. + * + * In case of doubt, the global domain is returned. + */ +static const KPerDomainSettings& lookup_hostname_policy(const WebSettingsPrivate* const d, + const QString& hostname) +{ +#ifdef DEBUG_SETTINGS + kDebug() << "lookup_hostname_policy(" << hostname << ")"; +#endif + if (hostname.isEmpty()) { +#ifdef DEBUG_SETTINGS + d->global.dump("global"); +#endif + return d->global; + } + + const PolicyMap::const_iterator notfound = d->domainPolicy.constEnd(); + + // First check whether there is a perfect match. + PolicyMap::const_iterator it = d->domainPolicy.find(hostname); + if( it != notfound ) { +#ifdef DEBUG_SETTINGS + kDebug() << "perfect match"; + (*it).dump(hostname); +#endif + // yes, use it (unless dunno) + return *it; + } + + // Now, check for partial match. Chop host from the left until + // there's no dots left. + QString host_part = hostname; + int dot_idx = -1; + while( (dot_idx = host_part.indexOf(QChar('.'))) >= 0 ) { + host_part.remove(0,dot_idx); + it = d->domainPolicy.find(host_part); + Q_ASSERT(notfound == d->domainPolicy.end()); + if( it != notfound ) { +#ifdef DEBUG_SETTINGS + kDebug() << "partial match"; + (*it).dump(host_part); +#endif + return *it; + } + // assert(host_part[0] == QChar('.')); + host_part.remove(0,1); // Chop off the dot. + } + + // No domain-specific entry: use global domain +#ifdef DEBUG_SETTINGS + kDebug() << "no match"; + d->global.dump("global"); +#endif + return d->global; +} + +bool WebSettings::isOpenMiddleClickEnabled() +{ + return d->m_bOpenMiddleClick; +} + +bool WebSettings::accessKeysEnabled() const +{ + return d->m_accessKeysEnabled; +} + +bool WebSettings::favIconsEnabled() const +{ + return d->m_bEnableFavicon; +} + +bool WebSettings::isAdFilterEnabled() const +{ + return d->m_adFilterEnabled; +} + +bool WebSettings::isHideAdsEnabled() const +{ + return d->m_hideAdsEnabled; +} + +bool WebSettings::isAdFiltered( const QString &url ) const +{ + if (!d->m_adFilterEnabled) + return false; + + if (url.startsWith(QLatin1String("data:"))) + return false; + + return d->adBlackList.isUrlMatched(url) && !d->adWhiteList.isUrlMatched(url); +} + +QString WebSettings::adFilteredBy( const QString &url, bool *isWhiteListed ) const +{ + QString m = d->adWhiteList.urlMatchedBy(url); + + if (!m.isEmpty()) { + if (isWhiteListed != 0) + *isWhiteListed = true; + return m; + } + + m = d->adBlackList.urlMatchedBy(url); + if (m.isEmpty()) + return QString(); + + if (isWhiteListed != 0) + *isWhiteListed = false; + return m; +} + +void WebSettings::addAdFilter( const QString &url ) +{ + KConfigGroup config = KSharedConfig::openConfig( QStringLiteral("khtmlrc"), KConfig::NoGlobals )->group( "Filter Settings" ); + + QRegExp rx; + + // Try compiling to avoid invalid stuff. Only support the basic syntax here... + // ### refactor somewhat + if (url.length()>2 && url[0]=='/' && url[url.length()-1] == '/') + { + const QString inside = url.mid(1, url.length()-2); + rx.setPattern(inside); + } + else + { + rx.setPatternSyntax(QRegExp::Wildcard); + rx.setPattern(url); + } + + if (rx.isValid()) + { + int last=config.readEntry("Count", 0); + const QString key = "Filter-" + QString::number(last); + config.writeEntry(key, url); + config.writeEntry("Count",last+1); + config.sync(); + + if (url.startsWith(QLatin1String("@@"))) + d->adWhiteList.addFilter(url); + else + d->adBlackList.addFilter(url); + } + else + { + KMessageBox::error(0, + rx.errorString(), + i18n("Filter error")); + } +} + +bool WebSettings::isJavaEnabled( const QString& hostname ) const +{ + return lookup_hostname_policy(d,hostname.toLower()).m_bEnableJava; +} + +bool WebSettings::isJavaScriptEnabled( const QString& hostname ) const +{ + return lookup_hostname_policy(d,hostname.toLower()).m_bEnableJavaScript; +} + +bool WebSettings::isJavaScriptDebugEnabled( const QString& /*hostname*/ ) const +{ + // debug setting is global for now, but could change in the future + return d->m_bEnableJavaScriptDebug; +} + +bool WebSettings::isJavaScriptErrorReportingEnabled( const QString& /*hostname*/ ) const +{ + // error reporting setting is global for now, but could change in the future + return d->m_bEnableJavaScriptErrorReporting; +} + +bool WebSettings::isPluginsEnabled( const QString& hostname ) const +{ + return lookup_hostname_policy(d,hostname.toLower()).m_bEnablePlugins; +} + +KParts::HtmlSettingsInterface::JSWindowOpenPolicy WebSettings::windowOpenPolicy(const QString& hostname) const { + return lookup_hostname_policy(d,hostname.toLower()).m_windowOpenPolicy; +} + +KParts::HtmlSettingsInterface::JSWindowMovePolicy WebSettings::windowMovePolicy(const QString& hostname) const { + return lookup_hostname_policy(d,hostname.toLower()).m_windowMovePolicy; +} + +KParts::HtmlSettingsInterface::JSWindowResizePolicy WebSettings::windowResizePolicy(const QString& hostname) const { + return lookup_hostname_policy(d,hostname.toLower()).m_windowResizePolicy; +} + +KParts::HtmlSettingsInterface::JSWindowStatusPolicy WebSettings::windowStatusPolicy(const QString& hostname) const { + return lookup_hostname_policy(d,hostname.toLower()).m_windowStatusPolicy; +} + +KParts::HtmlSettingsInterface::JSWindowFocusPolicy WebSettings::windowFocusPolicy(const QString& hostname) const { + return lookup_hostname_policy(d,hostname.toLower()).m_windowFocusPolicy; +} + +int WebSettings::mediumFontSize() const +{ + return d->m_fontSize; +} + +int WebSettings::minFontSize() const +{ + return d->m_minFontSize; +} + +QString WebSettings::settingsToCSS() const +{ + // lets start with the link properties + QString str = QStringLiteral("a:link {\ncolor: "); + str += d->m_linkColor.name(); + str += ';'; + if(d->m_underlineLink) + str += QLatin1String("\ntext-decoration: underline;"); + + if( d->m_bChangeCursor ) + { + str += QLatin1String("\ncursor: pointer;"); + str += QLatin1String("\n}\ninput[type=image] { cursor: pointer;"); + } + str += QLatin1String("\n}\n"); + str += QLatin1String("a:visited {\ncolor: "); + str += d->m_vLinkColor.name(); + str += ';'; + if(d->m_underlineLink) + str += QLatin1String("\ntext-decoration: underline;"); + + if( d->m_bChangeCursor ) + str += QLatin1String("\ncursor: pointer;"); + str += QLatin1String("\n}\n"); + + if(d->m_hoverLink) + str += QLatin1String("a:link:hover, a:visited:hover { text-decoration: underline; }\n"); + + return str; +} + +QString WebSettings::lookupFont(int i) const +{ + if (d->fonts.count() > i) { + return d->fonts.at(i); + } + + if (d->defaultFonts.count() > i) { + return d->defaultFonts.at(i); + } + + return QString(); +} + +QString WebSettings::stdFontName() const +{ + return lookupFont(0); +} + +QString WebSettings::fixedFontName() const +{ + return lookupFont(1); +} + +QString WebSettings::serifFontName() const +{ + return lookupFont(2); +} + +QString WebSettings::sansSerifFontName() const +{ + return lookupFont(3); +} + +QString WebSettings::cursiveFontName() const +{ + return lookupFont(4); +} + +QString WebSettings::fantasyFontName() const +{ + return lookupFont(5); +} + +void WebSettings::setStdFontName(const QString &n) +{ + while(d->fonts.count() <= 0) + d->fonts.append(QString()); + d->fonts[0] = n; +} + +void WebSettings::setFixedFontName(const QString &n) +{ + while(d->fonts.count() <= 1) + d->fonts.append(QString()); + d->fonts[1] = n; +} + +QString WebSettings::userStyleSheet() const +{ + return d->m_userSheet; +} + +bool WebSettings::isFormCompletionEnabled() const +{ + return d->m_formCompletionEnabled; +} + +int WebSettings::maxFormCompletionItems() const +{ + return d->m_maxFormCompletionItems; +} + +const QString &WebSettings::encoding() const +{ + return d->m_encoding; +} + +bool WebSettings::followSystemColors() const +{ + return d->m_follow_system_colors; +} + +const QColor& WebSettings::textColor() const +{ + return d->m_textColor; +} + +const QColor& WebSettings::baseColor() const +{ + return d->m_baseColor; +} + +const QColor& WebSettings::linkColor() const +{ + return d->m_linkColor; +} + +const QColor& WebSettings::vLinkColor() const +{ + return d->m_vLinkColor; +} + +bool WebSettings::autoPageRefresh() const +{ + return d->m_bAutoRefreshPage; +} + +bool WebSettings::autoLoadImages() const +{ + return d->m_bAutoLoadImages; +} + +bool WebSettings::unfinishedImageFrame() const +{ + return d->m_bUnfinishedImageFrame; +} + +WebSettings::KAnimationAdvice WebSettings::showAnimations() const +{ + return d->m_showAnimations; +} + +WebSettings::KSmoothScrollingMode WebSettings::smoothScrolling() const +{ + return d->m_smoothScrolling; +} + +bool WebSettings::zoomTextOnly() const +{ + return d->m_zoomTextOnly; +} + +bool WebSettings::isAutoDelayedActionsEnabled() const +{ + return d->m_autoDelayedActionsEnabled; +} + +bool WebSettings::jsErrorsEnabled() const +{ + return d->m_jsErrorsEnabled; +} + +void WebSettings::setJSErrorsEnabled(bool enabled) +{ + d->m_jsErrorsEnabled = enabled; + // save it + KConfigGroup cg( KSharedConfig::openConfig(), "HTML Settings"); + cg.writeEntry("ReportJSErrors", enabled); + cg.sync(); +} + +bool WebSettings::allowTabulation() const +{ + return d->m_allowTabulation; +} + +bool WebSettings::autoSpellCheck() const +{ + return d->m_autoSpellCheck; +} + +QList< QPair< QString, QChar > > WebSettings::fallbackAccessKeysAssignments() const +{ + return d->m_fallbackAccessKeysAssignments; +} + +void WebSettings::setJSPopupBlockerPassivePopup(bool enabled) +{ + d->m_jsPopupBlockerPassivePopup = enabled; + // save it + KConfigGroup cg( KSharedConfig::openConfig(), "Java/JavaScript Settings"); + cg.writeEntry("PopupBlockerPassivePopup", enabled); + cg.sync(); +} + +bool WebSettings::jsPopupBlockerPassivePopup() const +{ + return d->m_jsPopupBlockerPassivePopup; +} + +bool WebSettings::isCookieJarEnabled() const +{ + return d->m_useCookieJar; +} + +// Password storage... +static KConfigGroup nonPasswordStorableSitesCg(KSharedConfig::Ptr& configPtr) +{ + if (!configPtr) { + configPtr = KSharedConfig::openConfig(QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("khtml/formcompletions")), KConfig::NoGlobals); + } + + return KConfigGroup(configPtr, "NonPasswordStorableSites"); +} + +bool WebSettings::isNonPasswordStorableSite(const QString &host) const +{ + KConfigGroup cg = nonPasswordStorableSitesCg(d->nonPasswordStorableSites); + const QStringList sites = cg.readEntry("Sites", QStringList()); + return sites.contains(host); +} + +void WebSettings::addNonPasswordStorableSite(const QString &host) +{ + KConfigGroup cg = nonPasswordStorableSitesCg(d->nonPasswordStorableSites); + QStringList sites = cg.readEntry("Sites", QStringList()); + sites.append(host); + cg.writeEntry("Sites", sites); + cg.sync(); +} + +void WebSettings::removeNonPasswordStorableSite(const QString &host) +{ + KConfigGroup cg = nonPasswordStorableSitesCg(d->nonPasswordStorableSites); + QStringList sites = cg.readEntry("Sites", QStringList()); + sites.removeOne(host); + cg.writeEntry("Sites", sites); + cg.sync(); +} + +bool WebSettings::askToSaveSitePassword() const +{ + return d->m_offerToSaveWebSitePassword; +} + +bool WebSettings::isInternalPluginHandlingDisabled() const +{ + return d->m_disableInternalPluginHandling; +} + +bool WebSettings::isLoadPluginsOnDemandEnabled() const +{ + return d->m_loadPluginsOnDemand; +} + +bool WebSettings::allowMixedContentDisplay() const +{ + return d->m_allowMixedContentDisplay; +} + +bool WebSettings::alowActiveMixedContent() const +{ + return d->m_allowActiveMixedContent; +} + + +void WebSettings::initWebSettings() +{ + KConfig cfg (QStringLiteral("webkitpartrc"), KConfig::NoGlobals); + KConfigGroup generalCfg (&cfg, "General"); + d->m_disableInternalPluginHandling = generalCfg.readEntry("DisableInternalPluginHandling", false); + d->m_enableLocalStorage = generalCfg.readEntry("EnableLocalStorage", true); + d->m_enableOfflineStorageDb = generalCfg.readEntry("EnableOfflineStorageDatabase", true); + d->m_enableOfflineWebAppCache = generalCfg.readEntry("EnableOfflineWebApplicationCache", true); + d->m_enableWebGL = generalCfg.readEntry("EnableWebGL", true); + d->m_allowActiveMixedContent = generalCfg.readEntry("AllowActiveMixedContent", false); + d->m_allowMixedContentDisplay = generalCfg.readEntry("AllowMixedContentDisplay", true); + + // Force the reloading of the non password storable sites settings. + d->nonPasswordStorableSites.reset(); +} + +void WebSettings::initCookieJarSettings() +{ + KSharedConfig::Ptr cookieCfgPtr = KSharedConfig::openConfig(QStringLiteral("kcookiejarrc"), KConfig::NoGlobals); + KConfigGroup cookieCfg ( cookieCfgPtr, "Cookie Policy"); + d->m_useCookieJar = cookieCfg.readEntry("Cookies", false); +} + +void WebSettings::initNSPluginSettings() +{ + KSharedConfig::Ptr cookieCfgPtr = KSharedConfig::openConfig(QStringLiteral("kcmnspluginrc"), KConfig::NoGlobals); + KConfigGroup cookieCfg ( cookieCfgPtr, "Misc"); + d->m_loadPluginsOnDemand = cookieCfg.readEntry("demandLoad", false); +} + + +WebSettings* WebSettings::self() +{ + static WebSettings s_WebSettings; + return &s_WebSettings; +} + +#include "webkitsettings.moc" diff --git b/webkitpart/src/settings/webkitsettings.h b/webkitpart/src/settings/webkitsettings.h new file mode 100644 index 000000000..bf850c980 --- /dev/null +++ b/webkitpart/src/settings/webkitsettings.h @@ -0,0 +1,213 @@ +/* This file is part of the KDE project + Copyright (C) 1999 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef WEBSETTINGS_H +#define WEBSETTINGS_H + +class KConfig; +class KConfigGroup; + +#include +#include +#include + +#include +#include + +struct KPerDomainSettings; +class WebSettingsPrivate; + +/** + * Settings for the HTML view. + */ +class WebSettings +{ +public: + + enum KAnimationAdvice { + KAnimationDisabled=0, + KAnimationLoopOnce, + KAnimationEnabled + }; + + enum KSmoothScrollingMode { + KSmoothScrollingDisabled=0, + KSmoothScrollingWhenEfficient, + KSmoothScrollingEnabled + }; + + /** + * Called by constructor and reparseConfiguration + */ + void init(); + + /** + * Destructor. Don't delete any instance by yourself. + */ + virtual ~WebSettings(); + + void computeFontSizes(int logicalDpi); + bool zoomToDPI() const; + void setZoomToDPI(bool b); + + // Automatic page reload/refresh... + bool autoPageRefresh() const; + + bool isOpenMiddleClickEnabled(); + + // Java and JavaScript + bool isJavaEnabled( const QString& hostname = QString() ) const; + bool isJavaScriptEnabled( const QString& hostname = QString() ) const; + bool isJavaScriptDebugEnabled( const QString& hostname = QString() ) const; + bool isJavaScriptErrorReportingEnabled( const QString& hostname = QString() ) const; + bool isPluginsEnabled( const QString& hostname = QString() ) const; + bool isLoadPluginsOnDemandEnabled() const; + bool isInternalPluginHandlingDisabled() const; + + // AdBlocK Filtering + bool isAdFiltered( const QString &url ) const; + bool isAdFilterEnabled() const; + bool isHideAdsEnabled() const; + void addAdFilter( const QString &url ); + QString adFilteredBy( const QString &url, bool *isWhiteListed = 0 ) const; + + // Access Keys + bool accessKeysEnabled() const; + + // Favicons + bool favIconsEnabled() const; + + KParts::HtmlSettingsInterface::JSWindowOpenPolicy windowOpenPolicy( const QString& hostname = QString() ) const; + KParts::HtmlSettingsInterface::JSWindowMovePolicy windowMovePolicy( const QString& hostname = QString() ) const; + KParts::HtmlSettingsInterface::JSWindowResizePolicy windowResizePolicy( const QString& hostname = QString() ) const; + KParts::HtmlSettingsInterface::JSWindowStatusPolicy windowStatusPolicy( const QString& hostname = QString() ) const; + KParts::HtmlSettingsInterface::JSWindowFocusPolicy windowFocusPolicy( const QString& hostname = QString() ) const; + + QString settingsToCSS() const; + QString userStyleSheet() const; + + // Form completion + bool isFormCompletionEnabled() const; + int maxFormCompletionItems() const; + + // Meta refresh/redirect (http-equiv) + bool isAutoDelayedActionsEnabled () const; + + // CookieJar... + bool isCookieJarEnabled() const; + + // Password storage... + bool isNonPasswordStorableSite(const QString &host) const; + void addNonPasswordStorableSite(const QString &host); + void removeNonPasswordStorableSite(const QString &host); + bool askToSaveSitePassword() const; + + // Mixed content + bool alowActiveMixedContent() const; + bool allowMixedContentDisplay() const; + + // Global config object stuff. + static WebSettings* self(); + +private: + /** + * Read settings from @p config. + * @param config is a pointer to KConfig object. + * @param reset if true, settings are always set; if false, + * settings are only set if the config file has a corresponding key. + */ + void init( KConfig * config, bool reset = true ); + + // Behavior settings + bool changeCursor() const; + bool underlineLink() const; + bool hoverLink() const; + bool allowTabulation() const; + bool autoSpellCheck() const; + KAnimationAdvice showAnimations() const; + KSmoothScrollingMode smoothScrolling() const; + bool zoomTextOnly() const; + + // Font settings + QString stdFontName() const; + QString fixedFontName() const; + QString serifFontName() const; + QString sansSerifFontName() const; + QString cursiveFontName() const; + QString fantasyFontName() const; + + // these two can be set. Mainly for historical reasons (the method in KHTMLPart exists...) + void setStdFontName(const QString &n); + void setFixedFontName(const QString &n); + + int minFontSize() const; + int mediumFontSize() const; + + bool jsErrorsEnabled() const; + void setJSErrorsEnabled(bool enabled); + + const QString &encoding() const; + + bool followSystemColors() const; + + // Color settings + const QColor& textColor() const; + const QColor& baseColor() const; + const QColor& linkColor() const; + const QColor& vLinkColor() const; + + // Autoload images + bool autoLoadImages() const; + bool unfinishedImageFrame() const; + + /** + * reads from @p config's current group, forcing initialization + * if @p reset is true. + * @param config is a pointer to KConfig object. + * @param reset true if initialization is to be forced. + * @param global true if the global domain is to be read. + * @param pd_settings will be initialised with the computed (inherited) + * settings. + */ + void readDomainSettings(const KConfigGroup &config, bool reset, + bool global, KPerDomainSettings &pd_settings); + + + QList< QPair< QString, QChar > > fallbackAccessKeysAssignments() const; + + // Whether to show passive popup when windows are blocked + void setJSPopupBlockerPassivePopup(bool enabled); + bool jsPopupBlockerPassivePopup() const; + + + QString lookupFont(int i) const; + + void initWebSettings(); + void initCookieJarSettings(); + void initNSPluginSettings(); + + /** + * @internal Constructor + */ + WebSettings(); + + WebSettingsPrivate* const d; +}; + +#endif diff --git b/webkitpart/src/ui/featurepermissionbar.cpp b/webkitpart/src/ui/featurepermissionbar.cpp new file mode 100644 index 000000000..538c658aa --- /dev/null +++ b/webkitpart/src/ui/featurepermissionbar.cpp @@ -0,0 +1,75 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2009 Dawit Alemayehu + * Copyright (C) 2013 Allan Sandfeld Jensen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "featurepermissionbar.h" + +#include + +#include + + +FeaturePermissionBar::FeaturePermissionBar(QWidget *parent) + :KMessageWidget(parent) +{ + setCloseButtonVisible(false); + setMessageType(KMessageWidget::Information); + + QAction* action = new QAction(i18nc("@action:deny access", "&Deny access"), this); + connect(action, SIGNAL(triggered()), this, SLOT(onDeniedButtonClicked())); + addAction(action); + + action = new QAction(i18nc("@action:grant access", "&Grant access"), this); + connect(action, SIGNAL(triggered()), this, SLOT(onGrantedButtonClicked())); + addAction(action); + + // FIXME: Add option to allow and remember for this site. +} + +FeaturePermissionBar::~FeaturePermissionBar() +{ +} + +QWebPage::Feature FeaturePermissionBar::feature() const +{ + return m_feature; +} + +void FeaturePermissionBar::setFeature (QWebPage::Feature feature) +{ + m_feature = feature; +} + +void FeaturePermissionBar::onDeniedButtonClicked() +{ + animatedHide(); + emit permissionDenied(m_feature); + emit done(); +} + +void FeaturePermissionBar::onGrantedButtonClicked() +{ + animatedHide(); + emit permissionGranted(m_feature); + emit done(); +} + +#include "featurepermissionbar.moc" diff --git b/webkitpart/src/ui/featurepermissionbar.h b/webkitpart/src/ui/featurepermissionbar.h new file mode 100644 index 000000000..ca4b7e6eb --- /dev/null +++ b/webkitpart/src/ui/featurepermissionbar.h @@ -0,0 +1,54 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2013 Allan Sandfeld Jensen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FEATUREPERMISSIONBAR_H +#define FEATUREPERMISSIONBAR_H + +#include + +#include + + +class FeaturePermissionBar : public KMessageWidget +{ + Q_OBJECT +public: + explicit FeaturePermissionBar(QWidget *parent = Q_NULLPTR); + ~FeaturePermissionBar(); + + QWebPage::Feature feature() const; + + void setFeature(QWebPage::Feature); + +Q_SIGNALS: + void permissionGranted(QWebPage::Feature); + void permissionDenied(QWebPage::Feature); + void done(); + +private Q_SLOTS: + void onDeniedButtonClicked(); + void onGrantedButtonClicked(); + +private: + QWebPage::Feature m_feature; +}; + +#endif // FEATUREPERMISSIONBAR_H diff --git b/webkitpart/src/ui/passwordbar.cpp b/webkitpart/src/ui/passwordbar.cpp new file mode 100644 index 000000000..b6dde17ed --- /dev/null +++ b/webkitpart/src/ui/passwordbar.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2009 Dawit Alemayehu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "passwordbar.h" + +#include "settings/websettings.h" + +#include +#include + +#include +#include +#include + + +PasswordBar::PasswordBar(QWidget *parent) + :KMessageWidget(parent) +{ + setCloseButtonVisible(false); + setMessageType(KMessageWidget::Information); + + QAction* action = new QAction(i18nc("@action:remember password", "&Remember"), this); + connect(action, SIGNAL(triggered()), this, SLOT(onRememberButtonClicked())); + addAction(action); + + action = new QAction(i18nc("@action:never for this site", "Ne&ver for this site"), this); + connect(action, SIGNAL(triggered()), this, SLOT(onNeverButtonClicked())); + addAction(action); + + action = new QAction(i18nc("@action:not now", "N&ot now"), this); + connect(action, SIGNAL(triggered()), this, SLOT(onNotNowButtonClicked())); + addAction(action); +} + +PasswordBar::~PasswordBar() +{ +} + +QUrl PasswordBar::url() const +{ + return m_url; +} + +QString PasswordBar::requestKey() const +{ + return m_requestKey; +} + +void PasswordBar::setUrl (const QUrl& url) +{ + m_url = url; +} + +void PasswordBar::setRequestKey (const QString& key) +{ + m_requestKey = key; +} + +void PasswordBar::onNotNowButtonClicked() +{ + animatedHide(); + emit saveFormDataRejected (m_requestKey); + emit done(); + clear(); +} + +void PasswordBar::onNeverButtonClicked() +{ + WebSettings::self()->addNonPasswordStorableSite(m_url.host()); + onNotNowButtonClicked(); +} + +void PasswordBar::onRememberButtonClicked() +{ + animatedHide(); + emit saveFormDataAccepted(m_requestKey); + emit done(); + clear(); +} + +void PasswordBar::clear() +{ + m_requestKey.clear(); + m_url.clear(); +} + +#include "passwordbar.moc" diff --git b/webkitpart/src/ui/passwordbar.h b/webkitpart/src/ui/passwordbar.h new file mode 100644 index 000000000..9f641a625 --- /dev/null +++ b/webkitpart/src/ui/passwordbar.h @@ -0,0 +1,60 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2009 Dawit Alemayehu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef PASSWORDBAR_H +#define PASSWORDBAR_H + +#include + +#include + + +class PasswordBar : public KMessageWidget +{ + Q_OBJECT +public: + explicit PasswordBar(QWidget *parent = Q_NULLPTR); + ~PasswordBar(); + + QUrl url() const; + QString requestKey() const; + + void setUrl(const QUrl&); + void setRequestKey(const QString&); + +Q_SIGNALS: + void saveFormDataRejected(const QString &key); + void saveFormDataAccepted(const QString &key); + void done(); + +private Q_SLOTS: + void onNotNowButtonClicked(); + void onNeverButtonClicked(); + void onRememberButtonClicked(); + +private: + void clear(); + + QUrl m_url; + QString m_requestKey; +}; + +#endif // PASSWORDBAR_H diff --git b/webkitpart/src/ui/searchbar.cpp b/webkitpart/src/ui/searchbar.cpp new file mode 100644 index 000000000..aca133ff6 --- /dev/null +++ b/webkitpart/src/ui/searchbar.cpp @@ -0,0 +1,194 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2008 Laurent Montel + * Copyright (C) 2008 Benjamin C. Meyer + * Copyright (C) 2008 Urs Wolfer + * Copyright (C) 2009 Dawit Alemayehu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "searchbar.h" + +#include +#include +#include +#include + +#include + + +SearchBar::SearchBar(QWidget *parent) + :QWidget(parent) +{ + + // Get the widget that currently has the focus so we can properly + // restore it when the filter bar is closed. + QWidget* widgetWindow = (parent ? parent->window() : 0); + m_focusWidget = (widgetWindow ? widgetWindow->focusWidget() : 0); + + // Initialize the user interface... + m_ui.setupUi(this); + m_ui.optionsButton->addAction(m_ui.actionMatchCase); + m_ui.optionsButton->addAction(m_ui.actionHighlightMatch); + m_ui.optionsButton->addAction(m_ui.actionSearchAutomatically); + m_ui.closeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); + m_ui.previousButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up-search"))); + m_ui.nextButton->setIcon(QIcon::fromTheme(QStringLiteral("go-down-search"))); + m_ui.previousButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_ui.nextButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_ui.searchInfo->setText(i18nc("label for input line to find text", "&Find:")); + + setFocusProxy(m_ui.searchComboBox); + + connect(m_ui.nextButton, SIGNAL(clicked()), + this, SLOT(findNext())); + connect(m_ui.previousButton, SIGNAL(clicked()), + this, SLOT(findPrevious())); + connect(m_ui.searchComboBox, SIGNAL(returnPressed()), + this, SLOT(findNext())); + connect(m_ui.searchComboBox, SIGNAL(editTextChanged(QString)), + this, SLOT(textChanged(QString))); + + // Start off hidden by default... + setVisible(false); +} + +SearchBar::~SearchBar() +{ + // NOTE: For some reason, if we do not clear the focus from the line edit + // widget before we delete this object, it seems to cause a crash!! + m_ui.searchComboBox->clearFocus(); +} + +void SearchBar::clear() +{ + m_ui.searchComboBox->clear(); +} + +void SearchBar::setVisible (bool visible) +{ + if (visible) { + m_ui.searchComboBox->setFocus(Qt::ActiveWindowFocusReason); + m_ui.searchComboBox->lineEdit()->selectAll(); + } else { + m_ui.searchComboBox->setPalette(QPalette()); + emit searchTextChanged(QString()); + } + + QWidget::setVisible(visible); +} + +QString SearchBar::searchText() const +{ + return m_ui.searchComboBox->currentText(); +} + +bool SearchBar::caseSensitive() const +{ + return m_ui.actionMatchCase->isChecked(); +} + +bool SearchBar::highlightMatches() const +{ + return m_ui.actionHighlightMatch->isChecked(); +} + +void SearchBar::setSearchText(const QString& text) +{ + show(); + m_ui.searchComboBox->setEditText(text); +} + +void SearchBar::setFoundMatch(bool match) +{ + //kDebug() << match; + if (m_ui.searchComboBox->currentText().isEmpty()) { + m_ui.searchComboBox->setPalette(QPalette()); + return; + } + + KColorScheme::BackgroundRole role = (match ? KColorScheme::PositiveBackground : KColorScheme::NegativeBackground); + QPalette newPal(m_ui.searchComboBox->palette()); + KColorScheme::adjustBackground(newPal, role); + m_ui.searchComboBox->setPalette(newPal); +} + +void SearchBar::findNext() +{ + if (!isVisible()) + return; + + const QString text (m_ui.searchComboBox->currentText()); + if (m_ui.searchComboBox->findText(text) == -1) { + m_ui.searchComboBox->addItem(text); + } + + emit searchTextChanged(text); +} + +void SearchBar::findPrevious() +{ + if (!isVisible()) + return; + + const QString text (m_ui.searchComboBox->currentText()); + if (m_ui.searchComboBox->findText(text) == -1) { + m_ui.searchComboBox->addItem(text); + } + + emit searchTextChanged(m_ui.searchComboBox->currentText(), true); +} + +void SearchBar::textChanged(const QString &text) +{ + if (text.isEmpty()) { + m_ui.searchComboBox->setPalette(QPalette()); + m_ui.nextButton->setEnabled(false); + m_ui.previousButton->setEnabled(false); + } else { + m_ui.nextButton->setEnabled(true); + m_ui.previousButton->setEnabled(true); + } + + if (m_ui.actionSearchAutomatically->isChecked()) { + emit searchTextChanged(m_ui.searchComboBox->currentText()); + } +} + +bool SearchBar::event(QEvent* e) +{ + // Close the bar when Escape is pressed. Note we cannot + // assign Escape as a shortcut key because it would cause + // a conflict with the Stop button. + if (e->type() == QEvent::ShortcutOverride) { + QKeyEvent* kev = static_cast(e); + if (kev->key() == Qt::Key_Escape) { + e->accept(); + close(); + if (m_focusWidget) { + m_focusWidget->setFocus(); + m_focusWidget = 0; + } + return true; + } + } + return QWidget::event(e); +} + +#include "searchbar.moc" diff --git b/webkitpart/src/ui/searchbar.h b/webkitpart/src/ui/searchbar.h new file mode 100644 index 000000000..598fe69ff --- /dev/null +++ b/webkitpart/src/ui/searchbar.h @@ -0,0 +1,68 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2008 Laurent Montel + * Copyright 2008 Benjamin C. Meyer + * Copyright (C) 2008 Urs Wolfer + * Copyright (C) 2009 Dawit Alemayehu + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SEARCHBAR_P_H +#define SEARCHBAR_P_H + +#include + +#include "ui_searchbar.h" + +class QEvent; + +/** + * This is the widget that shows up when the search is initiated. + */ +class SearchBar : public QWidget +{ + Q_OBJECT + +public: + SearchBar(QWidget *parent = Q_NULLPTR); + ~SearchBar(); + + QString searchText() const; + bool caseSensitive() const; + bool highlightMatches() const; + void setFoundMatch(bool match); + void setSearchText(const QString&); + + bool event(QEvent* e) Q_DECL_OVERRIDE; + +public Q_SLOTS: + void setVisible(bool visible) Q_DECL_OVERRIDE; + void clear(); + void findNext(); + void findPrevious(); + void textChanged(const QString&); + +Q_SIGNALS: + void searchTextChanged(const QString& text, bool backward = false); + +private: + Ui::SearchBar m_ui; + QPointer m_focusWidget; +}; + +#endif // SEARCHBAR_P_H diff --git b/webkitpart/src/ui/searchbar.ui b/webkitpart/src/ui/searchbar.ui new file mode 100644 index 000000000..0ed50bdda --- /dev/null +++ b/webkitpart/src/ui/searchbar.ui @@ -0,0 +1,168 @@ + + + SearchBar + + + + 0 + 0 + 564 + 34 + + + + + 0 + 0 + + + + + + + Close the search bar + + + true + + + + + + + &Find: + + + searchComboBox + + + + + + + + 0 + 0 + + + + + + + + false + + + Find the next match for the current search phrase + + + &Next + + + + + + + false + + + Find the previous match for the current search phrase + + + &Previous + + + + + + + Find the previous match for the current search phrase + + + &Options + + + QToolButton::InstantPopup + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 20 + 20 + + + + + + + + true + + + &Match Case + + + + + true + + + true + + + &Search As You Type + + + + + true + + + &Highlight All Matches + + + Highlight Matches + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KHistoryComboBox + KComboBox +
khistorycombobox.h
+
+
+ + + + closeButton + clicked() + SearchBar + close() + + + 16 + 16 + + + 290 + 16 + + + + +
diff --git b/webkitpart/src/utils.h b/webkitpart/src/utils.h new file mode 100644 index 000000000..fc35a28c2 --- /dev/null +++ b/webkitpart/src/utils.h @@ -0,0 +1,16 @@ +#ifndef WEBKITPART_UTILS_H +#define WEBKITPART_UTILS_H + +namespace Utils +{ + +#define QL1S(x) QLatin1String(x) +#define QL1C(x) QLatin1Char(x) + +inline bool isBlankUrl(const QUrl& url) +{ + return (url.isEmpty() || url.url() == QL1S("about:blank")); +} + +} +#endif // WEBKITPART_UTILS_H diff --git b/webkitpart/src/webhistoryinterface.cpp b/webkitpart/src/webhistoryinterface.cpp new file mode 100644 index 000000000..74e2c096e --- /dev/null +++ b/webkitpart/src/webhistoryinterface.cpp @@ -0,0 +1,38 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2011 Dawit Alemayehu + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#include "webhistoryinterface.h" + +#include + + +WebHistoryInterface::WebHistoryInterface(QObject* parent) +{ +} + +void WebHistoryInterface::addHistoryEntry(const QString& url) +{ + KParts::HistoryProvider::self()->insert(url); +} + +bool WebHistoryInterface::historyContains(const QString& url) const +{ + return KParts::HistoryProvider::self()->contains(url); +} diff --git b/webkitpart/src/webhistoryinterface.h b/webkitpart/src/webhistoryinterface.h new file mode 100644 index 000000000..fbc6d6f8b --- /dev/null +++ b/webkitpart/src/webhistoryinterface.h @@ -0,0 +1,34 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2011 Dawit Alemayehu + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ +#ifndef WEBHISTORYINTERFACE_H +#define WEBHISTORYINTERFACE_H + +#include + + +class WebHistoryInterface +{ +public: + WebHistoryInterface(QObject* parent = Q_NULLPTR); + void addHistoryEntry (const QString & url); + bool historyContains (const QString & url) const; +}; + +#endif //WEBHISTORYINTERFACE_H diff --git b/webkitpart/src/webkitpage.cpp b/webkitpart/src/webkitpage.cpp new file mode 100644 index 000000000..1cef75875 --- /dev/null +++ b/webkitpart/src/webkitpage.cpp @@ -0,0 +1,887 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2008 Dirk Mueller + * Copyright (C) 2008 - 2010 Urs Wolfer + * Copyright (C) 2009 Dawit Alemayehu + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#include "webkitpage.h" + +#include "webkitpart.h" +#include "websslinfo.h" +#include "webkitview.h" +#include "settings/webkitsettings.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include // Qt::escape +#include +#include +#include +#include +#include +#include +//#include +#include "utils.h" + + +WebPage::WebPage(WebKitPart *part, QWidget *parent) + : QWebPage(parent), + m_kioErrorCode(0), + m_ignoreError(false), + m_part(part) +{ + if (view()) + WebSettings::self()->computeFontSizes(view()->logicalDpiY()); + + //setForwardUnsupportedContent(true); + + connect(this, &QWebPage::geometryChangeRequested, + this, &WebPage::slotGeometryChangeRequested); +// connect(this, SIGNAL(unsupportedContent(QNetworkReply*)), +// this, SLOT(slotUnsupportedContent(QNetworkReply*))); + connect(this, &QWebPage::featurePermissionRequested, + this, &WebPage::slotFeaturePermissionRequested); + connect(this, &QWebPage::loadFinished, + this, &WebPage::slotLoadFinished); + connect(this->profile(), this, &WebPage::downloadRequest); + if(!this->profile()->httpUserAgent().contains(QLatin1String("Konqueror"))) + { + this->profile()->setHttpUserAgent(this->profile()->httpUserAgent() + " Konqueror (WebKitPart)"); + } +} + +WebPage::~WebPage() +{ + //kDebug() << this; +} + +const WebSslInfo& WebPage::sslInfo() const +{ + return m_sslInfo; +} + +void WebPage::setSslInfo (const WebSslInfo& info) +{ + m_sslInfo = info; +} + +static void checkForDownloadManager(QWidget* widget, QString& cmd) +{ + cmd.clear(); + KConfigGroup cfg (KSharedConfig::openConfig(QStringLiteral("konquerorrc"), KConfig::NoGlobals), "HTML Settings"); + const QString fileName (cfg.readPathEntry("DownloadManager", QString())); + if (fileName.isEmpty()) + return; + + const QString exeName = QStandardPaths::findExecutable(fileName); + if (exeName.isEmpty()) { + KMessageBox::detailedSorry(widget, + i18n("The download manager (%1) could not be found in your installation.", fileName), + i18n("Try to reinstall it and make sure that it is available in $PATH. \n\nThe integration will be disabled.")); + cfg.writePathEntry("DownloadManager", QString()); + cfg.sync(); + return; + } + + cmd = exeName; +} + +void WebPage::downloadRequest(QWebDownloadItem* request) +{ + const QUrl url(request->url()); + + // Integration with a download manager... + if (!url.isLocalFile()) { + QString managerExe; + checkForDownloadManager(view(), managerExe); + if (!managerExe.isEmpty()) { + //kDebug() << "Calling command" << cmd; + KRun::runCommand((managerExe + QLatin1Char(' ') + KShell::quoteArg(url.url())), view()); + return; + } + } + request->accept(); + +} + +QWebPage *WebPage::createWindow(WebWindowType type) +{ + //qDebug() << "window type:" << type; + // Crete an instance of NewWindowPage class to capture all the + // information we need to create a new window. See documentation of + // the class for more information... + NewWindowPage* page = new NewWindowPage(type, part()); + return page; +} + +// Returns true if the scheme and domain of the two urls match... +static bool domainSchemeMatch(const QUrl& u1, const QUrl& u2) +{ + if (u1.scheme() != u2.scheme()) + return false; + + QStringList u1List = u1.host().split(QL1C('.'), QString::SkipEmptyParts); + QStringList u2List = u2.host().split(QL1C('.'), QString::SkipEmptyParts); + + if (qMin(u1List.count(), u2List.count()) < 2) + return false; // better safe than sorry... + + while (u1List.count() > 2) + u1List.removeFirst(); + + while (u2List.count() > 2) + u2List.removeFirst(); + + return (u1List == u2List); +} + +bool WebPage::acceptNavigationRequest(const QUrl& url, NavigationType type, bool isMainFrame) +{ + qDebug() << url << "type=" << type; + QUrl reqUrl(url); + + // Handle "mailto:" url here... + if (handleMailToUrl(reqUrl, type)) + return false; + + const bool isTypedUrl = property("NavigationTypeUrlEntered").toBool(); + + /* + NOTE: We use a dynamic QObject property called "NavigationTypeUrlEntered" + to distinguish between requests generated by user entering a url vs those + that were generated programatically through javascript (AJAX requests). + */ + if (isMainFrame && isTypedUrl) + setProperty("NavigationTypeUrlEntered", QVariant()); + + // inPage requests are those generarted within the current page through + // link clicks, javascript queries, and button clicks (form submission). + bool inPageRequest = true; + switch (type) { + case QWebPage::NavigationTypeFormSubmitted: + //if (!checkFormData(request)) + // return false; + break; +#if 0 + case QWebPage::NavigationTypeFormResubmitted: + if (!checkFormData(request)) + return false; + if (KMessageBox::warningContinueCancel(view(), + i18n("

To display the requested web page again, " + "the browser needs to resend information you have " + "previously submitted.

" + "

If you were shopping online and made a purchase, " + "click the Cancel button to prevent a duplicate purchase." + "Otherwise, click the Continue button to display the web" + "page again.

"), + i18n("Resubmit Information")) == KMessageBox::Cancel) { + return false; + } + break; +#endif + case QWebPage::NavigationTypeBackForward: + // If history navigation is locked, ignore all such requests... + if (property("HistoryNavigationLocked").toBool()) { + setProperty("HistoryNavigationLocked", QVariant()); + qDebug() << "Rejected history navigation because 'HistoryNavigationLocked' property is set!"; + return false; + } + //kDebug() << "Navigating to item (" << history()->currentItemIndex() + // << "of" << history()->count() << "):" << history()->currentItem().url(); + inPageRequest = false; + break; + case QWebPage::NavigationTypeReload: +// setRequestMetaData(QL1S("cache"), QL1S("reload")); + inPageRequest = false; + break; + case QWebPage::NavigationTypeOther: // triggered by javascript + qDebug() << "Triggered by javascript"; + inPageRequest = !isTypedUrl; + break; + default: + break; + } + + if (inPageRequest) { + // if (!checkLinkSecurity(request, type)) + // return false; + + // if (m_sslInfo.isValid()) + // setRequestMetaData(QL1S("ssl_was_in_use"), QL1S("TRUE")); + } + + + // Honor the enabling/disabling of plugins per host. + settings()->setAttribute(QWebSettings::PluginsEnabled, WebSettings::self()->isPluginsEnabled(reqUrl.host())); + // Insert the request into the queue... + return QWebPage::acceptNavigationRequest(url, type, isMainFrame); +} + +#if 0 +static int errorCodeFromReply(QNetworkReply* reply) +{ + // First check if there is a KIO error code sent back and use that, + // if not attempt to convert QNetworkReply's NetworkError to KIO::Error. + QVariant attr = reply->attribute(static_cast(KIO::AccessManager::KioError)); + if (attr.isValid() && attr.type() == QVariant::Int) + return attr.toInt(); + + switch (reply->error()) { + case QNetworkReply::ConnectionRefusedError: + return KIO::ERR_COULD_NOT_CONNECT; + case QNetworkReply::HostNotFoundError: + return KIO::ERR_UNKNOWN_HOST; + case QNetworkReply::TimeoutError: + return KIO::ERR_SERVER_TIMEOUT; + case QNetworkReply::OperationCanceledError: + return KIO::ERR_USER_CANCELED; + case QNetworkReply::ProxyNotFoundError: + return KIO::ERR_UNKNOWN_PROXY_HOST; + case QNetworkReply::ContentAccessDenied: + return KIO::ERR_ACCESS_DENIED; + case QNetworkReply::ContentOperationNotPermittedError: + return KIO::ERR_WRITE_ACCESS_DENIED; + case QNetworkReply::ContentNotFoundError: + return KIO::ERR_NO_CONTENT; + case QNetworkReply::AuthenticationRequiredError: + return KIO::ERR_COULD_NOT_AUTHENTICATE; + case QNetworkReply::ProtocolUnknownError: + return KIO::ERR_UNSUPPORTED_PROTOCOL; + case QNetworkReply::ProtocolInvalidOperationError: + return KIO::ERR_UNSUPPORTED_ACTION; + case QNetworkReply::UnknownNetworkError: + return KIO::ERR_UNKNOWN; + case QNetworkReply::NoError: + default: + break; + } + + return 0; +} +#endif + +WebPart* WebPage::part() const +{ + return m_part.data(); +} + +void WebPage::setPart(WebPart* part) +{ + m_part = part; +} + +void WebPage::slotLoadFinished(bool ok) +{ + QUrl requestUrl = url(); + requestUrl.setUserInfo(QString()); + const bool shouldResetSslInfo = (m_sslInfo.isValid() && !domainSchemeMatch(requestUrl, m_sslInfo.url())); +#if 0 + QWebFrame* frame = qobject_cast(reply->request().originatingObject()); + if (!frame) + return; + const bool isMainFrameRequest = (frame == mainFrame()); +#else + // PORTING_TODO + const bool isMainFrameRequest = true; +#endif + +#if 0 + // Only deal with non-redirect responses... + const QVariant redirectVar = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); + + if (isMainFrameRequest && redirectVar.isValid()) { + m_sslInfo.restoreFrom(reply->attribute(static_cast(KIO::AccessManager::MetaData)), + reply->url(), shouldResetSslInfo); + return; + } + + const int errCode = errorCodeFromReply(reply); + kDebug() << frame << "is main frame request?" << isMainFrameRequest << requestUrl; +#endif + + if (ok) { + if (isMainFrameRequest) { +#if 0 + m_sslInfo.restoreFrom(reply->attribute(static_cast(KIO::AccessManager::MetaData)), + reply->url(), shouldResetSslInfo); +#endif + setPageJScriptPolicy(url()); + } + } else { + // Handle any error... +#if 0 + switch (errCode) { + case 0: + case KIO::ERR_NO_CONTENT: + break; + case KIO::ERR_ABORTED: + case KIO::ERR_USER_CANCELED: // Do nothing if request is cancelled/aborted + //kDebug() << "User aborted request!"; + m_ignoreError = true; + emit loadAborted(QUrl()); + return; + // Handle the user clicking on a link that refers to a directory + // Since KIO cannot automatically convert a GET request to a LISTDIR one. + case KIO::ERR_IS_DIRECTORY: + m_ignoreError = true; + emit loadAborted(reply->url()); + return; + default: + // Make sure the saveFrameStateRequested signal is emitted so + // the page can restored properly. + if (isMainFrameRequest) + emit saveFrameStateRequested(frame, 0); + + m_ignoreError = (reply->attribute(QNetworkRequest::User).toInt() == QNetworkReply::ContentAccessDenied); + m_kioErrorCode = errCode; + break; +#endif + } + + if (isMainFrameRequest) { + const WebPageSecurity security = (m_sslInfo.isValid() ? PageEncrypted : PageUnencrypted); + emit m_part->browserExtension()->setPageSecurity(security); + } +} + +void WebPage::slotUnsupportedContent(QNetworkReply* reply) +{ +#if 0 + //kDebug() << reply->url(); + QString mimeType; + KIO::MetaData metaData; + + KIO::AccessManager::putReplyOnHold(reply); + QString downloadCmd; + checkForDownloadManager(view(), downloadCmd); + if (!downloadCmd.isEmpty()) { + reply->setProperty("DownloadManagerExe", downloadCmd); + } + + if (QWePage::handleReply(reply, &mimeType, &metaData)) { + reply->deleteLater(); + if (qobject_cast(this) && isBlankUrl(m_part->url())) { + m_part->closeUrl(); + if (m_part->arguments().metaData().contains(QL1S("new-window"))) { + m_part->widget()->topLevelWidget()->close(); + } else { + delete m_part; + } + } + return; + } + + //kDebug() << "mimetype=" << mimeType << "metadata:" << metaData; + + if (reply->request().originatingObject() == this->mainFrame()) { + KParts::OpenUrlArguments args; + args.setMimeType(mimeType); + args.metaData() = metaData; + emit m_part->browserExtension()->openUrlRequest(reply->url(), args, KParts::BrowserArguments()); + return; + } +#endif + reply->deleteLater(); + +} +void WebPage::slotFeaturePermissionRequested(const QUrl& url, QWebPage::Feature feature) +{ + if (url == this->url()) { + part()->slotShowFeaturePermissionBar(feature); + return; + } + switch(feature) { + case QWebPage::Notifications: + // FIXME: We should have a setting to tell if this is enabled, but so far it is always enabled. + setFeaturePermission(url, feature, QWebPage::PermissionGrantedByUser); + break; + case QWebPage::Geolocation: + if (KMessageBox::warningContinueCancel(0, i18n("This site is attempting to " + "access information about your " + "physical location.\n" + "Do you want to allow it access?"), + i18n("Network Transmission"), + KGuiItem(i18n("Allow access")), + KStandardGuiItem::cancel(), + QStringLiteral("WarnGeolocation")) == KMessageBox::Cancel) { + setFeaturePermission(url, feature, QWebPage::PermissionDeniedByUser); + } else { + setFeaturePermission(url, feature, QWebPage::PermissionGrantedByUser); + } + break; + default: + setFeaturePermission(url, feature, QWebPage::PermissionUnknown); + break; + } +} + +void WebPage::slotGeometryChangeRequested(const QRect & rect) +{ + const QString host = url().host(); + + // NOTE: If a new window was created from another window which is in + // maximized mode and its width and/or height were not specified at the + // time of its creation, which is always the case in QWebPage::createWindow, + // then any move operation will seem not to work. That is because the new + // window will be in maximized mode where moving it will not be possible... + if (WebSettings::self()->windowMovePolicy(host) == KParts::HtmlSettingsInterface::JSWindowMoveAllow && + (view()->x() != rect.x() || view()->y() != rect.y())) + emit m_part->browserExtension()->moveTopLevelWidget(rect.x(), rect.y()); + + const int height = rect.height(); + const int width = rect.width(); + + // parts of following code are based on kjs_window.cpp + // Security check: within desktop limits and bigger than 100x100 (per spec) + if (width < 100 || height < 100) { + qWarning() << "Window resize refused, window would be too small (" << width << "," << height << ")"; + return; + } + + QRect sg = QApplication::desktop()->screenGeometry(view()); + + if (width > sg.width() || height > sg.height()) { + qWarning() << "Window resize refused, window would be too big (" << width << "," << height << ")"; + return; + } + + if (WebSettings::self()->windowResizePolicy(host) == KParts::HtmlSettingsInterface::JSWindowResizeAllow) { + //kDebug() << "resizing to " << width << "x" << height; + emit m_part->browserExtension()->resizeTopLevelWidget(width, height); + } + + // If the window is out of the desktop, move it up/left + // (maybe we should use workarea instead of sg, otherwise the window ends up below kicker) + const int right = view()->x() + view()->frameGeometry().width(); + const int bottom = view()->y() + view()->frameGeometry().height(); + int moveByX = 0, moveByY = 0; + if (right > sg.right()) + moveByX = - right + sg.right(); // always <0 + if (bottom > sg.bottom()) + moveByY = - bottom + sg.bottom(); // always <0 + + if ((moveByX || moveByY) && WebSettings::self()->windowMovePolicy(host) == KParts::HtmlSettingsInterface::JSWindowMoveAllow) + emit m_part->browserExtension()->moveTopLevelWidget(view()->x() + moveByX, view()->y() + moveByY); +} + +bool WebPage::checkLinkSecurity(const QNetworkRequest &req, NavigationType type) const +{ + // Check whether the request is authorized or not... + if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("redirect"), url(), req.url())) { + + //kDebug() << "*** Failed security check: base-url=" << mainFrame()->url() << ", dest-url=" << req.url(); + QString buttonText, title, message; + + int response = KMessageBox::Cancel; + QUrl linkUrl (req.url()); + + if (type == QWebPage::NavigationTypeLinkClicked) { + message = i18n("This untrusted page links to
%1." + "
Do you want to follow the link?
", linkUrl.url()); + title = i18n("Security Warning"); + buttonText = i18nc("follow link despite of security warning", "Follow"); + } else { + title = i18n("Security Alert"); + message = i18n("Access by untrusted page to
%1
denied.
", + linkUrl.toDisplayString().toHtmlEscaped()); + } + + if (buttonText.isEmpty()) { + KMessageBox::error( 0, message, title); + } else { + // Dangerous flag makes the Cancel button the default + response = KMessageBox::warningContinueCancel(0, message, title, + KGuiItem(buttonText), + KStandardGuiItem::cancel(), + QString(), // no don't ask again info + KMessageBox::Notify | KMessageBox::Dangerous); + } + + return (response == KMessageBox::Continue); + } + + return true; +} + +bool WebPage::checkFormData(const QNetworkRequest &req) const +{ + const QString scheme (req.url().scheme()); + + if (m_sslInfo.isValid() && + !scheme.compare(QL1S("https")) && !scheme.compare(QL1S("mailto")) && + (KMessageBox::warningContinueCancel(0, + i18n("Warning: This is a secure form " + "but it is attempting to send " + "your data back unencrypted.\n" + "A third party may be able to " + "intercept and view this " + "information.\nAre you sure you " + "want to send the data unencrypted?"), + i18n("Network Transmission"), + KGuiItem(i18n("&Send Unencrypted"))) == KMessageBox::Cancel)) { + + return false; + } + + + if (scheme.compare(QL1S("mailto")) == 0 && + (KMessageBox::warningContinueCancel(0, i18n("This site is attempting to " + "submit form data via email.\n" + "Do you want to continue?"), + i18n("Network Transmission"), + KGuiItem(i18n("&Send Email")), + KStandardGuiItem::cancel(), + QStringLiteral("WarnTriedEmailSubmit")) == KMessageBox::Cancel)) { + return false; + } + + return true; +} + +// Sanitizes the "mailto:" url, e.g. strips out any "attach" parameters. +static QUrl sanitizeMailToUrl(const QUrl &url, QStringList& files) { + QUrl sanitizedUrl; + + // NOTE: This is necessary to ensure we can properly use QUrl's query + // related APIs to process 'mailto:' urls of form 'mailto:foo@bar.com'. + if (url.hasQuery()) + sanitizedUrl = url; + else + sanitizedUrl = QUrl(url.scheme() + QL1S(":?") + url.path()); + + QUrlQuery query(sanitizedUrl); + const QList > items (query.queryItems()); + + QUrlQuery sanitizedQuery; + for(auto queryItem : items) { + if (queryItem.first.contains(QL1C('@')) && queryItem.second.isEmpty()) { + // ### DF: this hack breaks mailto:faure@kde.org, kmail doesn't expect mailto:?to=faure@kde.org + queryItem.second = queryItem.first; + queryItem.first = QStringLiteral("to"); + } else if (QString::compare(queryItem.first, QL1S("attach"), Qt::CaseInsensitive) == 0) { + files << queryItem.second; + continue; + } + sanitizedQuery.addQueryItem(queryItem.first, queryItem.second); + } + + sanitizedUrl.setQuery(sanitizedQuery); + return sanitizedUrl; +} + +bool WebPage::handleMailToUrl (const QUrl &url, NavigationType type) const +{ + if (QString::compare(url.scheme(), QL1S("mailto"), Qt::CaseInsensitive) == 0) { + QStringList files; + QUrl mailtoUrl (sanitizeMailToUrl(url, files)); + + switch (type) { + case QWebPage::NavigationTypeLinkClicked: + if (!files.isEmpty() && KMessageBox::warningContinueCancelList(0, + i18n("Do you want to allow this site to attach " + "the following files to the email message?"), + files, i18n("Email Attachment Confirmation"), + KGuiItem(i18n("&Allow attachments")), + KGuiItem(i18n("&Ignore attachments")), QL1S("WarnEmailAttachment")) == KMessageBox::Continue) { + + // Re-add the attachments... + QStringListIterator filesIt (files); + QUrlQuery query(mailtoUrl); + while (filesIt.hasNext()) { + query.addQueryItem(QL1S("attach"), filesIt.next()); + } + mailtoUrl.setQuery(query); + } + break; + case QWebPage::NavigationTypeFormSubmitted: + //case QWebPage::NavigationTypeFormResubmitted: + if (!files.isEmpty()) { + KMessageBox::information(0, i18n("This site attempted to attach a file from your " + "computer in the form submission. The attachment " + "was removed for your protection."), + i18n("Attachment Removed"), QStringLiteral("InfoTriedAttach")); + } + break; + default: + break; + } + + //kDebug() << "Emitting openUrlRequest with " << mailtoUrl; + emit m_part->browserExtension()->openUrlRequest(mailtoUrl); + return true; + } + + return false; +} + +void WebPage::setPageJScriptPolicy(const QUrl &url) +{ + const QString hostname (url.host()); + settings()->setAttribute(QWebSettings::JavascriptEnabled, + WebSettings::self()->isJavaScriptEnabled(hostname)); + + const KParts::HtmlSettingsInterface::JSWindowOpenPolicy policy = WebSettings::self()->windowOpenPolicy(hostname); + settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, + (policy != KParts::HtmlSettingsInterface::JSWindowOpenDeny && + policy != KParts::HtmlSettingsInterface::JSWindowOpenSmart)); +} + + + + + +/************************************* Begin NewWindowPage ******************************************/ + +NewWindowPage::NewWindowPage(WebWindowType type, WebPart* part, QWidget* parent) + :WebPage(part, parent) , m_type(type) , m_createNewWindow(true) +{ + Q_ASSERT_X (part, "NewWindowPage", "Must specify a valid KPart"); + + connect(this, SIGNAL(menuBarVisibilityChangeRequested(bool)), + this, SLOT(slotMenuBarVisibilityChangeRequested(bool))); + connect(this, SIGNAL(toolBarVisibilityChangeRequested(bool)), + this, SLOT(slotToolBarVisibilityChangeRequested(bool))); + connect(this, SIGNAL(statusBarVisibilityChangeRequested(bool)), + this, SLOT(slotStatusBarVisibilityChangeRequested(bool))); + connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool))); +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (m_type == WebBrowserBackgroundTab) { + m_windowArgs.setLowerWindow(true); + } +#endif +} + +NewWindowPage::~NewWindowPage() +{ +} + +static KParts::BrowserArguments browserArgs(WebPage::WebWindowType type) +{ + KParts::BrowserArguments bargs; + switch (type) { + case WebPage::WebDialog: + case WebPage::WebBrowserWindow: + bargs.setForcesNewWindow(true); + break; + case WebPage::WebBrowserTab: +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + case WebPage::WebBrowserBackgroundTab: +#endif + // let konq decide, based on user configuration + //bargs.setNewTab(true); + break; + } + return bargs; +} + +bool NewWindowPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) +{ + //qDebug() << "url:" << url << ", type:" << type << ", isMainFrame:" << isMainFrame << "m_createNewWindow=" << m_createNewWindow; + if (m_createNewWindow) { + const QUrl reqUrl (url); + + const bool actionRequestedByUser = type != QWebPage::NavigationTypeOther; + + if (actionRequestedByUser) { + if (!part() && !isMainFrame) { + return false; + } + const KParts::HtmlSettingsInterface::JSWindowOpenPolicy policy = WebSettings::self()->windowOpenPolicy(reqUrl.host()); + switch (policy) { + case KParts::HtmlSettingsInterface::JSWindowOpenDeny: + // TODO: Implement support for dealing with blocked pop up windows. + this->deleteLater(); + return false; + case KParts::HtmlSettingsInterface::JSWindowOpenAsk: { + const QString message = (reqUrl.isEmpty() ? + i18n("This site is requesting to open a new popup window.\n" + "Do you want to allow this?") : + i18n("This site is requesting to open a popup window to" + "

%1


Do you want to allow this?
", + KStringHandler::rsqueeze(reqUrl.toDisplayString().toHtmlEscaped(), 100))); + if (KMessageBox::questionYesNo(view(), message, + i18n("Javascript Popup Confirmation"), + KGuiItem(i18n("Allow")), + KGuiItem(i18n("Do Not Allow"))) == KMessageBox::No) { + // TODO: Implement support for dealing with blocked pop up windows. + this->deleteLater(); + return false; + } + break; + } + default: + break; + } + } + + // Browser args... + KParts::BrowserArguments bargs = browserArgs(m_type); + + // OpenUrl args... + KParts::OpenUrlArguments uargs; + uargs.setMimeType(QL1S("text/html")); + uargs.setActionRequestedByUser(actionRequestedByUser); + + // Window args... + KParts::WindowArgs wargs (m_windowArgs); + + KParts::ReadOnlyPart* newWindowPart =0; + part()->browserExtension()->createNewWindow(QUrl(), uargs, bargs, wargs, &newWindowPart); + qDebug() << "Created new window" << newWindowPart; + + if (!newWindowPart) { + return false; + } else if (newWindowPart->widget()->topLevelWidget() != part()->widget()->topLevelWidget()) { + KParts::OpenUrlArguments args; + args.metaData().insert(QL1S("new-window"), QL1S("true")); + newWindowPart->setArguments(args); + } + + // Get the webview... + WebPart* webkitPart = qobject_cast(newWindowPart); + WebView* webView = webkitPart ? qobject_cast(webkitPart->view()) : 0; + + // If the newly created window is NOT a webkitpart... + if (!webView) { + qDebug() << "Opening URL on" << newWindowPart; + newWindowPart->openUrl(reqUrl); + this->deleteLater(); + return false; + } + // Reparent this page to the new webview to prevent memory leaks. + setParent(webView); + // Replace the webpage of the new webview with this one. Nice trick... + webView->setPage(this); + // Set the new part as the one this page will use going forward. + setPart(webkitPart); + // Connect all the signals from this page to the slots in the new part. + webkitPart->connectWebPageSignals(this); + //Set the create new window flag to false... + m_createNewWindow = false; + } + + return WebPage::acceptNavigationRequest(url, type, isMainFrame); +} + +void NewWindowPage::slotGeometryChangeRequested(const QRect & rect) +{ + if (!rect.isValid()) + return; + + if (!m_createNewWindow) { + WebPage::slotGeometryChangeRequested(rect); + return; + } + + m_windowArgs.setX(rect.x()); + m_windowArgs.setY(rect.y()); + m_windowArgs.setWidth(qMax(rect.width(), 100)); + m_windowArgs.setHeight(qMax(rect.height(), 100)); +} + +void NewWindowPage::slotMenuBarVisibilityChangeRequested(bool visible) +{ + //kDebug() << visible; + m_windowArgs.setMenuBarVisible(visible); +} + +void NewWindowPage::slotStatusBarVisibilityChangeRequested(bool visible) +{ + //kDebug() << visible; + m_windowArgs.setStatusBarVisible(visible); +} + +void NewWindowPage::slotToolBarVisibilityChangeRequested(bool visible) +{ + //kDebug() << visible; + m_windowArgs.setToolBarsVisible(visible); +} + +// When is this called? (and acceptNavigationRequest is not called?) +// The only case I found is Ctrl+click on link to data URL (like in konqviewmgrtest), that's quite specific... +// Everything else seems to work with this method being commented out... +void NewWindowPage::slotLoadFinished(bool ok) +{ + Q_UNUSED(ok) + qDebug() << ok; + if (!m_createNewWindow) + return; + + const bool actionRequestedByUser = true; // ### we don't have the information here, unlike in acceptNavigationRequest + + // Browser args... + KParts::BrowserArguments bargs = browserArgs(m_type); + //bargs.frameName = mainFrame()->frameName(); + + // OpenUrl args... + KParts::OpenUrlArguments uargs; + uargs.setMimeType(QL1S("text/html")); + uargs.setActionRequestedByUser(actionRequestedByUser); + + // Window args... + KParts::WindowArgs wargs (m_windowArgs); + + KParts::ReadOnlyPart* newWindowPart =0; + part()->browserExtension()->createNewWindow(QUrl(), uargs, bargs, wargs, &newWindowPart); + + qDebug() << "Created new window or tab" << newWindowPart; + + // Get the webview... + WebKitPart* webkitPart = newWindowPart ? qobject_cast(newWindowPart) : 0; + WebView* webView = webkitPart ? qobject_cast(webkitPart->view()) : 0; + + if (webView) { + // if a new window is created, set a new window meta-data flag. + if (newWindowPart->widget()->topLevelWidget() != part()->widget()->topLevelWidget()) { + KParts::OpenUrlArguments args; + args.metaData().insert(QL1S("new-window"), QL1S("true")); + newWindowPart->setArguments(args); + } + // Reparent this page to the new webview to prevent memory leaks. + setParent(webView); + // Replace the webpage of the new webview with this one. Nice trick... + webView->setPage(this); + // Set the new part as the one this page will use going forward. + setPart(webkitPart); + // Connect all the signals from this page to the slots in the new part. + webkitPart->connectWebPageSignals(this); + } + + //Set the create new window flag to false... + m_createNewWindow = false; +} + +/****************************** End NewWindowPage *************************************************/ + diff --git b/webkitpart/src/webkitpage.h b/webkitpart/src/webkitpage.h new file mode 100644 index 000000000..489f32881 --- /dev/null +++ b/webkitpart/src/webkitpage.h @@ -0,0 +1,162 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2008 Dirk Mueller + * Copyright (C) 2008 Urs Wolfer + * Copyright (C) 2009 Dawit Alemayehu + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#ifndef WEBKITPAGE_H +#define WEBKITPAGE_H + +#include "websslinfo.h" + +#include +#include + +#include +#include +#include +#include + +class QUrl; +class WebSslInfo; +class WebKitPart; +class QWebDownloadItem; + + +class WebPage : public QWebPage +{ + Q_OBJECT +public: + explicit WebPage(WebKitPart *wpart, QWidget *parent = Q_NULLPTR); + ~WebPage(); + + /** + * Returns the SSL information for the current page. + * + * @see WebSslInfo. + */ + const WebSslInfo& sslInfo() const; + + /** + * Sets the page's SSL information to @p other. + * + * @see WebSslInfo + */ + void setSslInfo (const WebSslInfo &other); + + /** + * Reimplemented for internal reasons. The API is not affected. + * + * @internal + * @see KWebPage::downloadRequest. + */ + void downloadRequest(QWebDownloadItem* request); + +Q_SIGNALS: + /** + * This signal is emitted whenever a user cancels/aborts a load resource + * request. + */ + void loadAborted(const QUrl &url); + +protected: + /** + * Returns the webkit part in use by this object. + * @internal + */ + WebKitPart* part() const; + + /** + * Sets the webkit part to be used by this object. + * @internal + */ + void setPart(WebKitPart*); + + /** + * Reimplemented for internal reasons, the API is not affected. + * @internal + */ + QWebPage* createWindow(WebWindowType type) Q_DECL_OVERRIDE; + + /** + * Reimplemented for internal reasons, the API is not affected. + * @internal + */ + bool acceptNavigationRequest(const QUrl& request, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE; + +protected Q_SLOTS: + void slotLoadFinished(bool ok); + void slotUnsupportedContent(QNetworkReply* reply); + virtual void slotGeometryChangeRequested(const QRect& rect); + void slotFeaturePermissionRequested(const QUrl& url, QWebPage::Feature feature); + +private: + bool checkLinkSecurity(const QNetworkRequest& req, NavigationType type) const; + bool checkFormData(const QNetworkRequest& req) const; + bool handleMailToUrl (const QUrl& , NavigationType type) const; + void setPageJScriptPolicy(const QUrl& url); + +private: + enum WebPageSecurity { PageUnencrypted, PageEncrypted, PageMixed }; + + int m_kioErrorCode; + bool m_ignoreError; + + WebSslInfo m_sslInfo; + QPointer m_part; +}; + + +/** + * This is a fake implementation of WebPage to workaround the ugly API used + * to request for the creation of a new window from javascript in QtWebKit. PORTING_TODO + * + * The KPart API for creating new windows requires all the information about the + * new window up front. Unfortunately QWebPage::createWindow function does not + * provide any of these necessary information except for the window type. All + * the other necessary information is emitted as signals instead! Hence, the + * need for this class to collect all of the necessary information, such as + * window name, size and position, before calling KPart's createNewWindow + * function. + */ +class NewWindowPage : public WebPage +{ + Q_OBJECT +public: + NewWindowPage(WebWindowType windowType, WebKitPart* part, + QWidget* parent = Q_NULLPTR); + virtual ~NewWindowPage(); + +protected: + bool acceptNavigationRequest(const QUrl& request, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE; + +private Q_SLOTS: + void slotGeometryChangeRequested(const QRect& rect) override; + void slotMenuBarVisibilityChangeRequested(bool visible); + void slotStatusBarVisibilityChangeRequested(bool visible); + void slotToolBarVisibilityChangeRequested(bool visible); + void slotLoadFinished(bool); + +private: + KParts::WindowArgs m_windowArgs; + WebWindowType m_type; + bool m_createNewWindow; +}; + +#endif // WEBPAGE_H diff --git b/webkitpart/src/webkitpart.cpp b/webkitpart/src/webkitpart.cpp new file mode 100644 index 000000000..096475c63 --- /dev/null +++ b/webkitpart/src/webkitpart.cpp @@ -0,0 +1,925 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2007 Trolltech ASA + * Copyright (C) 2008 - 2010 Urs Wolfer + * Copyright (C) 2008 Laurent Montel + * Copyright (C) 2009 Dawit Alemayehu + * Copyright (C) 2013 Allan Sandfeld Jensen + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +#include "webkitpart.h" + +//#include +#include +#include + +#include "webkitpart_ext.h" +#include "webkitview.h" +#include "webkitpage.h" +#include "websslinfo.h" +#include "webhistoryinterface.h" + +#include "ui/searchbar.h" +#include "ui/passwordbar.h" +#include "ui/featurepermissionbar.h" +#include "settings/webkitsettings.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" + +WebKitPart::WebKitPart(QWidget *parentWidget, QObject *parent, + const QByteArray& cachedHistory, const QStringList& /*args*/) + :KParts::ReadOnlyPart(parent), + m_emitOpenUrlNotify(true), + m_hasCachedFormData(false), + m_doLoadFinishedActions(false), + m_statusBarWalletLabel(0), + m_searchBar(0), + m_passwordBar(0), + m_featurePermissionBar(0) +{ + KAboutData about = KAboutData(QStringLiteral("webkitpart"), + i18nc("Program Name", "WebKitPart"), + /*version*/ QStringLiteral("1.3.0"), + i18nc("Short Description", "QtWebKit Browser Engine Component"), + KAboutLicense::LGPL, + i18n("(C) 2009-2010 Dawit Alemayehu\n" + "(C) 2008-2010 Urs Wolfer\n" + "(C) 2007 Trolltech ASA")); + + about.addAuthor(i18n("Sune Vuorela"), i18n("Maintainer, Developer"), QStringLiteral("sune@kde.org")); + about.addAuthor(i18n("Dawit Alemayehu"), i18n("Developer"), QStringLiteral("adawit@kde.org")); + about.addAuthor(i18n("Urs Wolfer"), i18n("Maintainer, Developer"), QStringLiteral("uwolfer@kde.org")); + about.addAuthor(i18n("Michael Howell"), i18n("Developer"), QStringLiteral("mhowell123@gmail.com")); + about.addAuthor(i18n("Laurent Montel"), i18n("Developer"), QStringLiteral("montel@kde.org")); + about.addAuthor(i18n("Dirk Mueller"), i18n("Developer"), QStringLiteral("mueller@kde.org")); + about.setProductName("webkitpart/general"); +// KComponentData componentData(&about); + setComponentData(about, false /*don't load plugins yet*/); + +#if 0 + // NOTE: If the application does not set its version number, we automatically + // set it to KDE's version number so that the default user-agent string contains + // proper application version number information. See QWebPage::userAgentForUrl... + if (QCoreApplication::applicationVersion().isEmpty()) + QCoreApplication::setApplicationVersion(QString("%1.%2.%3") + .arg(KDE::versionMajor()) + .arg(KDE::versionMinor()) + .arg(KDE::versionRelease())); +#endif + setXMLFile(QL1S("webkitpart.rc")); + + // Create this KPart's widget + QWidget *mainWidget = new QWidget (parentWidget); + mainWidget->setObjectName(QStringLiteral("webkitpart")); + + // Create the WebView... + m_webView = new WebView (this, parentWidget); + + // Create the browser extension. + m_browserExtension = new WebBrowserExtension(this, cachedHistory); + + // Add status bar extension... + m_statusBarExtension = new KParts::StatusBarExtension(this); + + // Add a web history interface for storing visited links. +// if (!QWebHistoryInterface::defaultInterface()) +// QWebHistoryInterface::setDefaultInterface(new WebHistoryInterface(this)); + + // Add text and html extensions... + new WebTextExtension(this); + new WebHtmlExtension(this); + new WebScriptableExtension(this); + + + // Layout the GUI... + QVBoxLayout* l = new QVBoxLayout(mainWidget); + l->setContentsMargins(0, 0, 0, 0); + l->setSpacing(0); + l->addWidget(m_webView); + + // Set the part's widget + setWidget(mainWidget); + + // Set the web view as the the focus object + mainWidget->setFocusProxy(m_webView); + + // Connect the signals from the webview + connect(m_webView, &QWebView::titleChanged, + this, &Part::setWindowCaption); + connect(m_webView, &QWebView::urlChanged, + this, &WebKitPart::slotUrlChanged); +// connect(m_webView, SIGNAL(linkMiddleOrCtrlClicked(QUrl)), +// this, SLOT(slotLinkMiddleOrCtrlClicked(QUrl))); +// connect(m_webView, SIGNAL(selectionClipboardUrlPasted(QUrl,QString)), +// this, SLOT(slotSelectionClipboardUrlPasted(QUrl,QString))); + connect(m_webView, &QWebView::loadFinished, + this, &WebKitPart::slotLoadFinished); + + // Connect the signals from the page... + connectWebPageSignals(page()); + + // Init the QAction we are going to use... + initActions(); + + // Load plugins once we are fully ready + loadPlugins(); +} + +WebKitPart::~WebKitPart() +{ +} + +WebPage* WebKitPart::page() +{ + if (m_webView) + return qobject_cast(m_webView->page()); + return Q_NULLPTR; +} + +const WebPage* WebKitPart::page() const +{ + if (m_webView) + return qobject_cast(m_webView->page()); + return Q_NULLPTR; +} + +void WebKitPart::initActions() +{ + actionCollection()->addAction(KStandardAction::SaveAs, QStringLiteral("saveDocument"), + m_browserExtension, SLOT(slotSaveDocument())); + + QAction* action = new QAction(i18n("Save &Frame As..."), this); + actionCollection()->addAction(QStringLiteral("saveFrame"), action); + connect(action, &QAction::triggered, m_browserExtension, &WebBrowserExtension::slotSaveFrame); + + action = new QAction(QIcon::fromTheme(QStringLiteral("document-print-preview")), i18n("Print Preview"), this); + actionCollection()->addAction(QStringLiteral("printPreview"), action); + connect(action, &QAction::triggered, m_browserExtension, &WebBrowserExtension::slotPrintPreview); + + action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-in")), i18nc("zoom in action", "Zoom In"), this); + actionCollection()->addAction(QStringLiteral("zoomIn"), action); + actionCollection()->setDefaultShortcuts(action, QList () << QKeySequence(QStringLiteral("CTRL++")) << QKeySequence(QStringLiteral("CTRL+="))); + connect(action, &QAction::triggered, m_browserExtension, &WebBrowserExtension::zoomIn); + + action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-out")), i18nc("zoom out action", "Zoom Out"), this); + actionCollection()->addAction(QStringLiteral("zoomOut"), action); + actionCollection()->setDefaultShortcuts(action, QList () << QKeySequence(QStringLiteral("CTRL+-")) << QKeySequence(QStringLiteral("CTRL+_"))); + connect(action, &QAction::triggered, m_browserExtension, &WebBrowserExtension::zoomOut); + + action = new QAction(QIcon::fromTheme(QStringLiteral("zoom-original")), i18nc("reset zoom action", "Actual Size"), this); + actionCollection()->addAction(QStringLiteral("zoomNormal"), action); + actionCollection()->setDefaultShortcut(action, QKeySequence(QStringLiteral("CTRL+0"))); + connect(action, &QAction::triggered, m_browserExtension, &WebBrowserExtension::zoomNormal); + + action = new QAction(i18n("Zoom Text Only"), this); + action->setCheckable(true); + KConfigGroup cgHtml(KSharedConfig::openConfig(), "HTML Settings"); + bool zoomTextOnly = cgHtml.readEntry("ZoomTextOnly", false); + action->setChecked(zoomTextOnly); + actionCollection()->addAction(QStringLiteral("zoomTextOnly"), action); + connect(action, &QAction::triggered, m_browserExtension, &WebBrowserExtension::toogleZoomTextOnly); + + action = new QAction(i18n("Zoom To DPI"), this); + action->setCheckable(true); + bool zoomToDPI = cgHtml.readEntry("ZoomToDPI", false); + action->setChecked(zoomToDPI); + actionCollection()->addAction(QStringLiteral("zoomToDPI"), action); + connect(action, &QAction::triggered, m_browserExtension, &WebBrowserExtension::toogleZoomToDPI); + + action = actionCollection()->addAction(KStandardAction::SelectAll, QStringLiteral("selectAll"), + m_browserExtension, SLOT(slotSelectAll())); + action->setShortcutContext(Qt::WidgetShortcut); + m_webView->addAction(action); + + KCodecAction *codecAction = new KCodecAction( QIcon::fromTheme(QStringLiteral("character-set")), i18n( "Set &Encoding" ), this, true ); + actionCollection()->addAction( QStringLiteral("setEncoding"), codecAction ); + connect(codecAction, SIGNAL(triggered(QTextCodec*)), SLOT(slotSetTextEncoding(QTextCodec*))); + + action = new QAction(i18n("View Do&cument Source"), this); + actionCollection()->addAction(QStringLiteral("viewDocumentSource"), action); + actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_U)); + connect(action, &QAction::triggered, m_browserExtension, &WebBrowserExtension::slotViewDocumentSource); + + action = new QAction(i18nc("Secure Sockets Layer", "SSL"), this); + actionCollection()->addAction(QStringLiteral("security"), action); + connect(action, &QAction::triggered, this, &WebKitPart::slotShowSecurity); + + action = actionCollection()->addAction(KStandardAction::Find, QStringLiteral("find"), this, SLOT(slotShowSearchBar())); + action->setWhatsThis(i18nc("find action \"whats this\" text", "

Find text

" + "Shows a dialog that allows you to find text on the displayed page.")); +} + +void WebKitPart::updateActions() +{ + m_browserExtension->updateActions(); + + QAction* action = actionCollection()->action(QL1S("saveDocument")); + if (action) { + const QString protocol (url().scheme()); + action->setEnabled(protocol != QL1S("about") && protocol != QL1S("error")); + } + + action = actionCollection()->action(QL1S("printPreview")); + if (action) { + action->setEnabled(m_browserExtension->isActionEnabled("print")); + } + +} + +void WebKitPart::connectWebPageSignals(WebPage* page) +{ + if (!page) + return; + + connect(page, SIGNAL(loadStarted()), + this, SLOT(slotLoadStarted())); + connect(page, SIGNAL(loadAborted(QUrl)), + this, SLOT(slotLoadAborted(QUrl))); + connect(page, &QWebPage::linkHovered, + this, &WebKitPart::slotLinkHovered); +// connect(page, SIGNAL(saveFrameStateRequested(QWebFrame*,QWebHistoryItem*)), +// this, SLOT(slotSaveFrameState(QWebFrame*,QWebHistoryItem*))); +// connect(page, SIGNAL(restoreFrameStateRequested(QWebFrame*)), +// this, SLOT(slotRestoreFrameState(QWebFrame*))); +// connect(page, SIGNAL(statusBarMessage(QString)), +// this, SLOT(slotSetStatusBarText(QString))); + connect(page, SIGNAL(windowCloseRequested()), + this, SLOT(slotWindowCloseRequested())); +// connect(page, SIGNAL(printRequested(QWebFrame*)), +// m_browserExtension, SLOT(slotPrintRequested(QWebFrame*))); + // connect(page, SIGNAL(frameCreated(QWebFrame*)), + // this, SLOT(slotFrameCreated(QWebFrame*))); + +// connect(m_webView, SIGNAL(linkShiftClicked(QUrl)), +// page, SLOT(downloadUrl(QUrl))); + + connect(page, SIGNAL(loadProgress(int)), + m_browserExtension, SIGNAL(loadingProgress(int))); + connect(page, SIGNAL(selectionChanged()), + m_browserExtension, SLOT(updateEditActions())); +// connect(m_browserExtension, SIGNAL(saveUrl(QUrl)), +// page, SLOT(downloadUrl(QUrl))); + + connect(page, &QWebPage::iconUrlChanged, [page, this](const QUrl& url) { + if (WebSettings::self()->favIconsEnabled() + && !page->profile()->isOffTheRecord()){ + m_browserExtension->setIconUrl(url); + } + }); + +#if 0 + KWebWallet *wallet = page->wallet(); + if (wallet) { + connect(wallet, SIGNAL(saveFormDataRequested(QString,QUrl)), + this, SLOT(slotSaveFormDataRequested(QString,QUrl))); + connect(wallet, SIGNAL(fillFormRequestCompleted(bool)), + this, SLOT(slotFillFormRequestCompleted(bool))); + connect(wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed())); + } +#endif +} + +bool WebKitPart::openUrl(const QUrl &_u) +{ + QUrl u (_u); + + qDebug() << u; + + // Ignore empty requests... + if (u.isEmpty()) + return false; + + // If the URL given is a supported local protocol, e.g. "bookmark" but lacks + // a path component, we set the path to "/" here so that the security context + // will properly allow access to local resources. + if (u.host().isEmpty() && u.path().isEmpty() + && KProtocolInfo::protocolClass(u.scheme()) == QL1S(":local")) { + u.setPath(QL1S("/")); + } + + // Do not emit update history when url is typed in since the host + // should handle that automatically itself. + m_emitOpenUrlNotify = false; + + // Pointer to the page object... + WebPage* p = page(); + Q_ASSERT(p); + + KParts::BrowserArguments bargs (m_browserExtension->browserArguments()); + KParts::OpenUrlArguments args (arguments()); + + if (!Utils::isBlankUrl(u)) { + // Get the SSL information sent, if any... + if (args.metaData().contains(QL1S("ssl_in_use"))) { + WebSslInfo sslInfo; + sslInfo.restoreFrom(KIO::MetaData(args.metaData()).toVariant()); + sslInfo.setUrl(u); + p->setSslInfo(sslInfo); + } + } + + // Set URL in KParts before emitting started; konq plugins rely on that. + setUrl(u); + m_doLoadFinishedActions = true; + m_webView->loadUrl(u, args, bargs); + return true; +} + +bool WebKitPart::closeUrl() +{ + m_webView->triggerPageAction(QWebPage::Stop); + m_webView->stop(); + return true; +} + +QWebView* WebKitPart::view() +{ + return m_webView; +} + +bool WebKitPart::isModified() const +{ + //return m_webView->isModified(); + return false; +} + +void WebKitPart::guiActivateEvent(KParts::GUIActivateEvent *event) +{ + if (event && event->activated() && m_webView) { + emit setWindowCaption(m_webView->title()); + } +} + +bool WebKitPart::openFile() +{ + // never reached + return false; +} + + +/// slots... + +void WebKitPart::slotLoadStarted() +{ + if(!Utils::isBlankUrl(url())) + { + emit started(0); + } + updateActions(); + + // If "NoEmitOpenUrlNotification" property is set to true, do not + // emit the open url notification. Property is set by this part's + // extension to prevent openUrl notification being sent when + // handling history navigation requests (back/forward). + const bool doNotEmitOpenUrl = property("NoEmitOpenUrlNotification").toBool(); + if (doNotEmitOpenUrl) { + setProperty("NoEmitOpenUrlNotification", QVariant()); + } else { + if (m_emitOpenUrlNotify) { + emit m_browserExtension->openUrlNotify(); + } + } + // Unless we go via openUrl again, the next time we are here we emit (e.g. after clicking on a link) + m_emitOpenUrlNotify = true; +} + +void WebKitPart::slotLoadFinished (bool ok) +{ + if (!ok || !m_doLoadFinishedActions) + return; + + slotWalletClosed(); + m_doLoadFinishedActions = false; + + // If the document contains no tag, then set it to the current url. + if (m_webView->title().trimmed().isEmpty()) { + // If the document title is empty, then set it to the current url + const QUrl url (m_webView->url()); + const QString caption (url.toString((QUrl::RemoveQuery|QUrl::RemoveFragment))); + emit setWindowCaption(caption); + + // The urlChanged signal is emitted if and only if the main frame + // receives the title of the page so we manually invoke the slot as a + // work around here for pages that do not contain it, such as text + // documents... + slotUrlChanged(url); + } + if (!Utils::isBlankUrl(url())) { + m_hasCachedFormData = false; + + if (WebSettings::self()->isNonPasswordStorableSite(url().host())) { + addWalletStatusBarIcon(); + } else { +// Attempt to fill the web form... +// KWebWallet *webWallet = page() ? page()->wallet() : 0; +// if (webWallet) { +// webWallet->fillFormData(frame, false); +// } + } + } + + bool pending = false; + // QWebFrame* frame = (page() ? page()->currentFrame() : 0); + // if (ok && + // frame == page()->mainFrame() && + // !frame->findFirstElement(QL1S("head>meta[http-equiv=refresh]")).isNull()) { + // if (WebSettings::self()->autoPageRefresh()) { + // pending = true; + // } else { + // frame->page()->triggerAction(QWebPage::Stop); + // } + // } + emit completed ((ok && pending)); + + updateActions(); +} + +void WebKitPart::slotLoadAborted(const QUrl & url) +{ + closeUrl(); + m_doLoadFinishedActions = false; + if (url.isValid()) + emit m_browserExtension->openUrlRequest(url); + else + setUrl(m_webView->url()); +} + +void WebKitPart::slotUrlChanged(const QUrl& url) +{ + // Ignore if empty + if (url.isEmpty()) + return; + + // Ignore if error url + if (url.scheme() == QL1S("error")) + return; + + const QUrl u (url); + + // Ignore if url has not changed! + if (this->url() == u) + return; + + m_doLoadFinishedActions = true; + setUrl(u); + + // Do not update the location bar with about:blank + if (!Utils::isBlankUrl(url)) { + //kDebug() << "Setting location bar to" << u.prettyUrl() << "current URL:" << this->url(); + emit m_browserExtension->setLocationBarUrl(u.toDisplayString()); + } +} + +void WebKitPart::slotShowSecurity() +{ + if (!page()) + return; + + const WebSslInfo& sslInfo = page()->sslInfo(); + if (!sslInfo.isValid()) { + KMessageBox::information(0, i18n("The SSL information for this site " + "appears to be corrupt."), + i18nc("Secure Sockets Layer", "SSL")); + return; + } + + KSslInfoDialog *dlg = new KSslInfoDialog (widget()); + dlg->setSslInfo(sslInfo.certificateChain(), + sslInfo.peerAddress().toString(), + url().host(), + sslInfo.protocol(), + sslInfo.ciphers(), + sslInfo.usedChiperBits(), + sslInfo.supportedChiperBits(), + KSslInfoDialog::errorsFromString(sslInfo.certificateErrors())); + + dlg->open(); +} + +#if 0 +void WebKitPart::slotSaveFrameState(QWebFrame *frame, QWebHistoryItem *item) +{ + if (!frame || !item) { + return; + } + + // Handle actions that apply only to the mainframe... + if (frame == view()->page()->mainFrame()) { + } + + // For some reason, QtWebKit PORTING_TODO does not restore scroll position when + // QWebHistory is restored from persistent storage. Therefore, we + // preserve that information and restore it as needed. See + // slotRestoreFrameState. + const QPoint scrollPos (frame->scrollPosition()); + if (!scrollPos.isNull()) { + // kDebug() << "Saving scroll position:" << scrollPos; + item->setUserData(scrollPos); + } +} +#endif + +#if 0 +void WebKitPart::slotRestoreFrameState(QWebFrame *frame) +{ + QWebPage* page = (frame ? frame->page() : 0); + QWebHistory* history = (page ? page->history() : 0); + + // No history item... + if (!history || history->count() < 1) + return; + + QWebHistoryItem currentHistoryItem (history->currentItem()); + + // Update the scroll position if needed. See comment in slotSaveFrameState above. + if (frame->baseUrl().resolved(frame->url()) == currentHistoryItem.url()) { + const QPoint currentPos (frame->scrollPosition()); + const QPoint desiredPos (currentHistoryItem.userData().toPoint()); + if (currentPos.isNull() && !desiredPos.isNull()) { + frame->setScrollPosition(desiredPos); + } + } +} +#endif + +void WebKitPart::slotLinkHovered(const QString& _link) +{ + QString message; + + if (_link.isEmpty()) { + message = QL1S(""); + emit m_browserExtension->mouseOverInfo(KFileItem()); + } else { + QUrl linkUrl (_link); + const QString scheme = linkUrl.scheme(); + + // Protect the user against URL spoofing! + linkUrl.setUserName(QString()); + const QString link (linkUrl.toString()); + + if (QString::compare(scheme, QL1S("mailto"), Qt::CaseInsensitive) == 0) { + message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", "Email: "); + + // Workaround: for QUrl's parsing deficiencies of "mailto:foo@bar.com". + if (!linkUrl.hasQuery()) + linkUrl = QUrl(scheme + '?' + linkUrl.path()); + + QMap<QString, QStringList> fields; + QUrlQuery query(linkUrl); + QList<QPair<QString, QString> > queryItems = query.queryItems(); + const int count = queryItems.count(); + + for(int i = 0; i < count; ++i) { + const QPair<QString, QString> queryItem (queryItems.at(i)); + //kDebug() << "query: " << queryItem.first << queryItem.second; + if (queryItem.first.contains(QL1C('@')) && queryItem.second.isEmpty()) + fields[QStringLiteral("to")] << queryItem.first; + if (QString::compare(queryItem.first, QL1S("to"), Qt::CaseInsensitive) == 0) + fields[QStringLiteral("to")] << queryItem.second; + if (QString::compare(queryItem.first, QL1S("cc"), Qt::CaseInsensitive) == 0) + fields[QStringLiteral("cc")] << queryItem.second; + if (QString::compare(queryItem.first, QL1S("bcc"), Qt::CaseInsensitive) == 0) + fields[QStringLiteral("bcc")] << queryItem.second; + if (QString::compare(queryItem.first, QL1S("subject"), Qt::CaseInsensitive) == 0) + fields[QStringLiteral("subject")] << queryItem.second; + } + + if (fields.contains(QL1S("to"))) + message += fields.value(QL1S("to")).join(QL1S(", ")); + if (fields.contains(QL1S("cc"))) + message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - CC: ") + fields.value(QL1S("cc")).join(QL1S(", ")); + if (fields.contains(QL1S("bcc"))) + message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - BCC: ") + fields.value(QL1S("bcc")).join(QL1S(", ")); + if (fields.contains(QL1S("subject"))) + message += i18nc("status bar text when hovering email links; looks like \"Email: xy@kde.org - CC: z@kde.org -BCC: x@kde.org - Subject: Hi translator\"", " - Subject: ") + fields.value(QL1S("subject")).join(QL1S(" ")); + } else if (scheme == QL1S("javascript")) { + message = KStringHandler::rsqueeze(link, 150); + if (link.startsWith(QL1S("javascript:window.open"))) + message += i18n(" (In new window)"); + } else { + message = link; +#if 0 + QWebFrame* frame = page() ? page()->currentFrame() : 0; + if (frame) { + QWebHitTestResult result = frame->hitTestContent(page()->view()->mapFromGlobal(QCursor::pos())); + QWebFrame* target = result.linkTargetFrame(); + if (frame->parentFrame() && target == frame->parentFrame()) { + message += i18n(" (In parent frame)"); + } else if (!target || target != frame) { + message += i18n(" (In new window)"); + } + } +#endif + KFileItem item (linkUrl, QString(), KFileItem::Unknown); + emit m_browserExtension->mouseOverInfo(item); + } + } + + emit setStatusBarText(message); +} + +void WebKitPart::slotSearchForText(const QString &text, bool backward) +{ + QWebPage::FindFlags flags; // = QWebPage::FindWrapsAroundDocument; + + if (backward) + flags |= QWebPage::FindBackward; + + if (m_searchBar->caseSensitive()) + flags |= QWebPage::FindCaseSensitively; + + //kDebug() << "search for text:" << text << ", backward ?" << backward; + page()->findText(text, flags, [this](bool found) { + m_searchBar->setFoundMatch(found); + }); +} + +void WebKitPart::slotShowSearchBar() +{ + if (!m_searchBar) { + // Create the search bar... + m_searchBar = new SearchBar(widget()); + connect(m_searchBar, SIGNAL(searchTextChanged(QString,bool)), + this, SLOT(slotSearchForText(QString,bool))); + + actionCollection()->addAction(KStandardAction::FindNext, QStringLiteral("findnext"), + m_searchBar, SLOT(findNext())); + actionCollection()->addAction(KStandardAction::FindPrev, QStringLiteral("findprev"), + m_searchBar, SLOT(findPrevious())); + + QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); + if (lay) { + lay->addWidget(m_searchBar); + } + } + const QString text = m_webView->selectedText(); + m_searchBar->setSearchText(text.left(150)); +} + +void WebKitPart::slotLinkMiddleOrCtrlClicked(const QUrl& linkUrl) +{ + emit m_browserExtension->createNewWindow(linkUrl); +} + +void WebKitPart::slotSelectionClipboardUrlPasted(const QUrl& selectedUrl, const QString& searchText) +{ + if (!WebSettings::self()->isOpenMiddleClickEnabled()) + return; + + if (!searchText.isEmpty() && + KMessageBox::questionYesNo(m_webView, + i18n("<qt>Do you want to search for <b>%1</b>?</qt>", searchText), + i18n("Internet Search"), KGuiItem(i18n("&Search"), QStringLiteral("edit-find")), + KStandardGuiItem::cancel(), QStringLiteral("MiddleClickSearch")) != KMessageBox::Yes) + return; + + emit m_browserExtension->openUrlRequest(selectedUrl); +} + +void WebKitPart::slotWalletClosed() +{ + if (!m_statusBarWalletLabel) + return; + + m_statusBarExtension->removeStatusBarItem(m_statusBarWalletLabel); + delete m_statusBarWalletLabel; + m_statusBarWalletLabel = 0; + m_hasCachedFormData = false; +} + +void WebKitPart::slotShowWalletMenu() +{ + QMenu *menu = new QMenu(0); + + if (m_webView && WebSettings::self()->isNonPasswordStorableSite(m_webView->url().host())) + menu->addAction(i18n("&Allow password caching for this site"), this, SLOT(slotDeleteNonPasswordStorableSite())); + + if (m_hasCachedFormData) + menu->addAction(i18n("Remove all cached passwords for this site"), this, SLOT(slotRemoveCachedPasswords())); + + menu->addSeparator(); + menu->addAction(i18n("&Close Wallet"), this, SLOT(slotWalletClosed())); + + KAcceleratorManager::manage(menu); + menu->popup(QCursor::pos()); +} + +void WebKitPart::slotLaunchWalletManager() +{ + QDBusInterface r(QStringLiteral("org.kde.kwalletmanager"), QStringLiteral("/kwalletmanager/MainWindow_1")); + if (r.isValid()) + r.call(QDBus::NoBlock, QStringLiteral("show")); + else + KToolInvocation::startServiceByDesktopName(QStringLiteral("kwalletmanager_show")); +} + +void WebKitPart::slotDeleteNonPasswordStorableSite() +{ + if (m_webView) + WebSettings::self()->removeNonPasswordStorableSite(m_webView->url().host()); +} + +void WebKitPart::slotRemoveCachedPasswords() +{ + if (!page()) // || !page()->wallet()) + return; + +// page()->wallet()->removeFormData(page()->mainFrame(), true); + m_hasCachedFormData = false; +} + +void WebKitPart::slotSetTextEncoding(QTextCodec * codec) +{ + // FIXME: The code below that sets the text encoding has been reported not to work. + if (!page()) + return; + + QWebSettings *localSettings = page()->settings(); + if (!localSettings) + return; + + qDebug() << "Encoding: new=>" << localSettings->defaultTextEncoding() << ", old=>" << codec->name(); + + localSettings->setDefaultTextEncoding(codec->name()); + page()->triggerAction(QWebPage::Reload); +} + +void WebKitPart::slotSetStatusBarText(const QString& text) +{ + const QString host (page() ? page()->url().host() : QString()); + if (WebSettings::self()->windowStatusPolicy(host) == KParts::HtmlSettingsInterface::JSWindowStatusAllow) + emit setStatusBarText(text); +} + +void WebKitPart::slotWindowCloseRequested() +{ + emit m_browserExtension->requestFocus(this); +#if 0 + if (KMessageBox::questionYesNo(m_webView, + i18n("Close window?"), i18n("Confirmation Required"), + KStandardGuiItem::close(), KStandardGuiItem::cancel()) + != KMessageBox::Yes) + return; +#endif + this->deleteLater(); +} + +void WebKitPart::slotShowFeaturePermissionBar(QWebPage::Feature feature) +{ + // FIXME: Allow multiple concurrent feature permission requests. + if (m_featurePermissionBar && m_featurePermissionBar->isVisible()) + return; + + if (!m_featurePermissionBar) { + m_featurePermissionBar = new FeaturePermissionBar(widget()); + + connect(m_featurePermissionBar, SIGNAL(permissionGranted(QWebPage::Feature)), + this, SLOT(slotFeaturePermissionGranted(QWebPage::Feature))); + connect(m_featurePermissionBar, SIGNAL(permissionDenied(QWebPage::Feature)), + this, SLOT(slotFeaturePermissionDenied(QWebPage::Feature))); +// connect(m_passwordBar, SIGNAL(done()), +// this, SLOT(slotSaveFormDataDone())); + QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); + if (lay) + lay->insertWidget(0, m_featurePermissionBar); + } + m_featurePermissionBar->setFeature(feature); +// m_featurePermissionBar->setText(i18n("<html>Do you want to grant the site <b>%1</b> " +// "access to information about your current physical location?", +// url.host())); + m_featurePermissionBar->setText(i18n("<html>Do you want to grant the site " + "access to information about your current physical location?")); + m_featurePermissionBar->animatedShow(); +} + +void WebKitPart::slotFeaturePermissionGranted(QWebPage::Feature feature) +{ + Q_ASSERT(m_featurePermissionBar && m_featurePermissionBar->feature() == feature); + page()->setFeaturePermission(page()->url(), feature, QWebPage::PermissionGrantedByUser); +} + +void WebKitPart::slotFeaturePermissionDenied(QWebPage::Feature feature) +{ + Q_ASSERT(m_featurePermissionBar && m_featurePermissionBar->feature() == feature); + page()->setFeaturePermission(page()->url(), feature, QWebPage::PermissionDeniedByUser); +} + +void WebKitPart::slotSaveFormDataRequested (const QString& key, const QUrl& url) +{ + if (WebSettings::self()->isNonPasswordStorableSite(url.host())) + return; + + if (!WebSettings::self()->askToSaveSitePassword()) + return; + + if (m_passwordBar && m_passwordBar->isVisible()) + return; + + if (!m_passwordBar) { + m_passwordBar = new PasswordBar(widget()); +#if 0 + KWebWallet* wallet = page()->wallet(); + if (!wallet) { + kWarning() << "No wallet instance found! This should never happen!"; + return; + } + connect(m_passwordBar, SIGNAL(saveFormDataAccepted(QString)), + wallet, SLOT(acceptSaveFormDataRequest(QString))); + connect(m_passwordBar, SIGNAL(saveFormDataRejected(QString)), + wallet, SLOT(rejectSaveFormDataRequest(QString))); + connect(m_passwordBar, SIGNAL(done()), + this, SLOT(slotSaveFormDataDone())); +#endif + } + + Q_ASSERT(m_passwordBar); + + m_passwordBar->setUrl(url); + m_passwordBar->setRequestKey(key); + m_passwordBar->setText(i18n("<html>Do you want %1 to remember the login " + "information for <b>%2</b>?</html>", + QCoreApplication::applicationName(), + url.host())); + + QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); + if (lay) + lay->insertWidget(0, m_passwordBar); + + m_passwordBar->animatedShow(); +} + +void WebKitPart::slotSaveFormDataDone() +{ + if (!m_passwordBar) + return; + + QBoxLayout* lay = qobject_cast<QBoxLayout*>(widget()->layout()); + if (lay) + lay->removeWidget(m_passwordBar); +} + +void WebKitPart::addWalletStatusBarIcon () +{ + if (m_statusBarWalletLabel) { + m_statusBarExtension->removeStatusBarItem(m_statusBarWalletLabel); + } else { + m_statusBarWalletLabel = new KUrlLabel(m_statusBarExtension->statusBar()); + m_statusBarWalletLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum)); + m_statusBarWalletLabel->setUseCursor(false); + m_statusBarWalletLabel->setPixmap(QIcon::fromTheme(QStringLiteral("wallet-open")).pixmap(QSize(16,16))); + connect(m_statusBarWalletLabel, SIGNAL(leftClickedUrl()), SLOT(slotLaunchWalletManager())); + connect(m_statusBarWalletLabel, SIGNAL(rightClickedUrl()), SLOT(slotShowWalletMenu())); + } + m_statusBarExtension->addStatusBarItem(m_statusBarWalletLabel, 0, false); +} + +void WebKitPart::slotFillFormRequestCompleted (bool ok) +{ + if ((m_hasCachedFormData = ok)) + addWalletStatusBarIcon(); +} + diff --git b/webkitpart/src/webkitpart.desktop b/webkitpart/src/webkitpart.desktop new file mode 100644 index 000000000..fb77cfc8e --- /dev/null +++ b/webkitpart/src/webkitpart.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Type=Service +Comment=Embeddable HTML component +Comment[ca]=Component HTML incrustable +Comment[ca@valencia]=Component HTML incrustable +Comment[cs]=Zapouzdřitelná HTML komponenta +Comment[da]=HTML-komponent som kan indlejres +Comment[de]=Einbettungsfähige HTML-Komponente +Comment[en_GB]=Embeddable HTML component +Comment[es]=Componente HTML empotrable +Comment[et]=Põimitav HTML-komponent +Comment[fi]=Upotettava HTML-osa +Comment[it]=Componente HTML incorporabile +Comment[ko]=끼워넣을 수 있는 HTML 구성 요소 +Comment[nb]=Innebyggbar HTML-komponent +Comment[nl]=In te bedden HTML-component +Comment[nn]=Innebyggbar HTML-komponent +Comment[pl]=Osadzalny składnik HTML +Comment[pt]=Componente incorporada de HTML +Comment[pt_BR]=Componete HTML embutido +Comment[sk]=Vložiteľný HTML komponent +Comment[sl]=Vgradljiv sestavni del HTML +Comment[sr]=Угнездива ХТМЛ компонента +Comment[sr@ijekavian]=Угњездива ХТМЛ компонента +Comment[sr@ijekavianlatin]=Ugnjezdiva HTML komponenta +Comment[sr@latin]=Ugnezdiva HTML komponenta +Comment[sv]=Inbäddningsbar HTML-komponent +Comment[uk]=Придатний до вбудовування компонент HTML +Comment[x-test]=xxEmbeddable HTML componentxx +Comment[zh_CN]=可嵌入的 HTML 组件 +Comment[zh_TW]=可內嵌的 HTML 元件 +Icon=webkit +MimeType=text/html;application/xml;application/xhtml+xml; +Name=WebKit +Name[ca]=WebKit +Name[ca@valencia]=WebKit +Name[cs]=WebKit +Name[da]=WebKit +Name[de]=WebKit +Name[en_GB]=WebKit +Name[es]=Motor Web +Name[et]=WebKit +Name[fi]=WebKit +Name[it]=WebKit +Name[ko]=WebKit +Name[nl]=WebKit +Name[nn]=Vevmotor +Name[pl]=SilnikSieciowy +Name[pt]=Motor Web +Name[pt_BR]=WebKit +Name[sk]=WebKit +Name[sl]=Spletni pogon +Name[sr]=КуТ‑вебенџин +Name[sr@ijekavian]=КуТ‑вебенџин +Name[sr@ijekavianlatin]=QtWebKit +Name[sr@latin]=QtWebKit +Name[sv]=Webbgränssnitt +Name[uk]=Вебрушій +Name[x-test]=xxWebKitxx +Name[zh_CN]=WebKit +Name[zh_TW]=WebKit +X-KDE-Default-UserAgent=Mozilla/5.0 (%PLATFORM%; %SECURITY%; %OSNAME% %OSVERSION% %SYSTYPE%; %LANGUAGE%) AppleWebKit/534.34 (KHTML, like Gecko) %APPVERSION% Safari/534.34 +X-KDE-ServiceTypes=KParts/ReadOnlyPart,Browser/View +X-KDE-Library=kf5/parts/webkitpart +InitialPreference=12 diff --git b/webkitpart/src/webkitpart.h b/webkitpart/src/webkitpart.h new file mode 100644 index 000000000..4ee00403d --- /dev/null +++ b/webkitpart/src/webkitpart.h @@ -0,0 +1,165 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2007 Trolltech ASA + * Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org> + * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ +#ifndef WEBKITPART_H +#define WEBKITPART_H + +#include "kwebkitpartlib_export.h" + +#include <QtWebKitWidgets/QWebPage> + +#include <KParts/ReadOnlyPart> +#include <QUrl> + +namespace KParts { + class BrowserExtension; + class StatusBarExtension; +} + +class QWebView; +class WebView; +class WebPage; +class SearchBar; +class PasswordBar; +class FeaturePermissionBar; +class KUrlLabel; +class WebBrowserExtension; + +/** + * A KPart wrapper for the QtWebKit's browser rendering engine. + * + * This class attempts to provide the same type of integration into KPart + * plugin applications, such as Konqueror, in much the same way as KHTML. + * + * Unlink the KHTML part however, access into the internals of the rendering + * engine are provided through existing QtWebKit class ; @see QWebView. + * + */ +class KWEBKITPARTLIB_EXPORT WebKitPart : public KParts::ReadOnlyPart +{ + Q_OBJECT + Q_PROPERTY( bool modified READ isModified ) +public: + explicit WebKitPart(QWidget* parentWidget = 0, QObject* parent = Q_NULLPTR, + const QByteArray& cachedHistory = QByteArray(), + const QStringList& = QStringList()); + ~WebKitPart(); + + /** + * Re-implemented for internal reasons. API remains unaffected. + * + * @see KParts::ReadOnlyPart::openUrl + */ + bool openUrl(const QUrl &) Q_DECL_OVERRIDE; + + /** + * Re-implemented for internal reasons. API remains unaffected. + * + * @see KParts::ReadOnlyPart::closeUrl + */ + bool closeUrl() Q_DECL_OVERRIDE; + + /** + * Returns a pointer to the render widget used to display a web page. + * + * @see QWebView. + */ + virtual QWebView *view(); + + /** + * Checks whether the page contains unsubmitted form changes. + * + * @return @p true if form changes exist. + */ + bool isModified() const; + + /** + * Connects the appropriate signals from the given page to the slots + * in this class. + */ + void connectWebPageSignals(WebPage* page); + + void slotShowFeaturePermissionBar(QWebPage::Feature); +protected: + /** + * Re-implemented for internal reasons. API remains unaffected. + * + * @see KParts::ReadOnlyPart::guiActivateEvent + */ + void guiActivateEvent(KParts::GUIActivateEvent *) Q_DECL_OVERRIDE; + + /** + * Re-implemented for internal reasons. API remains unaffected. + * + * @see KParts::ReadOnlyPart::openFile + */ + bool openFile() Q_DECL_OVERRIDE; + +private Q_SLOTS: + void slotShowSecurity(); + void slotShowSearchBar(); + void slotLoadStarted(); + void slotLoadAborted(const QUrl &); + void slotLoadFinished(bool); + + void slotSearchForText(const QString &text, bool backward); + void slotLinkHovered(const QString &); + //void slotSaveFrameState(QWebFrame *frame, QWebHistoryItem *item); + //void slotRestoreFrameState(QWebFrame *frame); + void slotLinkMiddleOrCtrlClicked(const QUrl&); + void slotSelectionClipboardUrlPasted(const QUrl&, const QString&); + + void slotUrlChanged(const QUrl &); + void slotWalletClosed(); + void slotShowWalletMenu(); + void slotLaunchWalletManager(); + void slotDeleteNonPasswordStorableSite(); + void slotRemoveCachedPasswords(); + void slotSetTextEncoding(QTextCodec*); + void slotSetStatusBarText(const QString& text); + void slotWindowCloseRequested(); + void slotSaveFormDataRequested(const QString &, const QUrl &); + void slotSaveFormDataDone(); + void slotFillFormRequestCompleted(bool); + + void slotFeaturePermissionGranted(QWebPage::Feature); + void slotFeaturePermissionDenied(QWebPage::Feature); + +private: + WebPage* page(); + const WebPage* page() const; + void initActions(); + void updateActions(); + void addWalletStatusBarIcon(); + + bool m_emitOpenUrlNotify; + bool m_hasCachedFormData; + bool m_doLoadFinishedActions; + KUrlLabel* m_statusBarWalletLabel; + SearchBar* m_searchBar; + PasswordBar* m_passwordBar; + FeaturePermissionBar* m_featurePermissionBar; + WebBrowserExtension* m_browserExtension; + KParts::StatusBarExtension* m_statusBarExtension; + WebView* m_webView; +}; + +#endif // WEBPART_H diff --git b/webkitpart/src/webkitpart.rc b/webkitpart/src/webkitpart.rc new file mode 100644 index 000000000..2b564ca97 --- /dev/null +++ b/webkitpart/src/webkitpart.rc @@ -0,0 +1,32 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="kwebkitpart" version="8"> +<MenuBar> + <Menu name="file"> + <Action name="saveDocument" /> + <Action name="saveFrame" /> + <Separator /> + <Action name="printPreview" group="print" /> + </Menu> + <Menu name="edit"> + <Action name="selectAll" /> + <Separator /> + <Action name="find" /> + </Menu> + <Menu name="view"> + <Action name="zoomIn" /> + <Action name="zoomOut" /> + <Action name="zoomNormal" /> + <Action name="zoomTextOnly" /> + <Action name="zoomToDPI" /> + <Separator /> + <Action name="setEncoding" /> + <Action name="viewDocumentSource" /> + <ActionList name="debugScriptList" /> + </Menu> +</MenuBar> +<ToolBar name="htmlToolBar" iconText="icononly" iconSize="22" hidden="true"><text>HTML Toolbar</text> + <Action name="zoomIn" /> + <Action name="zoomOut" /> + <Action name="zoomNormal" /> +</ToolBar> +</kpartgui> diff --git b/webkitpart/src/webkitpart_ext.cpp b/webkitpart/src/webkitpart_ext.cpp new file mode 100644 index 000000000..d47c7e8e0 --- /dev/null +++ b/webkitpart/src/webkitpart_ext.cpp @@ -0,0 +1,1237 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <QtWebKit/QtWebKitVersion> +#include "webkitpart_ext.h" + +#include "webkitpart.h" +#include "webkitview.h" +#include "webkitpage.h" +#include "settings/webkitsettings.h" +#include <QtWebKit/QWebSettings> + +#include <KDesktopFile> +#include <KConfigGroup> +#include <KToolInvocation> +#include <KSharedConfig> +#include <KRun> +#include <KProtocolInfo> +#include <QInputDialog> +#include <KLocalizedString> +#include <QTemporaryFile> +#include <KUriFilter> +#include <Sonnet/Dialog> +#include <sonnet/backgroundchecker.h> + +#include <QBuffer> +#include <QVariant> +#include <QClipboard> +#include <QApplication> +#include <QAction> +#include <QPrinter> +#include <QPrintDialog> +#include <QPrintPreviewDialog> +#include <QInputDialog> +#include <QWebHistory> +#include <QMimeData> +#define QL1S(x) QLatin1String(x) +#define QL1C(x) QLatin1Char(x) + +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; +} + +WebBrowserExtension::WebBrowserExtension(WebKitPart *parent, const QByteArray& cachedHistoryData) + :KParts::BrowserExtension(parent), + m_part(parent), + mCurrentPrinter(Q_NULLPTR) +{ + enableAction("cut", false); + enableAction("copy", false); + enableAction("paste", false); + enableAction("print", true); + + if (cachedHistoryData.isEmpty()) { + return; + } + + QBuffer buffer; + buffer.setData(cachedHistoryData); + if (!buffer.open(QIODevice::ReadOnly)) { + return; + } + + // NOTE: When restoring history, webkit PORTING_TODO automatically navigates to + // the previous "currentItem". Since we do not want that to happen, + // we set a property on the WebPage object that is used to allow or + // disallow history navigation in WebPage::acceptNavigationRequest. + view()->page()->setProperty("HistoryNavigationLocked", true); + QDataStream s (&buffer); + s >> *(view()->history()); +} + +WebBrowserExtension::~WebBrowserExtension() +{ +} + +WebView* WebBrowserExtension::view() +{ + if (!m_view && m_part) { + m_view = qobject_cast<WebView*>(m_part->view()); + } + + return m_view; +} + +int WebBrowserExtension::xOffset() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (view()) + return view()->page()->scrollPosition().x(); +#endif + + return KParts::BrowserExtension::xOffset(); +} + +int WebBrowserExtension::yOffset() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (view()) + return view()->page()->scrollPosition().y(); +#endif + + return KParts::BrowserExtension::yOffset(); +} + +void WebBrowserExtension::saveState(QDataStream &stream) +{ + // TODO: Save information such as form data from the current page. + QWebHistory* history = (view() ? view()->history() : 0); + const int historyIndex = (history ? history->currentItemIndex() : -1); + const QUrl historyUrl = (history && historyIndex > -1) ? QUrl(history->currentItem().url()) : m_part->url(); + + stream << historyUrl + << static_cast<qint32>(xOffset()) + << static_cast<qint32>(yOffset()) + << historyIndex + << m_historyData; +} + +void WebBrowserExtension::restoreState(QDataStream &stream) +{ + QUrl u; + QByteArray historyData; + qint32 xOfs = -1, yOfs = -1, historyItemIndex = -1; + stream >> u >> xOfs >> yOfs >> historyItemIndex >> historyData; + + QWebHistory* history = (view() ? view()->page()->history() : 0); + if (history) { + bool success = false; + if (history->count() == 0) { // Handle restoration: crash recovery, tab close undo, session restore + if (!historyData.isEmpty()) { + historyData = qUncompress(historyData); // uncompress the history data... + QBuffer buffer (&historyData); + if (buffer.open(QIODevice::ReadOnly)) { + QDataStream stream (&buffer); + view()->page()->setProperty("HistoryNavigationLocked", true); + stream >> *history; + QWebHistoryItem currentItem (history->currentItem()); + if (currentItem.isValid()) { + if (currentItem.isValid() && (xOfs != -1 || yOfs != -1)) { + const QPoint scrollPos (xOfs, yOfs); +// currentItem.setUserData(scrollPos); + } + // NOTE 1: The following Konqueror specific workaround is necessary + // because Konqueror only preserves information for the last visited + // page. However, we save the entire history content in saveState and + // and hence need to elimiate all but the current item here. + // NOTE 2: This condition only applies when Konqueror is restored from + // abnormal termination ; a crash and/or a session restoration. + if (QCoreApplication::applicationName() == QLatin1String("konqueror")) { + history->clear(); + } + //kDebug() << "Restoring URL:" << currentItem.url(); + m_part->setProperty("NoEmitOpenUrlNotification", true); + history->goToItem(currentItem); + } + } + } + success = (history->count() > 0); + } else { // Handle navigation: back and forward button navigation. + //kDebug() << "history count:" << history->count() << "request index:" << historyItemIndex; + if (history->count() > historyItemIndex && historyItemIndex > -1) { + QWebHistoryItem item (history->itemAt(historyItemIndex)); + //kDebug() << "URL:" << u << "Item URL:" << item.url(); + if (u == item.url()) { + if (item.isValid() && (xOfs != -1 || yOfs != -1)) { + const QPoint scrollPos (xOfs, yOfs); +// item.setUserData(scrollPos); + } + m_part->setProperty("NoEmitOpenUrlNotification", true); + history->goToItem(item); + success = true; + } + } + } + + if (success) { + return; + } + } + + // As a last resort, in case the history restoration logic above fails, + // attempt to open the requested URL directly. + qDebug() << "Normal history navgation logic failed! Falling back to opening url directly."; + m_part->openUrl(u); +} + + +void WebBrowserExtension::cut() +{ + if (view()) + view()->triggerPageAction(QWebPage::Cut); +} + +void WebBrowserExtension::copy() +{ + if (view()) + view()->triggerPageAction(QWebPage::Copy); +} + +void WebBrowserExtension::paste() +{ + if (view()) + view()->triggerPageAction(QWebPage::Paste); +} + +void WebBrowserExtension::slotSaveDocument() +{ + if (view()) + emit saveUrl(view()->url()); +} + +void WebBrowserExtension::slotSaveFrame() +{ + if (view()) + emit saveUrl(view()->page()->url()); // TODO lol +} + +void WebBrowserExtension::print() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (view()) { + mCurrentPrinter = new QPrinter(); + QPointer<QPrintDialog> dialog = new QPrintDialog(mCurrentPrinter, Q_NULLPTR); + dialog->setWindowTitle(i18n("Print Document")); + if (dialog->exec() != QDialog::Accepted) { + slotHandlePagePrinted(false); + delete dialog; + return; + } + delete dialog; + view()->page()->print(mCurrentPrinter, invoke(this, &WebBrowserExtension::slotHandlePagePrinted)); + } +#endif +} + +void WebBrowserExtension::slotHandlePagePrinted(bool result) +{ + Q_UNUSED(result); + delete mCurrentPrinter; + mCurrentPrinter = Q_NULLPTR; +} + + +void WebBrowserExtension::updateEditActions() +{ + if (!view()) + return; + + enableAction("cut", view()->pageAction(QWebPage::Cut)->isEnabled()); + enableAction("copy", view()->pageAction(QWebPage::Copy)->isEnabled()); + enableAction("paste", view()->pageAction(QWebPage::Paste)->isEnabled()); +} + +void WebBrowserExtension::updateActions() +{ + const QString protocol (m_part->url().scheme()); + const bool isValidDocument = (protocol != QL1S("about") && protocol != QL1S("error")); + enableAction("print", isValidDocument); +} + +void WebBrowserExtension::searchProvider() +{ + if (!view()) + return; + + QAction *action = qobject_cast<QAction*>(sender()); + if (!action) + return; + + QUrl url = action->data().toUrl(); + + if (url.host().isEmpty()) { + KUriFilterData data; + data.setData(action->data().toString()); + if (KUriFilter::self()->filterSearchUri(data, KUriFilter::WebShortcutFilter)) + url = data.uri(); + } + + if (!url.isValid()) + return; + + KParts::BrowserArguments bargs; + bargs.frameName = QL1S("_blank"); + emit openUrlRequest(url, KParts::OpenUrlArguments(), bargs); +} + +void WebBrowserExtension::reparseConfiguration() +{ + // Force the configuration stuff to reparse... + WebSettings::self()->init(); +} + +void WebBrowserExtension::disableScrolling() +{ + QWebView* currentView = view(); + QWebPage* page = currentView ? currentView->page() : 0; + + if (!page) + return; + + page->runJavaScript(QStringLiteral("document.documentElement.style.overflow = 'hidden';")); +} + +void WebBrowserExtension::zoomIn() +{ + if (view()) + view()->setZoomFactor(view()->zoomFactor() + 0.1); +} + +void WebBrowserExtension::zoomOut() +{ + if (view()) + view()->setZoomFactor(view()->zoomFactor() - 0.1); +} + +void WebBrowserExtension::zoomNormal() +{ + if (view()) { + if (WebSettings::self()->zoomToDPI()) + view()->setZoomFactor(view()->logicalDpiY() / 96.0f); + else + view()->setZoomFactor(1); + } +} + +void WebBrowserExtension::toogleZoomTextOnly() +{ + if (!view()) + return; + + KConfigGroup cgHtml(KSharedConfig::openConfig(), "HTML Settings"); + bool zoomTextOnly = cgHtml.readEntry( "ZoomTextOnly", false ); + cgHtml.writeEntry("ZoomTextOnly", !zoomTextOnly); + cgHtml.sync(); + + // view()->settings()->setAttribute(QWebSettings::ZoomTextOnly, !zoomTextOnly); +} + +void WebBrowserExtension::toogleZoomToDPI() +{ + if (!view()) + return; + + bool zoomToDPI = !WebSettings::self()->zoomToDPI(); + WebSettings::self()->setZoomToDPI(zoomToDPI); + + if (zoomToDPI) + view()->setZoomFactor(view()->zoomFactor() * view()->logicalDpiY() / 96.0f); + else + view()->setZoomFactor(view()->zoomFactor() * 96.0f / view()->logicalDpiY()); + + // Recompute default font-sizes since they are only DPI dependent when zoomToDPI is false. + WebSettings::self()->computeFontSizes(view()->logicalDpiY()); +} + +void WebBrowserExtension::slotSelectAll() +{ + if (view()) + view()->triggerPageAction(QWebPage::SelectAll); +} + +void WebBrowserExtension::slotSaveImageAs() +{ + if (view()) + view()->triggerPageAction(QWebPage::DownloadImageToDisk); +} + +void WebBrowserExtension::slotSendImage() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + QStringList urls; + urls.append(view()->contextMenuResult().mediaUrl().path()); + const QString subject = view()->contextMenuResult().mediaUrl().path(); + KToolInvocation::invokeMailer(QString(), QString(), QString(), subject, + QString(), //body + QString(), + urls); // attachments +#endif +} + +void WebBrowserExtension::slotCopyImageURL() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + QUrl safeURL = view()->contextMenuResult().mediaUrl(); + safeURL.setPassword(QString()); + // Set it in both the mouse selection and in the clipboard + QMimeData* mimeData = new QMimeData; +//TODO: Porting: test + QList<QUrl> safeURLList; + safeURLList.append(safeURL); + mimeData->setUrls(safeURLList); + QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); + + mimeData = new QMimeData; + mimeData->setUrls(safeURLList); + QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection); +#endif +} + + +void WebBrowserExtension::slotCopyImage() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + QUrl safeURL; //(view()->contextMenuResult().imageUrl()); + safeURL.setPassword(QString()); + + // Set it in both the mouse selection and in the clipboard + QMimeData* mimeData = new QMimeData; +// mimeData->setImageData(view()->contextMenuResult().pixmap()); +//TODO: Porting: test + QList<QUrl> safeURLList; + safeURLList.append(safeURL); + mimeData->setUrls(safeURLList); + QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); + + mimeData = new QMimeData; +// mimeData->setImageData(view()->contextMenuResult().pixmap()); + mimeData->setUrls(safeURLList); + QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection); +#endif +} + +void WebBrowserExtension::slotViewImage() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (view()) + emit createNewWindow(view()->contextMenuResult().mediaUrl()); +#endif +} + +void WebBrowserExtension::slotBlockImage() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + bool ok = false; + const QString url = QInputDialog::getText(view(), i18n("Add URL to Filter"), + i18n("Enter the URL:"), QLineEdit::Normal, + view()->contextMenuResult().mediaUrl().toString(), + &ok); + if (ok) { + WebSettings::self()->addAdFilter(url); + reparseConfiguration(); + } +#endif +} + +void WebBrowserExtension::slotBlockHost() +{ + if (!view()) + return; + + QUrl url; // (view()->contextMenuResult().imageUrl()); + url.setPath(QL1S("/*")); + WebSettings::self()->addAdFilter(url.toString(QUrl::RemoveUserInfo | QUrl::RemovePort)); + reparseConfiguration(); +} + +void WebBrowserExtension::slotCopyLinkURL() +{ + if (view()) + view()->triggerPageAction(QWebPage::CopyLinkToClipboard); +} + +void WebBrowserExtension::slotCopyLinkText() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (view()) { + QMimeData* data = new QMimeData; + data->setText(view()->contextMenuResult().linkText()); + QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard); + } +#endif +} + +void WebBrowserExtension::slotCopyEmailAddress() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (view()) { + QMimeData* data = new QMimeData; + const QUrl url(view()->contextMenuResult().linkUrl()); + data->setText(url.path()); + QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard); + } +#endif +} + +void WebBrowserExtension::slotSaveLinkAs() +{ + if (view()) + view()->triggerPageAction(QWebPage::DownloadLinkToDisk); +} + +void WebBrowserExtension::slotViewDocumentSource() +{ + if (!view()) + return; + + const QUrl pageUrl (view()->url()); + if (pageUrl.isLocalFile()) { + KRun::runUrl(pageUrl, QL1S("text/plain"), view(), false); + } else { + view()->page()->toHtml([this](const QString& html) { + QTemporaryFile tempFile; + tempFile.setFileTemplate(tempFile.fileTemplate() + QL1S(".html")); + tempFile.setAutoRemove(false); + if (tempFile.open()) { + tempFile.write(html.toUtf8()); + KRun::runUrl(QUrl::fromLocalFile(tempFile.fileName()), QL1S("text/plain"), view(), true, false); + } + }); + } +} + +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) +static bool isMultimediaElement(QWebContextMenuData::MediaType mediaType) +{ + switch(mediaType) + { + case QWebContextMenuData::MediaTypeVideo: + case QWebContextMenuData::MediaTypeAudio: + return true; + default: + return false; + } +} +#endif + +void WebBrowserExtension::slotLoopMedia() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + QWebContextMenuData data = view()->contextMenuResult(); + if (!isMultimediaElement( data.mediaType())) + return; + view()->page()->triggerAction(QWebPage::ToggleMediaLoop); +#endif +} + +void WebBrowserExtension::slotMuteMedia() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + QWebContextMenuData data = view()->contextMenuResult(); + if (!isMultimediaElement( data.mediaType())) + return; + view()->page()->triggerAction(QWebPage::ToggleMediaMute); +#endif +} + +void WebBrowserExtension::slotPlayMedia() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + QWebContextMenuData data = view()->contextMenuResult(); + if (!isMultimediaElement( data.mediaType())) + return; + view()->page()->triggerAction(QWebPage::ToggleMediaPlayPause); +#endif +} + +void WebBrowserExtension::slotShowMediaControls() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + QWebContextMenuData data = view()->contextMenuResult(); + if (!isMultimediaElement( data.mediaType())) + return; + view()->page()->triggerAction(QWebPage::ToggleMediaControls); +#endif +} + +#if 0 +static QUrl mediaUrlFrom(QWebElement& element) +{ + QWebFrame* frame = element.webFrame(); + QString src = frame ? element.attribute(QL1S("src")) : QString(); + if (src.isEmpty()) + src = frame ? element.evaluateJavaScript(QL1S("this.src")).toString() : QString(); + + if (src.isEmpty()) + return QUrl(); + + return QUrl(frame->baseUrl().resolved(QUrl::fromEncoded(QUrl::toPercentEncoding(src), QUrl::StrictMode))); +} +#endif + +void WebBrowserExtension::slotSaveMedia() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + QWebContextMenuData data = view()->contextMenuResult(); + if (!isMultimediaElement( data.mediaType())) + return; + emit saveUrl(data.mediaUrl()); +#endif +} + +void WebBrowserExtension::slotCopyMedia() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + QWebContextMenuData data = view()->contextMenuResult(); + if (!isMultimediaElement( data.mediaType())) + return; + + QUrl safeURL(data.mediaUrl()); + if (!safeURL.isValid()) + return; + + safeURL.setPassword(QString()); + // Set it in both the mouse selection and in the clipboard + QMimeData* mimeData = new QMimeData; +//TODO: Porting: test + QList<QUrl> safeURLList; + safeURLList.append(safeURL); + mimeData->setUrls(safeURLList); + QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); + + mimeData = new QMimeData; + mimeData->setUrls(safeURLList); + QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection); +#endif +} + +void WebBrowserExtension::slotTextDirectionChanged() +{ + QAction* action = qobject_cast<QAction*>(sender()); + if (action) { + bool ok = false; + const int value = action->data().toInt(&ok); + if (ok) { + view()->triggerPageAction(static_cast<QWebPage::WebAction>(value)); + } + } +} + +static QVariant execJScript(WebView* view, const QString& script) +{ +#if 0 + QWebElement element (view->contextMenuResult().element()); + if (element.isNull()) + return QVariant(); + return element.evaluateJavaScript(script); +#endif + return QVariant(); +} + +void WebBrowserExtension::slotCheckSpelling() +{ + const QString text (execJScript(view(), QL1S("this.value")).toString()); + + if ( text.isEmpty() ) { + return; + } + + m_spellTextSelectionStart = 0; + m_spellTextSelectionEnd = 0; + + Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker; + Sonnet::Dialog* spellDialog = new Sonnet::Dialog(backgroundSpellCheck, view()); + backgroundSpellCheck->setParent(spellDialog); + spellDialog->setAttribute(Qt::WA_DeleteOnClose, true); + spellDialog->showSpellCheckCompletionMessage(true); + connect(spellDialog, SIGNAL(replace(QString,int,QString)), this, SLOT(spellCheckerCorrected(QString,int,QString))); + connect(spellDialog, SIGNAL(misspelling(QString,int)), this, SLOT(spellCheckerMisspelling(QString,int))); + spellDialog->setBuffer(text); + spellDialog->show(); +} + +void WebBrowserExtension::slotSpellCheckSelection() +{ + QString text (execJScript(view(), QL1S("this.value")).toString()); + + if ( text.isEmpty() ) { + return; + } + + m_spellTextSelectionStart = qMax(0, execJScript(view(), QL1S("this.selectionStart")).toInt()); + m_spellTextSelectionEnd = qMax(0, execJScript(view(), QL1S("this.selectionEnd")).toInt()); + // kDebug() << "selection start:" << m_spellTextSelectionStart << "end:" << m_spellTextSelectionEnd; + + Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker; + Sonnet::Dialog* spellDialog = new Sonnet::Dialog(backgroundSpellCheck, view()); + backgroundSpellCheck->setParent(spellDialog); + spellDialog->setAttribute(Qt::WA_DeleteOnClose, true); + spellDialog->showSpellCheckCompletionMessage(true); + connect(spellDialog, SIGNAL(replace(QString,int,QString)), this, SLOT(spellCheckerCorrected(QString,int,QString))); + connect(spellDialog, SIGNAL(misspelling(QString,int)), this, SLOT(spellCheckerMisspelling(QString,int))); + connect(spellDialog, SIGNAL(done(QString)), this, SLOT(slotSpellCheckDone(QString))); + spellDialog->setBuffer(text.mid(m_spellTextSelectionStart, (m_spellTextSelectionEnd - m_spellTextSelectionStart))); + spellDialog->show(); +} + +void WebBrowserExtension::spellCheckerCorrected(const QString& original, int pos, const QString& replacement) +{ + // Adjust the selection end... + if (m_spellTextSelectionEnd > 0) { + m_spellTextSelectionEnd += qMax (0, (replacement.length() - original.length())); + } + + const int index = pos + m_spellTextSelectionStart; + QString script(QL1S("this.value=this.value.substring(0,")); + script += QString::number(index); + script += QL1S(") + \""); + script += replacement; + script += QL1S("\" + this.value.substring("); + script += QString::number(index + original.length()); + script += QL1S(")"); + + //kDebug() << "**** script:" << script; + execJScript(view(), script); +} + +void WebBrowserExtension::spellCheckerMisspelling(const QString& text, int pos) +{ + // kDebug() << text << pos; + QString selectionScript (QL1S("this.setSelectionRange(")); + selectionScript += QString::number(pos + m_spellTextSelectionStart); + selectionScript += QL1C(','); + selectionScript += QString::number(pos + text.length() + m_spellTextSelectionStart); + selectionScript += QL1C(')'); + execJScript(view(), selectionScript); +} + +void WebBrowserExtension::slotSpellCheckDone(const QString&) +{ + // Restore the text selection if one was present before we started the + // spell check. + if (m_spellTextSelectionStart > 0 || m_spellTextSelectionEnd > 0) { + QString script (QL1S("; this.setSelectionRange(")); + script += QString::number(m_spellTextSelectionStart); + script += QL1C(','); + script += QString::number(m_spellTextSelectionEnd); + script += QL1C(')'); + execJScript(view(), script); + } +} + + +void WebBrowserExtension::saveHistory() +{ + QWebHistory* history = (view() ? view()->history() : 0); + + if (history && history->count() > 0) { + //kDebug() << "Current history: index=" << history->currentItemIndex() << "url=" << history->currentItem().url(); + QByteArray histData; + QBuffer buff (&histData); + m_historyData.clear(); + if (buff.open(QIODevice::WriteOnly)) { + QDataStream stream (&buff); + stream << *history; + m_historyData = qCompress(histData, 9); + } + QWidget* mainWidget = m_part ? m_part->widget() : 0; + QWidget* frameWidget = mainWidget ? mainWidget->parentWidget() : 0; + if (frameWidget) { + emit saveHistory(frameWidget, m_historyData); + // kDebug() << "# of items:" << history->count() << "current item:" << history->currentItemIndex() << "url:" << history->currentItem().url(); + } + } else { + Q_ASSERT(false); // should never happen!!! + } +} + +void WebBrowserExtension::slotPrintPreview() +{ +#if 0 + // Make it non-modal, in case a redirection deletes the part + QPointer<QPrintPreviewDialog> dlg (new QPrintPreviewDialog(view())); + connect(dlg.data(), SIGNAL(paintRequested(QPrinter*)), + view()->page()->currentFrame(), SLOT(print(QPrinter*))); + dlg->exec(); + delete dlg; +#endif +} + +void WebBrowserExtension::slotOpenSelection() +{ + QAction *action = qobject_cast<QAction*>(sender()); + if (action) { + KParts::BrowserArguments browserArgs; + browserArgs.frameName = QStringLiteral("_blank"); + emit openUrlRequest(QUrl(action->data().toUrl()), KParts::OpenUrlArguments(), browserArgs); + } +} + +void WebBrowserExtension::slotLinkInTop() +{ +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) + if (!view()) + return; + + KParts::OpenUrlArguments uargs; + uargs.setActionRequestedByUser(true); + + KParts::BrowserArguments bargs; + bargs.frameName = QL1S("_top"); + + const QUrl url(view()->contextMenuResult().linkUrl()); + + emit openUrlRequest(url, uargs, bargs); +#endif +} + +//// + +WebTextExtension::WebTextExtension(WebKitPart* part) + : KParts::TextExtension(part) +{ + connect(part->view(), SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged())); +} + +WebKitPart* WebTextExtension::part() const +{ + return static_cast<WebKitPart*>(parent()); +} + +bool WebTextExtension::hasSelection() const +{ + return part()->view()->hasSelection(); +} + +QString WebTextExtension::selectedText(Format format) const +{ + switch(format) { + case PlainText: + return part()->view()->selectedText(); + case HTML: + // PORTING_TODO selectedText might not be html + return part()->view()->selectedText(); + } + return QString(); +} + +QString WebTextExtension::completeText(Format format) const +{ + // TODO David will hunt me down with a rusty spork if he sees this + QEventLoop ev; + QString str; + switch(format) { + case PlainText: + part()->view()->page()->toPlainText([&ev,&str](const QString& data) { + str = data; + ev.quit(); + }); + case HTML: + part()->view()->page()->toHtml([&ev,&str](const QString& data) { + str = data; + ev.quit(); + }); + } + ev.exec(); + return QString(); +} + +//// + +WebHtmlExtension::WebHtmlExtension(WebKitPart* part) + : KParts::HtmlExtension(part) +{ +} + + +QUrl WebHtmlExtension::baseUrl() const +{ + return part()->view()->page()->url(); +} + +bool WebHtmlExtension::hasSelection() const +{ + return part()->view()->hasSelection(); +} + +KParts::SelectorInterface::QueryMethods WebHtmlExtension::supportedQueryMethods() const +{ + return (KParts::SelectorInterface::EntireContent + | KParts::SelectorInterface::SelectedContent); +} + +#if 0 +static KParts::SelectorInterface::Element convertWebElement(const QWebElement& webElem) +{ + KParts::SelectorInterface::Element element; + element.setTagName(webElem.tagName()); + Q_FOREACH(const QString &attr, webElem.attributeNames()) { + element.setAttribute(attr, webElem.attribute(attr)); + } + return element; +} +#endif + +static QString queryOne(const QString& query) +{ + QString jsQuery = QL1S("(function(query) { var element; var selectedElement = window.getSelection().getRangeAt(0).cloneContents().querySelector(\""); + jsQuery += query; + jsQuery += QL1S("\"); if (selectedElement && selectedElement.length > 0) { element = new Object; " + "element.tagName = String(selectedElements[0].tagName); element.href = String(selectedElements[0].href); } " + "return element; }())"); + return jsQuery; +} + +static QString queryAll(const QString& query) +{ + QString jsQuery = QL1S("(function(query) { var elements = []; var selectedElements = window.getSelection().getRangeAt(0).cloneContents().querySelectorAll(\""); + jsQuery += query; + jsQuery += QL1S("\"); var numSelectedElements = (selectedElements ? selectedElements.length : 0);" + "for (var i = 0; i < numSelectedElements; ++i) { var element = new Object; " + "element.tagName = String(selectedElements[i].tagName); element.href = String(selectedElements[i].href);" + "elements.push(element); } return elements; } ())"); + return jsQuery; +} + +static KParts::SelectorInterface::Element convertSelectionElement(const QVariant& variant) +{ + KParts::SelectorInterface::Element element; + if (!variant.isNull() && variant.type() == QVariant::Map) { + const QVariantMap elementMap (variant.toMap()); + element.setTagName(elementMap.value(QL1S("tagName")).toString()); + element.setAttribute(QL1S("href"), elementMap.value(QL1S("href")).toString()); + } + return element; +} + +static QList<KParts::SelectorInterface::Element> convertSelectionElements(const QVariant& variant) +{ + QList<KParts::SelectorInterface::Element> elements; + const QVariantList resultList (variant.toList()); + Q_FOREACH(const QVariant& result, resultList) { + const QVariantMap elementMap = result.toMap(); + KParts::SelectorInterface::Element element; + element.setTagName(elementMap.value(QL1S("tagName")).toString()); + element.setAttribute(QL1S("href"), elementMap.value(QL1S("href")).toString()); + elements.append(element); + } + return elements; +} + +KParts::SelectorInterface::Element WebHtmlExtension::querySelector(const QString& query, KParts::SelectorInterface::QueryMethod method) const +{ + KParts::SelectorInterface::Element element; + + // If the specified method is None, return an empty list... + if (method == KParts::SelectorInterface::None) + return element; + + // If the specified method is not supported, return an empty list... + if (!(supportedQueryMethods() & method)) + return element; + +#if 0 + switch (method) { + case KParts::SelectorInterface::EntireContent: { + const QWebFrame* webFrame = part()->view()->page()->mainFrame(); + element = convertWebElement(webFrame->findFirstElement(query)); + break; + } + case KParts::SelectorInterface::SelectedContent: { + QWebFrame* webFrame = part()->view()->page()->mainFrame(); + element = convertSelectionElement(webFrame->evaluateJavaScript(queryOne(query))); + break; + } + default: + break; + } +#endif + + return element; +} + +QList<KParts::SelectorInterface::Element> WebHtmlExtension::querySelectorAll(const QString& query, KParts::SelectorInterface::QueryMethod method) const +{ + QList<KParts::SelectorInterface::Element> elements; + + // If the specified method is None, return an empty list... + if (method == KParts::SelectorInterface::None) + return elements; + + // If the specified method is not supported, return an empty list... + if (!(supportedQueryMethods() & method)) + return elements; +#if 0 + switch (method) { + case KParts::SelectorInterface::EntireContent: { + const QWebFrame* webFrame = part()->view()->page()->mainFrame(); + const QWebElementCollection collection = webFrame->findAllElements(query); + elements.reserve(collection.count()); + Q_FOREACH(const QWebElement& element, collection) + elements.append(convertWebElement(element)); + break; + } + case KParts::SelectorInterface::SelectedContent: { + QWebFrame* webFrame = part()->view()->page()->mainFrame(); + elements = convertSelectionElements(webFrame->evaluateJavaScript(queryAll(query))); + break; + } + default: + break; + } +#endif + return elements; +} + +QVariant WebHtmlExtension::htmlSettingsProperty(KParts::HtmlSettingsInterface::HtmlSettingsType type) const +{ + QWebView* view = part() ? part()->view() : 0; + QWebPage* page = view ? view->page() : 0; + QWebSettings* settings = page ? page->settings() : 0; + + if (settings) { + switch (type) { + case KParts::HtmlSettingsInterface::AutoLoadImages: + return settings->testAttribute(QWebSettings::AutoLoadImages); + case KParts::HtmlSettingsInterface::JavaEnabled: + return false; // settings->testAttribute(QWebSettings::JavaEnabled); + case KParts::HtmlSettingsInterface::JavascriptEnabled: + return settings->testAttribute(QWebSettings::JavascriptEnabled); + case KParts::HtmlSettingsInterface::PluginsEnabled: + return settings->testAttribute(QWebSettings::PluginsEnabled); + case KParts::HtmlSettingsInterface::DnsPrefetchEnabled: + return false; //settings->testAttribute(QWebSettings::DnsPrefetchEnabled); + case KParts::HtmlSettingsInterface::MetaRefreshEnabled: + return view->pageAction(QWebPage::Stop)->isEnabled(); + case KParts::HtmlSettingsInterface::LocalStorageEnabled: + return settings->testAttribute(QWebSettings::LocalStorageEnabled); + case KParts::HtmlSettingsInterface::OfflineStorageDatabaseEnabled: + return false; //settings->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled); + case KParts::HtmlSettingsInterface::OfflineWebApplicationCacheEnabled: + return false ;//settings->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled); + case KParts::HtmlSettingsInterface::PrivateBrowsingEnabled: + return false; //settings->testAttribute(QWebSettings::PrivateBrowsingEnabled); + case KParts::HtmlSettingsInterface::UserDefinedStyleSheetURL: + return false; //settings->userStyleSheetUrl(); + default: + break; + } + } + + return QVariant(); +} + +bool WebHtmlExtension::setHtmlSettingsProperty(KParts::HtmlSettingsInterface::HtmlSettingsType type, const QVariant& value) +{ + QWebView* view = part() ? part()->view() : 0; + QWebPage* page = view ? view->page() : 0; + QWebSettings* settings = page ? page->settings() : 0; + + if (settings) { + switch (type) { + case KParts::HtmlSettingsInterface::AutoLoadImages: + settings->setAttribute(QWebSettings::AutoLoadImages, value.toBool()); + return true; + case KParts::HtmlSettingsInterface::JavaEnabled: + //settings->setAttribute(QWebESettings::JavaEnabled, value.toBool()); + return false; + case KParts::HtmlSettingsInterface::JavascriptEnabled: + settings->setAttribute(QWebSettings::JavascriptEnabled, value.toBool()); + return true; + case KParts::HtmlSettingsInterface::PluginsEnabled: + settings->setAttribute(QWebSettings::PluginsEnabled, value.toBool()); + return true; + case KParts::HtmlSettingsInterface::DnsPrefetchEnabled: +// settings->setAttribute(QWebSettings::DnsPrefetchEnabled, value.toBool()); + return false; + case KParts::HtmlSettingsInterface::MetaRefreshEnabled: + view->triggerPageAction(QWebPage::Stop); + return true; + case KParts::HtmlSettingsInterface::LocalStorageEnabled: + settings->setAttribute(QWebSettings::LocalStorageEnabled, value.toBool()); + return false; + case KParts::HtmlSettingsInterface::OfflineStorageDatabaseEnabled: + //settings->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, value.toBool()); + return false; + case KParts::HtmlSettingsInterface::OfflineWebApplicationCacheEnabled: + //settings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, value.toBool()); + return false; + case KParts::HtmlSettingsInterface::PrivateBrowsingEnabled: + //settings->setAttribute(QWebEnngineSettings::PrivateBrowsingEnabled, value.toBool()); + return false; + case KParts::HtmlSettingsInterface::UserDefinedStyleSheetURL: + //kDebug() << "Setting user style sheet for" << page << "to" << value.toUrl(); + // settings->setUserStyleSheetUrl(value.toUrl()); + return false; + default: + break; + } + } + + return false; +} + +WebKitPart* WebHtmlExtension::part() const +{ + return static_cast<WebKitPart*>(parent()); +} + +WebScriptableExtension::WebScriptableExtension(WebKitPart* part) + : ScriptableExtension(part) +{ +} + +QVariant WebScriptableExtension::rootObject() +{ + return QVariant::fromValue(KParts::ScriptableExtension::Object(this, reinterpret_cast<quint64>(this))); +} + +bool WebScriptableExtension::setException (KParts::ScriptableExtension* callerPrincipal, const QString& message) +{ + return KParts::ScriptableExtension::setException (callerPrincipal, message); +} + +QVariant WebScriptableExtension::get (KParts::ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName) +{ + //kDebug() << "caller:" << callerPrincipal << "id:" << objId << "propName:" << propName; + return callerPrincipal->get (0, objId, propName); +} + +bool WebScriptableExtension::put (KParts::ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName, const QVariant& value) +{ + return KParts::ScriptableExtension::put (callerPrincipal, objId, propName, value); +} + +static QVariant exception(const char* msg) +{ + qWarning() << msg; + return QVariant::fromValue(KParts::ScriptableExtension::Exception(QString::fromLatin1(msg))); +} + +QVariant WebScriptableExtension::evaluateScript (KParts::ScriptableExtension* callerPrincipal, + quint64 contextObjectId, + const QString& code, + KParts::ScriptableExtension::ScriptLanguage lang) +{ + Q_UNUSED(contextObjectId); + Q_UNUSED(code) + //kDebug() << "principal:" << callerPrincipal << "id:" << contextObjectId << "language:" << lang << "code:" << code; + + if (lang != ECMAScript) + return exception("unsupported language"); + + + KParts::ReadOnlyPart* part = callerPrincipal ? qobject_cast<KParts::ReadOnlyPart*>(callerPrincipal->parent()) : 0; + // QWebFrame* frame = part ? qobject_cast<QWebFrame*>(part->parent()) : 0; + // if (!frame) + return exception("failed to resolve principal"); +#if 0 + QVariant result (frame->evaluateJavaScript(code)); + + if (result.type() == QVariant::Map) { + const QVariantMap map (result.toMap()); + for (QVariantMap::const_iterator it = map.constBegin(), itEnd = map.constEnd(); it != itEnd; ++it) { + callerPrincipal->put(callerPrincipal, 0, it.key(), it.value()); + } + } else { + const QString propName(code.contains(QLatin1String("__nsplugin")) ? QLatin1String("__nsplugin") : QString()); + callerPrincipal->put(callerPrincipal, 0, propName, result.toString()); + } + + return QVariant::fromValue(ScriptableExtension::Null()); +#endif +} + +bool WebScriptableExtension::isScriptLanguageSupported (KParts::ScriptableExtension::ScriptLanguage lang) const +{ + return (lang == KParts::ScriptableExtension::ECMAScript); +} + +QVariant WebScriptableExtension::encloserForKid (KParts::ScriptableExtension* kid) +{ +#if 0 + KParts::ReadOnlyPart* part = kid ? qobject_cast<KParts::ReadOnlyPart*>(kid->parent()) : 0; + QWebFrame* frame = part ? qobject_cast<QWebFrame*>(part->parent()) : 0; + if (frame) { + return QVariant::fromValue(KParts::ScriptableExtension::Object(kid, reinterpret_cast<quint64>(kid))); + } +#endif + + return QVariant::fromValue(ScriptableExtension::Null()); +} + +WebKitPart* WebScriptableExtension::part() +{ + return qobject_cast<WebKitPart*>(parent()); +} + diff --git b/webkitpart/src/webkitpart_ext.h b/webkitpart/src/webkitpart_ext.h new file mode 100644 index 000000000..b375cede2 --- /dev/null +++ b/webkitpart/src/webkitpart_ext.h @@ -0,0 +1,201 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef WEBKITPART_EXT_H +#define WEBKITPART_EXT_H + +#include "kwebkitpartlib_export.h" + +#include <QPointer> + +#include <KParts/BrowserExtension> +#include <KParts/TextExtension> +#include <KParts/HtmlExtension> +#include <KParts/HtmlSettingsInterface> +#include <KParts/ScriptableExtension> +#include <KParts/SelectorInterface> + +class QUrl; +class WebPart; +class WebView; +class QPrinter; +class KWEBKITPARTLIB_EXPORT WebBrowserExtension : public KParts::BrowserExtension +{ + Q_OBJECT + +public: + WebBrowserExtension(WebKitPart *parent, const QByteArray& cachedHistoryData); + ~WebBrowserExtension(); + + virtual int xOffset() override; + virtual int yOffset() override; + virtual void saveState(QDataStream &) override; + virtual void restoreState(QDataStream &) override; + void saveHistory(); + +Q_SIGNALS: + void saveUrl(const QUrl &); + void saveHistory(QObject*, const QByteArray&); + +public Q_SLOTS: + void cut(); + void copy(); + void paste(); + void print(); + + void slotSaveDocument(); + void slotSaveFrame(); + void searchProvider(); + void reparseConfiguration(); + void disableScrolling(); + + void zoomIn(); + void zoomOut(); + void zoomNormal(); + void toogleZoomTextOnly(); + void toogleZoomToDPI(); + void slotSelectAll(); + + void slotSaveImageAs(); + void slotSendImage(); + void slotCopyImageURL(); + void slotCopyImage(); + void slotViewImage(); + void slotBlockImage(); + void slotBlockHost(); + + void slotCopyLinkURL(); + void slotCopyLinkText(); + void slotSaveLinkAs(); + void slotCopyEmailAddress(); + + void slotViewDocumentSource(); + + void updateEditActions(); + void updateActions(); + + void slotPlayMedia(); + void slotMuteMedia(); + void slotLoopMedia(); + void slotShowMediaControls(); + void slotSaveMedia(); + void slotCopyMedia(); + void slotTextDirectionChanged(); + void slotCheckSpelling(); + void slotSpellCheckSelection(); + void slotSpellCheckDone(const QString&); + void spellCheckerCorrected(const QString&, int, const QString&); + void spellCheckerMisspelling(const QString&, int); + //void slotPrintRequested(QWebFrame*); + void slotPrintPreview(); + + void slotOpenSelection(); + void slotLinkInTop(); + +private Q_SLOTS: + void slotHandlePagePrinted(bool result); +private: + WebView* view(); + QPointer<WebPart> m_part; + QPointer<WebView> m_view; + quint32 m_spellTextSelectionStart; + quint32 m_spellTextSelectionEnd; + QByteArray m_historyData; + QPrinter *mCurrentPrinter; +}; + +/** + * @internal + * Implements the TextExtension interface + */ +class WebTextExtension : public KParts::TextExtension +{ + Q_OBJECT +public: + WebTextExtension(WebKitPart* part); + + bool hasSelection() const Q_DECL_OVERRIDE; + QString selectedText(Format format) const Q_DECL_OVERRIDE; + QString completeText(Format format) const Q_DECL_OVERRIDE; + +private: + WebKitPart* part() const; +}; + +/** + * @internal + * Implements the HtmlExtension interface + */ +class WebHtmlExtension : public KParts::HtmlExtension, + public KParts::SelectorInterface, + public KParts::HtmlSettingsInterface +{ + Q_OBJECT + Q_INTERFACES(KParts::SelectorInterface) + Q_INTERFACES(KParts::HtmlSettingsInterface) + +public: + WebHtmlExtension(WebKitPart* part); + + // HtmlExtension + QUrl baseUrl() const Q_DECL_OVERRIDE; + bool hasSelection() const Q_DECL_OVERRIDE; + + // SelectorInterface + QueryMethods supportedQueryMethods() const Q_DECL_OVERRIDE; + Element querySelector(const QString& query, KParts::SelectorInterface::QueryMethod method) const Q_DECL_OVERRIDE; + QList<Element> querySelectorAll(const QString& query, KParts::SelectorInterface::QueryMethod method) const Q_DECL_OVERRIDE; + + // HtmlSettingsInterface + QVariant htmlSettingsProperty(HtmlSettingsType type) const Q_DECL_OVERRIDE; + bool setHtmlSettingsProperty(HtmlSettingsType type, const QVariant& value) Q_DECL_OVERRIDE; + +private: + WebKitPart* part() const; +}; + +class WebScriptableExtension : public KParts::ScriptableExtension +{ + Q_OBJECT + +public: + WebScriptableExtension(WebKitPart* part); + + QVariant rootObject() Q_DECL_OVERRIDE; + + QVariant get(ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName) Q_DECL_OVERRIDE; + + bool put(ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName, const QVariant& value) Q_DECL_OVERRIDE; + + bool setException(ScriptableExtension* callerPrincipal, const QString& message) Q_DECL_OVERRIDE; + + QVariant evaluateScript(ScriptableExtension* callerPrincipal, + quint64 contextObjectId, + const QString& code, + ScriptLanguage language = ECMAScript) Q_DECL_OVERRIDE; + + bool isScriptLanguageSupported(ScriptLanguage lang) const Q_DECL_OVERRIDE; + +private: + QVariant encloserForKid(KParts::ScriptableExtension* kid) Q_DECL_OVERRIDE; + WebKitPart* part(); +}; + +#endif // WEBKITPART_EXT_H diff --git b/webkitpart/src/webkitpartfactory.cpp b/webkitpart/src/webkitpartfactory.cpp new file mode 100644 index 000000000..1156db0e7 --- /dev/null +++ b/webkitpart/src/webkitpartfactory.cpp @@ -0,0 +1,65 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2008 Laurent Montel <montel@kde.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "webkitpartfactory.h" +#include "webkitpart_ext.h" +#include "webkitpart.h" + +#include <QWidget> + +WebFactory::~WebFactory() +{ + // kDebug() << this; +} + +QObject *WebFactory::create(const char* iface, QWidget *parentWidget, QObject *parent, const QVariantList &args, const QString& keyword) +{ + Q_UNUSED(iface); + Q_UNUSED(keyword); + Q_UNUSED(args); + + qDebug() << parentWidget << parent; + connect(parentWidget, SIGNAL(destroyed(QObject*)), this, SLOT(slotDestroyed(QObject*))); + + // NOTE: The code below is what makes it possible to properly integrate QtWebKit's PORTING_TODO + // history management with any KParts based application. + QByteArray histData (m_historyBufContainer.value(parentWidget)); + if (!histData.isEmpty()) histData = qUncompress(histData); + WebKitPart* part = new WebKitPart(parentWidget, parent, histData); + WebBrowserExtension* ext = qobject_cast<WebBrowserExtension*>(part->browserExtension()); + if (ext) { + connect(ext, SIGNAL(saveHistory(QObject*,QByteArray)), this, SLOT(slotSaveHistory(QObject*,QByteArray))); + } + return part; +} + +void WebFactory::slotSaveHistory(QObject* widget, const QByteArray& buffer) +{ + // kDebug() << "Caching history data from" << widget; + m_historyBufContainer.insert(widget, buffer); +} + +void WebFactory::slotDestroyed(QObject* object) +{ + // kDebug() << "Removing cached history data of" << object; + m_historyBufContainer.remove(object); +} + +K_EXPORT_PLUGIN(WebFactory) diff --git b/webkitpart/src/webkitpartfactory.h b/webkitpart/src/webkitpartfactory.h new file mode 100644 index 000000000..f53ed41b7 --- /dev/null +++ b/webkitpart/src/webkitpartfactory.h @@ -0,0 +1,47 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2008 Laurent Montel <montel@kde.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef WEBKITPARTFACTORY +#define WEBKITPARTFACTORY + +#include <kpluginfactory.h> + +#include <QHash> + +class QWidget; + +class WebFactory : public KPluginFactory +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.kde.KPluginFactory" FILE "") + Q_INTERFACES(KPluginFactory) +public: + virtual ~WebFactory(); + QObject *create(const char* iface, QWidget *parentWidget, QObject *parent, const QVariantList& args, const QString &keyword) Q_DECL_OVERRIDE; + +private Q_SLOTS: + void slotDestroyed(QObject* object); + void slotSaveHistory(QObject* widget, const QByteArray&); + +private: + QHash<QObject*, QByteArray> m_historyBufContainer; +}; + +#endif // WEBKITPARTFACTORY diff --git b/webkitpart/src/webkitview.cpp b/webkitpart/src/webkitview.cpp new file mode 100644 index 000000000..a106451d2 --- /dev/null +++ b/webkitpart/src/webkitview.cpp @@ -0,0 +1,594 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2007 Trolltech ASA + * Copyright (C) 2008 - 2010 Urs Wolfer <uwolfer @ kde.org> + * Copyright (C) 2008 Laurent Montel <montel@kde.org> + * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "webkitview.h" +#include "webkitpage.h" +#include "webkitpart.h" +#include "settings/webkitsettings.h" + +#include <kio/global.h> +#include <KAboutData> +#include <KActionCollection> +#include <KConfigGroup> +#include <KService> +#include <KUriFilter> +#include <KActionMenu> +#include <KIO/AccessManager> +#include <KStringHandler> +#include <KLocalizedString> + +#include <QTimer> +#include <QMimeData> +#include <QDropEvent> +#include <QLabel> +#include <QNetworkRequest> +#include <QToolTip> +#include <QCoreApplication> +#include <unistd.h> +#include <QMimeType> +#include <QMimeDatabase> + +#define QL1S(x) QLatin1String(x) +#define QL1C(x) QLatin1Char(x) + +#define ALTERNATE_DEFAULT_WEB_SHORTCUT QL1S("google") +#define ALTERNATE_WEB_SHORTCUTS QStringList() << QL1S("google") << QL1S("wikipedia") << QL1S("webster") << QL1S("dmoz") + +WebView::WebView(WebKitPart* part, QWidget* parent) + :QWebView(parent), + m_actionCollection(new KActionCollection(this)), + m_part(part), + m_autoScrollTimerId(-1), + m_verticalAutoScrollSpeed(0), + m_horizontalAutoScrollSpeed(0) +{ + setAcceptDrops(true); + + // Create the custom page... + setPage(new WebPage(part, this)); + + connect(this, SIGNAL(loadStarted()), this, SLOT(slotStopAutoScroll())); + + if (WebSettings::self()->zoomToDPI()) + setZoomFactor(logicalDpiY() / 96.0f); + +#ifndef HAVE_WEBCONTEXTMENUDATA + m_result = 0; +#endif +} + +WebView::~WebView() +{ + //kDebug(); +} + +void WebView::loadUrl(const QUrl& url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments& bargs) +{ + page()->setProperty("NavigationTypeUrlEntered", true); + + if (args.reload() && url == this->url()) { + reload(); + return; + } + + QNetworkRequest request(url); + if (args.reload()) { + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + } + + if (bargs.postData.isEmpty()) { + QWebView::load(url); + } else { + // QWebView::load(url, QNetworkAccessManager::PostOperation, bargs.postData); + } +} + +QWebContextMenuData WebView::contextMenuResult() const +{ + return m_result; +} + +static void extractMimeTypeFor(const QUrl& url, QString& mimeType) +{ + const QString fname(url.fileName()); + + if (fname.isEmpty() || url.hasFragment() || url.hasQuery()) + return; + + QMimeType pmt = QMimeDatabase().mimeTypeForFile(fname); + + // Further check for mime types guessed from the extension which, + // on a web page, are more likely to be a script delivering content + // of undecidable type. If the mime type from the extension is one + // of these, don't use it. Retain the original type 'text/html'. + if (pmt.isDefault() || + pmt.inherits(QL1S("application/x-perl")) || + pmt.inherits(QL1S("application/x-perl-module")) || + pmt.inherits(QL1S("application/x-php")) || + pmt.inherits(QL1S("application/x-python-bytecode")) || + pmt.inherits(QL1S("application/x-python")) || + pmt.inherits(QL1S("application/x-shellscript"))) + return; + + mimeType = pmt.name(); +} + +void WebView::contextMenuEvent(QContextMenuEvent* e) +{ +#ifdef HAVE_WEBCONTEXTMENUDATA + m_result = page()->contextMenuData(); + + // Clear the previous collection entries first... + m_actionCollection->clear(); + + KParts::BrowserExtension::PopupFlags flags = KParts::BrowserExtension::DefaultPopupItems; + KParts::BrowserExtension::ActionGroupMap mapAction; + QString mimeType (QL1S("text/html")); + bool forcesNewWindow = false; + + QUrl emitUrl; + + if (m_result.isContentEditable()) { + flags |= KParts::BrowserExtension::ShowTextSelectionItems; + editableContentActionPopupMenu(mapAction); + } else if (m_result.mediaType() == QWebContextMenuData::MediaTypeVideo || m_result.mediaType() == QWebContextMenuData::MediaTypeAudio) { + multimediaActionPopupMenu(mapAction); + } else if (!m_result.linkUrl().isValid()) { + if (m_result.mediaType() == QWebContextMenuData::MediaTypeImage) { + emitUrl = m_result.mediaUrl(); + extractMimeTypeFor(emitUrl, mimeType); + } else { + flags |= KParts::BrowserExtension::ShowBookmark; + emitUrl = m_part->url(); + + if (!m_result.selectedText().isEmpty()) { + flags |= KParts::BrowserExtension::ShowTextSelectionItems; + selectActionPopupMenu(mapAction); + } + } + partActionPopupMenu(mapAction); + } else { + flags |= KParts::BrowserExtension::ShowBookmark; + flags |= KParts::BrowserExtension::IsLink; + emitUrl = m_result.linkUrl(); + linkActionPopupMenu(mapAction); + if (emitUrl.isLocalFile()) + mimeType = QMimeDatabase().mimeTypeForUrl(emitUrl).name(); + else + extractMimeTypeFor(emitUrl, mimeType); + partActionPopupMenu(mapAction); + + // Show the OpenInThisWindow context menu item +// forcesNewWindow = (page()->currentFrame() != m_result.linkTargetFrame()); + } + + if (!mapAction.isEmpty()) { + KParts::OpenUrlArguments args; + KParts::BrowserArguments bargs; + args.setMimeType(mimeType); + bargs.setForcesNewWindow(forcesNewWindow); + e->accept(); + emit m_part->browserExtension()->popupMenu(e->globalPos(), emitUrl, static_cast<mode_t>(-1), args, bargs, flags, mapAction); + return; + } + +#endif + QWebView::contextMenuEvent(e); +} + +void WebView::keyPressEvent(QKeyEvent* e) +{ + if (e && hasFocus()) { + const int key = e->key(); + if (e->modifiers() & Qt::ShiftModifier) { + switch (key) { + case Qt::Key_Up: + /* if (!isEditableElement(page()))*/ { + m_verticalAutoScrollSpeed--; + if (m_autoScrollTimerId == -1) + m_autoScrollTimerId = startTimer(100); + e->accept(); + return; + } + break; + case Qt::Key_Down: + /*if (!isEditableElement(page()))*/ { + m_verticalAutoScrollSpeed++; + if (m_autoScrollTimerId == -1) + m_autoScrollTimerId = startTimer(100); + e->accept(); + return; + } + break; + case Qt::Key_Left: + /*if (!isEditableElement(page()))*/ { + m_horizontalAutoScrollSpeed--; + if (m_autoScrollTimerId == -1) + m_autoScrollTimerId = startTimer(100); + e->accept(); + return; + } + break; + case Qt::Key_Right: + /*if (!isEditableElement(page()))*/ { + m_horizontalAutoScrollSpeed--; + if (m_autoScrollTimerId == -1) + m_autoScrollTimerId = startTimer(100); + e->accept(); + return; + } + break; + default: + break; + } + } else if (m_autoScrollTimerId != -1) { + // kDebug() << "scroll timer id:" << m_autoScrollTimerId; + slotStopAutoScroll(); + e->accept(); + return; + } + } + QWebView::keyPressEvent(e); +} + +void WebView::keyReleaseEvent(QKeyEvent *e) +{ + QWebView::keyReleaseEvent(e); +} + +void WebView::mouseReleaseEvent(QMouseEvent* e) +{ + QWebView::mouseReleaseEvent(e); +} + +void WebView::wheelEvent (QWheelEvent* e) +{ + QWebView::wheelEvent(e); +} + + +void WebView::timerEvent(QTimerEvent* e) +{ +#if 0 + if (e && e->timerId() == m_autoScrollTimerId) { + // do the scrolling + scroll(m_horizontalAutoScrollSpeed, m_verticalAutoScrollSpeed); + // check if we reached the end + const int y = page()->scrollPosition().y(); + if (y == page()->currentFrame()->scrollBarMinimum(Qt::Vertical) || + y == page()->currentFrame()->scrollBarMaximum(Qt::Vertical)) { + m_verticalAutoScrollSpeed = 0; + } + + const int x = page()->scrollPosition().x(); + if (x == page()->currentFrame()->scrollBarMinimum(Qt::Horizontal) || + x == page()->currentFrame()->scrollBarMaximum(Qt::Horizontal)) { + m_horizontalAutoScrollSpeed = 0; + } + + // Kill the timer once the max/min scroll limit is reached. + if (m_horizontalAutoScrollSpeed == 0 && m_verticalAutoScrollSpeed == 0) { + killTimer(m_autoScrollTimerId); + m_autoScrollTimerId = -1; + } + e->accept(); + return; + } +#endif + QWebView::timerEvent(e); +} + +void WebView::editableContentActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& partGroupMap) +{ + QList<QAction*> editableContentActions; + + QActionGroup* group = new QActionGroup(this); + group->setExclusive(true); + + QAction* action = new QAction(m_actionCollection); + action->setSeparator(true); + editableContentActions.append(action); + + action = m_actionCollection->addAction(KStandardAction::Copy, QL1S("copy"), m_part->browserExtension(), SLOT(copy())); + action->setEnabled(pageAction(QWebPage::Copy)->isEnabled()); + editableContentActions.append(action); + + action = m_actionCollection->addAction(KStandardAction::Cut, QL1S("cut"), m_part->browserExtension(), SLOT(cut())); + action->setEnabled(pageAction(QWebPage::Cut)->isEnabled()); + editableContentActions.append(action); + + action = m_actionCollection->addAction(KStandardAction::Paste, QL1S("paste"), m_part->browserExtension(), SLOT(paste())); + action->setEnabled(pageAction(QWebPage::Paste)->isEnabled()); + editableContentActions.append(action); + + action = new QAction(m_actionCollection); + action->setSeparator(true); + editableContentActions.append(action); + + editableContentActions.append(pageAction(QWebPage::SelectAll)); + editableContentActions.append(pageAction(QWebPage::InspectElement)); + + partGroupMap.insert(QStringLiteral("editactions") , editableContentActions); +} + + +void WebView::partActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& partGroupMap) +{ + QList<QAction*> partActions; + +#ifdef HAVE_WEBCONTEXTMENUDATA + if (m_result.mediaUrl().isValid()) { + QAction *action; + action = new QAction(i18n("Save Image As..."), this); + m_actionCollection->addAction(QL1S("saveimageas"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotSaveImageAs())); + partActions.append(action); + + action = new QAction(i18n("Send Image..."), this); + m_actionCollection->addAction(QL1S("sendimage"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotSendImage())); + partActions.append(action); + + action = new QAction(i18n("Copy Image URL"), this); + m_actionCollection->addAction(QL1S("copyimageurl"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyImageURL())); + partActions.append(action); + +#if 0 + action = new QAction(i18n("Copy Image"), this); + m_actionCollection->addAction(QL1S("copyimage"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyImage())); + action->setEnabled(!m_result.pixmap().isNull()); + partActions.append(action); +#endif + + action = new QAction(i18n("View Image (%1)", QUrl(m_result.mediaUrl()).fileName()), this); + m_actionCollection->addAction(QL1S("viewimage"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotViewImage())); + partActions.append(action); + + if (WebSettings::self()->isAdFilterEnabled()) { + action = new QAction(i18n("Block Image..."), this); + m_actionCollection->addAction(QL1S("blockimage"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotBlockImage())); + partActions.append(action); + + if (!m_result.mediaUrl().host().isEmpty() && + !m_result.mediaUrl().scheme().isEmpty()) + { + action = new QAction(i18n("Block Images From %1" , m_result.mediaUrl().host()), this); + m_actionCollection->addAction(QL1S("blockhost"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotBlockHost())); + partActions.append(action); + } + } + } +#endif + + { + QAction *separatorAction = new QAction(m_actionCollection); + separatorAction->setSeparator(true); + partActions.append(separatorAction); + } + + partActions.append(m_part->actionCollection()->action(QStringLiteral("viewDocumentSource"))); + + partActions.append(pageAction(QWebPage::InspectElement)); + + partGroupMap.insert(QStringLiteral("partactions"), partActions); +} + +void WebView::selectActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& selectGroupMap) +{ + QList<QAction*> selectActions; + + QAction* copyAction = m_actionCollection->addAction(KStandardAction::Copy, QL1S("copy"), m_part->browserExtension(), SLOT(copy())); + copyAction->setText(i18n("&Copy Text")); + copyAction->setEnabled(m_part->browserExtension()->isActionEnabled("copy")); + selectActions.append(copyAction); + + addSearchActions(selectActions, this); + + KUriFilterData data (selectedText().simplified().left(256)); + data.setCheckForExecutables(false); + if (KUriFilter::self()->filterUri(data, QStringList() << QStringLiteral("kshorturifilter") << QStringLiteral("fixhosturifilter")) && + data.uri().isValid() && data.uriType() == KUriFilterData::NetProtocol) { + QAction *action = new QAction(QIcon::fromTheme(QStringLiteral("window-new")), i18nc("open selected url", "Open '%1'", + KStringHandler::rsqueeze(data.uri().url(), 18)), this); + m_actionCollection->addAction(QL1S("openSelection"), action); + action->setData(QUrl(data.uri())); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotOpenSelection())); + selectActions.append(action); + } + + selectGroupMap.insert(QStringLiteral("editactions"), selectActions); +} + +void WebView::linkActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& linkGroupMap) +{ +#ifdef HAVE_WEBCONTEXTMENUDATA + Q_ASSERT(!m_result.linkUrl().isEmpty()); + + const QUrl url(m_result.linkUrl()); +#else + const QUrl url; +#endif + + QList<QAction*> linkActions; + + QAction* action; + +#ifdef HAVE_WEBCONTEXTMENUDATA + if (!m_result.selectedText().isEmpty()) { + action = m_actionCollection->addAction(KStandardAction::Copy, QL1S("copy"), m_part->browserExtension(), SLOT(copy())); + action->setText(i18n("&Copy Text")); + action->setEnabled(m_part->browserExtension()->isActionEnabled("copy")); + linkActions.append(action); + } +#endif + + if (url.scheme() == QLatin1String("mailto")) { +#ifdef HAVE_WEBCONTEXTMENUDATA + action = new QAction(i18n("&Copy Email Address"), this); + m_actionCollection->addAction(QL1S("copylinklocation"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyEmailAddress())); + linkActions.append(action); +#endif + } else { +#ifdef HAVE_WEBCONTEXTMENUDATA + if (!m_result.linkText().isEmpty()) { + action = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy Link &Text"), this); + m_actionCollection->addAction(QL1S("copylinktext"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyLinkText())); + linkActions.append(action); + } +#endif + + action = new QAction(i18n("Copy Link &URL"), this); + m_actionCollection->addAction(QL1S("copylinkurl"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotCopyLinkURL())); + linkActions.append(action); + + action = new QAction(i18n("&Save Link As..."), this); + m_actionCollection->addAction(QL1S("savelinkas"), action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(slotSaveLinkAs())); + linkActions.append(action); + } + + linkGroupMap.insert(QStringLiteral("linkactions"), linkActions); +} + +void WebView::multimediaActionPopupMenu(KParts::BrowserExtension::ActionGroupMap& mmGroupMap) +{ +#ifdef HAVE_WEBCONTEXTMENUDATA + QList<QAction*> multimediaActions; + + const bool isVideoElement = m_result.mediaType() == QWebContextMenuData::MediaTypeVideo; + const bool isAudioElement = m_result.mediaType() == QWebContextMenuData::MediaTypeAudio; + + QAction* action = new QAction(i18n("&Play/Pause"), this); + m_actionCollection->addAction(QL1S("playmultimedia"), action); + connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotPlayMedia())); + multimediaActions.append(action); + + action = new QAction(i18n("Un&mute/&Mute"), this); + m_actionCollection->addAction(QL1S("mutemultimedia"), action); + connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotMuteMedia())); + multimediaActions.append(action); + + action = new QAction(i18n("Toggle &Loop"), this); + m_actionCollection->addAction(QL1S("loopmultimedia"), action); + connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotLoopMedia())); + multimediaActions.append(action); + + action = new QAction(i18n("Toggle &Controls"), this); + m_actionCollection->addAction(QL1S("showmultimediacontrols"), action); + connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotShowMediaControls())); + multimediaActions.append(action); + + action = new QAction(m_actionCollection); + action->setSeparator(true); + multimediaActions.append(action); + + QString saveMediaText, copyMediaText; + if (isVideoElement) { + saveMediaText = i18n("Sa&ve Video As..."); + copyMediaText = i18n("C&opy Video URL"); + } else if (isAudioElement) { + saveMediaText = i18n("Sa&ve Audio As..."); + copyMediaText = i18n("C&opy Audio URL"); + } else { + saveMediaText = i18n("Sa&ve Media As..."); + copyMediaText = i18n("C&opy Media URL"); + } + + action = new QAction(saveMediaText, this); + m_actionCollection->addAction(QL1S("savemultimedia"), action); + connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotSaveMedia())); + multimediaActions.append(action); + + action = new QAction(copyMediaText, this); + m_actionCollection->addAction(QL1S("copymultimediaurl"), action); + connect(action, SIGNAL(triggered()), m_part->browserExtension(), SLOT(slotCopyMedia())); + multimediaActions.append(action); + + mmGroupMap.insert(QStringLiteral("partactions"), multimediaActions); +#endif +} + +void WebView::slotStopAutoScroll() +{ + if (m_autoScrollTimerId == -1) { + return; + } + + killTimer(m_autoScrollTimerId); + m_autoScrollTimerId = -1; + m_verticalAutoScrollSpeed = 0; + m_horizontalAutoScrollSpeed = 0; + +} + +void WebView::addSearchActions(QList<QAction*>& selectActions, QWebView* view) +{ + // search text + const QString selectedText = view->selectedText().simplified(); + if (selectedText.isEmpty()) + return; + + KUriFilterData data; + data.setData(selectedText); + data.setAlternateDefaultSearchProvider(ALTERNATE_DEFAULT_WEB_SHORTCUT); + data.setAlternateSearchProviders(ALTERNATE_WEB_SHORTCUTS); + + if (KUriFilter::self()->filterSearchUri(data, KUriFilter::NormalTextFilter)) { + const QString squeezedText = KStringHandler::rsqueeze(selectedText, 20); + QAction *action = new QAction(QIcon::fromTheme(data.iconName()), + i18nc("Search \"search provider\" for \"text\"", "Search %1 for '%2'", + data.searchProvider(), squeezedText), view); + action->setData(QUrl(data.uri())); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(searchProvider())); + m_actionCollection->addAction(QL1S("defaultSearchProvider"), action); + selectActions.append(action); + + + const QStringList preferredSearchProviders = data.preferredSearchProviders(); + if (!preferredSearchProviders.isEmpty()) { + KActionMenu* providerList = new KActionMenu(i18nc("Search for \"text\" with", + "Search for '%1' with", squeezedText), view); + Q_FOREACH(const QString &searchProvider, preferredSearchProviders) { + if (searchProvider == data.searchProvider()) + continue; + + QAction *action = new QAction(QIcon::fromTheme(data.iconNameForPreferredSearchProvider(searchProvider)), searchProvider, view); + action->setData(data.queryForPreferredSearchProvider(searchProvider)); + m_actionCollection->addAction(searchProvider, action); + connect(action, SIGNAL(triggered(bool)), m_part->browserExtension(), SLOT(searchProvider())); + + providerList->addAction(action); + } + m_actionCollection->addAction(QL1S("searchProviderList"), providerList); + selectActions.append(providerList); + } + } +} diff --git b/webkitpart/src/webkitview.h b/webkitpart/src/webkitview.h new file mode 100644 index 000000000..2f846f073 --- /dev/null +++ b/webkitpart/src/webkitview.h @@ -0,0 +1,132 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2007 Trolltech ASA + * Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org> + * Copyright (C) 2008 Laurent Montel <montel@kde.org> + * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ +#ifndef WEBVIEW_H +#define WEBVIEW_H + +#include <QPointer> +#include <KParts/BrowserExtension> + +#include <QWebView> +#include <QtWebKit/QtWebKitVersion> +#if QTWEBKIT_VERSION >= QT_VERSION_CHECK(5, 602, 3) +#define HAVE_WEBCONTEXTMENUDATA +#include <QWebContextMenuData> +#else +typedef void* QWebContextMenuData; +#endif + +class QUrl; +class WebKitPart; + +class WebView : public QWebView +{ + Q_OBJECT +public: + WebView(WebKitPart* part, QWidget* parent); + ~WebView(); + + /** + * Same as QWebPage::load, but with KParts style arguments instead. + * + * @see KParts::OpenUrlArguments, KParts::BrowserArguments. + * + * @param url the url to load. + * @param args reference to a OpenUrlArguments object. + * @param bargs reference to a BrowserArguments object. + */ + void loadUrl(const QUrl& url, const KParts::OpenUrlArguments& args, const KParts::BrowserArguments& bargs); + + QWebContextMenuData contextMenuResult() const; + +protected: + /** + * Reimplemented for internal reasons, the API is not affected. + * + * @see QWidget::contextMenuEvent + * @internal + */ + void contextMenuEvent(QContextMenuEvent*) Q_DECL_OVERRIDE; + + /** + * Reimplemented for internal reasons, the API is not affected. + * + * @see QWidget::keyPressEvent + * @internal + */ + void keyPressEvent(QKeyEvent*) Q_DECL_OVERRIDE; + + /** + * Reimplemented for internal reasons, the API is not affected. + * + * @see QWidget::keyReleaseEvent + * @internal + */ + void keyReleaseEvent(QKeyEvent*) Q_DECL_OVERRIDE; + + /** + * Reimplemented for internal reasons, the API is not affected. + * + * @see QWidget::mouseReleaseEvent + * @internal + */ + void mouseReleaseEvent(QMouseEvent*) Q_DECL_OVERRIDE; + + /** + * Reimplemented for internal reasons, the API is not affected. + * + * @see QObject::timerEvent + * @internal + */ + void timerEvent(QTimerEvent*) Q_DECL_OVERRIDE; + + /** + * Reimplemented for internal reasons, the API is not affected. + * + * @see QWidget::wheelEvent + * @internal + */ + void wheelEvent(QWheelEvent*) Q_DECL_OVERRIDE; + +private Q_SLOTS: + void slotStopAutoScroll(); + +private: + void editableContentActionPopupMenu(KParts::BrowserExtension::ActionGroupMap&); + void selectActionPopupMenu(KParts::BrowserExtension::ActionGroupMap&); + void linkActionPopupMenu(KParts::BrowserExtension::ActionGroupMap&); + void partActionPopupMenu(KParts::BrowserExtension::ActionGroupMap &); + void multimediaActionPopupMenu(KParts::BrowserExtension::ActionGroupMap&); + void addSearchActions(QList<QAction*>& selectActions, QWebView*); + + KActionCollection* m_actionCollection; + QWebContextMenuData m_result; + QPointer<WebKitPart> m_part; + + qint32 m_autoScrollTimerId; + qint32 m_verticalAutoScrollSpeed; + qint32 m_horizontalAutoScrollSpeed; + + QHash<QString, QChar> m_duplicateLinkElements; +}; + +#endif // WEBVIEW_H diff --git b/webkitpart/src/websslinfo.cpp b/webkitpart/src/websslinfo.cpp new file mode 100644 index 000000000..7960007d0 --- /dev/null +++ b/webkitpart/src/websslinfo.cpp @@ -0,0 +1,224 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "websslinfo.h" + +#include <QVariant> + + +class WebSslInfo::WebSslInfoPrivate +{ +public: + WebSslInfoPrivate() + : usedCipherBits(0), supportedCipherBits(0) {} + + QUrl url; + QString ciphers; + QString protocol; + QString certErrors; + QHostAddress peerAddress; + QHostAddress parentAddress; + QList<QSslCertificate> certificateChain; + + int usedCipherBits; + int supportedCipherBits; +}; + +WebSslInfo::WebSslInfo() + :d(new WebSslInfo::WebSslInfoPrivate) +{ +} + +WebSslInfo::WebSslInfo(const WebSslInfo& other) + :d(new WebSslInfo::WebSslInfoPrivate) +{ + *this = other; +} + +WebSslInfo::~WebSslInfo() +{ + delete d; + d = 0; +} + +bool WebSslInfo::isValid() const +{ + return (d ? !d->peerAddress.isNull() : false); +} + +QUrl WebSslInfo::url() const +{ + return (d ? d->url : QUrl()); +} + +QHostAddress WebSslInfo::parentAddress() const +{ + return (d ? d->parentAddress : QHostAddress()); +} + +QHostAddress WebSslInfo::peerAddress() const +{ + return (d ? d->peerAddress : QHostAddress()); +} + +QString WebSslInfo::protocol() const +{ + return (d ? d->protocol : QString()); +} + +QString WebSslInfo::ciphers() const +{ + return (d ? d->ciphers : QString()); +} + +QString WebSslInfo::certificateErrors() const +{ + return (d ? d->certErrors : QString()); +} + +int WebSslInfo::supportedChiperBits () const +{ + return (d ? d->supportedCipherBits : 0); +} + +int WebSslInfo::usedChiperBits () const +{ + return (d ? d->usedCipherBits : 0); +} + +QList<QSslCertificate> WebSslInfo::certificateChain() const +{ + return (d ? d->certificateChain : QList<QSslCertificate>()); +} + +WebSslInfo& WebSslInfo::operator=(const WebSslInfo& other) +{ + if (d) { + d->ciphers = other.d->ciphers; + d->protocol = other.d->protocol; + d->certErrors = other.d->certErrors; + d->peerAddress = other.d->peerAddress; + d->parentAddress = other.d->parentAddress; + d->certificateChain = other.d->certificateChain; + + d->usedCipherBits = other.d->usedCipherBits; + d->supportedCipherBits = other.d->supportedCipherBits; + d->url = other.d->url; + } + + return *this; +} + +bool WebSslInfo::saveTo(QMap<QString, QVariant>& data) const +{ + const bool ok = isValid(); + if (ok) { + data.insert(QStringLiteral("ssl_in_use"), true); + data.insert(QStringLiteral("ssl_peer_ip"), d->peerAddress.toString()); + data.insert(QStringLiteral("ssl_parent_ip"), d->parentAddress.toString()); + data.insert(QStringLiteral("ssl_protocol_version"), d->protocol); + data.insert(QStringLiteral("ssl_cipher"), d->ciphers); + data.insert(QStringLiteral("ssl_cert_errors"), d->certErrors); + data.insert(QStringLiteral("ssl_cipher_used_bits"), d->usedCipherBits); + data.insert(QStringLiteral("ssl_cipher_bits"), d->supportedCipherBits); + QByteArray certChain; + Q_FOREACH(const QSslCertificate& cert, d->certificateChain) + certChain += cert.toPem(); + data.insert(QStringLiteral("ssl_peer_chain"), certChain); + } + + return ok; +} + +void WebSslInfo::restoreFrom(const QVariant& value, const QUrl& url, bool reset) +{ + if (reset) { + *this = WebSslInfo(); + } + + if (value.isValid() && value.type() == QVariant::Map) { + QMap<QString,QVariant> metaData = value.toMap(); + if (metaData.value(QStringLiteral("ssl_in_use"), false).toBool()) { + setCertificateChain(metaData.value(QStringLiteral("ssl_peer_chain")).toByteArray()); + setPeerAddress(metaData.value(QStringLiteral("ssl_peer_ip")).toString()); + setParentAddress(metaData.value(QStringLiteral("ssl_parent_ip")).toString()); + setProtocol(metaData.value(QStringLiteral("ssl_protocol_version")).toString()); + setCiphers(metaData.value(QStringLiteral("ssl_cipher")).toString()); + setCertificateErrors(metaData.value(QStringLiteral("ssl_cert_errors")).toString()); + setUsedCipherBits(metaData.value(QStringLiteral("ssl_cipher_used_bits")).toString()); + setSupportedCipherBits(metaData.value(QStringLiteral("ssl_cipher_bits")).toString()); + setUrl(url); + } + } +} + +void WebSslInfo::setUrl (const QUrl &url) +{ + if (d) + d->url = url; +} + +void WebSslInfo::setPeerAddress(const QString& address) +{ + if (d) + d->peerAddress = address; +} + +void WebSslInfo::setParentAddress(const QString& address) +{ + if (d) + d->parentAddress = address; +} + +void WebSslInfo::setProtocol(const QString& protocol) +{ + if (d) + d->protocol = protocol; +} + +void WebSslInfo::setCertificateChain(const QByteArray& chain) +{ + if (d) + d->certificateChain = QSslCertificate::fromData(chain); +} + +void WebSslInfo::setCiphers(const QString& ciphers) +{ + if (d) + d->ciphers = ciphers; +} + +void WebSslInfo::setUsedCipherBits(const QString& bits) +{ + if (d) + d->usedCipherBits = bits.toInt(); +} + +void WebSslInfo::setSupportedCipherBits(const QString& bits) +{ + if (d) + d->supportedCipherBits = bits.toInt(); +} + +void WebSslInfo::setCertificateErrors(const QString& certErrors) +{ + if (d) + d->certErrors = certErrors; +} diff --git b/webkitpart/src/websslinfo.h b/webkitpart/src/websslinfo.h new file mode 100644 index 000000000..7c7d09ca7 --- /dev/null +++ b/webkitpart/src/websslinfo.h @@ -0,0 +1,70 @@ +/* + * This file is part of the KDE project. + * + * Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ +#ifndef WEBSSLINFO_H +#define WEBSSLINFO_H + +//#include <kdemacros.h> + +#include <QUrl> +#include <QList> +#include <QString> +#include <QHostAddress> +#include <QSslCertificate> + +class WebSslInfo +{ +public: + WebSslInfo(); + WebSslInfo(const WebSslInfo&); + virtual ~WebSslInfo(); + + bool isValid() const; + QUrl url() const; + QHostAddress peerAddress() const; + QHostAddress parentAddress() const; + QString ciphers() const; + QString protocol() const; + QString certificateErrors() const; + int supportedChiperBits () const; + int usedChiperBits () const; + QList<QSslCertificate> certificateChain() const; + + bool saveTo(QMap<QString, QVariant>&) const; + void restoreFrom(const QVariant &, const QUrl& = QUrl(), bool reset = false); + + void setUrl (const QUrl &url); + WebSslInfo& operator = (const WebSslInfo&); + +protected: + void setCiphers(const QString& ciphers); + void setProtocol(const QString& protocol); + void setPeerAddress(const QString& address); + void setParentAddress(const QString& address); + void setCertificateChain(const QByteArray& chain); + void setCertificateErrors(const QString& certErrors); + void setUsedCipherBits(const QString& bits); + void setSupportedCipherBits(const QString& bits); + +private: + class WebSslInfoPrivate; + WebSslInfoPrivate* d; +}; + +#endif // WEBSSLINFO_H diff --git b/webkitpart/testfiles/embed_tag_test.html b/webkitpart/testfiles/embed_tag_test.html new file mode 100644 index 000000000..8afe2d611 --- /dev/null +++ b/webkitpart/testfiles/embed_tag_test.html @@ -0,0 +1,20 @@ +<html> +<head> + <title> <EMBED> tests + + +

KDE e.V. Report 2011 Q2

+
+ +
+

+

KDE e.V. Report 2011 Q1

+
+ +
+

+

+
+ + diff --git b/webkitpart/testfiles/form_save_restore_test.html b/webkitpart/testfiles/form_save_restore_test.html new file mode 100644 index 000000000..d1adaeb76 --- /dev/null +++ b/webkitpart/testfiles/form_save_restore_test.html @@ -0,0 +1,68 @@ + + + Form save restore test + + + +
+ + +
+ + +
+ + +
+One +
+Two +
+Three +
+
+ +

+Enter some text in the box below:
+ +

+ +

+Disabled text area:
+ +

+ +

+Read only text area:
+ +

+ +

+Text area with spell check disabled:
+ +

+ +

+Choose one: + +

+ +

+Select one or more items:
+ +

+ + + diff --git b/webkitpart/testfiles/frameset_test.html b/webkitpart/testfiles/frameset_test.html new file mode 100644 index 000000000..25a295937 --- /dev/null +++ b/webkitpart/testfiles/frameset_test.html @@ -0,0 +1,9 @@ + + +<FRAMESET> test + + + + + + diff --git b/webkitpart/testfiles/frametest/frame_a.html b/webkitpart/testfiles/frametest/frame_a.html new file mode 100644 index 000000000..0ea08f3f6 --- /dev/null +++ b/webkitpart/testfiles/frametest/frame_a.html @@ -0,0 +1,7 @@ + + + +

Frame A

+ + + diff --git b/webkitpart/testfiles/frametest/frame_b.html b/webkitpart/testfiles/frametest/frame_b.html new file mode 100644 index 000000000..fe36a8d98 --- /dev/null +++ b/webkitpart/testfiles/frametest/frame_b.html @@ -0,0 +1,7 @@ + + + +

Frame B

+ + + \ No newline at end of file diff --git b/webkitpart/testfiles/frametest/frame_c.html b/webkitpart/testfiles/frametest/frame_c.html new file mode 100644 index 000000000..3ed0e0e67 --- /dev/null +++ b/webkitpart/testfiles/frametest/frame_c.html @@ -0,0 +1,7 @@ + + + +

Frame C

+Go to KDE website + + \ No newline at end of file diff --git b/webkitpart/testfiles/frametest/frame_navigation.html b/webkitpart/testfiles/frametest/frame_navigation.html new file mode 100644 index 000000000..3632a0d8b --- /dev/null +++ b/webkitpart/testfiles/frametest/frame_navigation.html @@ -0,0 +1,9 @@ + + +Frame a
+Frame b
+Frame c
+Invalid frame
+bugs.kde.org + + \ No newline at end of file diff --git b/webkitpart/testfiles/js.html b/webkitpart/testfiles/js.html new file mode 100644 index 000000000..4c03c3473 --- /dev/null +++ b/webkitpart/testfiles/js.html @@ -0,0 +1,52 @@ + + +Javascript Link Tests + + + + +

Javascript Link Tests

+resizeTo
+moveTo
+promptAndAlertMessage
+status
+JS open new window
+JS open new frameset
+ + diff --git b/webkitpart/testfiles/link_tests.html b/webkitpart/testfiles/link_tests.html new file mode 100644 index 000000000..f2d73007a --- /dev/null +++ b/webkitpart/testfiles/link_tests.html @@ -0,0 +1,136 @@ + + + Link Tests + + + +

MAILTO Link Tests

+ Email link #1 +
+ Email link #2 +
+

FTP Link Tests

+ FTP link #1 (new window) +
+ FTP link #2 (new window) +
+ FTP link #3 +
+ Text File Link +
+ Anchor test +
+ Anchor test (new window) +
+

HTTP Link Tests

+ Web site link (new window) +
+ Web site link with bogus username +
+ Web site link with different bogus username +
+ PDF link +
+ PDF link (new window) +
+ Duplicate PDF link (new window) +
+ Movie link +
+ Movie link (new window) +
+ Text Document Link +
+ Bogus link +
+

Javascript Link Tests

+ Open dialog like window link #1 +
+ Open dialog like window link #2 +
+ Open new window link #2 (might be opened as Tab) +
+ Open PDF Document (new window) +
+ Javscript + Target test +
+ Close window +
+ On mouse over open window test +
+ Redirect test +
+

KDE specific URL Tests

+ Text Document Link +
+

Form Tests

+
+ Choose file to upload:
+
+ + +
+
+

URL Fragment Test

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git b/webkitpart/testfiles/meta_tag_refresh_test.html b/webkitpart/testfiles/meta_tag_refresh_test.html new file mode 100644 index 000000000..4ea95a59c --- /dev/null +++ b/webkitpart/testfiles/meta_tag_refresh_test.html @@ -0,0 +1,14 @@ + + + Meta redirect test + + + +You will be redirected to kde.org in 10 seconds.
+

+If the stop button is active (not disabled) after the page has completely loaded, it +means the rendering engine allows you to cancel <META> based redirect requests. +Otherwise, you are not able to stop redirects or refresh requests set by web pages. +

+ + \ No newline at end of file diff --git b/webkitpart/tests/CMakeLists.txt b/webkitpart/tests/CMakeLists.txt new file mode 100644 index 000000000..85d8f12c6 --- /dev/null +++ b/webkitpart/tests/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(webkitpart_tester webkitpart_tester.cpp) +target_link_libraries(webkitpart_tester kwebkitpartlib Qt5::Core Qt5::Gui Qt5::Widgets Qt5::WebKitWidgets KF5::I18n KF5::KDELibs4Support) diff --git b/webkitpart/tests/webkitpart_tester.cpp b/webkitpart/tests/webkitpart_tester.cpp new file mode 100644 index 000000000..e4c1e45f6 --- /dev/null +++ b/webkitpart/tests/webkitpart_tester.cpp @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2006 George Staikos + * Copyright (C) 2006 Dirk Mueller + * Copyright (C) 2006 Zack Rusin + * Copyright (C) 2006 Simon Hausmann + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//#include +//#include +#include +//#include +#include +//#include +//#include + +#if !defined(QT_NO_PRINTER) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + MainWindow(const QString& url = QString()): currentZoom(100) { + view = new WebKitPart(this); + setCentralWidget(view->widget()); + + connect(view->view(), &QWebView::loadFinished, + this, &MainWindow::loadFinished); + connect(view->view(), SIGNAL(titleChanged(QString)), + this, SLOT(setWindowTitle(QString))); + connect(view->view()->page(), SIGNAL(linkHovered(QString)), + this, SLOT(showLinkHover(QString))); + connect(view->view()->page(), SIGNAL(windowCloseRequested()), this, SLOT(deleteLater())); + + setupUI(); + + QUrl qurl(KUriFilter::self()->filteredUri(url, QStringList() << QStringLiteral("kshorturifilter"))); + if (qurl.isValid()) { + urlEdit->setText(qurl.toEncoded()); + view->openUrl(qurl); + + // the zoom values are chosen to be like in Mozilla Firefox 3 + zoomLevels << 30 << 50 << 67 << 80 << 90; + zoomLevels << 100; + zoomLevels << 110 << 120 << 133 << 150 << 170 << 200 << 240 << 300; + } + } + + QWebPage* webPage() const { + return view->view()->page(); + } + + QWebView* webView() const { + return view->view(); + } + +protected slots: + + void changeLocation() { + QUrl url (KUriFilter::self()->filteredUri(urlEdit->text(), QStringList() << QStringLiteral("kshorturifilter"))); + view->openUrl(url); + view->view()->setFocus(Qt::OtherFocusReason); + } + + void loadFinished() { + urlEdit->setText(view->url().toString()); + + QUrl::FormattingOptions opts; + opts |= QUrl::RemoveScheme; + opts |= QUrl::RemoveUserInfo; + opts |= QUrl::StripTrailingSlash; + QString s = view->url().toString(opts); + s = s.mid(2); + if (s.isEmpty()) + return; + + if (!urlList.contains(s)) + urlList += s; + urlModel.setStringList(urlList); + } + + void showLinkHover(const QString &link) { + statusBar()->showMessage(link); + } + + void zoomIn() { + int i = zoomLevels.indexOf(currentZoom); + Q_ASSERT(i >= 0); + if (i < zoomLevels.count() - 1) + currentZoom = zoomLevels[i + 1]; + + view->view()->setZoomFactor(qreal(currentZoom)/100.0); + } + + void zoomOut() { + int i = zoomLevels.indexOf(currentZoom); + Q_ASSERT(i >= 0); + if (i > 0) + currentZoom = zoomLevels[i - 1]; + + view->view()->setZoomFactor(qreal(currentZoom)/100.0); + } + + void resetZoom() + { + currentZoom = 100; + view->view()->setZoomFactor(1.0); + } + + void toggleZoomTextOnly(bool b) + { +// view->view()->page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, b); + } + + void print() { +#if !defined(QT_NO_PRINTER) + QScopedPointer dlg (new QPrintPreviewDialog(this)); + connect(dlg.data(), SIGNAL(paintRequested(QPrinter*)), + view, SLOT(print(QPrinter*))); + dlg->exec(); +#endif + } + + void setEditable(bool on) { +// view->view()->page()->setContentEditable(on); + formatMenuAction->setVisible(on); + } + + void dumpHtml() { + view->view()->page()->toHtml([](const QString& text) { + kDebug() << "HTML: " << text; + }); + } + + void selectElements() { + bool ok; + QString str = QInputDialog::getText(this, i18nc("input dialog window title for selecting html elements", "Select elements"), + i18nc("input dialog text for selecting html elements", "Choose elements"), QLineEdit::Normal, + QStringLiteral("a"), &ok); + if (ok && !str.isEmpty()) { + //QWebElementCollection collection = view->page()->mainFrame()->findAllElements(str); + //const int count = collection.count(); + //for (int i=0; i < count; i++) + // collection.at(i).setStyleProperty("background-color", "yellow"); + //statusBar()->showMessage(i18np("%1 element selected", "%1 elements selected", count), 5000); + } + } + +public slots: + + void newWindow(const QString &url = QString()) { + MainWindow *mw = new MainWindow(url); + mw->show(); + } + +private: + + QVector zoomLevels; + int currentZoom; + + // create the status bar, tool bar & menu + void setupUI() { + progress = new QProgressBar(this); + progress->setRange(0, 100); + progress->setMinimumSize(100, 20); + progress->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + progress->hide(); + statusBar()->addPermanentWidget(progress); + + connect(view->view(), SIGNAL(loadProgress(int)), progress, SLOT(show())); + connect(view->view(), SIGNAL(loadProgress(int)), progress, SLOT(setValue(int))); + connect(view->view(), SIGNAL(loadFinished(bool)), progress, SLOT(hide())); + + urlEdit = new KLineEdit(this); + urlEdit->setSizePolicy(QSizePolicy::Expanding, urlEdit->sizePolicy().verticalPolicy()); + connect(urlEdit, SIGNAL(returnPressed()), + SLOT(changeLocation())); + QCompleter *completer = new QCompleter(this); + urlEdit->setCompleter(completer); + completer->setModel(&urlModel); + + QToolBar *bar = addToolBar(QStringLiteral("Navigation")); + bar->addAction(view->view()->pageAction(QWebPage::Back)); + bar->addAction(view->view()->pageAction(QWebPage::Forward)); + bar->addAction(view->view()->pageAction(QWebPage::Reload)); + bar->addAction(view->view()->pageAction(QWebPage::Stop)); + bar->addWidget(urlEdit); + + QMenu *fileMenu = menuBar()->addMenu(i18n("&File")); + QAction *newWindow = fileMenu->addAction(i18n("New Window"), this, SLOT(newWindow())); + + fileMenu->addAction(i18n("Print"), this, SLOT(print())); + fileMenu->addAction(i18n("Close"), this, SLOT(close())); + + QMenu *editMenu = menuBar()->addMenu(i18n("&Edit")); + editMenu->addAction(view->view()->pageAction(QWebPage::Undo)); + editMenu->addAction(view->view()->pageAction(QWebPage::Redo)); + editMenu->addSeparator(); + editMenu->addAction(view->view()->pageAction(QWebPage::Cut)); + editMenu->addAction(view->view()->pageAction(QWebPage::Copy)); + editMenu->addAction(view->view()->pageAction(QWebPage::Paste)); + editMenu->addSeparator(); + QAction *setEditable = editMenu->addAction(i18n("Set Editable"), this, SLOT(setEditable(bool))); + setEditable->setCheckable(true); + + QMenu *viewMenu = menuBar()->addMenu(i18n("&View")); + viewMenu->addAction(view->view()->pageAction(QWebPage::Stop)); + viewMenu->addAction(view->view()->pageAction(QWebPage::Reload)); + viewMenu->addSeparator(); + QAction *zoomIn = viewMenu->addAction(i18n("Zoom &In"), this, SLOT(zoomIn())); + QAction *zoomOut = viewMenu->addAction(i18n("Zoom &Out"), this, SLOT(zoomOut())); + QAction *resetZoom = viewMenu->addAction(i18n("Reset Zoom"), this, SLOT(resetZoom())); + QAction *zoomTextOnly = viewMenu->addAction(i18n("Zoom Text Only"), this, SLOT(toggleZoomTextOnly(bool))); + zoomTextOnly->setCheckable(true); + zoomTextOnly->setChecked(false); + viewMenu->addSeparator(); + viewMenu->addAction(i18n("Dump HTML"), this, SLOT(dumpHtml())); + +#if 0 + QMenu *formatMenu = new QMenu(i18n("F&ormat")); + formatMenuAction = menuBar()->addMenu(formatMenu); + formatMenuAction->setVisible(false); + formatMenu->addAction(view->view()->pageAction(QWebPage::ToggleBold)); + formatMenu->addAction(view->view()->pageAction(QWebPage::ToggleItalic)); + formatMenu->addAction(view->view()->pageAction(QWebPage::ToggleUnderline)); + QMenu *writingMenu = formatMenu->addMenu(i18n("Writing Direction")); + writingMenu->addAction(view->view()->pageAction(QWebPage::SetTextDirectionDefault)); + writingMenu->addAction(view->view()->pageAction(QWebPage::SetTextDirectionLeftToRight)); + writingMenu->addAction(view->view()->pageAction(QWebPage::SetTextDirectionRightToLeft)); +#endif + newWindow->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_N)); + view->view()->pageAction(QWebPage::Back)->setShortcut(QKeySequence::Back); + view->view()->pageAction(QWebPage::Stop)->setShortcut(Qt::Key_Escape); + view->view()->pageAction(QWebPage::Forward)->setShortcut(QKeySequence::Forward); + view->view()->pageAction(QWebPage::Reload)->setShortcut(QKeySequence::Refresh); + view->view()->pageAction(QWebPage::Undo)->setShortcut(QKeySequence::Undo); + view->view()->pageAction(QWebPage::Redo)->setShortcut(QKeySequence::Redo); + view->view()->pageAction(QWebPage::Cut)->setShortcut(QKeySequence::Cut); + view->view()->pageAction(QWebPage::Copy)->setShortcut(QKeySequence::Copy); + view->view()->pageAction(QWebPage::Paste)->setShortcut(QKeySequence::Paste); + zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus)); + zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus)); + resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0)); +// view->view()->pageAction(QWebPage::ToggleBold)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_B)); +// view->view()->pageAction(QWebPage::ToggleItalic)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_I)); +// view->view()->pageAction(QWebPage::ToggleUnderline)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_U)); + + QMenu *toolsMenu = menuBar()->addMenu(i18n("&Tools")); + toolsMenu->addAction(i18n("Select elements..."), this, SLOT(selectElements())); + + } + + WebKitPart *view; + KLineEdit *urlEdit; + QProgressBar *progress; + + QAction *formatMenuAction; + + QStringList urlList; + QStringListModel urlModel; +}; + +class URLLoader : public QObject +{ + Q_OBJECT +public: + URLLoader(QWebView* view, const QString& inputFileName) + : m_view(view) + , m_stdOut(stdout) + { + init(inputFileName); + } + +public slots: + void loadNext() + { + QString qstr; + if (getUrl(qstr)) { + QUrl url(qstr, QUrl::StrictMode); + if (url.isValid()) { + m_stdOut << "Loading " << qstr << " ......" << endl; + m_view->load(url); + } else + loadNext(); + } else + disconnect(m_view, 0, this, 0); + } + +private: + void init(const QString& inputFileName) + { + QFile inputFile(inputFileName); + if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream stream(&inputFile); + QString line; + while (true) { + line = stream.readLine(); + if (line.isNull()) + break; + m_urls.append(line); + } + } else { + kDebug() << "Can't open list file"; + exit(0); + } + m_index = 0; + inputFile.close(); + } + + bool getUrl(QString& qstr) + { + if (m_index == m_urls.size()) + return false; + + qstr = m_urls[m_index++]; + return true; + } + +private: + QVector m_urls; + int m_index; + QWebView* m_view; + QTextStream m_stdOut; +}; + + +int main(int argc, char **argv) +{ + KAboutData about(QStringLiteral("KDELauncher"), i18n("KDELauncher"), QStringLiteral("0.0000013")); + QApplication app(argc, argv); + QCommandLineParser parser; + KAboutData::setApplicationData(about); + parser.addVersionOption(); + parser.addHelpOption(); + //PORTING SCRIPT: adapt aboutdata variable if necessary + about.setupCommandLine(&parser); + parser.process(app); + about.processCommandLine(&parser); + + QString url = QStringLiteral("%1/%2").arg(QDir::homePath()).arg(QStringLiteral("index.html")); + +// QWebSettings::globalSettings()->setMaximumPagesInCache(4); + +// QWebSettings::setObjectCacheCapacities((16*1024*1024) / 8, (16*1024*1024) / 8, 16*1024*1024); + + QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true); +// QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); + + const QStringList args = app.arguments(); + + if (args.contains(QStringLiteral("-r"))) { + // robotized + QString listFile = args.at(2); + if (!(args.count() == 3) && QFile::exists(listFile)) { + kDebug() << "Usage: KDELauncher -r listfile"; + exit(0); + } + MainWindow window; + QWebView *view = window.webView(); + URLLoader loader(view, listFile); + QObject::connect(view, SIGNAL(loadFinished(bool)), &loader, SLOT(loadNext())); + loader.loadNext(); + window.show(); + return app.exec(); + } else { + if (args.count() > 1) + url = args.at(1); + + MainWindow window(url); + + // Opens every given urls in new windows + for (int i = 2; i < args.count(); i++) + window.newWindow(args.at(i)); + + window.show(); + return app.exec(); + } +} + +#include "webkitpart_tester.moc" diff --git b/webkitpart/webkitpart.lsm b/webkitpart/webkitpart.lsm new file mode 100644 index 000000000..1b94c5a24 --- /dev/null +++ b/webkitpart/webkitpart.lsm @@ -0,0 +1,18 @@ +Begin3 +Title: webkitpart +Version: 1.2.0 +Entered-date: 06APR2011 +Description: A WebKit browser component for KDE (KPart) +Keywords: webkit, webkitpart +Author: Trolltech ASA + Urs Wolfer + Laurent Montel + Dawit Alemayehu + Sune Vuorela +Maintained-by: Sune Vuorela +Primary-site: +Home-Page: +Original-site: None +Platforms: KF5 and higher +Copying-policy: LGPL +End