diff options
author | Panagiotis Papadopoulos <pano_90@gmx.net> | 2010-04-21 13:34:20 +0200 |
---|---|---|
committer | Panagiotis Papadopoulos <pano_90@gmx.net> | 2010-04-21 13:34:20 +0200 |
commit | f9153663cb8210ac4d6e7055838344839b4e19b6 (patch) | |
tree | b70233b32eadfbebff062c0000f007ca2f99d732 | |
parent | Merge branch 'master' of git://gitorious.org/rekonq/mainline into i18n (diff) | |
parent | Nebulon's patch. (diff) | |
download | rekonq-f9153663cb8210ac4d6e7055838344839b4e19b6.tar.xz |
Merge branch 'master' of git://gitorious.org/rekonq/mainline into i18n
128 files changed, 9501 insertions, 2802 deletions
@@ -5,4 +5,5 @@ Lionel Chauvin megabigbug@yahoo.fr Johannes Zellner webmaster@nebulon.de Matthieu Gicquel matgic78@gmail.com Ronny Scholz ronny_scholz@web.de -Jonas Gastal jgastal@gmail.com +Jonas Gastal jgastal@gmail.com + diff --git a/CMakeLists.txt b/CMakeLists.txt index 55ea5127..c01220d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ PROJECT( rekonq ) # Informations to update before to release this package. # rekonq info -SET(REKONQ_VERSION "0.3.34" ) +SET(REKONQ_VERSION "0.4.62" ) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/version.h ) @@ -23,7 +23,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6.2) SET(QT_MIN_VERSION 4.6.0) FIND_PACKAGE(Qt4 REQUIRED) -SET(KDE_MIN_VERSION 4.3.80) +SET(KDE_MIN_VERSION 4.4.0) FIND_PACKAGE(KDE4 REQUIRED) INCLUDE(MacroOptionalFindPackage) @@ -97,6 +97,7 @@ IF(REKONQ_CAN_BE_COMPILED) ADD_SUBDIRECTORY( src ) ADD_SUBDIRECTORY( icons ) ADD_SUBDIRECTORY( docs ) +# ADD_SUBDIRECTORY( i18n ) ENDIF(REKONQ_CAN_BE_COMPILED) @@ -1,3 +1,28 @@ +0.4 +- moved to kdewebkit (this means based on kde 4.4) +- kwallet support +- KIO full support (cookies, cache, proxy, network) +- file:// && ftp:// protocol easy handling +- improved rekonq pages (in the about: protocol) +- multithreaded url resolver (hopefully, no more UI freezes) +- adblock support, first part (load manually links, for now...) +- improved fullscreen mode +- embedded inspector (A-LA firebug) +- first kget integration +- optional "clickToFlash" feature +- tons of bugs fixed + +0.3 +- Simpler UI +- new icon +- multi windows support +- KDE proxy setting support +- "new tab home page" (tech preview) +- Initial handbook added +- tab previews +- save & restore session support +- Compiles on Windows, too + 0.2 - simpler and better UI - unique urlbar (integrated google search) diff --git a/docs/index.docbook b/docs/index.docbook index ca07e9cf..5c4afac7 100644 --- a/docs/index.docbook +++ b/docs/index.docbook @@ -50,7 +50,7 @@ <abstract> <para> -&rekonq; is a lightweight web browser for &kde; based on WebKit. +&rekonq; is a lightweight web browser for &kde; based on QtWebKit. </para> </abstract> @@ -70,14 +70,14 @@ <title>Overview</title> <para> -&rekonq; is a lightweight web browser for &kde; based on WebKit. It can currently +&rekonq; is a lightweight web browser for &kde; based on QtWebKit. Amongst other it provides the following features: <itemizedlist> -<listitem><para>Share bookmarks with &konqueror;</para></listitem> -<listitem><para>Share Cookies with &konqueror;</para></listitem> -<listitem><para>Handle tabbed browsing</para></listitem> -<listitem><para>Display tab previews</para></listitem> -<listitem><para>Handle support for NS plugins (eg: flash)</para></listitem> -<listitem><para>Share General &kde; Proxy settings</para></listitem> +<listitem><para>Shared bookmarks with &konqueror;</para></listitem> +<listitem><para>Shared cookies with &konqueror;</para></listitem> +<listitem><para>Tabbed browsing</para></listitem> +<listitem><para>Display of tab previews</para></listitem> +<listitem><para>Support for NS plugins (⪚: Flash)</para></listitem> +<listitem><para>Shared general &kde; proxy settings</para></listitem> <listitem><para>Browse anonymously</para></listitem> <listitem><para>Inspect web pages</para></listitem> </itemizedlist> @@ -91,8 +91,8 @@ <title>Introduction</title> <para> -&rekonq; is a lightweight web browser for &kde; based on WebKit. Its code is based on Nokia QtDemoBrowser. -Its implementation is going to embrace &kde; technologies to have a full-featured &kde; web browser. +&rekonq; is a lightweight web browser for &kde; based on QtWebKit. Its code is based on the Nokia QtDemoBrowser. +Its implementation is going to embrace &kde; technologies, in order to have a full-featured &kde; web browser. </para> </chapter> <!-- ================== CHAPTER ================== --> @@ -169,7 +169,7 @@ Documentation copyright 2009 &Rohan.Garg; &Rohan.Garg.mail; <!--TRANS:CREDIT_FOR_TRANSLATORS--> &underFDL; <!-- FDL: do not remove --> -&underBSDLicense; <!-- BSD License --> +&underGPL; <!-- GPL License --> </chapter> @@ -185,15 +185,16 @@ Documentation copyright 2009 &Rohan.Garg; &Rohan.Garg.mail; <title>Requirements</title> <para> -In order to successfully use &rekonq;, you need at least &Qt; 4.5.x and &kde; 4.3.x. +In order to successfully use &rekonq;, you need at least &Qt; 4.6.x and &kde; 4.4.x. </para> </sect1> <sect1 id="compilation"> <title>Compilation and Installation</title> -<para>If you wish to compile &rekonq;,go to +<para>If you wish to compile &rekonq;, go to <ulink url="http://techbase.kde.org/Projects/rekonq/Compiling_rekonq">The how to compile &rekonq; page</ulink>. +<!-- TODO: add the instructions from the webpage above, to this docbook --> </para> </sect1> diff --git a/scripts/RELEASE_HOWTO b/scripts/RELEASE_HOWTO index c0ae221e..eb3c3665 100644 --- a/scripts/RELEASE_HOWTO +++ b/scripts/RELEASE_HOWTO @@ -8,7 +8,7 @@ SECTION 0: A few days in advance SECTION 1: Preparation -* Check the README file is still relevant +* Update CHANGELOG file * Bump Version Number (in the CMakeLists.txt file) * Commit the source to GIT diff --git a/scripts/codingstyle.sh b/scripts/codingstyle.sh index bb3add49..bb3add49 100755..100644 --- a/scripts/codingstyle.sh +++ b/scripts/codingstyle.sh diff --git a/scripts/download_i18n.sh b/scripts/download_i18n.sh new file mode 100644 index 00000000..a70c11d8 --- /dev/null +++ b/scripts/download_i18n.sh @@ -0,0 +1,83 @@ +#!/bin/sh +# use this stupid script to just prepare rekonq +# dir with translations. +# +# 1. Update the lists of the ready (about 80%) translations +# check the situation here: http://l10n.kde.org/stats/gui/trunk-kde4/po/rekonq.po/ +LIST="pt_BR en_GB ca zh_CN cs da nl fr gl de hu it nds pl pt ru sr es sv tr uk" + +# 2. run this script. It will create an i18n dir in rekonq sources ($RK_SRCS variable, set it to your source path) +# dir with all the listed translations (eg: italian translation = rekonq_it.po file) +# plus the CMakeLists.txt file needed to compile them. +RK_SRCS=/DATI/KDE/SRC/rekonq + +# 3. Uncomment the "ADD_SUBDIRECTORY( i18n )" line in main CMakeLists.txt file. + +# 4. test a package creation (to see the translations installed) + +# THAT's ALL!! + +######################################################################################################## + +# exit on most errors +set -e + +# current dir +CWD=$(pwd) + +# create the i18n dir +cd $RK_SRCS +mkdir -p i18n +cd i18n + +# download the po files +for lang in $LIST +do + wget http://websvn.kde.org/*checkout*/trunk/l10n-kde4/$lang/messages/playground-network/rekonq.po; + mv rekonq.po rekonq_$lang.po; +done + +# create the CMakeLists.txt file for the translations + + +echo ' + +FIND_PROGRAM(GETTEXT_MSGFMT_EXECUTABLE msgfmt) + +IF(NOT GETTEXT_MSGFMT_EXECUTABLE) + MESSAGE( +"------ + NOTE: msgfmt not found. Translations will *not* be installed +------") +ELSE(NOT GETTEXT_MSGFMT_EXECUTABLE) + + SET(catalogname rekonq) + + ADD_CUSTOM_TARGET(translations ALL) + + FILE(GLOB PO_FILES ${catalogname}*.po) + + FOREACH(_poFile ${PO_FILES}) + GET_FILENAME_COMPONENT(_poFileName ${_poFile} NAME) + STRING(REGEX REPLACE "^${catalogname}_?" "" _langCode ${_poFileName} ) + STRING(REGEX REPLACE "\\.po$" "" _langCode ${_langCode} ) + + IF( _langCode ) + GET_FILENAME_COMPONENT(_lang ${_poFile} NAME_WE) + SET(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo) + + ADD_CUSTOM_COMMAND(TARGET translations + COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} --check -o ${_gmoFile} ${_poFile} + DEPENDS ${_poFile}) + INSTALL(FILES ${_gmoFile} DESTINATION ${LOCALE_INSTALL_DIR}/${_langCode}/LC_MESSAGES/ RENAME ${catalogname}.mo) + ENDIF( _langCode ) + + ENDFOREACH(_poFile ${PO_FILES}) + +ENDIF(NOT GETTEXT_MSGFMT_EXECUTABLE) + +' > CMakeLists.txt + +# done :) +cd $CWD +echo "Done. Yuppy!" diff --git a/scripts/i18n.sh b/scripts/i18n.sh index e9b5444d..e9b5444d 100755..100644 --- a/scripts/i18n.sh +++ b/scripts/i18n.sh diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b0a3fbd8..2ab308de 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,37 +8,41 @@ ADD_SUBDIRECTORY( tests ) SET( rekonq_KDEINIT_SRCS application.cpp + clicktoflash.cpp + filterurljob.cpp findbar.cpp mainview.cpp mainwindow.cpp - previewimage.cpp + networkaccessmanager.cpp + newtabpage.cpp + paneltreeview.cpp + previewselectorbar.cpp + protocolhandler.cpp sessionmanager.cpp tabbar.cpp + walletbar.cpp + webinspectorpanel.cpp webpage.cpp webpluginfactory.cpp + websslinfo.cpp websnap.cpp webview.cpp webtab.cpp - clicktoflash.cpp - networkaccessmanager.cpp - webinspectorpanel.cpp - walletbar.cpp - protocolhandler.cpp - filterurljob.cpp #---------------------------------------- history/autosaver.cpp history/historymanager.cpp history/historymodels.cpp history/historypanel.cpp #---------------------------------------- - rekonqpage/newtabpage.cpp - #---------------------------------------- settings/settingsdialog.cpp + settings/adblockwidget.cpp + settings/networkwidget.cpp #---------------------------------------- bookmarks/bookmarksmanager.cpp bookmarks/bookmarkspanel.cpp bookmarks/bookmarkstreemodel.cpp bookmarks/bookmarksproxy.cpp + bookmarks/bookmarkcontextmenu.cpp #---------------------------------------- adblock/adblockmanager.cpp adblock/adblocknetworkreply.cpp @@ -46,6 +50,9 @@ SET( rekonq_KDEINIT_SRCS #---------------------------------------- urlbar/urlbar.cpp urlbar/lineedit.cpp + urlbar/completionwidget.cpp + urlbar/urlresolver.cpp + urlbar/listitem.cpp ) @@ -54,6 +61,7 @@ KDE4_ADD_UI_FILES( rekonq_KDEINIT_SRCS settings/settings_tabs.ui settings/settings_fonts.ui settings/settings_webkit.ui + settings/settings_adblock.ui cleardata.ui ) diff --git a/src/Messages.sh b/src/Messages.sh index b22743a6..efa6adff 100644 --- a/src/Messages.sh +++ b/src/Messages.sh @@ -1,2 +1,2 @@ #! /bin/sh -$XGETTEXT *.cpp -o $podir/rekonq.pot +$XGETTEXT *.cpp */*.cpp -o $podir/rekonq.pot diff --git a/src/adblock/adblockmanager.cpp b/src/adblock/adblockmanager.cpp index c2a42f0b..0a139bdc 100644 --- a/src/adblock/adblockmanager.cpp +++ b/src/adblock/adblockmanager.cpp @@ -2,7 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -28,6 +28,9 @@ #include "adblockmanager.h" #include "adblockmanager.moc" +// Auto Includes +#include "rekonq.h" + // Local Includes #include "adblocknetworkreply.h" #include "webpage.h" @@ -36,6 +39,7 @@ #include <KSharedConfig> #include <KConfigGroup> #include <KDebug> +#include <KIO/TransferJob> // Qt Includes #include <QUrl> @@ -46,8 +50,8 @@ AdBlockManager::AdBlockManager(QObject *parent) : QObject(parent) , _isAdblockEnabled(false) , _isHideAdsEnabled(false) + , _index(0) { - loadSettings(); } @@ -56,60 +60,95 @@ AdBlockManager::~AdBlockManager() } -void AdBlockManager::loadSettings() +void AdBlockManager::loadSettings(bool checkUpdateDate) { - KSharedConfig::Ptr config = KSharedConfig::openConfig("khtmlrc", KConfig::NoGlobals); - KConfigGroup cg( config, "Filter Settings" ); + _index = 0; + _buffer.clear(); + + _whiteList.clear(); + _blackList.clear(); + _hideList.clear(); + + _isAdblockEnabled = ReKonfig::adBlockEnabled(); + kDebug() << "ADBLOCK ENABLED = " << _isAdblockEnabled; + + // no need to load filters if adblock is not enabled :) + if(!_isAdblockEnabled) + return; + + // just to be sure.. + _isHideAdsEnabled = ReKonfig::hideAdsEnabled(); + + // local settings + KSharedConfig::Ptr config = KGlobal::config(); + KConfigGroup rulesGroup( config, "rules" ); + QStringList rules; + rules = rulesGroup.readEntry( "local-rules" , QStringList() ); + loadRules(rules); - if ( cg.exists() ) + // ---------------------------------------------------------- + + QDateTime today = QDateTime::currentDateTime(); + QDateTime lastUpdate = ReKonfig::lastUpdate(); // the day of the implementation.. :) + int days = ReKonfig::updateInterval(); + + if( !checkUpdateDate || today > lastUpdate.addDays( days ) ) { - _isAdblockEnabled = cg.readEntry("Enabled", false); - _isHideAdsEnabled = cg.readEntry("Shrink", false); + ReKonfig::setLastUpdate( today ); + + updateNextSubscription(); + return; + } - // no need to load filters if adblock is not enabled :) - if(!_isAdblockEnabled) - return; + // else + QStringList titles = ReKonfig::subscriptionTitles(); + foreach(const QString &title, titles) + { + rules = rulesGroup.readEntry( title + "-rules" , QStringList() ); + loadRules(rules); + } +} - _whiteList.clear(); - _blackList.clear(); - _hideList.clear(); + +void AdBlockManager::loadRules(const QStringList &rules) +{ + foreach(const QString &stringRule, rules) + { + // ! rules are comments + if( stringRule.startsWith('!') ) + continue; + + // [ rules are ABP infos + if( stringRule.startsWith('[') ) + continue; - QMap<QString,QString> entryMap = cg.entryMap(); - QMap<QString,QString>::ConstIterator it; - for( it = entryMap.constBegin(); it != entryMap.constEnd(); ++it ) + // empty rules are just dangerous.. + // (an empty rule in whitelist allows all, in blacklist blocks all..) + if( stringRule.isEmpty() ) + continue; + + // white rules + if( stringRule.startsWith( QLatin1String("@@") ) ) { - QString name = it.key(); - QString url = it.value(); - - if (name.startsWith(QLatin1String("Filter"))) - { - if(!url.startsWith("!")) - { - // white rules - if(url.startsWith("@@")) - { - AdBlockRule rule( url.mid(2) ); - _whiteList << rule; - continue; - } - - // hide (CSS) rules - if(url.startsWith("##")) - { - _hideList << url.mid(2); - continue; - } - - AdBlockRule rule( url ); - _blackList << rule; - } - } + AdBlockRule rule( stringRule.mid(2) ); + _whiteList << rule; + continue; + } + + // hide (CSS) rules + if( stringRule.startsWith( QLatin1String("##") ) ) + { + _hideList << stringRule.mid(2); + continue; } + + AdBlockRule rule( stringRule ); + _blackList << rule; } } -QNetworkReply *AdBlockManager::block(const QNetworkRequest &request) +QNetworkReply *AdBlockManager::block(const QNetworkRequest &request, WebPage *page) { if (!_isAdblockEnabled) return 0; @@ -125,7 +164,9 @@ QNetworkReply *AdBlockManager::block(const QNetworkRequest &request) { if(filter.match(urlString)) { - kDebug() << "****ADBLOCK: WHITE RULE (@@) Matched: ***********" << urlString; + kDebug() << "****ADBLOCK: WHITE RULE (@@) Matched: ***********"; + kDebug() << "Filter exp: " << filter.pattern(); + kDebug() << "UrlString: " << urlString; return 0; } } @@ -135,7 +176,23 @@ QNetworkReply *AdBlockManager::block(const QNetworkRequest &request) { if(filter.match(urlString)) { - kDebug() << "****ADBLOCK: BLACK RULE Matched: ***********" << urlString; + kDebug() << "****ADBLOCK: BLACK RULE Matched: ***********"; + kDebug() << "Filter exp: " << filter.pattern(); + kDebug() << "UrlString: " << urlString; + + QWebElement document = page->mainFrame()->documentElement(); + QWebElementCollection elements = document.findAll("*"); + foreach (QWebElement el, elements) + { + if(filter.match( el.attribute("src") ) ) + { + kDebug() << "MATCHES ATTRIBUTE!!!!!"; + el.setStyleProperty(QLatin1String("visibility"), QLatin1String("hidden")); + el.setStyleProperty(QLatin1String("width"), QLatin1String("0")); + el.setStyleProperty(QLatin1String("height"), QLatin1String("0")); + } + } + AdBlockNetworkReply *reply = new AdBlockNetworkReply(request, urlString, this); return reply; } @@ -148,7 +205,7 @@ QNetworkReply *AdBlockManager::block(const QNetworkRequest &request) void AdBlockManager::applyHidingRules(WebPage *page) { - if(!page || !page->mainFrame()) + if(!page) return; if (!_isAdblockEnabled) @@ -156,16 +213,116 @@ void AdBlockManager::applyHidingRules(WebPage *page) if (!_isHideAdsEnabled) return; + + QWebElement document = page->mainFrame()->documentElement(); + // HIDE RULES foreach(const QString &filter, _hideList) { - QWebElement document = page->mainFrame()->documentElement(); QWebElementCollection elements = document.findAll(filter); - foreach (QWebElement element, elements) + foreach (QWebElement el, elements) { - element.setStyleProperty(QLatin1String("visibility"), QLatin1String("hidden")); - element.removeFromDocument(); + if(el.isNull()) + continue; + kDebug() << "Hide element: " << el.localName(); + el.setStyleProperty(QLatin1String("visibility"), QLatin1String("hidden")); + el.removeFromDocument(); } } } + + +void AdBlockManager::updateNextSubscription() +{ + QStringList locations = ReKonfig::subscriptionLocations(); + + if( _index < locations.size() ) + { + QString urlString = locations.at(_index); + kDebug() << "DOWNLOADING FROM " << urlString; + KUrl subUrl = KUrl( urlString ); + + KIO::TransferJob* job = KIO::get( subUrl , KIO::Reload , KIO::HideProgressInfo ); + connect(job, SIGNAL(data(KIO::Job*, const QByteArray&)), this, SLOT(subscriptionData(KIO::Job*, const QByteArray&))); + connect(job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*))); + + return; + } + + _index = 0; + _buffer.clear(); +} + + +void AdBlockManager::slotResult(KJob *job) +{ + kDebug() << "SLOTRESULT"; + if(job->error()) + return; + + QList<QByteArray> list = _buffer.split('\n'); + QStringList ruleList; + foreach(const QByteArray &ba, list) + { + kDebug() << ba; + ruleList << QString(ba); + } + loadRules(ruleList); + saveRules(ruleList); + + _index++; + + // last.. + updateNextSubscription(); +} + + +void AdBlockManager::subscriptionData(KIO::Job* job, const QByteArray& data) +{ + kDebug() << "subscriptionData"; + Q_UNUSED(job) + + if (data.isEmpty()) + return; + + int oldSize = _buffer.size(); + _buffer.resize( _buffer.size() + data.size() ); + memcpy( _buffer.data() + oldSize, data.data(), data.size() ); +} + + +void AdBlockManager::saveRules(const QStringList &rules) +{ + QStringList cleanedRules; + foreach(const QString &r, rules) + { + if( !r.startsWith('!') && !r.startsWith('[') && !r.isEmpty() ) + cleanedRules << r; + } + + QStringList titles = ReKonfig::subscriptionTitles(); + QString title = titles.at(_index) + "-rules"; + + KSharedConfig::Ptr config = KGlobal::config(); + KConfigGroup cg( config , "rules" ); + cg.writeEntry( title, cleanedRules ); +} + + +void AdBlockManager::addSubscription(const QString &title, const QString &location) +{ + QStringList titles = ReKonfig::subscriptionTitles(); + if( titles.contains(title) ) + return; + + QStringList locations = ReKonfig::subscriptionLocations(); + if( locations.contains(location) ) + return; + + titles << title; + locations << location; + + ReKonfig::setSubscriptionTitles(titles); + ReKonfig::setSubscriptionLocations(locations); +} diff --git a/src/adblock/adblockmanager.h b/src/adblock/adblockmanager.h index f01aaca0..9b1cc915 100644 --- a/src/adblock/adblockmanager.h +++ b/src/adblock/adblockmanager.h @@ -2,7 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -105,12 +105,15 @@ // Local Includes +#include "rekonqprivate_export.h" #include "adblockrule.h" // Qt Includes #include <QObject> #include <QNetworkReply> #include <QStringList> +#include <QByteArray> +#include <KIO/Job> // Forward Includes class QNetworkRequest; @@ -120,7 +123,7 @@ class WebPage; typedef QList<AdBlockRule> AdBlockRuleList; -class AdBlockManager : public QObject +class REKONQ_TESTS_EXPORT AdBlockManager : public QObject { Q_OBJECT @@ -128,9 +131,21 @@ public: AdBlockManager(QObject *parent = 0); ~AdBlockManager(); - void loadSettings(); - QNetworkReply *block(const QNetworkRequest &request); + QNetworkReply *block(const QNetworkRequest &request, WebPage *page); void applyHidingRules(WebPage *page); + void addSubscription(const QString &title, const QString &location); + +public slots: + void loadSettings(bool checkUpdateDate = true); + +private: + void updateNextSubscription(); + void saveRules(const QStringList &); + void loadRules(const QStringList &); + +private slots: + void slotResult(KJob *); + void subscriptionData(KIO::Job*, const QByteArray&); private: bool _isAdblockEnabled; @@ -139,6 +154,9 @@ private: AdBlockRuleList _blackList; AdBlockRuleList _whiteList; QStringList _hideList; + + int _index; + QByteArray _buffer; }; #endif diff --git a/src/adblock/adblocknetworkreply.cpp b/src/adblock/adblocknetworkreply.cpp index 1ccca96d..3b73b8a0 100644 --- a/src/adblock/adblocknetworkreply.cpp +++ b/src/adblock/adblocknetworkreply.cpp @@ -28,7 +28,7 @@ * * This file is a part of the rekonq project * - * Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> + * Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -68,7 +68,7 @@ AdBlockNetworkReply::AdBlockNetworkReply(const QNetworkRequest &request, const Q setOperation(QNetworkAccessManager::GetOperation); setRequest(request); setUrl(request.url()); - setError(QNetworkReply::ContentAccessDenied, i18n("Blocked by AdBlockRule: %1").arg(urlString)); + setError(QNetworkReply::ContentAccessDenied, i18n("Blocked by AdBlockRule: %1", urlString) ); QTimer::singleShot(0, this, SLOT(delayedFinished())); } diff --git a/src/adblock/adblocknetworkreply.h b/src/adblock/adblocknetworkreply.h index b5bb8300..bbc3471e 100644 --- a/src/adblock/adblocknetworkreply.h +++ b/src/adblock/adblocknetworkreply.h @@ -28,7 +28,7 @@ * * This file is a part of the rekonq project * - * Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> + * Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -54,6 +54,9 @@ #define ADBLOCK_NETWORK_REPLY_H +// Local Includes +#include "rekonqprivate_export.h" + // Qt Includes #include <QNetworkReply> #include <QString> @@ -62,7 +65,7 @@ class AdBlockRule; -class AdBlockNetworkReply : public QNetworkReply +class REKONQ_TESTS_EXPORT AdBlockNetworkReply : public QNetworkReply { Q_OBJECT diff --git a/src/adblock/adblockrule.cpp b/src/adblock/adblockrule.cpp index 9f86ffee..c0c3fd5b 100644 --- a/src/adblock/adblockrule.cpp +++ b/src/adblock/adblockrule.cpp @@ -30,7 +30,7 @@ * * This file is a part of the rekonq project * - * Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> + * Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -181,3 +181,9 @@ QString AdBlockRule::convertPatternToRegExp(const QString &wildcardPattern) // Finally, return... return pattern; } + + +QString AdBlockRule::pattern() const +{ + return m_regExp.pattern(); +} diff --git a/src/adblock/adblockrule.h b/src/adblock/adblockrule.h index 35715051..ee4825d1 100644 --- a/src/adblock/adblockrule.h +++ b/src/adblock/adblockrule.h @@ -29,7 +29,7 @@ * * This file is a part of the rekonq project * - * Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> + * Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -54,6 +54,7 @@ #ifndef ADBLOCKRULE_H #define ADBLOCKRULE_H + // Qt Includes #include <QRegExp> #include <QString> @@ -68,7 +69,9 @@ public: AdBlockRule(const QString &filter); bool match(const QString &encodedUrl) const; - + + QString pattern() const; + private: QString convertPatternToRegExp(const QString &wildcardPattern); diff --git a/src/application.cpp b/src/application.cpp index 05004f30..db6d3c32 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -2,9 +2,9 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -53,7 +53,6 @@ #include <KToolInvocation> #include <KUriFilter> #include <KMessageBox> -#include <KWindowInfo> #include <KUrl> #include <ThreadWeaver/Weaver> @@ -64,10 +63,10 @@ #include <QtCore/QTimer> -QPointer<HistoryManager> Application::s_historyManager; -QPointer<BookmarkProvider> Application::s_bookmarkProvider; -QPointer<SessionManager> Application::s_sessionManager; -QPointer<AdBlockManager> Application::s_adblockManager; +QWeakPointer<HistoryManager> Application::s_historyManager; +QWeakPointer<BookmarkProvider> Application::s_bookmarkProvider; +QWeakPointer<SessionManager> Application::s_sessionManager; +QWeakPointer<AdBlockManager> Application::s_adblockManager; Application::Application() @@ -80,27 +79,51 @@ Application::Application() Application::~Application() { - qDeleteAll(m_mainWindows); + // ok, we are closing well. + // Don't recover on next load.. + ReKonfig::setRecoverOnCrash(0); + saveConfiguration(); + + foreach( QWeakPointer<MainWindow> window, m_mainWindows) + { + delete window.data(); + window.clear(); + } - delete s_bookmarkProvider; - delete s_historyManager; - delete s_sessionManager; - delete s_adblockManager; + delete s_bookmarkProvider.data(); + s_bookmarkProvider.clear(); + + delete s_historyManager.data(); + s_historyManager.clear(); + + delete s_sessionManager.data(); + s_sessionManager.clear(); + + delete s_adblockManager.data(); + s_adblockManager.clear(); } int Application::newInstance() { - KCmdLineArgs::setCwd(QDir::currentPath().toUtf8()); + KCmdLineArgs::setCwd( QDir::currentPath().toUtf8() ); KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); - - // we share one process for several mainwindows, - // so initialize only once - static bool first = true; + + bool isFirstLoad = m_mainWindows.isEmpty(); + + // is your app session restored? restore session... + // this mechanism also falls back to load usual plain rekonq + // if something goes wrong... + if (isFirstLoad && ReKonfig::recoverOnCrash() == 1 && sessionManager()->restoreSession()) + { + QTimer::singleShot(0, this, SLOT(postLaunch())); + kDebug() << "session restored"; + return 1; + } if(args->count() == 0) { - if(first) // we are starting rekonq, for the first time with no args: use startup behaviour + if(isFirstLoad) // we are starting rekonq, for the first time with no args: use startup behaviour { switch(ReKonfig::startupBehaviour()) { @@ -120,54 +143,34 @@ int Application::newInstance() } else // rekonq has just been started. Just open a new window { - newMainWindow(); + loadUrl( KUrl("about:home") , Rekonq::NewWindow ); } } - - if (first) - { - QTimer::singleShot(0, this, SLOT(postLaunch())); - first = false; - } - - // is your app session restored? restore session... - // this mechanism also falls back to load usual plain rekonq - // if something goes wrong... - if (isSessionRestored() && sessionManager()->restoreSession()) - { - kDebug() << "session restored"; - return 1; - } - - // are there args? load them.. - if (args->count() > 0) + else { - // is there a window open on the current desktop ? use it! - for (int i = 0; i < m_mainWindows.size(); ++i) + if(isFirstLoad) { - MainWindow *m = m_mainWindows.at(i); - KWindowInfo w = KWindowInfo(m->winId(), NET::WMDesktop); - if(w.isOnCurrentDesktop()) + // No windows in the current desktop? No windows at all? + // Create a new one and load there sites... + loadUrl(args->arg(0), Rekonq::CurrentTab); + for (int i = 1; i < args->count(); ++i) + loadUrl( KUrl( args->arg(i) ), Rekonq::SettingOpenTab); + } + else + { + // are there any windows there? use it + int index = m_mainWindows.size(); + if(index > 0) { + MainWindow *m = m_mainWindows.at(index - 1).data(); m->activateWindow(); - m->raise(); - for (int i = 0; i < args->count(); ++i) - loadUrl(args->arg(i), Rekonq::NewCurrentTab); - - return 2; + loadUrl( KUrl( args->arg(i) ), Rekonq::NewCurrentTab); } } - - // No windows in the current desktop? No windows at all? - // Create a new one and load there sites... - loadUrl(args->arg(0), Rekonq::CurrentTab); - for (int i = 1; i < args->count(); ++i) - loadUrl(args->arg(i), Rekonq::SettingOpenTab); - - return 3; } - + + QTimer::singleShot(0, this, SLOT(postLaunch())); return 0; } @@ -192,6 +195,11 @@ void Application::postLaunch() // bookmarks loading connect(Application::bookmarkProvider(), SIGNAL(openUrl(const KUrl&, const Rekonq::OpenType&)), Application::instance(), SLOT(loadUrl(const KUrl&, const Rekonq::OpenType&))); + + // crash recovering + int n = ReKonfig::recoverOnCrash(); + ReKonfig::setRecoverOnCrash(++n); + saveConfiguration(); } @@ -210,7 +218,7 @@ MainWindow *Application::mainWindow() if(!active) { - return m_mainWindows.at(0); + return m_mainWindows.at(0).data(); } return active; } @@ -218,53 +226,55 @@ MainWindow *Application::mainWindow() HistoryManager *Application::historyManager() { - if (!s_historyManager) + if ( s_historyManager.isNull() ) { s_historyManager = new HistoryManager(); - QWebHistoryInterface::setDefaultInterface(s_historyManager); + QWebHistoryInterface::setDefaultInterface( s_historyManager.data() ); } - return s_historyManager; + return s_historyManager.data(); } BookmarkProvider *Application::bookmarkProvider() { - if (!s_bookmarkProvider) + if ( s_bookmarkProvider.isNull() ) { s_bookmarkProvider = new BookmarkProvider(instance()); } - return s_bookmarkProvider; + return s_bookmarkProvider.data(); } SessionManager *Application::sessionManager() { - if(!s_sessionManager) + if( s_sessionManager.isNull() ) { s_sessionManager = new SessionManager(instance()); } - return s_sessionManager; + return s_sessionManager.data(); } KIcon Application::icon(const KUrl &url) { - if(!Application::instance()->mainWindowList().isEmpty()) // avoid infinite loop at startup - { + // avoid infinite loop at startup + if( Application::instance()->mainWindowList().isEmpty() ) + return KIcon("text-html"); - if(url == KUrl("about:closedTabs")) - return KIcon("tab-close"); - if(url == KUrl("about:history")) - return KIcon("view-history"); - if(url == KUrl("about:bookmarks")) - return KIcon("bookmarks"); - if(url == KUrl("about:favorites")) - return KIcon("emblem-favorite"); - } - + // first things first.. if(url.isEmpty()) return KIcon("text-html"); - + + // rekonq icons.. + if(url == KUrl("about:closedTabs")) + return KIcon("tab-close"); + if(url == KUrl("about:history")) + return KIcon("view-history"); + if(url == KUrl("about:bookmarks")) + return KIcon("bookmarks"); + if(url == KUrl("about:favorites")) + return KIcon("emblem-favorite"); + KIcon icon = KIcon(QWebSettings::iconForUrl(url)); if (icon.isNull()) { @@ -279,12 +289,9 @@ void Application::loadUrl(const KUrl& url, const Rekonq::OpenType& type) if (url.isEmpty()) return; - // sanitization - KUrl loadingUrl( url.toEncoded() ); - - if ( !loadingUrl.isValid() ) + if ( !url.isValid() ) { - KMessageBox::error(0, i18n("Malformed URL:\n%1", loadingUrl.url(KUrl::RemoveTrailingSlash))); + KMessageBox::error(0, i18n("Malformed URL:\n%1", url.url(KUrl::RemoveTrailingSlash))); return; } @@ -316,19 +323,12 @@ void Application::loadUrl(const KUrl& url, const Rekonq::OpenType& type) if (view) { - FilterUrlJob *job = new FilterUrlJob(view, loadingUrl.pathOrUrl(), this); + FilterUrlJob *job = new FilterUrlJob(view, url.pathOrUrl(), this); Weaver::instance()->enqueue(job); } } - -void Application::loadUrl(const QString& urlString, const Rekonq::OpenType& type) -{ - return loadUrl( QUrl::fromUserInput(urlString), type ); -} - - MainWindow *Application::newMainWindow() { MainWindow *w = new MainWindow(); @@ -343,7 +343,7 @@ MainWindow *Application::newMainWindow() void Application::removeMainWindow(MainWindow *window) { - m_mainWindows.removeAt(m_mainWindows.indexOf(window, 0)); + m_mainWindows.removeOne(window); } @@ -355,11 +355,11 @@ MainWindowList Application::mainWindowList() AdBlockManager *Application::adblockManager() { - if(!s_adblockManager) + if( s_adblockManager.isNull() ) { s_adblockManager = new AdBlockManager(instance()); } - return s_adblockManager; + return s_adblockManager.data(); } @@ -369,9 +369,11 @@ void Application::loadResolvedUrl(ThreadWeaver::Job *job) KUrl url = threadedJob->url(); WebView *view = threadedJob->view(); + // Bye and thanks :) + delete threadedJob; + if (view) { - view->setFocus(); view->load(url); // we are sure of the url now, let's add it to history @@ -380,7 +382,11 @@ void Application::loadResolvedUrl(ThreadWeaver::Job *job) if( url.protocol() == QLatin1String("http") || url.protocol() == QLatin1String("https") ) historyManager()->addHistoryEntry( url.prettyUrl() ); } - - // Bye and thanks :) - delete threadedJob; +} + + +void Application::newWindow() +{ + loadUrl( KUrl("about:home"), Rekonq::NewWindow ); + mainWindow()->mainView()->urlBarWidget()->setFocus(); } diff --git a/src/application.h b/src/application.h index 4b951ded..c268d586 100644 --- a/src/application.h +++ b/src/application.h @@ -2,9 +2,9 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -29,6 +29,8 @@ #ifndef APPLICATION_H #define APPLICATION_H +// Local Includes +#include "rekonqprivate_export.h" // KDE Includes #include <KUniqueApplication> @@ -38,7 +40,7 @@ #include <ThreadWeaver/Job> // Qt Includes -#include <QPointer> +#include <QWeakPointer> #include <QList> // Forward Declarations @@ -52,7 +54,7 @@ class AdBlockManager; class WebView; -typedef QList< QPointer<MainWindow> > MainWindowList; +typedef QList< QWeakPointer<MainWindow> > MainWindowList; namespace Rekonq @@ -89,7 +91,7 @@ namespace Rekonq /** * */ -class Application : public KUniqueApplication +class REKONQ_TESTS_EXPORT Application : public KUniqueApplication { Q_OBJECT @@ -100,6 +102,7 @@ public: static Application *instance(); MainWindow *mainWindow(); + MainWindow *newMainWindow(); MainWindowList mainWindowList(); static KIcon icon(const KUrl &url); @@ -117,16 +120,11 @@ public slots: */ void saveConfiguration() const; - MainWindow *newMainWindow(); - void loadUrl( const KUrl& url, const Rekonq::OpenType& type = Rekonq::CurrentTab ); - - void loadUrl( const QString& urlString, - const Rekonq::OpenType& type = Rekonq::CurrentTab - ); + void newWindow(); void removeMainWindow(MainWindow *window); private slots: @@ -139,10 +137,10 @@ private slots: void loadResolvedUrl(ThreadWeaver::Job *); private: - static QPointer<HistoryManager> s_historyManager; - static QPointer<BookmarkProvider> s_bookmarkProvider; - static QPointer<SessionManager> s_sessionManager; - static QPointer<AdBlockManager> s_adblockManager; + static QWeakPointer<HistoryManager> s_historyManager; + static QWeakPointer<BookmarkProvider> s_bookmarkProvider; + static QWeakPointer<SessionManager> s_sessionManager; + static QWeakPointer<AdBlockManager> s_adblockManager; MainWindowList m_mainWindows; }; diff --git a/src/bookmarks/bookmarkcontextmenu.cpp b/src/bookmarks/bookmarkcontextmenu.cpp new file mode 100644 index 00000000..aab6af90 --- /dev/null +++ b/src/bookmarks/bookmarkcontextmenu.cpp @@ -0,0 +1,325 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Yoann Laissus <yoann dot laissus at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "bookmarkcontextmenu.h" +#include "bookmarkcontextmenu.moc" + +// Local Includes +#include "application.h" +#include "bookmarksmanager.h" + +// KDE Includes +#include <KMessageBox> +#include <KActionCollection> +#include <KBookmarkDialog> + +// Qt Includes +#include <QClipboard> + + +BookmarkContextMenu::BookmarkContextMenu(const KBookmark & bookmark, KBookmarkManager *manager, KBookmarkOwner *owner, QWidget *parent) + : KBookmarkContextMenu(bookmark, manager, owner, parent) + , m_ac(new KActionCollection(this)) +{ + setupActions(); +} + + +void BookmarkContextMenu::setupActions() +{ + KAction* action; + + action = new KAction(KIcon("tab-new"), i18n("Open"), this); + connect(action, SIGNAL(triggered()), this, SLOT(openInCurrentTab())); + m_ac->addAction("open", action); + + action = new KAction(KIcon("tab-new"), i18n("Open in New Tab"), this); + connect(action, SIGNAL(triggered()), this, SLOT(openInNewTab())); + m_ac->addAction("open_tab", action); + + action = new KAction(KIcon("window-new"), i18n("Open in New Window"), this); + connect(action, SIGNAL(triggered()), this, SLOT(openInNewWindow())); + m_ac->addAction("open_window", action); + + action = new KAction(KIcon("bookmark-new"), i18n("Add Bookmark Here"), this); + connect(action, SIGNAL(triggered()), this, SLOT(bookmarkCurrentPage())); + m_ac->addAction("bookmark_page", action); + + action = new KAction(KIcon("folder-new"), i18n("New Bookmark Folder"), this); + connect(action, SIGNAL(triggered()), this, SLOT(newBookmarkGroup())); + m_ac->addAction("folder_new", action); + + action = new KAction(KIcon("edit-clear"), i18n("New Separator"), this); + connect(action, SIGNAL(triggered()), this, SLOT(newSeparator())); + m_ac->addAction("separator_new", action); + + action = new KAction(KIcon("edit-copy"), i18n("Copy Link Address"), this); + connect(action, SIGNAL(triggered()), this, SLOT(copyToClipboard())); + m_ac->addAction("copy", action); + + action = new KAction(KIcon("edit-delete"), i18n("Delete Bookmark"), this); + connect(action, SIGNAL(triggered()), this, SLOT(deleteBookmark())); + m_ac->addAction("delete", action); + + action = new KAction(KIcon("configure"), i18n("Properties"), this); + connect(action, SIGNAL(triggered()), this, SLOT(editBookmark())); + m_ac->addAction("properties", action); + + action = new KAction(KIcon("tab-new"), i18n("Open Folder in Tabs"), this); + connect(action, SIGNAL(triggered()), this, SLOT(openFolderInTabs())); + m_ac->addAction("open_all", action); +} + + +void BookmarkContextMenu::addBookmarkActions() +{ + addAction(m_ac->action("open")); + addAction(m_ac->action("open_tab")); + addAction(m_ac->action("open_window")); + + addSeparator(); + + addAction(m_ac->action("bookmark_page")); + addAction(m_ac->action("folder_new")); + addAction(m_ac->action("separator_new")); + + addSeparator(); + + addAction(m_ac->action("copy")); + + addSeparator(); + + addAction(m_ac->action("delete")); + addAction(m_ac->action("properties")); +} + + +void BookmarkContextMenu::addFolderActions() +{ + if(!bookmark().toGroup().first().isNull()) + { + addAction(m_ac->action("open_all")); + addSeparator(); + } + + addAction(m_ac->action("bookmark_page")); + addAction(m_ac->action("folder_new")); + addAction(m_ac->action("separator_new")); + + addSeparator(); + + addAction(m_ac->action("delete")); + addAction(m_ac->action("properties")); +} + + +void BookmarkContextMenu::addSeparatorActions() +{ + addAction(m_ac->action("bookmark_page")); + addAction(m_ac->action("folder_new")); + addAction(m_ac->action("separator_new")); + + addSeparator(); + + addAction(m_ac->action("delete")); +} + + +void BookmarkContextMenu::addActions() +{ + if(bookmark().isGroup()) + { + addFolderActions(); + } + + else if(bookmark().isSeparator()) + { + addSeparatorActions(); + } + + else if(bookmark().isNull()) + { + addAction(m_ac->action("bookmark_page")); + addAction(m_ac->action("folder_new")); + addAction(m_ac->action("separator_new")); + } + + else + { + addBookmarkActions(); + } +} + + +void BookmarkContextMenu::openInCurrentTab() +{ + Application::instance()->loadUrl(bookmark().url()); +} + + +void BookmarkContextMenu::openInNewTab() +{ + Application::instance()->loadUrl(bookmark().url(), Rekonq::SettingOpenTab); +} + + +void BookmarkContextMenu::openInNewWindow() +{ + Application::instance()->loadUrl(bookmark().url(), Rekonq::NewWindow); +} + + +void BookmarkContextMenu::copyToClipboard() +{ + if(bookmark().isNull()) + return; + + QClipboard *cb = QApplication::clipboard(); + cb->setText(bookmark().url().url()); +} + + +void BookmarkContextMenu::deleteBookmark() +{ + KBookmark bm = bookmark(); + bool folder = bm.isGroup(); + + if (KMessageBox::warningContinueCancel( + QApplication::activeWindow(), + folder ? i18n("Are you sure you wish to remove the bookmark folder\n\"%1\"?", bm.text()) + : i18n("Are you sure you wish to remove the bookmark\n\"%1\"?", bm.text()), + folder ? i18n("Bookmark Folder Deletion") + : i18n("Bookmark Deletion"), + KStandardGuiItem::del()) + != KMessageBox::Continue + ) + return; + + bm.parentGroup().deleteBookmark(bm); + manager()->emitChanged(); +} + + +void BookmarkContextMenu::editBookmark() +{ + KBookmark selected = bookmark(); + + KBookmarkDialog *dialog = owner()->bookmarkDialog(manager(), QApplication::activeWindow()); + dialog->editBookmark(selected); + delete dialog; +} + + +void BookmarkContextMenu::openFolderInTabs() +{ + if(bookmark().isGroup()) + owner()->openFolderinTabs(bookmark().toGroup()); +} + + +void BookmarkContextMenu::newBookmarkGroup() +{ + KBookmark selected = bookmark(); + KBookmarkDialog *dialog = owner()->bookmarkDialog(manager(), QApplication::activeWindow()); + + if(!selected.isNull()) + { + if(selected.isGroup()) + { + dialog->createNewFolder("New folder", selected); + } + + else + { + KBookmark newBk; + newBk = dialog->createNewFolder("New folder", selected.parentGroup()); + selected.parentGroup().moveBookmark(newBk, selected); + manager()->emitChanged(); + } + } + else + { + dialog->createNewFolder("New folder"); + } + + delete dialog; +} + + +void BookmarkContextMenu::newSeparator() +{ + KBookmark selected = bookmark(); + KBookmark newBk; + + if(!selected.isNull()) + { + if(selected.isGroup()) + newBk = selected.toGroup().createNewSeparator(); + else + newBk = selected.parentGroup().createNewSeparator(); + } + + else + { + newBk = Application::bookmarkProvider()->rootGroup().createNewSeparator(); + } + + KBookmarkGroup parent = newBk.parentGroup(); + newBk.setIcon(("edit-clear")); + parent.addBookmark(newBk); + + if(!selected.isNull()) + parent.moveBookmark(newBk, selected); + + manager()->emitChanged(); +} + + +void BookmarkContextMenu::bookmarkCurrentPage() +{ + KBookmarkGroup parent = Application::bookmarkProvider()->rootGroup(); + KBookmark selected = bookmark(); + + if(!selected.isNull()) + { + parent = selected.parentGroup(); + + if(selected.isGroup()) + parent = selected.toGroup(); + + KBookmark newBk = parent.addBookmark(owner()->currentTitle(), KUrl(owner()->currentUrl()), "text-html"); + parent.moveBookmark(newBk, selected.parentGroup().previous(selected)); + } + + else + { + parent.addBookmark(owner()->currentTitle(), KUrl(owner()->currentUrl()), "text-html"); + } + + manager()->emitChanged(); +} + diff --git a/src/bookmarks/bookmarkcontextmenu.h b/src/bookmarks/bookmarkcontextmenu.h new file mode 100644 index 00000000..c8c903d8 --- /dev/null +++ b/src/bookmarks/bookmarkcontextmenu.h @@ -0,0 +1,65 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Yoann Laissus <yoann dot laissus at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef BOOKMARKCONTEXTMENU_H +#define BOOKMARKCONTEXTMENU_H + +// Local Includes +#include "application.h" + +// Qt Includes +#include <KBookmarkMenu> + + +class BookmarkContextMenu : public KBookmarkContextMenu +{ + Q_OBJECT + +public: + BookmarkContextMenu(const KBookmark & bk, KBookmarkManager * manager, KBookmarkOwner *owner, QWidget * parent = 0); + virtual void addActions(); + +private slots: + void openInCurrentTab(); + void openInNewTab(); + void openInNewWindow(); + void copyToClipboard(); + void deleteBookmark(); + void openFolderInTabs(); + void editBookmark(); + void newBookmarkGroup(); + void newSeparator(); + void bookmarkCurrentPage(); + +private: + void setupActions(); + void addFolderActions(); + void addBookmarkActions(); + void addSeparatorActions(); + KActionCollection *m_ac; +}; + +#endif // BOOKMARKCONTEXTMENU_H diff --git a/src/bookmarks/bookmarksmanager.cpp b/src/bookmarks/bookmarksmanager.cpp index 6442192a..df6bc54b 100644 --- a/src/bookmarks/bookmarksmanager.cpp +++ b/src/bookmarks/bookmarksmanager.cpp @@ -2,9 +2,10 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2010 by Yoann Laissus <yoann dot laissus at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -34,28 +35,28 @@ #include "mainwindow.h" #include "webtab.h" #include "webview.h" +#include "mainview.h" +#include "bookmarkcontextmenu.h" // KDE Includes #include <KActionCollection> -#include <KBookmark> #include <KBookmarkAction> #include <KBookmarkGroup> -#include <KBookmarkMenu> #include <KToolBar> #include <KDebug> #include <KMenu> #include <KStandardDirs> #include <KUrl> +#include <KMessageBox> // Qt Includes #include <QtCore/QFile> #include <QtGui/QActionGroup> - BookmarkOwner::BookmarkOwner(QObject *parent) - : QObject(parent) - , KBookmarkOwner() + : QObject(parent) + , KBookmarkOwner() { } @@ -66,7 +67,7 @@ void BookmarkOwner::openBookmark(const KBookmark & bookmark, { if (keyboardModifiers & Qt::ControlModifier || mouseButtons == Qt::MidButton) { - emit openUrl(bookmark.url(), Rekonq::NewCurrentTab); + emit openUrl(bookmark.url(), Rekonq::SettingOpenTab); } else { @@ -93,14 +94,37 @@ QString BookmarkOwner::currentTitle() const } -void BookmarkOwner::openFolderinTabs(const KBookmarkGroup &bm) +void BookmarkOwner::openFolderinTabs(const KBookmarkGroup &bookmark) { - QList<KUrl> urlList = bm.groupUrlList(); + QList<KUrl> urlList = bookmark.groupUrlList(); + + if(urlList.length() > 8) + { + if(!(KMessageBox::warningContinueCancel(Application::instance()->mainWindow(), i18n("You are about to open %1 tabs.\nAre you sure ?", QString::number(urlList.length()))) == KMessageBox::Continue)) + return; + } + QList<KUrl>::iterator url; for (url = urlList.begin(); url != urlList.end(); ++url) { - Application::instance()->loadUrl(*url, Rekonq::NewCurrentTab); + emit openUrl(*url, Rekonq::NewCurrentTab); + } +} + + +QList< QPair<QString, QString> > BookmarkOwner::currentBookmarkList() const +{ + QList< QPair<QString, QString> > bkList; + int tabNumber = Application::instance()->mainWindow()->mainView()->count(); + + for(int i = 0; i < tabNumber; i++) + { + QPair<QString, QString> item; + item.first = Application::instance()->mainWindow()->mainView()->webTab(i)->view()->title(); + item.second = Application::instance()->mainWindow()->mainView()->webTab(i)->url().url(); + bkList += item; } + return bkList; } @@ -111,27 +135,36 @@ BookmarkMenu::BookmarkMenu(KBookmarkManager *manager, KBookmarkOwner *owner, KMenu *menu, KActionCollection* actionCollection) - : KBookmarkMenu(manager, owner, menu, actionCollection) - + : KBookmarkMenu(manager, owner, menu, actionCollection) { KAction *a = KStandardAction::addBookmark(this, SLOT(slotAddBookmark()), this); -// a->setText(i18n("Bookmark this Page")); actionCollection->addAction(QLatin1String("rekonq_add_bookmark"),a); + refill(); } + +BookmarkMenu::BookmarkMenu(KBookmarkManager *manager, + KBookmarkOwner *owner, + KMenu *parentMenu, + const QString &parentAddress) + : KBookmarkMenu(manager, owner, parentMenu, parentAddress) +{ + refill(); +} + + BookmarkMenu::~BookmarkMenu() { } -KMenu *BookmarkMenu::viewContextMenu(QAction *action) +KMenu * BookmarkMenu::contextMenu(QAction *act) { - // contextMenu() returns an invalid KMenu (seg fault) for the folders in the toolbar - KMenu *menu = contextMenu(action); - if(menu) - return menu; - return 0; // new KMenu(); + KBookmarkActionInterface* action = dynamic_cast<KBookmarkActionInterface *>(act); + if (!action) + return 0; + return new BookmarkContextMenu(action->bookmark(), manager(), owner()); } @@ -151,6 +184,76 @@ void BookmarkMenu::slotAddBookmark() } +QAction * BookmarkMenu::actionForBookmark(const KBookmark &bookmark) +{ + if(bookmark.isGroup()) + { + KBookmarkActionMenu *actionMenu = new KBookmarkActionMenu(bookmark, this); + new BookmarkMenu(manager(), owner(), actionMenu->menu(), bookmark.address()); + return actionMenu; + } + else if(bookmark.isSeparator()) + { + return KBookmarkMenu::actionForBookmark(bookmark); + } + else + { + Application::bookmarkProvider()->completionObject()->addItem(bookmark.url().url()); + return new KBookmarkAction( bookmark, owner(), this ); + } +} + + +void BookmarkMenu::refill() +{ + fillBookmarks(); + + if(parentMenu()->actions().count() > 0) + parentMenu()->addSeparator(); + + if(isRoot()) + { + addAddBookmark(); + addAddBookmarksList(); + addNewFolder(); + addEditBookmarks(); + + } + else + { + addOpenFolderInTabs(); + addAddBookmark(); + addAddBookmarksList(); + addNewFolder(); + } +} + + +void BookmarkMenu::addOpenFolderInTabs() +{ + KAction *action; + KBookmarkGroup group = manager()->findByAddress(parentAddress()).toGroup(); + + if(!group.first().isNull()) + { + KBookmark bookmark = group.first(); + + while(bookmark.isGroup() || bookmark.isSeparator()) + { + bookmark = group.next(bookmark); + } + + if(!bookmark.isNull()) + { + action = new KAction(KIcon("tab-new"), i18n("Open Folder in Tabs"), this); + action->setHelpText( i18n( "Open all bookmarks in this folder as a new tab." ) ); + connect(action, SIGNAL(triggered(bool)), this, SLOT(slotOpenFolderInTabs())); + parentMenu()->addAction(action); + } + } +} + + // ------------------------------------------------------------------------------------------------------ @@ -160,8 +263,12 @@ BookmarkProvider::BookmarkProvider(QObject *parent) , m_owner(0) , m_actionCollection(new KActionCollection(this)) , m_bookmarkMenu(0) - , m_bookmarkToolBar(0) + , m_completion(0) { + // take care of the completion object + m_completion = new KCompletion; + m_completion->setOrder( KCompletion::Weighted ); + KUrl bookfile = KUrl("~/.kde/share/apps/konqueror/bookmarks.xml"); // share konqueror bookmarks if (!QFile::exists(bookfile.path())) @@ -178,7 +285,9 @@ BookmarkProvider::BookmarkProvider(QObject *parent) bookfile = KUrl(bookmarksPath); } } - m_manager = KBookmarkManager::managerForExternalFile(bookfile.path()); + + m_manager = KBookmarkManager::managerForFile(bookfile.path(), "rekonq"); + connect(m_manager, SIGNAL(changed(const QString &, const QString &)), this, SLOT(slotBookmarksChanged(const QString &, const QString &))); @@ -197,37 +306,47 @@ BookmarkProvider::~BookmarkProvider() } -void BookmarkProvider::setupBookmarkBar(KToolBar *t) +void BookmarkProvider::setupBookmarkBar(KToolBar *toolbar) { - m_bookmarkToolBar = t; - connect(m_bookmarkToolBar, SIGNAL(customContextMenuRequested(const QPoint &)), + KToolBar *bookmarkToolBar = toolbar; + m_bookmarkToolBars.append(bookmarkToolBar); + bookmarkToolBar->setContextMenuPolicy(Qt::CustomContextMenu); + connect(bookmarkToolBar, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(contextMenu(const QPoint &))); slotBookmarksChanged("", ""); } +void BookmarkProvider::removeToolBar(KToolBar *toolbar) +{ + m_bookmarkToolBars.removeOne(toolbar); +} + + void BookmarkProvider::slotBookmarksChanged(const QString &group, const QString &caller) { Q_UNUSED(group) Q_UNUSED(caller) - if (!m_bookmarkToolBar) - return; - - KBookmarkGroup toolBarGroup = m_manager->toolbar(); - if (toolBarGroup.isNull()) - return; + m_completion->clear(); - if(m_bookmarkToolBar) + foreach(KToolBar *bookmarkToolBar, m_bookmarkToolBars) { - m_bookmarkToolBar->clear(); // FIXME CRASH - - KBookmark bookmark = toolBarGroup.first(); - while (!bookmark.isNull()) + if (bookmarkToolBar) { - m_bookmarkToolBar->addAction(fillBookmarkBar(bookmark)); - bookmark = toolBarGroup.next(bookmark); + KBookmarkGroup toolBarGroup = m_manager->toolbar(); + if (toolBarGroup.isNull()) + return; + + bookmarkToolBar->clear(); + + KBookmark bookmark = toolBarGroup.first(); + while (!bookmark.isNull()) + { + bookmarkToolBar->addAction(fillBookmarkBar(bookmark)); + bookmark = toolBarGroup.next(bookmark); + } } } } @@ -244,13 +363,22 @@ QAction *BookmarkProvider::actionByName(const QString &name) void BookmarkProvider::contextMenu(const QPoint &point) { - KAction* action = dynamic_cast<KAction*>(m_bookmarkToolBar->actionAt(point)); + if(m_bookmarkToolBars.isEmpty()) + return; + + KToolBar *bookmarkToolBar = m_bookmarkToolBars.at(0); + if(!bookmarkToolBar) + return; + + KBookmarkActionInterface* action = dynamic_cast<KBookmarkActionInterface *>(bookmarkToolBar->actionAt(point)); if (!action) return; - KMenu *menu = m_bookmarkMenu->viewContextMenu(action); + + KMenu *menu = new BookmarkContextMenu(action->bookmark(), bookmarkManager(), bookmarkOwner()); if (!menu) return; - menu->popup(m_bookmarkToolBar->mapToGlobal(point)); + + menu->popup(bookmarkToolBar->mapToGlobal(point)); } @@ -269,21 +397,18 @@ KAction *BookmarkProvider::fillBookmarkBar(const KBookmark &bookmark) { if (bookmark.isGroup()) { - KBookmarkGroup group = bookmark.toGroup(); - KBookmark bm = group.first(); - KActionMenu *menuAction = new KActionMenu(KIcon(bookmark.icon()), bookmark.text(), this); + KBookmarkActionMenu *menuAction = new KBookmarkActionMenu(bookmark.toGroup(), this); menuAction->setDelayed(false); - while (!bm.isNull()) - { - menuAction->addAction(fillBookmarkBar(bm)); - bm = group.next(bm); - } + new BookmarkMenu(bookmarkManager(), bookmarkOwner(), menuAction->menu(), bookmark.address()); + return menuAction; } if(bookmark.isSeparator()) { - KAction *a = new KAction(this); + KAction *a = new KBookmarkAction(bookmark, m_owner, this); + a->setText(""); + a->setIcon(QIcon()); a->setSeparator(true); return a; } @@ -298,3 +423,56 @@ KBookmarkGroup BookmarkProvider::rootGroup() { return m_manager->root(); } + + +KCompletion *BookmarkProvider::completionObject() const +{ + return m_completion; +} + + +QString BookmarkProvider::titleForBookmarkUrl(QString url) +{ + QString title = ""; + KBookmarkGroup bookGroup = Application::bookmarkProvider()->rootGroup(); + if (bookGroup.isNull()) + { + return title; + } + + KBookmark bookmark = bookGroup.first(); + while (!bookmark.isNull() && title.isEmpty()) + { + title = titleForBookmarkUrl(bookmark, url); + bookmark = bookGroup.next(bookmark); + } + + if (title.isEmpty()) + { + title = url; + } + + return title; +} + + +QString BookmarkProvider::titleForBookmarkUrl(const KBookmark &bookmark, QString url) +{ + QString title = ""; + if (bookmark.isGroup()) + { + KBookmarkGroup group = bookmark.toGroup(); + KBookmark bm = group.first(); + while (!bm.isNull() && title.isEmpty()) + { + title = titleForBookmarkUrl(bm, url); // it is .bookfolder + bm = group.next(bm); + } + } + else if(!bookmark.isSeparator() && bookmark.url()==url) + { + title = bookmark.fullText(); + } + + return title; +} diff --git a/src/bookmarks/bookmarksmanager.h b/src/bookmarks/bookmarksmanager.h index febac234..8d09e122 100644 --- a/src/bookmarks/bookmarksmanager.h +++ b/src/bookmarks/bookmarksmanager.h @@ -2,9 +2,10 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2010 by Yoann Laissus <yoann dot laissus at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -31,6 +32,7 @@ // Local Includes +#include "rekonqprivate_export.h" #include "application.h" // Qt Includes @@ -38,6 +40,7 @@ // KDE Includes #include <KBookmarkOwner> +#include <KCompletion> // Forward Declarations class BookmarkProvider; @@ -55,7 +58,7 @@ class KBookmarkManager; * bookmarks as actions * */ -class BookmarkOwner : public QObject , public KBookmarkOwner +class REKONQ_TESTS_EXPORT BookmarkOwner : public QObject , public KBookmarkOwner { Q_OBJECT @@ -110,7 +113,9 @@ public: * The default implementation does nothing. * This is only called if supportsTabs() returns true */ - virtual void openFolderinTabs(const KBookmarkGroup &bm); + virtual void openFolderinTabs(const KBookmarkGroup &bookmark); + + virtual QList< QPair<QString, QString> > currentBookmarkList() const; signals: /** @@ -128,7 +133,6 @@ signals: // KDE Includes #include <KBookmarkMenu> - /** * This class represent the rekonq bookmarks menu. * It's just a simple class inherited from KBookmarkMenu @@ -143,13 +147,23 @@ public: KBookmarkOwner* owner, KMenu* menu, KActionCollection* actionCollection); + BookmarkMenu(KBookmarkManager *manager, + KBookmarkOwner *owner, + KMenu *parentMenu, + const QString &parentAddress); ~BookmarkMenu(); - virtual KMenu *viewContextMenu(QAction* action); +protected: + virtual KMenu * contextMenu(QAction * act); + virtual void refill(); + virtual QAction* actionForBookmark(const KBookmark &bookmark); protected slots: void slotAddBookmark(); +private: + void addOpenFolderInTabs(); + }; @@ -192,6 +206,7 @@ public: */ void setupBookmarkBar(KToolBar *); + void removeToolBar(KToolBar*); /** * @short Get action by name @@ -209,7 +224,16 @@ public: */ KBookmarkGroup rootGroup(); - KBookmarkManager *bookmarkManager() { return m_manager; } + KBookmarkManager *bookmarkManager() { return m_manager; } + BookmarkOwner *bookmarkOwner() { return m_owner; } + + /** + * @returns the KCompletion object. + */ + KCompletion *completionObject() const; + + QString titleForBookmarkUrl(QString url); + signals: /** * @short This signal is emitted when an url has to be loaded @@ -236,14 +260,18 @@ public slots: */ void slotBookmarksChanged(const QString &group, const QString &caller); + private: KAction *fillBookmarkBar(const KBookmark &bookmark); + QString titleForBookmarkUrl(const KBookmark &bookmark, QString url); KBookmarkManager *m_manager; BookmarkOwner *m_owner; KActionCollection *m_actionCollection; BookmarkMenu *m_bookmarkMenu; - KToolBar *m_bookmarkToolBar; + QList<KToolBar*> m_bookmarkToolBars; + KCompletion *m_completion; }; + #endif diff --git a/src/bookmarks/bookmarkspanel.cpp b/src/bookmarks/bookmarkspanel.cpp index 9164dbb6..0caf0f31 100644 --- a/src/bookmarks/bookmarkspanel.cpp +++ b/src/bookmarks/bookmarkspanel.cpp @@ -3,7 +3,8 @@ * This file is a part of the rekonq project * * Copyright (C) 2009 by Nils Weigel <nehlsen at gmail dot com> -* +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Yoann Laissus <yoann dot laissus at gmail dot com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -29,8 +30,10 @@ #include "bookmarkspanel.moc" // Local Includes +#include "bookmarksmanager.h" #include "bookmarkstreemodel.h" #include "bookmarksproxy.h" +#include "bookmarkcontextmenu.h" // Auto Includes #include "rekonq.h" @@ -38,16 +41,19 @@ // Qt includes #include <QHBoxLayout> #include <QLabel> -#include <QTreeView> #include <QHeaderView> // KDE includes #include <KLineEdit> #include <KLocalizedString> +#include <KMenu> +#include <KMessageBox> BookmarksPanel::BookmarksPanel(const QString &title, QWidget *parent, Qt::WindowFlags flags) : QDockWidget(title, parent, flags) + , m_treeView(new PanelTreeView(this)) + , m_loadingState(false) { setup(); setShown(ReKonfig::showBookmarksPanel()); @@ -60,13 +66,6 @@ BookmarksPanel::~BookmarksPanel() } -void BookmarksPanel::bookmarkActivated( const QModelIndex &index ) -{ - if( index.isValid() ) - emit openUrl( qVariantValue< KUrl >( index.data( Qt::UserRole ) ) ); -} - - void BookmarksPanel::setup() { setObjectName("bookmarksPanel"); @@ -85,19 +84,20 @@ void BookmarksPanel::setup() searchLabel->setBuddy( search ); // setup tree view - QTreeView *treeView = new QTreeView(ui); - treeView->setUniformRowHeights(true); - treeView->setSelectionBehavior(QAbstractItemView::SelectRows); - treeView->setTextElideMode(Qt::ElideMiddle); - treeView->setAlternatingRowColors(true); - treeView->header()->hide(); - treeView->setRootIsDecorated( false ); + m_treeView->setUniformRowHeights(true); + m_treeView->setTextElideMode(Qt::ElideMiddle); + m_treeView->setAlternatingRowColors(true); + m_treeView->header()->hide(); + m_treeView->setDragEnabled(true); + m_treeView->setAutoExpandDelay(750); + m_treeView->setDefaultDropAction(Qt::MoveAction); + m_treeView->viewport()->setAcceptDrops(true); // put everything together QVBoxLayout *vBoxLayout = new QVBoxLayout; vBoxLayout->setContentsMargins(0, 0, 0, 0); vBoxLayout->addLayout(searchLayout); - vBoxLayout->addWidget(treeView); + vBoxLayout->addWidget(m_treeView); // add it to the UI ui->setLayout(vBoxLayout); @@ -106,8 +106,114 @@ void BookmarksPanel::setup() BookmarksTreeModel *model = new BookmarksTreeModel( this ); BookmarksProxy *proxy = new BookmarksProxy(ui); proxy->setSourceModel( model ); - treeView->setModel( proxy ); + m_treeView->setModel( proxy ); + + connect(m_treeView, SIGNAL(contextMenuItemRequested(const QPoint &)), this, SLOT(contextMenu(const QPoint &))); + connect(m_treeView, SIGNAL(contextMenuGroupRequested(const QPoint &)), this, SLOT(contextMenu(const QPoint &))); + connect(m_treeView, SIGNAL(contextMenuEmptyRequested(const QPoint &)), this, SLOT(contextMenu(const QPoint &))); + connect(m_treeView, SIGNAL(delKeyPressed()), this, SLOT(deleteBookmark())); + connect(m_treeView, SIGNAL(collapsed(const QModelIndex &)), this, SLOT(onCollapse(const QModelIndex &))); + connect(m_treeView, SIGNAL(expanded(const QModelIndex &)), this, SLOT(onExpand(const QModelIndex &))); + connect(search, SIGNAL(textChanged(const QString &)), proxy, SLOT(setFilterFixedString(const QString &))); + loadFoldedState(); +} + + +KBookmark BookmarksPanel::bookmarkForIndex(const QModelIndex &index) +{ + if(!index.isValid()) + return KBookmark(); + + const QAbstractProxyModel* proxyModel = dynamic_cast< const QAbstractProxyModel* >(index.model()); + QModelIndex originalIndex = proxyModel->mapToSource(index); + + BtmItem *node = static_cast< BtmItem* >( originalIndex.internalPointer() ); + return node->getBkm(); +} + + +void BookmarksPanel::onCollapse(const QModelIndex &index) +{ + if(m_loadingState) + return; + + KBookmark bookmark = bookmarkForIndex(index); + bookmark.internalElement().setAttribute("folded", "yes"); + emit saveOnlyRequested(); +} + + +void BookmarksPanel::onExpand(const QModelIndex &index) +{ + if(m_loadingState) + return; - connect(search, SIGNAL(textChanged(QString)), proxy, SLOT(setFilterFixedString(QString))); - connect(treeView, SIGNAL( activated(QModelIndex) ), this, SLOT( bookmarkActivated(QModelIndex) ) ); + KBookmark bookmark = bookmarkForIndex(index); + bookmark.internalElement().setAttribute("folded", "no"); + emit saveOnlyRequested(); +} + + +void BookmarksPanel::loadFoldedState() +{ + m_loadingState = true; + loadFoldedState(QModelIndex()); + m_loadingState = false; +} + + +void BookmarksPanel::loadFoldedState(const QModelIndex &root) +{ + + int count = m_treeView->model()->rowCount(root); + QModelIndex index; + + for(int i = 0; i < count; i++) + { + index = m_treeView->model()->index(i, 0, root); + if(index.isValid() && bookmarkForIndex(index).isGroup()) + { + m_treeView->setExpanded(index, bookmarkForIndex(index).toGroup().isOpen()); + loadFoldedState(index); + } + } +} + + +void BookmarksPanel::contextMenu(const QPoint &pos) +{ + QModelIndex index = m_treeView->indexAt(pos); + if(m_loadingState) + return; + + KBookmark selected = bookmarkForIndex(index); + + BookmarkContextMenu *menu = new BookmarkContextMenu(selected, Application::bookmarkProvider()->bookmarkManager(), Application::bookmarkProvider()->bookmarkOwner(), this); + menu->popup(m_treeView->mapToGlobal(pos)); +} + + +void BookmarksPanel::deleteBookmark() +{ + QModelIndex index = m_treeView->currentIndex(); + if(!index.isValid()) + return; + + KBookmark bm = bookmarkForIndex(index); + bool folder = bm.isGroup(); + + if (KMessageBox::warningContinueCancel( + QApplication::activeWindow(), + folder ? i18n("Are you sure you wish to remove the bookmark folder\n\"%1\"?", bm.text()) + : i18n("Are you sure you wish to remove the bookmark\n\"%1\"?", bm.text()), + folder ? i18n("Bookmark Folder Deletion") + : i18n("Bookmark Deletion"), + KStandardGuiItem::del()) + != KMessageBox::Continue + ) + return; + + + bm.parentGroup().deleteBookmark(bm); + Application::instance()->bookmarkProvider()->bookmarkManager()->emitChanged(); } diff --git a/src/bookmarks/bookmarkspanel.h b/src/bookmarks/bookmarkspanel.h index 6c0e153f..90597c73 100644 --- a/src/bookmarks/bookmarkspanel.h +++ b/src/bookmarks/bookmarkspanel.h @@ -3,6 +3,8 @@ * This file is a part of the rekonq project * * Copyright (C) 2009 by Nils Weigel <nehlsen at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Yoann Laissus <yoann dot laissus at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -27,15 +29,24 @@ #ifndef BOOKMARKSPANEL_H #define BOOKMARKSPANEL_H + +// Local Includes +#include "rekonqprivate_export.h" +#include "application.h" +#include "paneltreeview.h" + // Qt Includes #include <QDockWidget> +// KDE Includes +#include <KBookmark> + // Forward Declarations class KUrl; class QModelIndex; -class BookmarksPanel : public QDockWidget +class REKONQ_TESTS_EXPORT BookmarksPanel : public QDockWidget { Q_OBJECT @@ -44,13 +55,26 @@ public: ~BookmarksPanel(); signals: - void openUrl(const KUrl &); + void openUrl(const KUrl &, const Rekonq::OpenType &); + void itemHovered(const QString &); + void saveOnlyRequested(); private slots: - void bookmarkActivated( const QModelIndex &index ); + void contextMenu(const QPoint &pos); + + void deleteBookmark(); + void onCollapse(const QModelIndex &index); + void onExpand(const QModelIndex &index); + void loadFoldedState(const QModelIndex &root); + void loadFoldedState(); + private: void setup(); + KBookmark bookmarkForIndex(const QModelIndex &index); + + PanelTreeView *m_treeView; + bool m_loadingState; }; #endif // BOOKMARKSPANEL_H diff --git a/src/bookmarks/bookmarksproxy.cpp b/src/bookmarks/bookmarksproxy.cpp index e94fbeff..7fa34b3f 100644 --- a/src/bookmarks/bookmarksproxy.cpp +++ b/src/bookmarks/bookmarksproxy.cpp @@ -3,6 +3,7 @@ * This file is a part of the rekonq project * * Copyright (C) 2009 by Nils Weigel <nehlsen at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or diff --git a/src/bookmarks/bookmarksproxy.h b/src/bookmarks/bookmarksproxy.h index 99483331..2bf1d63a 100644 --- a/src/bookmarks/bookmarksproxy.h +++ b/src/bookmarks/bookmarksproxy.h @@ -3,6 +3,7 @@ * This file is a part of the rekonq project * * Copyright (C) 2009 by Nils Weigel <nehlsen at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -27,22 +28,27 @@ #ifndef BOOKMARKSPROXY_H #define BOOKMARKSPROXY_H + +// Local Includes +#include "rekonqprivate_export.h" + // Qt Includes #include <QSortFilterProxyModel> -class BookmarksProxy : public QSortFilterProxyModel + +class REKONQ_TESTS_EXPORT BookmarksProxy : public QSortFilterProxyModel { Q_OBJECT Q_DISABLE_COPY(BookmarksProxy) public: - BookmarksProxy( QObject *parent = 0 ); + BookmarksProxy( QObject *parent = 0 ); protected: - virtual bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const; + virtual bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const; - // returns true if any child(or childs-child...) matches filter - bool recursiveMatch( const QModelIndex &index ) const; + // returns true if any child(or children-child...) matches filter + bool recursiveMatch( const QModelIndex &index ) const; }; #endif // BOOKMARKSPROXY_H diff --git a/src/bookmarks/bookmarkstreemodel.cpp b/src/bookmarks/bookmarkstreemodel.cpp index 140fa9c8..836401a6 100644 --- a/src/bookmarks/bookmarkstreemodel.cpp +++ b/src/bookmarks/bookmarkstreemodel.cpp @@ -3,6 +3,7 @@ * This file is a part of the rekonq project * * Copyright (C) 2009 by Nils Weigel <nehlsen at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -32,94 +33,112 @@ #include "application.h" #include "bookmarksmanager.h" +// Qt Includes +#include <QMimeData> + // KDE includes #include <KBookmarkGroup> #include <KLocalizedString> -class BookmarksTreeModel::BtmItem +BtmItem::BtmItem(const KBookmark &bm) + : m_parent(0) + , m_kbm(bm) { -public: - BtmItem(const KBookmark &bm) - : m_parent(0) - , m_kbm(bm) - { - } - - - ~BtmItem() - { - qDeleteAll(m_children); - } +} - QVariant data( int role = Qt::DisplayRole ) const - { - if( m_kbm.isNull() ) - return QVariant(); // should only happen for root item +BtmItem::~BtmItem() +{ + qDeleteAll(m_children); +} - if( role == Qt::DisplayRole ) - return m_kbm.text(); - if( role == Qt::DecorationRole ) - return KIcon( m_kbm.icon() ); - if( role == Qt::UserRole ) - return m_kbm.url(); - return QVariant(); +QVariant BtmItem::data( int role ) const +{ + if( m_kbm.isNull() ) + return QVariant(); // should only happen for root item + + if( role == Qt::DisplayRole ) + return m_kbm.text(); + if( role == Qt::DecorationRole ) + return KIcon( m_kbm.icon() ); + if( role == Qt::UserRole ) + return m_kbm.url(); + if( role == Qt::ToolTipRole) + { + QString tooltip = ""; + + if(!m_kbm.text().isEmpty()) + { + tooltip += m_kbm.text(); + } + if(m_kbm.isGroup()) + { + tooltip += " [" + QString::number(childCount()) + " " + i18n("Items") + "]"; + } + if(!m_kbm.url().url().isEmpty()) + { + if(!tooltip.isEmpty()) + tooltip += "\n"; + tooltip += m_kbm.url().url(); + } + return tooltip; } + return QVariant(); +} - int row() const - { - if(m_parent) - return m_parent->m_children.indexOf( const_cast< BtmItem* >( this ) ); - return 0; - } +int BtmItem::row() const +{ + if(m_parent) + return m_parent->m_children.indexOf( const_cast< BtmItem* >( this ) ); + return 0; +} - int childCount() const - { - return m_children.count(); - } +int BtmItem::childCount() const +{ + return m_children.count(); +} - BtmItem* child( int n ) - { - Q_ASSERT(n>=0); - Q_ASSERT(n<childCount()); - return m_children.at(n); - } +BtmItem* BtmItem::child( int n ) +{ + Q_ASSERT(n>=0); + Q_ASSERT(n<childCount()); + return m_children.at(n); +} - BtmItem* parent() const - { - return m_parent; - } +BtmItem* BtmItem::parent() const +{ + return m_parent; +} - void appendChild(BtmItem *child) - { - if( !child ) - return; - child->m_parent = this; - m_children << child; - } +void BtmItem::appendChild(BtmItem *child) +{ + if( !child ) + return; + child->m_parent = this; + m_children << child; +} - void clear() - { - qDeleteAll(m_children); - m_children.clear(); - } -private: - BtmItem *m_parent; - QList< BtmItem* > m_children; - KBookmark m_kbm; -}; +void BtmItem::clear() +{ + qDeleteAll(m_children); + m_children.clear(); +} +KBookmark BtmItem::getBkm() const +{ + return m_kbm; +} // ------------------------------------------------------------------------------------- @@ -129,8 +148,9 @@ BookmarksTreeModel::BookmarksTreeModel(QObject *parent) , m_root(0) { resetModel(); - connect( Application::bookmarkProvider()->bookmarkManager(), SIGNAL( changed(QString,QString) ), this, SLOT( bookmarksChanged(QString) ) ); - connect( Application::bookmarkProvider()->bookmarkManager(), SIGNAL( bookmarksChanged(QString) ), this, SLOT( bookmarksChanged(QString) ) ); + connect( this, SIGNAL(bookmarksUpdated()), parent, SLOT(loadFoldedState())); + connect( Application::bookmarkProvider()->bookmarkManager(), SIGNAL( changed(QString,QString) ), this, SLOT( bookmarksChanged() ) ); + connect( parent, SIGNAL(saveOnlyRequested()), this, SLOT(saveOnly()) ); } @@ -178,8 +198,17 @@ QVariant BookmarksTreeModel::headerData(int section, Qt::Orientation orientation Qt::ItemFlags BookmarksTreeModel::flags(const QModelIndex &index) const { - Q_UNUSED(index) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + + if(!index.isValid()) + return flags | Qt::ItemIsDropEnabled; + + flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; + + if(bookmarkForIndex(index).isGroup()) + flags |= Qt::ItemIsDropEnabled; + + return flags; } @@ -255,32 +284,10 @@ QVariant BookmarksTreeModel::data(const QModelIndex &index, int role) const } -void BookmarksTreeModel::bookmarksChanged( const QString &groupAddress ) +void BookmarksTreeModel::bookmarksChanged() { - if( groupAddress.isEmpty() ) - { - resetModel(); - return; - } - - BtmItem *node = m_root; - QModelIndex nodeIndex; - - QStringList indexChain( groupAddress.split( '/', QString::SkipEmptyParts) ); - foreach( QString sIndex, indexChain ) - { - bool ok; - int i = sIndex.toInt( &ok ); - if( !ok ) - break; - - if( i < 0 || i >= node->childCount() ) - break; - - node = node->child( i ); - nodeIndex = index( i, 0, nodeIndex ); - } - emit dataChanged( index( 0, 0, nodeIndex ), index( node->childCount(), 0, nodeIndex ) ); + resetModel(); + emit bookmarksUpdated(); } @@ -321,3 +328,100 @@ void BookmarksTreeModel::populate( BtmItem *node, KBookmarkGroup bmg) bm = bmg.next( bm ); } } + + +KBookmark BookmarksTreeModel::bookmarkForIndex(const QModelIndex index) const +{ + return static_cast<BtmItem*>(index.internalPointer())->getBkm(); +} + + +void BookmarksTreeModel::saveOnly() +{ + disconnect(Application::bookmarkProvider()->bookmarkManager(), SIGNAL(changed(QString,QString)), this, SLOT(bookmarksChanged())); + connect(Application::bookmarkProvider()->bookmarkManager(), SIGNAL(changed(QString,QString)), this, SLOT(reconnectManager())); + Application::bookmarkProvider()->bookmarkManager()->emitChanged(); +} + + +void BookmarksTreeModel::reconnectManager() +{ + connect(Application::bookmarkProvider()->bookmarkManager(), SIGNAL( changed(QString,QString) ), this, SLOT(bookmarksChanged())); +} + + +Qt::DropActions BookmarksTreeModel::supportedDropActions () const +{ + return Qt::MoveAction; +} + + +QStringList BookmarksTreeModel::mimeTypes () const +{ + return KBookmark::List::mimeDataTypes(); +} + + +QMimeData* BookmarksTreeModel::mimeData( const QModelIndexList & indexes ) const +{ + QMimeData *mimeData = new QMimeData; + + QByteArray addresse = bookmarkForIndex(indexes.first()).address().toLatin1(); + mimeData->setData( "application/rekonq-bookmark", addresse); + bookmarkForIndex(indexes.first()).populateMimeData(mimeData); + + return mimeData; +} + + +bool BookmarksTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex & parent) +{ + if(action == Qt::MoveAction) + { + if(data->hasFormat("application/rekonq-bookmark")) + { + QByteArray addresses = data->data("application/rekonq-bookmark"); + KBookmark bookmark = Application::bookmarkProvider()->bookmarkManager()->findByAddress(QString::fromLatin1(addresses.data())); + + QModelIndex destIndex = index(row, column, parent); + + KBookmark dropDestBookmark; + if(destIndex.isValid()) + dropDestBookmark = bookmarkForIndex(destIndex); + + KBookmarkGroup root = Application::bookmarkProvider()->rootGroup(); + if(parent.isValid()) + root = bookmarkForIndex(parent).toGroup(); + + if(!destIndex.isValid()) + { + if(!parent.isValid()) // Drop into a blank area + { + Application::bookmarkProvider()->rootGroup().deleteBookmark(bookmark); + Application::bookmarkProvider()->rootGroup().addBookmark(bookmark); + } + else // Drop at the last item of the group or directly on the main item of the group + { + root.deleteBookmark(bookmark); + root.addBookmark(bookmark); + } + } + + else + { + if(row == -1) + { + root.deleteBookmark(bookmark); + root.addBookmark(bookmark); + } + else // A classic drop + { + root.moveBookmark(bookmark, root.previous(dropDestBookmark)); + } + } + + Application::bookmarkProvider()->bookmarkManager()->emitChanged(root); + } + } + return true; +} diff --git a/src/bookmarks/bookmarkstreemodel.h b/src/bookmarks/bookmarkstreemodel.h index 9753999c..b312ab2d 100644 --- a/src/bookmarks/bookmarkstreemodel.h +++ b/src/bookmarks/bookmarkstreemodel.h @@ -3,6 +3,7 @@ * This file is a part of the rekonq project * * Copyright (C) 2009 by Nils Weigel <nehlsen at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -27,13 +28,38 @@ #ifndef BOOKMARKSTREEMODEL_H #define BOOKMARKSTREEMODEL_H -// Qt Includes -#include <QAbstractItemModel> + +// Local Includes +#include "rekonqprivate_export.h" // KDE includes #include <KBookmark> -class BookmarksTreeModel : public QAbstractItemModel +// Qt Includes +#include <QAbstractItemModel> + +class BtmItem +{ +public: + BtmItem(const KBookmark &bm); + ~BtmItem(); + QVariant data( int role = Qt::DisplayRole ) const; + int row() const; + int childCount() const; + BtmItem* child( int n ); + BtmItem* parent() const; + void appendChild(BtmItem *child); + void clear(); + KBookmark getBkm() const; + +private: + BtmItem *m_parent; + QList< BtmItem* > m_children; + KBookmark m_kbm; +}; + + +class REKONQ_TESTS_EXPORT BookmarksTreeModel : public QAbstractItemModel { Q_OBJECT Q_DISABLE_COPY(BookmarksTreeModel) @@ -42,28 +68,36 @@ public: explicit BookmarksTreeModel(QObject *parent = 0); ~BookmarksTreeModel(); - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual Qt::ItemFlags flags(const QModelIndex &index) const; - virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; virtual QModelIndex parent(const QModelIndex &index) const; - virtual QVariant data(const QModelIndex &index, int role) const; -// virtual bool setData(const QModelIndex &index, const QVariant &value, int role); + virtual QVariant data(const QModelIndex &index, int role) const; + + virtual QStringList mimeTypes () const; + virtual bool dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent); + virtual Qt::DropActions supportedDropActions () const; + virtual QMimeData *mimeData( const QModelIndexList & indexes ) const; private slots: - void bookmarksChanged( const QString &groupAddress ); + void bookmarksChanged(); + void saveOnly(); + void reconnectManager(); -private: - class BtmItem; - BtmItem *m_root; +signals: + void bookmarksUpdated(); - void resetModel(); +private: + BtmItem *m_root; + void resetModel(); void setRoot(KBookmarkGroup bmg); - void populate( BtmItem *node, KBookmarkGroup bmg); + void populate( BtmItem *node, KBookmarkGroup bmg); + KBookmark bookmarkForIndex(const QModelIndex index) const; }; #endif // BOOKMARKSTREEMODEL_H diff --git a/src/cleardata.ui b/src/cleardata.ui index b70d3b5a..effb2d7e 100644 --- a/src/cleardata.ui +++ b/src/cleardata.ui @@ -2,12 +2,15 @@ <ui version="4.0"> <class>ClearDataWidget</class> <widget class="QWidget" name="ClearDataWidget"> + <property name="windowModality"> + <enum>Qt::WindowModal</enum> + </property> <property name="geometry"> <rect> <x>0</x> <y>0</y> - <width>260</width> - <height>208</height> + <width>245</width> + <height>226</height> </rect> </property> <property name="windowTitle"> @@ -16,15 +19,47 @@ <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="text"> - <string>Clear the following items:</string> + <string><h3>Clear the following items:</h3></string> </property> </widget> </item> <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>10</height> + </size> + </property> + </spacer> + </item> + <item> <widget class="QCheckBox" name="clearHistory"> <property name="text"> - <string>History</string> + <string>Visited pages history</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="clearDownloads"> + <property name="text"> + <string>Downloads history</string> </property> <property name="checked"> <bool>true</bool> @@ -76,10 +111,13 @@ <property name="orientation"> <enum>Qt::Vertical</enum> </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> - <height>40</height> + <height>15</height> </size> </property> </spacer> diff --git a/src/clicktoflash.cpp b/src/clicktoflash.cpp index b6e1df34..76637975 100644 --- a/src/clicktoflash.cpp +++ b/src/clicktoflash.cpp @@ -1,53 +1,28 @@ -/* - * Copyright (c) 2009, Benjamin C. Meyer - * - * 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. - * 3. Neither the name of the Benjamin Meyer nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. - * ============================================================ - * - * This file is a part of the rekonq project - * - * Copyright (C) 2009 by Matthieu Gicquel <matgic78@gmail.com> - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License or (at your option) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * ============================================================ */ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Benjamin C. Meyer <ben@meyerhome.net> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78@gmail.com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ // Self Includes @@ -56,6 +31,7 @@ // KDE Includes #include <KLocalizedString> +#include <KDebug> // Qt Includes #include <QWebFrame> @@ -114,39 +90,51 @@ void ClickToFlash::load() elements.append(docElement.findAll(selector.arg(QLatin1String("object")))); elements.append(docElement.findAll(selector.arg(QLatin1String("embed")))); - bool isRightElement = false; foreach (QWebElement element, elements) { - // TODO : find a proper solution to compare a QWebElement with a plugin - // With this "manual" test, it's probably not working everywhere - if(QUrl(element.attribute("data")) == m_url - || QUrl(element.attribute("src")) == m_url) - isRightElement = true; - else - { - QWebElementCollection collec = element.findAll("param"); - int i = 0; - while(i < collec.count() && isRightElement == false) - { - if(QUrl(collec.at(i).attribute("value")) == m_url) - isRightElement = true; - i++; - } - } - - if(isRightElement) + if( checkElement(element) ) { + kDebug() << "RETURNED TRUE ..........................."; QWebElement substitute = element.clone(); emit signalLoadClickToFlash(true); element.replace(substitute); + deleteLater(); return; } } - frames += frame->childFrames(); } - - deleteLater(); } +bool ClickToFlash::checkElement(QWebElement el) +{ + kDebug() << "src: " << QUrl(el.attribute("src")); + kDebug() << "url: " << m_url; + + QString checkString; + QString urlString; + + checkString = QUrl(el.attribute("src")).toString( QUrl::RemoveQuery ); + urlString = m_url.toString( QUrl::RemoveQuery ); + + if( urlString.contains( checkString ) ) + return true; + + QWebElementCollection collec = el.findAll("*"); + int i = 0; + while( i < collec.count() ) + { + QWebElement el = collec.at(i); + + checkString = QUrl(el.attribute("src")).toString( QUrl::RemoveQuery ); + urlString = m_url.toString( QUrl::RemoveQuery ); + + if( urlString.contains( checkString ) ) + return true; + + i++; + } + + return false; +} diff --git a/src/clicktoflash.h b/src/clicktoflash.h index 01bba257..186b5836 100644 --- a/src/clicktoflash.h +++ b/src/clicktoflash.h @@ -1,69 +1,52 @@ -/* - * Copyright (c) 2009, Benjamin C. Meyer - * - * 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. - * 3. Neither the name of the Benjamin Meyer nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. - * ============================================================ - * - * This file is a part of the rekonq project - * - * Copyright (C) 2009 by Matthieu Gicquel <matgic78@gmail.com> - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License or (at your option) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * ============================================================ */ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Benjamin C. Meyer <ben@meyerhome.net> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78@gmail.com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ #ifndef CLICKTOFLASH_H #define CLICKTOFLASH_H + +// Local Includes +#include "rekonqprivate_export.h" + +// Qt Includes #include <QWidget> #include <QUrl> +#include <QWebElement> - +// Forward Declarations class WebPluginFactory; -class ClickToFlash : public QWidget + +class REKONQ_TESTS_EXPORT ClickToFlash : public QWidget { Q_OBJECT + public: - ClickToFlash(QUrl pluginUrl, QWidget *parent = 0); + explicit ClickToFlash(QUrl pluginUrl, QWidget *parent = 0); signals: void signalLoadClickToFlash(bool); @@ -72,6 +55,8 @@ private slots: void load(); private: + bool checkElement(QWebElement el); + /** used to find the right QWebElement between the ones of the different plugins */ diff --git a/src/data/CMakeLists.txt b/src/data/CMakeLists.txt index 0af92f5e..ef777c9c 100644 --- a/src/data/CMakeLists.txt +++ b/src/data/CMakeLists.txt @@ -1,10 +1,15 @@ INSTALL( - FILES bg2.png bg.png bot.gif busywidget.gif closed.png loading.mng open.png tile.gif top.png webkit-icon.png category.png button.png + FILES + bg2.png bg.png tile.gif category.png button.png + busywidget.gif loading.mng + webkit-icon.png DESTINATION ${DATA_INSTALL_DIR}/rekonq/pics ) INSTALL( - FILES defaultbookmarks.xbel + FILES + defaultbookmarks.xbel + default.css DESTINATION ${DATA_INSTALL_DIR}/rekonq ) @@ -14,6 +19,8 @@ INSTALL( ) INSTALL( - FILES rekonqinfo.html home.html + FILES + rekonqinfo.html + home.html DESTINATION ${DATA_INSTALL_DIR}/rekonq/htmls ) diff --git a/src/data/bot.gif b/src/data/bot.gif Binary files differdeleted file mode 100644 index 2f9abde4..00000000 --- a/src/data/bot.gif +++ /dev/null diff --git a/src/data/closed.png b/src/data/closed.png Binary files differdeleted file mode 100644 index 2b1bf01e..00000000 --- a/src/data/closed.png +++ /dev/null diff --git a/src/data/default.css b/src/data/default.css new file mode 100644 index 00000000..3ddd3026 --- /dev/null +++ b/src/data/default.css @@ -0,0 +1,10 @@ +/* +rekonq default css properties +this file will not be considered +setting a local stylesheet in rekonq config +*/ + +/* Set background color to white for sites forgetting this */ +body{ +background-color:#FFFFFF; +}
\ No newline at end of file diff --git a/src/data/home.html b/src/data/home.html index 9d8f390f..25236743 100644 --- a/src/data/home.html +++ b/src/data/home.html @@ -6,134 +6,170 @@ <style type="text/css"> -/* ------------------------------------------------------- */ -/* generic styles */ - -html, body, div, h1, h2, h3, h4, a, p{ -margin:0; -padding:0; -border:0; +/* -------------------------------------------------------- */ +/* css reset */ +* { +border: 0; padding: 0; margin: 0; } -body{ +/* -------------------------------------------------------- */ +/* generic styles */ + +body { background: url(%2/tile.gif) repeat-x #fff; -font-family: sans-serif; -font-size: 0.8em; -text-align: center; +font-family: sans-serif; font-size: 0.8em; } -h1{ -font: normal bold 2em sans-serif; -text-align:right; -color: #3F7AB7; -margin-right:3%; -margin-top: 0.5%; -float:right; +#rekonq-newtabpage { +width: 100%; +text-align: center; /* center #navigation */ } -h2{ -font: normal bold 1.2em sans-serif; -color: #3F7AB7; -margin-top: 2em; +#content { +text-align: left; +margin: 0 1% 2% 1%; } -h3{ +h3 { border-bottom-width: 1px; -webkit-border-image: url(%2/category.png) 1 1 1 1 stretch stretch; -padding: 0.2em; -margin-top: 0.5em; -margin-bottom: 0.5em; -font: normal bold 1em sans-serif; +padding: 0.2em; margin: 0.5em 0; +font: normal bold 1em; } -h4{ -font-size: 1em; -margin-top: 0.5em; -} - -a{ +a { color: #3F7AB7; text-decoration: none; +-webkit-transition-property: color; +-webkit-transition-duration: 0.5s; +-webkit-transition-timing-function: ease; } -a:hover{ +a:hover { color: black; } -/* ------------------------------------------------------- */ -/* page sections */ +/* -------------------------------------------------------- */ +/* Top bar */ -#container { -width: 100%; +#top { +margin: 20px; } -#navigation { +.topBar { display: inline-block; -margin-top: 2%; -margin-bottom: 2%; -text-align: center; border-width: 5px; --webkit-border-image: url(%2/bg2.png) 12 12 12 12 stretch stretch; } -#content { -text-align: left; -margin: 2%; +#navigation { +-webkit-border-image: url(%2/bg2.png) 12 12 12 12 stretch stretch; +max-width: 55%; } -/* -------------------------------------------------------- */ -/* div navigations styles */ +#actions, #balance { +margin-top: 12px; +width: 20%; +} -.link{ -display: inline-block; +#actions { +float: right; } -.link img{ -vertical-align: middle; -margin-right: 5px; +#balance { +display: hidden; float: left; +height: 16px; } -.link a{ +.link { +display: inline-block; +} +.link img, .link span { +vertical-align: middle; display: inline-block; +} +.link a, .link span { color: black; -text-decoration:none; -font: normal 1em sans-serif; +} + +#actions .link { +-webkit-transition-property: opacity; +-webkit-transition-duration: 0.8s; +-webkit-transition-timing-function: ease; +opacity: 0.2; +} +#actions .link:hover { +opacity: 1; +} +#actions .link img { +margin-right: 3px; width: 16px; } .current{ border-width: 6px; -webkit-border-image: url(%2/button.png) 6 stretch stretch; } - -#navigation .link:not(.current){ -margin-right: 10px; -margin-left: 10px; +.link:not(.current){ +margin: 0 10px; } +/* -------------------------------------------------------- */ +/* Previews */ -.favorites{ +#content.favorites, #content.closedTabs { text-align: center; -margin-top: -5%; } -/* -------------------------------------------------------- */ -/* Thumbnail class */ - .thumbnail { -text-align: center; display: inline-block; -width:25%; -margin-top: 7%; -min-width:250px; -min-height:192px; +width: 25%; min-width: 240px; +height: 170px; +margin: 3% 0 3% 0; } -.thumbnail object{ -text-align: center; -width:228px; -height:192px; +.thumb-inner { +width: 232px; /* 200 + 16*2 */ +margin: auto; +} + +.preview { +display: table-cell; vertical-align: middle; +width: 200px; height: 150px; +padding: 14px 16px 12px; +background: url(%2/bg.png) no-repeat; +-webkit-background-size: 100% 100%; +} + +.title { +padding: 0 12px; +} + +.thumbnail:hover .preview , +.thumbnail:hover .button img { +opacity: 0.8; +} +.button img, .preview { +-webkit-transition-property: opacity; +-webkit-transition-duration: 0.8s; +-webkit-transition-timing-function: ease-in-out; +} + +.button img { +display: inline-block; +width: 16px; +height: 16px; +opacity: 0; +} +.remove { +float: right; +} +.modify { +float: left; +} + +.thumbnail a:hover, .thumbnail span { +color:#3F7AB7; } /* -------------------------------------------------------- */ -/* Bookmarks page*/ +/* Bookmarks page */ .bookfolder{ margin-left: 2em; @@ -141,39 +177,68 @@ margin-bottom: 0.5em; } /* -------------------------------------------------------- */ +/* Downloads page */ + +.download{ +margin: 1.5em 0; +} + +.download img{ +float: left; +margin-right: 5px; +} + +/* -------------------------------------------------------- */ +/* Empty pages : in the end : need to overwrite */ +#content.empty { +margin-top: 10%; +text-align: center; +} + + </style> </head> <body> -<div id="container"> - <div id="navigation"> +<div id="rekonq-newtabpage"> + <div id="top"> + <div class="topBar" id="balance"></div> <!-- This # is the same size as #actions to center #navigation --> + <div class="topBar" id="navigation"></div> + <div class="topBar" id="actions"></div> </div> - <div id="content"> - </div> </div> <div id="models" style="display:none"> + <div></div> <div class="link"> <a href=""> <img src="" /> + <span></span> </a> </div> <div class="thumbnail"> - <object type="application/image-preview" data=""> - <param name="title" /> - <param name="index" /> - <param name="isFavorite" /> - </object> + <div class ="thumb-inner"> + <a> + <div class ="preview"> + <img /> + </div> + </a> + <div class="title"> + <a class="button modify"><img /></a> + <span><a></a></span> + <a class="button remove"><img /></a> + </div> + </div> </div> <h3></h3> <a></a> - </br> - <p class="bookfolder"></h3> + <br /> + <img /> + <p class="bookfolder"></p> </div> - </body> </html> diff --git a/src/data/open.png b/src/data/open.png Binary files differdeleted file mode 100644 index fee6f3fb..00000000 --- a/src/data/open.png +++ /dev/null diff --git a/src/data/rekonq.desktop b/src/data/rekonq.desktop index 62998336..b0f8f2e3 100644 --- a/src/data/rekonq.desktop +++ b/src/data/rekonq.desktop @@ -1,17 +1,35 @@ [Desktop Entry] Name=rekonq +Name[cs]=rekonq +Name[da]=rekonq +Name[de]=rekonq +Name[en_GB]=rekonq +Name[es]=rekonq +Name[fr]=rekonq +Name[ga]=rekonq +Name[lt]=rekonq +Name[nds]=Rekonq +Name[pl]=rekonq +Name[pt]=rekonq +Name[pt_BR]=rekonq Name[sv]=Rekonq -Name[tr]=Rekonq +Name[uk]=rekonq Name[x-test]=xxrekonqxx GenericName=Webkit KDE Browser -GenericName[de]=Webkit-Browser für KDE -GenericName[et]=KDE Webkiti veebibrauser -GenericName[km]=កម្មវិធីរុករក Webkit KDE -GenericName[pt]=Navegador Web com WebKit +GenericName[cs]=Prohlížeč pro KDE založený na Webkitu +GenericName[da]=KDE-browser baseret på Webkit +GenericName[de]=WebKit-basierter Webbrowser für KDE +GenericName[en_GB]=Webkit KDE Browser +GenericName[es]=Navegador Webkit para KDE +GenericName[fr]=Navigateur Webkit pour KDE +GenericName[ga]=Brabhsálaí Webkit KDE +GenericName[lt]=Webkit KDE naršyklė +GenericName[nds]=Webkit-KDE-Kieker +GenericName[pl]=Przeglądarka Webkit dla KDE +GenericName[pt]=Navegador do KDE usando o WebKit GenericName[pt_BR]=Navegador Webkit do KDE GenericName[sv]=Webkit webbläsare för KDE -GenericName[tr]=Webkit KDE Tarayıcı -GenericName[uk]=Переглядач мережі на WebKit для KDE +GenericName[uk]=Переглядач інтернету на WebKit для KDE GenericName[x-test]=xxWebkit KDE Browserxx Icon=rekonq Type=Application diff --git a/src/data/top.png b/src/data/top.png Binary files differdeleted file mode 100644 index 9ebf0234..00000000 --- a/src/data/top.png +++ /dev/null diff --git a/src/data/webkit-icon.png b/src/data/webkit-icon.png Binary files differindex b3ec677a..780b0b16 100644 --- a/src/data/webkit-icon.png +++ b/src/data/webkit-icon.png diff --git a/src/filterurljob.cpp b/src/filterurljob.cpp index 00bdee36..f94b7810 100644 --- a/src/filterurljob.cpp +++ b/src/filterurljob.cpp @@ -31,9 +31,6 @@ #include <KUriFilter> #include <KUriFilterData> -// Qt Includes -#include <QUrl> - FilterUrlJob::FilterUrlJob(WebView *view, const QString &urlString, QObject *parent) : Job(parent) @@ -61,7 +58,12 @@ void FilterUrlJob::run() // the beautiful KDE web browsing shortcuts KUriFilterData data(_urlString); data.setCheckForExecutables(false); // if true, queries like "rekonq" or "dolphin" are considered as executables - _url = KUriFilter::self()->filterUri(data) - ? data.uri().pathOrUrl() - : QUrl::fromUserInput( _urlString ); + + if(KUriFilter::self()->filterUri(data) && data.uriType() != KUriFilterData::Error) + { + QString tempUrlString = data.uri().url(); + _url = KUrl(tempUrlString); + } + else + _url = QUrl::fromUserInput( _urlString ); } diff --git a/src/filterurljob.h b/src/filterurljob.h index 3a9511ea..9be058e3 100644 --- a/src/filterurljob.h +++ b/src/filterurljob.h @@ -28,6 +28,7 @@ #define FILTER_URL_JOB_H // Local Includes +#include "rekonqprivate_export.h" #include "webview.h" // KDE Includes @@ -41,7 +42,7 @@ using namespace ThreadWeaver; -class FilterUrlJob : public Job +class REKONQ_TESTS_EXPORT FilterUrlJob : public Job { public: FilterUrlJob(WebView *view, const QString &urlString, QObject *parent = 0); diff --git a/src/findbar.cpp b/src/findbar.cpp index bd1a5137..48a3c4e0 100644 --- a/src/findbar.cpp +++ b/src/findbar.cpp @@ -2,8 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -29,12 +29,14 @@ #include "findbar.h" #include "findbar.moc" +// Local Includes +#include "mainwindow.h" + // KDE Includes #include <KLineEdit> #include <KIcon> #include <KPushButton> #include <klocalizedstring.h> -#include <KMainWindow> #include <KApplication> // Qt Includes @@ -43,17 +45,20 @@ #include <QtGui/QToolButton> #include <QtGui/QLabel> #include <QtGui/QColor> -#include <QtGui/QKeyEvent> #include <QtCore/QString> #include <QtCore/QTimer> -FindBar::FindBar(KMainWindow *mainwindow) - : QWidget(mainwindow) +FindBar::FindBar(QWidget *parent) + : QWidget(parent) , m_lineEdit(new KLineEdit(this)) - , m_matchCase(new QCheckBox(i18n("&Match case"), this)) , m_hideTimer(new QTimer(this)) -{ + , m_matchCase(new QCheckBox(i18n("&Match case"), this)) + , m_highlightAll(new QCheckBox(i18n("&Highlight all"), this)) +{ + // mainwindow pointer + MainWindow *window = qobject_cast<MainWindow *>(parent); + QHBoxLayout *layout = new QHBoxLayout; // cosmetic @@ -64,6 +69,7 @@ FindBar::FindBar(KMainWindow *mainwindow) hideButton->setAutoRaise(true); hideButton->setIcon(KIcon("dialog-close")); connect(hideButton, SIGNAL(clicked()), this, SLOT(hide())); + connect(hideButton, SIGNAL(clicked()), window, SLOT(highlightAll())); layout->addWidget(hideButton); layout->setAlignment(hideButton, Qt::AlignLeft | Qt::AlignTop); @@ -77,22 +83,30 @@ FindBar::FindBar(KMainWindow *mainwindow) // lineEdit, focusProxy setFocusProxy(m_lineEdit); m_lineEdit->setMaximumWidth(250); - connect(m_lineEdit, SIGNAL(textChanged(const QString &)), mainwindow, SLOT(find(const QString &))); + connect(m_lineEdit, SIGNAL(textChanged(const QString &)), window, SLOT(find(const QString &))); + connect(m_lineEdit, SIGNAL(returnPressed()), window, SLOT(findNext())); layout->addWidget(m_lineEdit); // buttons KPushButton *findNext = new KPushButton(KIcon("go-down"), i18n("&Next"), this); KPushButton *findPrev = new KPushButton(KIcon("go-up"), i18n("&Previous"), this); - connect(findNext, SIGNAL(clicked()), mainwindow, SLOT(findNext())); - connect(findPrev, SIGNAL(clicked()), mainwindow, SLOT(findPrevious())); + connect(findNext, SIGNAL(clicked()), window, SLOT(findNext())); + connect(findPrev, SIGNAL(clicked()), window, SLOT(findPrevious())); layout->addWidget(findNext); layout->addWidget(findPrev); - + // Case sensitivity. Deliberately set so this is off by default. m_matchCase->setCheckState(Qt::Unchecked); m_matchCase->setTristate(false); + connect(m_matchCase, SIGNAL(toggled(bool)), window, SLOT(matchCaseUpdate())); layout->addWidget(m_matchCase); + // Hightlight All. On by default + m_highlightAll->setCheckState(Qt::Checked); + m_highlightAll->setTristate(false); + connect(m_highlightAll, SIGNAL(toggled(bool)), window, SLOT(highlightAll())); + layout->addWidget(m_highlightAll); + // stretching widget on the left layout->addStretch(); @@ -120,44 +134,29 @@ bool FindBar::matchCase() const } -void FindBar::clear() +bool FindBar::highlightAllState() const { - m_lineEdit->setText(QString()); + return m_highlightAll->isChecked(); } void FindBar::show() { - // set focus to findbar if user select showFindBar shortcut - m_lineEdit->setFocus(); - m_lineEdit->selectAll(); - // show findbar if not visible - if (isVisible()) - return; - - QWidget::show(); - m_hideTimer->start(60000); -} - - -void FindBar::keyPressEvent(QKeyEvent* event) -{ - if (event->key() == Qt::Key_Escape) - { - hide(); - m_hideTimer->stop(); - return; - } - if (event->key() == Qt::Key_Return && !m_lineEdit->text().isEmpty()) + if(isHidden()) { + QWidget::show(); emit searchString(m_lineEdit->text()); - return; } - QWidget::keyPressEvent(event); + m_hideTimer->start(60000); + + // set focus to findbar if user select showFindBar shortcut + m_lineEdit->setFocus(); + m_lineEdit->selectAll(); } + void FindBar::notifyMatch(bool match) { QPalette p = m_lineEdit->palette(); @@ -180,3 +179,11 @@ void FindBar::notifyMatch(bool match) m_lineEdit->setPalette(p); m_hideTimer->start(60000); } + + +void FindBar::hide() +{ + m_hideTimer->stop(); + QWidget::hide(); + emit(searchString(m_lineEdit->text())); +} diff --git a/src/findbar.h b/src/findbar.h index fa369f66..78615f9a 100644 --- a/src/findbar.h +++ b/src/findbar.h @@ -2,8 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -29,46 +29,44 @@ #define FINDBAR_H +// Local Includes +#include "rekonqprivate_export.h" + // KDE Includes #include <KLineEdit> // Qt Includes #include <QtGui/QWidget> #include <QtGui/QCheckBox> -#include <QtGui/QKeyEvent> // Forward Declarations -class KMainWindow; -class QKeyEvent; class QString; -class FindBar : public QWidget +class REKONQ_TESTS_EXPORT FindBar : public QWidget { Q_OBJECT public: - FindBar(KMainWindow *mainwindow); + FindBar(QWidget *parent); ~FindBar(); KLineEdit *lineEdit() const; bool matchCase() const; + void notifyMatch(bool match); + bool highlightAllState() const; public slots: - void clear(); void show(); - void notifyMatch(bool match); - -protected Q_SLOTS: - void keyPressEvent(QKeyEvent* event); + void hide(); signals: void searchString(const QString &); private: KLineEdit *m_lineEdit; - QCheckBox *m_matchCase; QTimer *m_hideTimer; - + QCheckBox *m_matchCase; + QCheckBox *m_highlightAll; }; #endif diff --git a/src/history/autosaver.cpp b/src/history/autosaver.cpp index 236922b5..1bfd5c9e 100644 --- a/src/history/autosaver.cpp +++ b/src/history/autosaver.cpp @@ -3,7 +3,7 @@ * This file is a part of the rekonq project * * Copyright (C) 2007-2008 Trolltech ASA. All rights reserved -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -52,7 +52,7 @@ AutoSaver::~AutoSaver() { if (m_timer.isActive()) { - kWarning() << "AutoSaver: still active when destroyed, changes not saved."; + kDebug() << "AutoSaver: still active when destroyed, changes not saved."; } } @@ -94,7 +94,7 @@ void AutoSaver::saveIfNeccessary() m_firstChange = QTime(); if (!QMetaObject::invokeMethod(parent(), "save", Qt::DirectConnection)) { - kWarning() << "AutoSaver: error invoking slot save() on parent"; + kDebug() << "AutoSaver: error invoking slot save() on parent"; } } diff --git a/src/history/autosaver.h b/src/history/autosaver.h index 80583f9c..c4c9045b 100644 --- a/src/history/autosaver.h +++ b/src/history/autosaver.h @@ -3,7 +3,7 @@ * This file is a part of the rekonq project * * Copyright (C) 2007-2008 Trolltech ASA. All rights reserved -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -29,6 +29,9 @@ #define AUTOSAVER_H +// Local Includes +#include "rekonqprivate_export.h" + // Qt Includes #include <QtCore/QObject> #include <QtCore/QBasicTimer> @@ -43,7 +46,7 @@ * */ -class AutoSaver : public QObject +class REKONQ_TESTS_EXPORT AutoSaver : public QObject { Q_OBJECT diff --git a/src/history/historymanager.cpp b/src/history/historymanager.cpp index 29bdb45b..097f9ee2 100644 --- a/src/history/historymanager.cpp +++ b/src/history/historymanager.cpp @@ -4,7 +4,7 @@ * * Copyright (C) 2007-2008 Trolltech ASA. All rights reserved * Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -69,10 +69,9 @@ HistoryManager::HistoryManager(QObject *parent) , m_historyModel(0) , m_historyFilterModel(0) , m_historyTreeModel(0) - , m_completion(0) + , m_completion(new KCompletion) { // take care of the completion object - m_completion = new KCompletion; m_completion->setOrder( KCompletion::Weighted ); m_expiredTimer.setSingleShot(true); @@ -317,7 +316,7 @@ void HistoryManager::load() return; if (!historyFile.open(QFile::ReadOnly)) { - kWarning() << "Unable to open history file" << historyFile.fileName(); + kDebug() << "Unable to open history file" << historyFile.fileName(); return; } @@ -363,7 +362,7 @@ void HistoryManager::load() // Add item to completion object QString _url = item.url; - _url.remove(QRegExp("^http://|/$")); + //_url.remove(QRegExp("^http://|/$")); m_completion->addItem(_url); } if (needToSort) @@ -417,7 +416,7 @@ void HistoryManager::save() if (!open) { - kWarning() << "Unable to open history file for saving" + kDebug() << "Unable to open history file for saving" << (saveAll ? tempFile.fileName() : historyFile.fileName()); return; } @@ -437,11 +436,11 @@ void HistoryManager::save() { if (historyFile.exists() && !historyFile.remove()) { - kWarning() << "History: error removing old history." << historyFile.errorString(); + kDebug() << "History: error removing old history." << historyFile.errorString(); } if (!tempFile.rename(historyFile.fileName())) { - kWarning() << "History: error moving new history over old." << tempFile.errorString() << historyFile.fileName(); + kDebug() << "History: error moving new history over old." << tempFile.errorString() << historyFile.fileName(); } } m_lastSavedUrl = m_history.value(0).url; @@ -452,3 +451,83 @@ KCompletion * HistoryManager::completionObject() const { return m_completion; } + + +void HistoryManager::addDownload(const QString &srcUrl, const QString &destUrl) +{ + QWebSettings *globalSettings = QWebSettings::globalSettings(); + if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) + return; + QString downloadFilePath = KStandardDirs::locateLocal("appdata" , "downloads"); + QFile downloadFile(downloadFilePath); + if ( !downloadFile.open(QFile::WriteOnly | QFile::Append) ) + { + kDebug() << "azz..."; + return; + } + QDataStream out(&downloadFile); + out << srcUrl; + out << destUrl; + out << QDateTime::currentDateTime(); + downloadFile.close(); +} + + +DownloadList HistoryManager::downloads() +{ + DownloadList list; + + QString downloadFilePath = KStandardDirs::locateLocal("appdata" , "downloads"); + QFile downloadFile(downloadFilePath); + if ( !downloadFile.open(QFile::ReadOnly) ) + { + kDebug() << "azz..."; + return list; + } + + QDataStream in(&downloadFile); + while(!in.atEnd()) + { + QString srcUrl; + in >> srcUrl; + QString destUrl; + in >> destUrl; + QDateTime dt; + in >> dt; + DownloadItem item(srcUrl, destUrl, dt); + list << item; + } + return list; +} + + +bool HistoryManager::clearDownloadsHistory() +{ + QString downloadFilePath = KStandardDirs::locateLocal("appdata" , "downloads"); + QFile downloadFile(downloadFilePath); + return downloadFile.remove(); +} + + +QString HistoryManager::titleForHistoryUrl(QString url) +{ + QString title = ""; + + int i = 0; + while (i< history().count() && title.isEmpty()) + { + if (history().at(i).url == url) + { + title = history().at(i).title; + } + i++; + } + + if (title.isEmpty()) + { + title = url; + } + + return title; +} + diff --git a/src/history/historymanager.h b/src/history/historymanager.h index ff3b4381..9a844672 100644 --- a/src/history/historymanager.h +++ b/src/history/historymanager.h @@ -4,7 +4,7 @@ * * Copyright (C) 2007-2008 Trolltech ASA. All rights reserved * Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -30,6 +30,9 @@ #define HISTORY_H +// Local Includes +#include "rekonqprivate_export.h" + // KDE Includes #include <KUrl> @@ -54,7 +57,10 @@ public: const QDateTime &d = QDateTime(), const QString &t = QString() ) - : title(t), url(u), dateTime(d) {} + : title(t) + , url(u), + dateTime(d) + {} inline bool operator==(const HistoryItem &other) const { @@ -74,6 +80,29 @@ public: }; +// --------------------------------------------------------------------------------------------------------------- + + +class DownloadItem +{ +public: + DownloadItem() {} + explicit DownloadItem(const QString &srcUrl, + const QString &destUrl, + const QDateTime &d + ) + : srcUrlString(srcUrl) + , destUrlString(destUrl) + , dateTime(d) + {} + + QString srcUrlString; + QString destUrlString; + QDateTime dateTime; +}; + + +typedef QList<DownloadItem> DownloadList; // --------------------------------------------------------------------------------------------------------------- @@ -92,7 +121,7 @@ class KCompletion; * It manages rekonq history * */ -class HistoryManager : public QWebHistoryInterface +class REKONQ_TESTS_EXPORT HistoryManager : public QWebHistoryInterface { Q_OBJECT Q_PROPERTY(int historyLimit READ historyLimit WRITE setHistoryLimit) @@ -112,6 +141,8 @@ public: void updateHistoryEntry(const KUrl &url, const QString &title); void removeHistoryEntry(const KUrl &url, const QString &title = QString()); + QString titleForHistoryUrl(QString url); + int historyLimit() const; void setHistoryLimit(int limit); @@ -128,6 +159,10 @@ public: */ KCompletion *completionObject() const; + void addDownload(const QString &srcUrl, const QString &destUrl); + DownloadList downloads(); + bool clearDownloadsHistory(); + public slots: void clear(); void loadSettings(); diff --git a/src/history/historymodels.cpp b/src/history/historymodels.cpp index cf8d1aed..736dbcd7 100644 --- a/src/history/historymodels.cpp +++ b/src/history/historymodels.cpp @@ -4,7 +4,7 @@ * * Copyright (C) 2007-2008 Trolltech ASA. All rights reserved * Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -118,6 +118,8 @@ QVariant HistoryModel::data(const QModelIndex &index, int role) const return item.dateTime.date(); case UrlRole: return QUrl(item.url); + case Qt::UserRole: + return KUrl(item.url); case UrlStringRole: return item.url; case Qt::DisplayRole: @@ -144,6 +146,12 @@ QVariant HistoryModel::data(const QModelIndex &index, int role) const { return Application::icon(item.url); } + case Qt::ToolTipRole: + QString tooltip = ""; + if(!item.title.isEmpty()) + tooltip = item.title + "\n"; + tooltip += item.dateTime.toString(Qt::SystemLocaleShortDate) + "\n" + item.url; + return tooltip; } return QVariant(); } diff --git a/src/history/historymodels.h b/src/history/historymodels.h index 08f3f63e..c2b1ede1 100644 --- a/src/history/historymodels.h +++ b/src/history/historymodels.h @@ -4,7 +4,7 @@ * * Copyright (C) 2007-2008 Trolltech ASA. All rights reserved * Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -31,6 +31,7 @@ // Local Includes +#include "rekonqprivate_export.h" #include "historymanager.h" // KDE Includes @@ -45,7 +46,7 @@ #include <QWebHistoryInterface> -class HistoryModel : public QAbstractTableModel +class REKONQ_TESTS_EXPORT HistoryModel : public QAbstractTableModel { Q_OBJECT @@ -85,7 +86,7 @@ private: * */ -class HistoryFilterModel : public QAbstractProxyModel +class REKONQ_TESTS_EXPORT HistoryFilterModel : public QAbstractProxyModel { Q_OBJECT diff --git a/src/history/historypanel.cpp b/src/history/historypanel.cpp index 08dc3800..8c36dfa8 100644 --- a/src/history/historypanel.cpp +++ b/src/history/historypanel.cpp @@ -2,8 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com>* * Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@gmail.com> +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -46,10 +46,14 @@ // KDE Includes #include <KLineEdit> #include <KLocalizedString> +#include <KMenu> +#include <KAction> +#include <KMessageBox> HistoryPanel::HistoryPanel(const QString &title, QWidget *parent, Qt::WindowFlags flags) : QDockWidget(title, parent, flags) + , m_treeView(new PanelTreeView(this)) { setup(); setShown(ReKonfig::showHistoryPanel()); @@ -70,11 +74,11 @@ void HistoryPanel::setup() QWidget *ui = new QWidget(this); - QTreeView *historyTreeView = new QTreeView(this); - historyTreeView->setUniformRowHeights(true); - historyTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); - historyTreeView->setTextElideMode(Qt::ElideMiddle); - historyTreeView->setAlternatingRowColors(true); + m_treeView->setUniformRowHeights(true); + m_treeView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_treeView->setTextElideMode(Qt::ElideMiddle); + m_treeView->setAlternatingRowColors(true); + m_treeView->header()->hide(); // add search bar QHBoxLayout *hBoxLayout = new QHBoxLayout; @@ -91,7 +95,7 @@ void HistoryPanel::setup() QVBoxLayout *vBoxLayout = new QVBoxLayout; vBoxLayout->setContentsMargins(0, 0, 0, 0); vBoxLayout->addWidget(searchBar); - vBoxLayout->addWidget(historyTreeView); + vBoxLayout->addWidget(m_treeView); // add it to the UI ui->setLayout(vBoxLayout); @@ -103,19 +107,83 @@ void HistoryPanel::setup() TreeProxyModel *treeProxyModel = new TreeProxyModel(this); treeProxyModel->setSourceModel(model); - historyTreeView->setModel(treeProxyModel); - historyTreeView->setExpanded(treeProxyModel->index(0, 0), true); - historyTreeView->header()->hideSection(1); + m_treeView->setModel(treeProxyModel); + m_treeView->setExpanded(treeProxyModel->index(0, 0), true); + m_treeView->header()->hideSection(1); QFontMetrics fm(font()); int header = fm.width(QLatin1Char('m')) * 40; - historyTreeView->header()->resizeSection(0, header); + m_treeView->header()->resizeSection(0, header); connect(search, SIGNAL(textChanged(QString)), treeProxyModel, SLOT(setFilterFixedString(QString))); - connect(historyTreeView, SIGNAL(activated(const QModelIndex &)), this, SLOT(itemActivated(const QModelIndex &))); + connect(m_treeView, SIGNAL(contextMenuItemRequested(const QPoint &)), this, SLOT(contextMenuItem(const QPoint &))); + connect(m_treeView, SIGNAL(contextMenuGroupRequested(const QPoint &)), this, SLOT(contextMenuGroup(const QPoint &))); } -void HistoryPanel::itemActivated(const QModelIndex &item) +void HistoryPanel::contextMenuItem(const QPoint &pos) { - emit openUrl( item.data(HistoryModel::UrlRole).toUrl() ); + KMenu *menu = new KMenu(this); + KAction* action; + + action = new KAction(KIcon("tab-new"), i18n("Open"), this); + connect(action, SIGNAL(triggered()), m_treeView, SLOT(openInCurrentTab())); + menu->addAction(action); + + action = new KAction(KIcon("tab-new"), i18n("Open in New Tab"), this); + connect(action, SIGNAL(triggered()), m_treeView, SLOT(openInNewTab())); + menu->addAction(action); + + action = new KAction(KIcon("window-new"), i18n("Open in New Window"), this); + connect(action, SIGNAL(triggered()), m_treeView, SLOT(openInNewWindow())); + menu->addAction(action); + + action = new KAction(KIcon("edit-copy"), i18n("Copy Link Address"), this); + connect(action, SIGNAL(triggered()), m_treeView, SLOT(copyToClipboard())); + menu->addAction(action); + + if (!menu) + return; + menu->popup(m_treeView->mapToGlobal(pos)); } + + +void HistoryPanel::contextMenuGroup(const QPoint &pos) +{ + KMenu *menu = new KMenu(this); + KAction* action; + + action = new KAction(KIcon("tab-new"), i18n("Open Folder in Tabs"), this); + connect(action, SIGNAL(triggered()), this, SLOT(openAll())); + + menu->addAction(action); + + if (!menu) + return; + menu->popup(m_treeView->mapToGlobal(pos)); +} + + +void HistoryPanel::openAll() +{ + QModelIndex index = m_treeView->currentIndex(); + if(!index.isValid()) + return; + + QList<KUrl> allChild; + + for(int i = 0; i < index.model()->rowCount(index); i++) + allChild << qVariantValue<KUrl>(index.child(i, 0).data(Qt::UserRole)); + + if(allChild.length() > 8) + { + if( !(KMessageBox::warningContinueCancel(this, + i18n("You are about to open %1 tabs.\nAre you sure ?", + QString::number(allChild.length()))) == KMessageBox::Continue) + ) + return; + } + + for(int i = 0; i < allChild.length(); i++) + emit openUrl(allChild.at(i).url(), Rekonq::SettingOpenTab); +} + diff --git a/src/history/historypanel.h b/src/history/historypanel.h index e07e2190..a4dfaf64 100644 --- a/src/history/historypanel.h +++ b/src/history/historypanel.h @@ -2,8 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com>* * Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@gmail.com> +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -29,6 +29,11 @@ #define HISTORYPANEL_H +// Local Includes +#include "rekonqprivate_export.h" +#include "application.h" +#include "paneltreeview.h" + // Qt Includes #include <QDockWidget> @@ -38,7 +43,7 @@ class QWidget; class QModelIndex; -class HistoryPanel : public QDockWidget +class REKONQ_TESTS_EXPORT HistoryPanel : public QDockWidget { Q_OBJECT @@ -47,13 +52,17 @@ public: ~HistoryPanel(); signals: - void openUrl(const KUrl &); + void openUrl(const KUrl &, const Rekonq::OpenType &); + void itemHovered(const QString &); private slots: - void itemActivated(const QModelIndex &); + void contextMenuItem(const QPoint &pos); + void contextMenuGroup(const QPoint &pos); + void openAll(); private: void setup(); + PanelTreeView *m_treeView; }; #endif // HISTORYPANEL_H diff --git a/src/main.cpp b/src/main.cpp index 030b8476..0be5a7ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -49,22 +49,17 @@ extern "C" KDE_EXPORT int kdemain( int argc, char **argv ) REKONQ_VERSION, ki18n(description), KAboutData::License_GPL_V3, - ki18n("(C) 2008-2009 Andrea Diamantini"), + ki18n("(C) 2008-2010 Andrea Diamantini"), KLocalizedString(), "http://rekonq.sourceforge.net" ); // --------------- about authors ----------------------------- about.addAuthor(ki18n("Andrea Diamantini"), - ki18n("Project Lead, Developer"), + ki18n("Project Lead, Developer, Maintainer"), "adjam7@gmail.com", "http://www.adjam.org"); - about.addAuthor(ki18n("Domrachev Alexandr"), - ki18n("Developer"), - "alexandr.domrachev@gmail.com", - ""); - about.addAuthor(ki18n("Panagiotis Papadopoulos"), ki18n("Quite everything but code"), "pano_90@gmx.net", @@ -91,6 +86,11 @@ extern "C" KDE_EXPORT int kdemain( int argc, char **argv ) ""); // --------------- about credits ----------------------------- + about.addCredit(ki18n("Domrachev Alexandr"), + ki18n("Developer"), + "alexandr.domrachev@gmail.com", + ""); + about.addCredit(ki18n("Henry de Valence"), ki18n("Promised help on multitask rekonq"), "hdevalence@gmail.com", diff --git a/src/mainview.cpp b/src/mainview.cpp index b26e7466..cb2e3b11 100644 --- a/src/mainview.cpp +++ b/src/mainview.cpp @@ -2,9 +2,10 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -60,17 +61,21 @@ #include <QWidget> #include <QVBoxLayout> +// Defines +#define QL1S(x) QLatin1String(x) + MainView::MainView(MainWindow *parent) - : KTabWidget(parent) - , m_urlBar(new UrlBar(this)) - , m_tabBar(new TabBar(this)) - , m_addTabButton(new QToolButton(this)) - , m_currentTabIndex(0) - , m_parentWindow(parent) + : KTabWidget(parent) + , _bars(new QStackedWidget(this)) + , m_addTabButton(0) + , m_currentTabIndex(0) + , m_parentWindow(parent) { // setting tabbar - setTabBar(m_tabBar); + TabBar *tabBar = new TabBar(this); + m_addTabButton = new QToolButton(this); + setTabBar(tabBar); // set mouse tracking for tab previews setMouseTracking(true); @@ -79,17 +84,18 @@ MainView::MainView(MainWindow *parent) m_loadingGitPath = KStandardDirs::locate("appdata" , "pics/loading.mng"); // connecting tabbar signals - connect(m_tabBar, SIGNAL(closeTab(int)), this, SLOT(closeTab(int))); - connect(m_tabBar, SIGNAL(mouseMiddleClick(int)), this, SLOT(closeTab(int))); - connect(m_tabBar, SIGNAL(newTabRequest()), this, SLOT(newTab())); + connect(tabBar, SIGNAL(closeTab(int)), this, SLOT(closeTab(int)) ); + connect(tabBar, SIGNAL(mouseMiddleClick(int)), this, SLOT(closeTab(int)) ); + connect(tabBar, SIGNAL(newTabRequest()), this, SLOT(newTab()) ); - connect(m_tabBar, SIGNAL(cloneTab(int)), this, SLOT(cloneTab(int))); - connect(m_tabBar, SIGNAL(closeOtherTabs(int)), this, SLOT(closeOtherTabs(int))); - connect(m_tabBar, SIGNAL(reloadTab(int)), this, SLOT(reloadTab(int))); - connect(m_tabBar, SIGNAL(reloadAllTabs()), this, SLOT(reloadAllTabs())); - connect(m_tabBar, SIGNAL(detachTab(int)), this, SLOT(detachTab(int))); + connect(tabBar, SIGNAL(cloneTab(int)), this, SLOT(cloneTab(int)) ); + connect(tabBar, SIGNAL(closeOtherTabs(int)), this, SLOT(closeOtherTabs(int)) ); + connect(tabBar, SIGNAL(reloadTab(int)), this, SLOT(reloadTab(int)) ); + connect(tabBar, SIGNAL(reloadAllTabs()), this, SLOT(reloadAllTabs()) ); + connect(tabBar, SIGNAL(detachTab(int)), this, SLOT(detachTab(int)) ); - connect(m_tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); + connect(tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)) ); + connect(tabBar, SIGNAL(tabMoved(int, int)), this, SLOT(movedTab(int, int)) ); // current page index changing connect(this, SIGNAL(currentChanged(int)), this, SLOT(currentChanged(int))); @@ -117,12 +123,10 @@ void MainView::postLaunch() void MainView::updateTabButtonPosition() { - kDebug() << "updating new tab button position.."; - static bool ButtonInCorner = false; int tabWidgetWidth = frameSize().width(); - int tabBarWidth = m_tabBar->tabSizeHint(0).width()*m_tabBar->count(); + int tabBarWidth = tabBar()->tabSizeHint(0).width() * tabBar()->count(); if (tabBarWidth + m_addTabButton->width() > tabWidgetWidth) { @@ -142,14 +146,13 @@ void MainView::updateTabButtonPosition() // detecting X position int newPosX = tabBarWidth; - int tabWidthHint = m_tabBar->tabSizeHint(0).width(); + int tabWidthHint = tabBar()->tabSizeHint(0).width(); if (tabWidthHint < sizeHint().width()/4) newPosX = tabWidgetWidth - m_addTabButton->width(); // Y position is fixed // Here I noticed with some emphiric valutations ( :D ) // that 2 look better than 0, just that.. - m_addTabButton->move(newPosX, 2); } } @@ -163,13 +166,20 @@ QToolButton *MainView::addTabButton() const TabBar *MainView::tabBar() const { - return m_tabBar; + TabBar *tabBar = qobject_cast<TabBar *>( KTabWidget::tabBar() ); + return tabBar; +} + + +UrlBar *MainView::urlBar() const +{ + return qobject_cast<UrlBar *>(_bars->widget(m_currentTabIndex)); } -UrlBar *MainView::urlBar() const +QWidget *MainView::urlBarWidget() const { - return m_urlBar; + return _bars; } @@ -181,13 +191,13 @@ WebTab *MainView::currentWebTab() const void MainView::updateTabBar() { - if (ReKonfig::alwaysShowTabBar()) + if( ReKonfig::alwaysShowTabBar() ) { if (!isTabBarHidden()) { - if (m_tabBar->isHidden()) + if (tabBar()->isHidden()) { - m_tabBar->show(); + tabBar()->show(); m_addTabButton->show(); } updateTabButtonPosition(); @@ -195,16 +205,16 @@ void MainView::updateTabBar() return; } - if (m_tabBar->count() == 1) + if( tabBar()->count() == 1 ) { - m_tabBar->hide(); + tabBar()->hide(); m_addTabButton->hide(); } - else if (!isTabBarHidden()) + else if( !isTabBarHidden() ) { - if (m_tabBar->isHidden()) + if ( tabBar()->isHidden() ) { - m_tabBar->show(); + tabBar()->show(); m_addTabButton->show(); } updateTabButtonPosition(); @@ -235,17 +245,6 @@ void MainView::webStop() } -void MainView::clear() -{ - // FIXME (the programmer, not the code) - // What exactly do we need to clear here? - m_urlBar->clearHistory(); - m_urlBar->clear(); - - m_recentlyClosedTabs.clear(); -} - - // When index is -1 index chooses the current tab void MainView::reloadTab(int index) { @@ -273,42 +272,41 @@ void MainView::currentChanged(int index) m_currentTabIndex = index; if (oldTab) - { - // disconnecting webview from urlbar - disconnect(oldTab->view(), SIGNAL(loadProgress(int)), urlBar(), SLOT(updateProgress(int))); - disconnect(oldTab->view(), SIGNAL(loadFinished(bool)), urlBar(), SLOT(loadFinished(bool))); - disconnect(oldTab->view(), SIGNAL(urlChanged(const QUrl &)), urlBar(), SLOT(setUrl(const QUrl &))); - + { // disconnecting webpage from mainview disconnect(oldTab->page(), SIGNAL(statusBarMessage(const QString&)), this, SIGNAL(showStatusBarMessage(const QString&))); disconnect(oldTab->page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)), this, SIGNAL(linkHovered(const QString&))); } - - // connecting webview with urlbar - connect(tab->view(), SIGNAL(loadProgress(int)), urlBar(), SLOT(updateProgress(int))); - connect(tab->view(), SIGNAL(loadFinished(bool)), urlBar(), SLOT(loadFinished(bool))); - connect(tab->view(), SIGNAL(urlChanged(const QUrl &)), urlBar(), SLOT(setUrl(const QUrl &))); - connect(tab->view()->page(), SIGNAL(statusBarMessage(const QString&)), + connect(tab->page(), SIGNAL(statusBarMessage(const QString&)), this, SIGNAL(showStatusBarMessage(const QString&))); - connect(tab->view()->page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)), + connect(tab->page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)), this, SIGNAL(linkHovered(const QString&))); - emit setCurrentTitle(tab->view()->title()); - urlBar()->setUrl(tab->view()->url()); - urlBar()->setProgress(tab->progress()); - emit showStatusBarMessage(tab->lastStatusBarText()); + emit currentTitle(tab->view()->title()); + _bars->setCurrentIndex(index); + + // clean up "status bar" + emit showStatusBarMessage( QString() ); // notify UI to eventually switch stop/reload button - if(urlBar()->isLoading()) - emit browserTabLoading(true); - else + int progr = tab->progress(); + if(progr == 0) emit browserTabLoading(false); + else + emit browserTabLoading(true); + + // update zoom slider + if(!Application::instance()->mainWindowList().isEmpty()) + Application::instance()->mainWindow()->setZoomSliderFactor(tab->view()->zoomFactor()); // set focus to the current webview - tab->setFocus(); + if(tab->url().scheme() == QL1S("about")) + _bars->currentWidget()->setFocus(); + else + tab->view()->setFocus(); } @@ -328,7 +326,8 @@ WebTab *MainView::webTab(int index) const WebTab *MainView::newWebTab(bool focused, bool nearParent) { WebTab* tab = new WebTab(this); - + UrlBar *bar = new UrlBar(tab); + // connecting webview with mainview connect(tab->view(), SIGNAL(loadStarted()), this, SLOT(webViewLoadStarted())); connect(tab->view(), SIGNAL(loadFinished(bool)), this, SLOT(webViewLoadFinished(bool))); @@ -341,10 +340,15 @@ WebTab *MainView::newWebTab(bool focused, bool nearParent) connect(tab->view()->page(), SIGNAL(printRequested(QWebFrame *)), this, SIGNAL(printRequested(QWebFrame *))); if (nearParent) + { insertTab(currentIndex() + 1, tab, i18n("(Untitled)")); + _bars->insertWidget(currentIndex() + 1, bar); + } else + { addTab(tab, i18n("(Untitled)")); - + _bars->addWidget(bar); + } updateTabBar(); if (focused) @@ -368,7 +372,7 @@ void MainView::newTab() w->load( KUrl("about:home") ); break; case 1: // blank page - urlBar()->setUrl(KUrl("")); + urlBar()->clear(); break; case 2: // homepage w->load( KUrl(ReKonfig::homePage()) ); @@ -376,7 +380,7 @@ void MainView::newTab() default: break; } - urlBar()->setFocus(); + _bars->currentWidget()->setFocus(); } @@ -458,12 +462,12 @@ void MainView::closeTab(int index) if (count() == 1) { WebView *w = currentWebTab()->view(); - urlBar()->setUrl(KUrl("")); switch(ReKonfig::newTabsBehaviour()) { case 0: // new tab page case 1: // blank page w->load( KUrl("about:home") ); + urlBar()->setFocus(); break; case 2: // homepage w->load( KUrl(ReKonfig::homePage()) ); @@ -471,7 +475,6 @@ void MainView::closeTab(int index) default: break; } - urlBar()->setFocus(); return; } @@ -480,43 +483,40 @@ void MainView::closeTab(int index) if (index < 0 || index >= count()) return; - bool hasFocus = false; WebTab *tab = webTab(index); - if (tab) + if (!tab) + return; + + if (tab->view()->isModified()) { - if (tab->view()->isModified()) - { - int risp = KMessageBox::questionYesNo(this, - i18n("This tab contains changes that have not been submitted.\n" - "Closing the tab will discard these changes.\n" - "Do you really want to close this tab?\n"), - i18n("Closing Modified Tab")); - if (risp == KMessageBox::No) - return; - } - hasFocus = tab->hasFocus(); + int risp = KMessageBox::warningContinueCancel(this, + i18n("This tab contains changes that have not been submitted.\n" + "Closing the tab will discard these changes.\n" + "Do you really want to close this tab?\n"), + i18n("Closing Modified Tab"), KGuiItem(i18n("Close &Tab"),"tab-close"), KStandardGuiItem::cancel()); + if (risp != KMessageBox::Continue) + return; + } - //store close tab except homepage - if (!tab->url().prettyUrl().startsWith( QLatin1String("about:") ) && !tab->url().isEmpty()) - { - QString title = tab->view()->title(); - QString url = tab->url().prettyUrl(); - HistoryItem item(url, QDateTime::currentDateTime(), title); - m_recentlyClosedTabs.removeAll(item); - m_recentlyClosedTabs.prepend(item); - } + // store close tab except homepage + if (!tab->url().prettyUrl().startsWith( QLatin1String("about:") ) && !tab->url().isEmpty()) + { + QString title = tab->view()->title(); + QString url = tab->url().prettyUrl(); + HistoryItem item(url, QDateTime::currentDateTime(), title); + m_recentlyClosedTabs.removeAll(item); + m_recentlyClosedTabs.prepend(item); + } - removeTab(index); - updateTabBar(); // UI operation: do it ASAP!! - tab->deleteLater(); // webView is scheduled for deletion. - - emit tabsChanged(); + removeTab(index); + updateTabBar(); // UI operation: do it ASAP!! + tab->deleteLater(); // tab is scheduled for deletion. - if (hasFocus && count() > 0) - { - currentWebTab()->setFocus(); - } - } + QWidget *urlbar = _bars->widget(index); + _bars->removeWidget(urlbar); + urlbar->deleteLater(); + + emit tabsChanged(); } @@ -533,11 +533,10 @@ void MainView::webViewLoadStarted() } } - emit browserTabLoading(true); - if (index != currentIndex()) return; + emit browserTabLoading(true); emit showStatusBarMessage(i18n("Loading...")); } @@ -579,14 +578,12 @@ void MainView::webViewIconChanged() int index = indexOf( view->parentWidget() ); if (-1 != index) { - QIcon icon = Application::icon(view->url()); + KIcon icon = Application::icon(view->url()); QLabel *label = animatedLoading(index, false); QMovie *movie = label->movie(); delete movie; label->setMovie(0); label->setPixmap(icon.pixmap(16, 16)); - - urlBar()->updateUrl(); } } @@ -606,7 +603,7 @@ void MainView::webViewTitleChanged(const QString &title) } if (currentIndex() == index) { - emit setCurrentTitle(tabTitle); + emit currentTitle(tabTitle); } Application::historyManager()->updateHistoryEntry(view->url(), tabTitle); } @@ -618,7 +615,7 @@ void MainView::webViewUrlChanged(const QUrl &url) int index = indexOf( view->parentWidget() ); if (-1 != index) { - m_tabBar->setTabData(index, url); + tabBar()->setTabData(index, url); } emit tabsChanged(); } @@ -647,7 +644,7 @@ QLabel *MainView::animatedLoading(int index, bool addMovie) if (index == -1) return 0; - QLabel *label = qobject_cast<QLabel*>(m_tabBar->tabButton(index, QTabBar::LeftSide)); + QLabel *label = qobject_cast<QLabel* >(tabBar()->tabButton(index, QTabBar::LeftSide)); if (!label) { label = new QLabel(this); @@ -659,8 +656,8 @@ QLabel *MainView::animatedLoading(int index, bool addMovie) label->setMovie(movie); movie->start(); } - m_tabBar->setTabButton(index, QTabBar::LeftSide, 0); - m_tabBar->setTabButton(index, QTabBar::LeftSide, label); + tabBar()->setTabButton(index, QTabBar::LeftSide, 0); + tabBar()->setTabButton(index, QTabBar::LeftSide, label); return label; } @@ -690,3 +687,11 @@ void MainView::detachTab(int index) Application::instance()->loadUrl(url, Rekonq::NewWindow); } + + +void MainView::movedTab(int from,int to) +{ + QWidget *bar = _bars->widget(from); + _bars->removeWidget(bar); + _bars->insertWidget(to, bar); +} diff --git a/src/mainview.h b/src/mainview.h index 908389b1..272cf82e 100644 --- a/src/mainview.h +++ b/src/mainview.h @@ -2,9 +2,10 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -43,6 +44,7 @@ // Qt Includes #include <QtGui/QToolButton> +#include <QStackedWidget> // Forward Declarations class QUrl; @@ -68,8 +70,7 @@ public: MainView(MainWindow *parent); ~MainView(); -public: - + QWidget *urlBarWidget() const; UrlBar *urlBar() const; WebTab *webTab(int index) const; @@ -86,7 +87,6 @@ public: void setTabBarHidden(bool hide); QToolButton *addTabButton() const; - void clear(); /** * This function creates a new empty tab @@ -106,7 +106,7 @@ signals: void lastTabClosed(); // current tab signals - void setCurrentTitle(const QString &url); + void currentTitle(const QString &url); void showStatusBarMessage(const QString &message, Rekonq::Notify status = Rekonq::Info); void linkHovered(const QString &link); void browserTabLoading(bool); @@ -147,7 +147,7 @@ private slots: void windowCloseRequested(); void postLaunch(); - + void movedTab(int,int); protected: virtual void resizeEvent(QResizeEvent *event); @@ -167,8 +167,10 @@ private: */ QLabel *animatedLoading(int index, bool addMovie); - UrlBar *m_urlBar; - TabBar *m_tabBar; + +// -------------------------------------------------------------------------- + + QStackedWidget *_bars; QString m_loadingGitPath; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index df600c05..cb90f818 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2,9 +2,10 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -70,13 +71,14 @@ #include <KToggleAction> #include <KStandardDirs> #include <KActionCategory> +#include <KProcess> // Qt Includes #include <QtCore/QTimer> #include <QtCore/QRect> #include <QtCore/QSize> #include <QtCore/QList> -#include <QtCore/QPointer> +#include <QtCore/QWeakPointer> #include <QtGui/QWidget> #include <QtGui/QVBoxLayout> @@ -102,8 +104,8 @@ MainWindow::MainWindow() , m_bookmarksPanel(0) , m_webInspectorPanel(0) , m_historyBackMenu(0) - , m_mainBar( new KToolBar( QString("MainToolBar"), this, Qt::TopToolBarArea, true, false, false) ) - , m_bmBar( new KToolBar( QString("BookmarkToolBar"), this, Qt::TopToolBarArea, true, false, false) ) + , m_mainBar( new KToolBar( QString("MainToolBar"), this, Qt::TopToolBarArea, true, true, true) ) + , m_bmBar( new KToolBar( QString("BookmarkToolBar"), this, Qt::TopToolBarArea, true, false, true) ) , m_popup( new KPassivePopup(this) ) , m_hidePopup( new QTimer(this) ) , m_ac( new KActionCollection(this) ) @@ -159,6 +161,7 @@ MainWindow::MainWindow() MainWindow::~MainWindow() { + Application::bookmarkProvider()->removeToolBar(m_bmBar); Application::instance()->removeMainWindow(this); delete m_popup; } @@ -167,8 +170,6 @@ MainWindow::~MainWindow() void MainWindow::setupToolbars() { // ============ Main ToolBar ================================ - m_mainBar->setToolButtonStyle(Qt::ToolButtonIconOnly); - m_mainBar->addAction( actionByName(KStandardAction::name(KStandardAction::Back)) ); m_mainBar->addAction( actionByName(KStandardAction::name(KStandardAction::Forward)) ); m_mainBar->addSeparator(); @@ -177,18 +178,31 @@ void MainWindow::setupToolbars() // location bar KAction *urlBarAction = new KAction(this); - urlBarAction->setDefaultWidget(m_view->urlBar()); + urlBarAction->setDefaultWidget(m_view->urlBarWidget()); m_mainBar->addAction( urlBarAction ); m_mainBar->addAction( actionByName("bookmarksActionMenu") ); m_mainBar->addAction( actionByName("rekonq_tools") ); - + + m_mainBar->show(); // this just to fix reopening rekonq after fullscreen close + // =========== Bookmarks ToolBar ================================ - m_bmBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_bmBar->setAcceptDrops(true); - m_bmBar->setContextMenuPolicy(Qt::CustomContextMenu); - m_bmBar->setIconDimensions(16); Application::bookmarkProvider()->setupBookmarkBar(m_bmBar); + + if(ReKonfig::firstExecution()) + { + m_mainBar->setToolButtonStyle(Qt::ToolButtonIconOnly); + + m_bmBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + m_bmBar->setIconDimensions(16); + m_bmBar->hide(); + + KToolBar::setToolBarsEditable(false); + KToolBar::setToolBarsLocked(true); + + ReKonfig::setFirstExecution(false); + } } @@ -202,7 +216,7 @@ void MainWindow::postLaunch() connect(m_view, SIGNAL(linkHovered(const QString&)), this, SLOT(notifyMessage(const QString&))); // --------- connect signals and slots - connect(m_view, SIGNAL(setCurrentTitle(const QString &)), this, SLOT(updateWindowTitle(const QString &))); + connect(m_view, SIGNAL(currentTitle(const QString &)), this, SLOT(updateWindowTitle(const QString &))); connect(m_view, SIGNAL(printRequested(QWebFrame *)), this, SLOT(printRequested(QWebFrame *))); // (shift +) ctrl + tab switching @@ -252,7 +266,7 @@ void MainWindow::setupActions() a = new KAction(KIcon("window-new"), i18n("&New Window"), this); a->setShortcut(KShortcut(Qt::CTRL | Qt::Key_N)); actionCollection()->addAction(QLatin1String("new_window"), a); - connect(a, SIGNAL(triggered(bool)), Application::instance(), SLOT(newMainWindow())); + connect(a, SIGNAL(triggered(bool)), Application::instance(), SLOT(newWindow())); // Standard Actions KStandardAction::open(this, SLOT(fileOpen()), actionCollection()); @@ -261,23 +275,27 @@ void MainWindow::setupActions() KStandardAction::quit(this , SLOT(close()), actionCollection()); a = KStandardAction::find(m_findBar, SLOT(show()), actionCollection()); - QList<QKeySequence> shortcutFindList; - shortcutFindList << KStandardShortcut::find() << QKeySequence( Qt::Key_Slash ); - a->setShortcuts( shortcutFindList ); + KShortcut findShortcut = KStandardShortcut::find(); + findShortcut.setAlternate( Qt::Key_Slash ); + a->setShortcut( findShortcut ); KStandardAction::findNext(this, SLOT(findNext()) , actionCollection()); KStandardAction::findPrev(this, SLOT(findPrevious()) , actionCollection()); a = KStandardAction::fullScreen(this, SLOT(viewFullScreen(bool)), this, actionCollection()); - QList<QKeySequence> shortcutFullScreenList; - shortcutFullScreenList << KStandardShortcut::fullScreen() << QKeySequence( Qt::Key_F11 ); - a->setShortcuts( shortcutFullScreenList ); + KShortcut fullScreenShortcut = KStandardShortcut::fullScreen(); + fullScreenShortcut.setAlternate( Qt::Key_F11 ); + a->setShortcut( fullScreenShortcut ); - KStandardAction::home(this, SLOT(homePage()), actionCollection()); + a = actionCollection()->addAction( KStandardAction::Home ); + connect(a, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), this, SLOT(homePage(Qt::MouseButtons, Qt::KeyboardModifiers))); KStandardAction::preferences(this, SLOT(preferences()), actionCollection()); a = KStandardAction::redisplay(m_view, SLOT(webReload()), actionCollection()); a->setText(i18n("Reload")); + KShortcut reloadShortcut = KStandardShortcut::reload(); + reloadShortcut.setAlternate( Qt::CTRL + Qt::Key_R ); + a->setShortcut( reloadShortcut ); a = new KAction(KIcon("process-stop"), i18n("&Stop"), this); a->setShortcut(KShortcut(Qt::CTRL | Qt::Key_Period)); @@ -298,20 +316,20 @@ void MainWindow::setupActions() // ============================= Zoom Actions =================================== - a = new KAction(KIcon("zoom-in"), i18n("&Enlarge Font"), this); + a = new KAction(KIcon("zoom-in"), i18n("&Zoom In"), this); a->setShortcut(KShortcut(Qt::CTRL | Qt::Key_Plus)); - actionCollection()->addAction(QLatin1String("bigger_font"), a); - connect(a, SIGNAL(triggered(bool)), this, SLOT(viewTextBigger())); - - a = new KAction(KIcon("zoom-original"), i18n("&Normal Font"), this); + actionCollection()->addAction(QLatin1String("zoom_in"), a); + connect(a, SIGNAL(triggered(bool)), this, SLOT(zoomIn())); + + a = new KAction(KIcon("zoom-original"), i18n("&Normal Zoom"), this); a->setShortcut(KShortcut(Qt::CTRL | Qt::Key_0)); - actionCollection()->addAction(QLatin1String("normal_font"), a); - connect(a, SIGNAL(triggered(bool)), this, SLOT(viewTextNormal())); + actionCollection()->addAction(QLatin1String("zoom_normal"), a); + connect(a, SIGNAL(triggered(bool)), this, SLOT(zoomNormal())); - a = new KAction(KIcon("zoom-out"), i18n("&Shrink Font"), this); + a = new KAction(KIcon("zoom-out"), i18n("&Zoom Out"), this); a->setShortcut(KShortcut(Qt::CTRL | Qt::Key_Minus)); - actionCollection()->addAction(QLatin1String("smaller_font"), a); - connect(a, SIGNAL(triggered(bool)), this, SLOT(viewTextSmaller())); + actionCollection()->addAction(QLatin1String("zoom_out"), a); + connect(a, SIGNAL(triggered(bool)), this, SLOT(zoomOut())); // =============================== Tools Actions ================================= a = new KAction(i18n("Page S&ource"), this); @@ -329,14 +347,16 @@ void MainWindow::setupActions() connect(a, SIGNAL(triggered(bool)), this, SLOT(clearPrivateData())); // ========================= History related actions ============================== - a = KStandardAction::back(this, SLOT(openPrevious()) , actionCollection()); + a = actionCollection()->addAction( KStandardAction::Back ); + connect(a, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), this, SLOT(openPrevious(Qt::MouseButtons, Qt::KeyboardModifiers))); m_historyBackMenu = new KMenu(this); a->setMenu(m_historyBackMenu); connect(m_historyBackMenu, SIGNAL(aboutToShow()), this, SLOT(aboutToShowBackMenu())); connect(m_historyBackMenu, SIGNAL(triggered(QAction *)), this, SLOT(openActionUrl(QAction *))); - KStandardAction::forward(this, SLOT(openNext()) , actionCollection()); + a = actionCollection()->addAction( KStandardAction::Forward ); + connect(a, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), this, SLOT(openNext(Qt::MouseButtons, Qt::KeyboardModifiers))); // ============================== General Tab Actions ==================================== a = new KAction(KIcon("tab-new"), i18n("New &Tab"), this); @@ -409,13 +429,41 @@ void MainWindow::setupTools() toolsMenu->addAction(actionByName(KStandardAction::name(KStandardAction::SaveAs))); toolsMenu->addAction(actionByName(KStandardAction::name(KStandardAction::Print))); toolsMenu->addAction(actionByName(KStandardAction::name(KStandardAction::Find))); - - KActionMenu *fontMenu = new KActionMenu(KIcon("page-zoom"), i18n("Zoom"), this); - fontMenu->addAction(actionByName(QLatin1String("smaller_font"))); - fontMenu->addAction(actionByName(QLatin1String("normal_font"))); - fontMenu->addAction(actionByName(QLatin1String("bigger_font"))); - toolsMenu->addAction(fontMenu); - + + // setup zoom widget + QWidget *zoomWidget = new QWidget(this); + + QToolButton *zoomOut = new QToolButton(zoomWidget); + zoomOut->setDefaultAction(actionByName(QLatin1String("zoom_out"))); + zoomOut->setAutoRaise(true); + + m_zoomSlider = new QSlider(Qt::Horizontal, zoomWidget); + m_zoomSlider->setTracking(true); + m_zoomSlider->setRange(1, 19); // divide by 10 to obtain a qreal for zoomFactor() + m_zoomSlider->setValue(10); + m_zoomSlider->setPageStep(3); + connect(m_zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setZoomFactor(int))); + + QToolButton *zoomIn = new QToolButton(zoomWidget); + zoomIn->setDefaultAction(actionByName(QLatin1String("zoom_in"))); + zoomIn->setAutoRaise(true); + + QToolButton *zoomNormal = new QToolButton(zoomWidget); + zoomNormal->setDefaultAction(actionByName(QLatin1String("zoom_normal"))); + zoomNormal->setAutoRaise(true); + + QHBoxLayout* zoomWidgetLayout = new QHBoxLayout(zoomWidget); + zoomWidgetLayout->setSpacing(0); + zoomWidgetLayout->setMargin(0); + zoomWidgetLayout->addWidget(zoomOut); + zoomWidgetLayout->addWidget(m_zoomSlider); + zoomWidgetLayout->addWidget(zoomIn); + zoomWidgetLayout->addWidget(zoomNormal); + + QWidgetAction *zoomAction = new QWidgetAction(this); + zoomAction->setDefaultWidget(zoomWidget); + toolsMenu->addAction(zoomAction); + toolsMenu->addSeparator(); toolsMenu->addAction(actionByName(QLatin1String("private_browsing"))); @@ -432,7 +480,7 @@ void MainWindow::setupTools() toolsMenu->addAction(actionByName(QLatin1String("bm_bar"))); toolsMenu->addAction(actionByName(QLatin1String("show_history_panel"))); - toolsMenu->addAction(actionByName(QLatin1String("show_bookmarks_panel"))); + toolsMenu->addAction(actionByName(QLatin1String("show_bookmarks_panel"))); toolsMenu->addAction(actionByName(KStandardAction::name(KStandardAction::FullScreen))); toolsMenu->addSeparator(); @@ -453,28 +501,30 @@ void MainWindow::setupPanels() // STEP 1 // Setup history panel m_historyPanel = new HistoryPanel(i18n("History Panel"), this); - connect(m_historyPanel, SIGNAL(openUrl(const KUrl&)), Application::instance(), SLOT(loadUrl(const KUrl&))); + connect(m_historyPanel, SIGNAL(openUrl(const KUrl&, const Rekonq::OpenType &)), Application::instance(), SLOT(loadUrl(const KUrl&, const Rekonq::OpenType &))); + connect(m_historyPanel, SIGNAL(itemHovered(QString)), this, SLOT(notifyMessage(QString))); connect(m_historyPanel, SIGNAL(destroyed()), Application::instance(), SLOT(saveConfiguration())); addDockWidget(Qt::LeftDockWidgetArea, m_historyPanel); // setup history panel action a = (KAction *) m_historyPanel->toggleViewAction(); - a->setShortcut( QKeySequence(Qt::CTRL + Qt::Key_H) ); + a->setShortcut( KShortcut(Qt::CTRL + Qt::Key_H) ); a->setIcon(KIcon("view-history")); actionCollection()->addAction(QLatin1String("show_history_panel"), a); // STEP 2 // Setup bookmarks panel m_bookmarksPanel = new BookmarksPanel(i18n("Bookmarks Panel"), this); - connect(m_bookmarksPanel, SIGNAL(openUrl(const KUrl&)), Application::instance(), SLOT(loadUrl(const KUrl&))); + connect(m_bookmarksPanel, SIGNAL(openUrl(const KUrl&, const Rekonq::OpenType &)), Application::instance(), SLOT(loadUrl(const KUrl&, const Rekonq::OpenType &))); + connect(m_bookmarksPanel, SIGNAL(itemHovered(QString)), this, SLOT(notifyMessage(QString))); connect(m_bookmarksPanel, SIGNAL(destroyed()), Application::instance(), SLOT(saveConfiguration())); addDockWidget(Qt::LeftDockWidgetArea, m_bookmarksPanel); // setup bookmarks panel action a = (KAction *) m_bookmarksPanel->toggleViewAction(); - a->setShortcut( QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_B) ); + a->setShortcut( KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_B) ); a->setIcon(KIcon("bookmarks-organize")); actionCollection()->addAction(QLatin1String("show_bookmarks_panel"), a); @@ -549,7 +599,10 @@ void MainWindow::updateConfiguration() // Applies user defined CSS to all open webpages. If there no longer is a // user defined CSS removes it from all open webpages. - defaultSettings->setUserStyleSheetUrl(ReKonfig::userCSS()); + if(ReKonfig::userCSS().isEmpty()) + defaultSettings->setUserStyleSheetUrl( KUrl(KStandardDirs::locate("appdata" , "default.css")) ); + else + defaultSettings->setUserStyleSheetUrl(ReKonfig::userCSS()); // ====== load Settings on main classes Application::historyManager()->loadSettings(); @@ -559,13 +612,6 @@ void MainWindow::updateConfiguration() } -void MainWindow::updateBrowser() -{ - updateConfiguration(); - mainView()->reloadAllTabs(); -} - - void MainWindow::openLocation() { m_view->urlBar()->selectAll(); @@ -602,7 +648,7 @@ void MainWindow::preferences() QPointer<SettingsDialog> s = new SettingsDialog(this); // keep us informed when the user changes settings - connect(s, SIGNAL(settingsChanged(const QString&)), this, SLOT(updateBrowser())); + connect(s, SIGNAL(settingsChanged(const QString&)), this, SLOT(updateConfiguration())); s->exec(); delete s; @@ -626,7 +672,7 @@ void MainWindow::updateWindowTitle(const QString &title) { if(settings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) { - setWindowTitle("rekonq (" + i18n("Private Browsing") + ")"); + setWindowTitle(i18nc("Window title when private browsing is activated", "rekonq (Private Browsing)")); } else { @@ -637,11 +683,11 @@ void MainWindow::updateWindowTitle(const QString &title) { if(settings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) { - setWindowTitle(title + " - rekonq (" + i18n("Private Browsing") + ")"); + setWindowTitle(i18nc("window title, %1 = title of the active website", "%1 – rekonq (Private Browsing)", title) ); } else { - setWindowTitle(title + " - rekonq"); + setWindowTitle(i18nc("window title, %1 = title of the active website", "%1 – rekonq", title)); } } } @@ -704,7 +750,7 @@ void MainWindow::privateBrowsing(bool enable) if (button == KMessageBox::Continue) { settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, true); - m_view->urlBar()->setBackgroundColor(Qt::lightGray); // palette().color(QPalette::Active, QPalette::Background)); + m_view->urlBar()->setPrivateMode(true); } else { @@ -714,10 +760,9 @@ void MainWindow::privateBrowsing(bool enable) else { settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false); - m_view->urlBar()->setBackgroundColor(palette().color(QPalette::Active, QPalette::Base)); - + m_view->urlBar()->setPrivateMode(false); + m_lastSearch.clear(); - m_view->clear(); m_view->reloadAllTabs(); } } @@ -728,57 +773,111 @@ void MainWindow::find(const QString & search) if (!currentTab()) return; m_lastSearch = search; + + findNext(); +} + + +void MainWindow::matchCaseUpdate() +{ + if (!currentTab()) + return; + + currentTab()->view()->findText(m_lastSearch, QWebPage::FindBackward); findNext(); } void MainWindow::findNext() { - if (!currentTab() && m_lastSearch.isEmpty()) + if (!currentTab()) return; + highlightAll(); + + if(m_findBar->isHidden()) + { + QPoint previous_position = currentTab()->view()->page()->currentFrame()->scrollPosition(); + currentTab()->view()->page()->focusNextPrevChild(true); + currentTab()->view()->page()->currentFrame()->setScrollPosition(previous_position); + return; + } + + highlightAll(); + QWebPage::FindFlags options = QWebPage::FindWrapsAroundDocument; if (m_findBar->matchCase()) options |= QWebPage::FindCaseSensitively; - m_findBar->notifyMatch(currentTab()->view()->findText(m_lastSearch, options)); + bool found = currentTab()->view()->findText(m_lastSearch, options); + m_findBar->notifyMatch(found); + + if(!found) + { + QPoint previous_position = currentTab()->view()->page()->currentFrame()->scrollPosition(); + currentTab()->view()->page()->focusNextPrevChild(true); + currentTab()->view()->page()->currentFrame()->setScrollPosition(previous_position); + } } void MainWindow::findPrevious() { - if (!currentTab() && m_lastSearch.isEmpty()) + if (!currentTab()) return; - + QWebPage::FindFlags options = QWebPage::FindBackward | QWebPage::FindWrapsAroundDocument; if (m_findBar->matchCase()) options |= QWebPage::FindCaseSensitively; - m_findBar->notifyMatch(currentTab()->view()->findText(m_lastSearch, options)); + bool found = currentTab()->view()->findText(m_lastSearch, options); + m_findBar->notifyMatch(found); } - -void MainWindow::viewTextBigger() +void MainWindow::highlightAll() { if (!currentTab()) return; - currentTab()->view()->setTextSizeMultiplier(currentTab()->view()->textSizeMultiplier() + 0.1); + + QWebPage::FindFlags options = QWebPage::HighlightAllOccurrences; + + currentTab()->view()->findText("", options); //Clear an existing highlight + + if(m_findBar->highlightAllState() && !m_findBar->isHidden()) + { + if (m_findBar->matchCase()) + options |= QWebPage::FindCaseSensitively; + + currentTab()->view()->findText(m_lastSearch, options); + } } -void MainWindow::viewTextNormal() +void MainWindow::zoomIn() { - if (!currentTab()) - return; - currentTab()->view()->setTextSizeMultiplier(1.0); + m_zoomSlider->setValue(m_zoomSlider->value() + 1); } +void MainWindow::zoomNormal() +{ + m_zoomSlider->setValue(10); +} -void MainWindow::viewTextSmaller() +void MainWindow::zoomOut() { - if (!currentTab()) + m_zoomSlider->setValue(m_zoomSlider->value() - 1); +} + +void MainWindow::setZoomFactor(int factor) +{ + if(!currentTab()) return; - currentTab()->view()->setTextSizeMultiplier(currentTab()->view()->textSizeMultiplier() - 0.1); + currentTab()->view()->setZoomFactor(QVariant(factor).toReal() / 10); +} + +void MainWindow::setZoomSliderFactor(qreal factor) +{ + m_zoomSlider->setValue(factor*10); } @@ -859,9 +958,12 @@ void MainWindow::viewPageSource() } -void MainWindow::homePage() +void MainWindow::homePage(Qt::MouseButtons mouseButtons, Qt::KeyboardModifiers keyboardModifiers) { - currentTab()->view()->load( QUrl(ReKonfig::homePage()) ); + if(mouseButtons == Qt::MidButton || keyboardModifiers == Qt::ControlModifier) + Application::instance()->loadUrl( KUrl(ReKonfig::homePage()), Rekonq::SettingOpenTab ); + else + currentTab()->view()->load( QUrl(ReKonfig::homePage()) ); } @@ -902,19 +1004,41 @@ void MainWindow::browserLoading(bool v) } -void MainWindow::openPrevious() +void MainWindow::openPrevious(Qt::MouseButtons mouseButtons, Qt::KeyboardModifiers keyboardModifiers) { QWebHistory *history = currentTab()->view()->history(); if (history->canGoBack()) - history->goToItem(history->backItem()); + { + if(mouseButtons == Qt::MidButton || keyboardModifiers == Qt::ControlModifier) + { + Application::instance()->loadUrl(history->backItem().url(), Rekonq::SettingOpenTab); + } + else + { + history->goToItem(history->backItem()); + } + + updateActions(); + } + } -void MainWindow::openNext() +void MainWindow::openNext(Qt::MouseButtons mouseButtons, Qt::KeyboardModifiers keyboardModifiers) { QWebHistory *history = currentTab()->view()->history(); if (history->canGoForward()) - history->goToItem(history->forwardItem()); + { + if(mouseButtons == Qt::MidButton || keyboardModifiers == Qt::ControlModifier) + { + Application::instance()->loadUrl(history->forwardItem().url(), Rekonq::SettingOpenTab); + } + else + { + history->goToItem(history->forwardItem()); + } + updateActions(); + } } @@ -924,6 +1048,7 @@ void MainWindow::keyPressEvent(QKeyEvent *event) if (event->key() == Qt::Key_Escape) { m_findBar->hide(); + currentTab()->setFocus(); // give focus to web pages return; } @@ -960,7 +1085,7 @@ QAction *MainWindow::actionByName(const QString name) return ret; /* else */ - kWarning() << "Action named: " << name << " not found, returning empty action."; + kDebug() << "Action named: " << name << " not found, returning empty action."; return new QAction(this); // return empty object instead of NULL pointer } @@ -1009,27 +1134,33 @@ void MainWindow::notifyMessage(const QString &msg, Rekonq::Notify status) m_popup->layout()->setMargin(margin); // useful values - + WebTab *tab = m_view->currentWebTab(); + + // fix crash on window close + if(!tab) + return; + // fix crash on window close - if(!m_view->currentWebTab()->page()->currentFrame()) + if(!tab->page()) return; - bool scrollbarIsVisible = m_view->currentWebTab()->page()->currentFrame()->scrollBarMaximum(Qt::Horizontal); + bool scrollbarIsVisible = tab->page()->currentFrame()->scrollBarMaximum(Qt::Horizontal); int scrollbarSize = 0; if (scrollbarIsVisible) { //TODO: detect QStyle size scrollbarSize = 17; } - QPoint webViewOrigin = m_view->currentWebTab()->mapToGlobal(QPoint(0,0)); - int bottomLeftY=webViewOrigin.y() + m_view->currentWebTab()->page()->viewportSize().height() - labelSize.height() - scrollbarSize; + + QPoint webViewOrigin = tab->view()->mapToGlobal(QPoint(0,0)); + int bottomLeftY = webViewOrigin.y() + tab->page()->viewportSize().height() - labelSize.height() - scrollbarSize; // setting popup in bottom-left position int x = geometry().x(); int y = bottomLeftY; - QPoint mousePos = m_view->currentWebTab()->mapToGlobal(m_view->currentWebTab()->view()->mousePos()); - if(QRect(webViewOrigin.x(),bottomLeftY,labelSize.width(),labelSize.height()).contains(mousePos)) + QPoint mousePos = tab->mapToGlobal( tab->view()->mousePos() ); + if( QRect( webViewOrigin.x() , bottomLeftY , labelSize.width() , labelSize.height() ).contains(mousePos) ) { // setting popup above the mouse y = bottomLeftY - labelSize.height(); @@ -1041,22 +1172,32 @@ void MainWindow::notifyMessage(const QString &msg, Rekonq::Notify status) void MainWindow::clearPrivateData() { - QPointer<KDialog> dialog = new KDialog(this, Qt::Sheet); + QPointer<KDialog> dialog = new KDialog(this); + dialog->setCaption(i18n("Clear Private Data")); dialog->setButtons(KDialog::Ok | KDialog::Cancel); + + dialog->button(KDialog::Ok)->setIcon(KIcon("edit-clear")); + dialog->button(KDialog::Ok)->setText(i18n("Clear")); Ui::ClearDataWidget clearWidget; QWidget widget; clearWidget.setupUi(&widget); dialog->setMainWidget(&widget); + dialog->exec(); - if (dialog->exec() == KDialog::Accepted) + if (dialog->result() == QDialog::Accepted) { if(clearWidget.clearHistory->isChecked()) { Application::historyManager()->clear(); } - + + if(clearWidget.clearDownloads->isChecked()) + { + Application::historyManager()->clearDownloadsHistory(); + } + if(clearWidget.clearCookies->isChecked()) { QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer"); @@ -1065,7 +1206,8 @@ void MainWindow::clearPrivateData() if(clearWidget.clearCachedPages->isChecked()) { - // TODO implement me! + KProcess::startDetached(KStandardDirs::findExe("kio_http_cache_cleaner"), + QStringList(QLatin1String("--clear-all"))); } if(clearWidget.clearWebIcons->isChecked()) @@ -1086,6 +1228,8 @@ void MainWindow::clearPrivateData() } } } + + dialog->deleteLater(); } @@ -1109,7 +1253,7 @@ void MainWindow::aboutToShowBackMenu() QWebHistoryItem item = historyList.at(i); KAction *action = new KAction(this); action->setData(i + offset); - QIcon icon = Application::icon( item.url() ); + KIcon icon = Application::icon( item.url() ); action->setIcon( icon ); action->setText( item.title() ); m_historyBackMenu->addAction(action); diff --git a/src/mainwindow.h b/src/mainwindow.h index 7083591d..d1509066 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -1,10 +1,12 @@ + /* ============================================================ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -31,7 +33,9 @@ // Local Includes +#include "rekonqprivate_export.h" #include "application.h" +#include "previewselectorbar.h" // KDE Includes #include <KMainWindow> @@ -41,6 +45,7 @@ // Forward Declarations class QWebFrame; +class QSlider; class KAction; class KPassivePopup; @@ -58,7 +63,7 @@ class MainView; * It handles the menus, toolbars, and status bars. * */ -class MainWindow : public KMainWindow +class REKONQ_TESTS_EXPORT MainWindow : public KMainWindow { Q_OBJECT @@ -72,7 +77,9 @@ public: virtual QSize sizeHint() const; virtual KActionCollection *actionCollection () const; void setWidgetsVisible(bool makeFullScreen); - + + void setZoomSliderFactor(qreal factor); + private: void setupActions(); void setupTools(); @@ -80,8 +87,7 @@ private: void setupPanels(); public slots: - void updateBrowser(); - void homePage(); + void homePage(Qt::MouseButtons = Qt::LeftButton, Qt::KeyboardModifiers = Qt::NoModifier); /** * Notifies a message in a popup @@ -116,18 +122,21 @@ private slots: void updateWindowTitle(const QString &title = QString()); // history related - void openPrevious(); - void openNext(); + void openPrevious(Qt::MouseButtons = Qt::LeftButton, Qt::KeyboardModifiers = Qt::NoModifier); + void openNext(Qt::MouseButtons = Qt::LeftButton, Qt::KeyboardModifiers = Qt::NoModifier); // Find Action slots void find(const QString &); + void matchCaseUpdate(); void findNext(); void findPrevious(); + void highlightAll(); // Zoom slots - void viewTextBigger(); - void viewTextNormal(); - void viewTextSmaller(); + void zoomIn(); + void zoomNormal(); + void zoomOut(); + void setZoomFactor(int factor); // File Menu slots void openLocation(); @@ -152,7 +161,7 @@ private slots: private: MainView *m_view; FindBar *m_findBar; - + HistoryPanel *m_historyPanel; BookmarksPanel *m_bookmarksPanel; WebInspectorPanel *m_webInspectorPanel; @@ -163,6 +172,8 @@ private: KToolBar *m_mainBar; KToolBar *m_bmBar; + QSlider *m_zoomSlider; + QString m_lastSearch; KPassivePopup *m_popup; diff --git a/src/networkaccessmanager.cpp b/src/networkaccessmanager.cpp index eadbfab3..99337206 100644 --- a/src/networkaccessmanager.cpp +++ b/src/networkaccessmanager.cpp @@ -3,7 +3,8 @@ * This file is a part of the rekonq project * * Copyright (C) 2007-2008 Trolltech ASA. All rights reserved -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com>* +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -31,22 +32,56 @@ // Local Includes #include "application.h" #include "adblockmanager.h" +#include "webpage.h" + +// KDE Includes #include <KDebug> + NetworkAccessManager::NetworkAccessManager(QObject *parent) : AccessManager(parent) + , _parentPage( qobject_cast<WebPage *>(parent) ) { } QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData) { - // Adblock - if (op == QNetworkAccessManager::GetOperation) + QNetworkReply *reply = 0; + + switch(op) { - QNetworkReply *reply = Application::adblockManager()->block(req); + case QNetworkAccessManager::HeadOperation: + kDebug() << "HEAD OPERATION"; +// if(outgoingData) +// { +// QByteArray outgoingDataByteArray = outgoingData->peek(1024 * 1024); +// kDebug() << outgoingDataByteArray; +// } + break; + + case QNetworkAccessManager::GetOperation: + kDebug() << "GET OPERATION"; + reply = Application::adblockManager()->block(req, _parentPage); if (reply) return reply; + break; + + case QNetworkAccessManager::PutOperation: + kDebug() << "PUT OPERATION"; + break; + + case QNetworkAccessManager::PostOperation: + kDebug() << "POST OPERATION"; + break; + + case QNetworkAccessManager::DeleteOperation: + kDebug() << "DELETE OPERATION"; + break; + + default: + kDebug() << "UNKNOWN OPERATION"; + break; } return AccessManager::createRequest(op,req,outgoingData); diff --git a/src/networkaccessmanager.h b/src/networkaccessmanager.h index 5c34ebd7..352f67d6 100644 --- a/src/networkaccessmanager.h +++ b/src/networkaccessmanager.h @@ -3,7 +3,8 @@ * This file is a part of the rekonq project * * Copyright (C) 2007-2008 Trolltech ASA. All rights reserved -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com>* +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -28,6 +29,10 @@ #define NETWORKACCESSMANAGER_H +// Local Includes +#include "rekonqprivate_export.h" +#include "webpage.h" + // KDE Includes #include <kio/accessmanager.h> @@ -35,15 +40,18 @@ using namespace KIO::Integration; -class NetworkAccessManager : public AccessManager +class REKONQ_TESTS_EXPORT NetworkAccessManager : public AccessManager { Q_OBJECT public: - NetworkAccessManager(QObject *parent = 0); + NetworkAccessManager(QObject *parent); protected: virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData = 0); + +private: + WebPage *_parentPage; }; #endif // NETWORKACCESSMANAGER_H diff --git a/src/newtabpage.cpp b/src/newtabpage.cpp new file mode 100644 index 00000000..b709375a --- /dev/null +++ b/src/newtabpage.cpp @@ -0,0 +1,596 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "newtabpage.h" +#include "newtabpage.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "historymodels.h" +#include "bookmarksmanager.h" +#include "application.h" +#include "mainwindow.h" +#include "mainview.h" +#include "websnap.h" +#include "previewselectorbar.h" +#include "webtab.h" + +// KDE Includes +#include <KStandardDirs> +#include <KIconLoader> +#include <KDebug> +#include <KConfig> +#include <KConfigGroup> +#include <KDialog> +#include <KCalendarSystem> + +// Qt Includes +#include <QFile> + +// Defines +#define QL1S(x) QLatin1String(x) + + +NewTabPage::NewTabPage(QWebFrame *frame) + : m_root(frame->documentElement()) +{ + QString htmlFilePath = KStandardDirs::locate("data", "rekonq/htmls/home.html"); + QString imagesPath = QString("file://") + KGlobal::dirs()->findResourceDir("data", "rekonq/pics/bg.png") + QString("rekonq/pics"); + + QFile file(htmlFilePath); + bool isOpened = file.open(QIODevice::ReadOnly); + if (!isOpened) + { + kDebug() << "Couldn't open the home.html file"; + } + else + { + m_html = file.readAll(); + m_html.replace(QString("%2"), imagesPath); + } +} + + +NewTabPage::~NewTabPage() +{ +} + + +void NewTabPage::generate(const KUrl &url) +{ + if(KUrl("about:preview").isParentOf(url)) + { + if(url.fileName() == QString("add")) + { + QStringList names = ReKonfig::previewNames(); + QStringList urls = ReKonfig::previewUrls(); + + names.append(""); + urls.append(""); + + ReKonfig::setPreviewNames(names); + ReKonfig::setPreviewUrls(urls); + + // Why doesn't it work well ? + // m_root.appendInside(emptyPreview(names.length() - 1)); + // Replacing with this : + generate(KUrl("about:favorites")); + return; + } + if(url.directory() == QString("preview/remove")) + { + removePreview(url.fileName().toInt()); + return; + } + if(url.directory() == QString("preview/modify")) + { + int index = url.fileName().toInt(); + Application::instance()->mainWindow()->currentTab()->createPreviewSelectorBar(index); + return; + } + } + if(url.fileName() == QString("clear")) + { + Application::instance()->mainWindow()->actionByName("clear_private_data")->trigger(); + generate(QString("about:" + url.directory())); + return; + } + if(url == KUrl("about:bookmarks/edit")) + { + Application::bookmarkProvider()->bookmarkManager()->slotEditBookmarks(); + return; + } + + QWebPage *page = m_root.webFrame()->page(); + page->mainFrame()->setHtml(m_html); + + m_root = page->mainFrame()->documentElement().findFirst("#content"); + + browsingMenu(url); + + QString title; + if(url == KUrl("about:favorites")) + { + favoritesPage(); + title = i18n("Favorites"); + } + else if(url == KUrl("about:closedTabs")) + { + closedTabsPage(); + title = i18n("Closed Tabs"); + } + else if(url == KUrl("about:history")) + { + historyPage(); + title = i18n("History"); + } + else if(url == KUrl("about:bookmarks")) + { + bookmarksPage(); + title = i18n("Bookmarks"); + } + else if(url == KUrl("about:downloads")) + { + downloadsPage(); + title = i18n("Downloads"); + } + + m_root.document().findFirst("title").setPlainText(title); +} + + +void NewTabPage::favoritesPage() +{ + m_root.addClass("favorites"); + + QWebElement add = markup(".link"); + add.findFirst("a").setAttribute("href", "about:preview/add"); + add.findFirst("img").setAttribute("src" , QString("file:///" + + KIconLoader::global()->iconPath("list-add", KIconLoader::Small || KIconLoader::SizeSmall))); + add.findFirst("span").appendInside(i18n("Add Preview")); + m_root.document().findFirst("#actions").appendInside(add); + + QStringList names = ReKonfig::previewNames(); + QStringList urls = ReKonfig::previewUrls(); + + if(urls.isEmpty()) + { + m_root.addClass("empty"); + m_root.setPlainText(i18n("You can add a preview by clicking the \"Add Preview\" button in the top-right corner of this page")); + return; + } + + for(int i=0; i < urls.count() ; ++i) + { + KUrl url = urls.at(i); + QWebElement prev; + + if(url.isEmpty()) + prev = emptyPreview(i); + else if(!QFile::exists(WebSnap::fileForUrl(url).toLocalFile())) + prev = loadingPreview(i, url); + else + prev = validPreview(i, url, names.at(i)); + + setupPreview(prev, i); + + m_root.appendInside(prev); + } +} + + +QWebElement NewTabPage::emptyPreview(int index) +{ + QWebElement prev = markup(".thumbnail"); + + prev.findFirst(".preview img").setAttribute("src" , QString("file:///") + + KIconLoader::global()->iconPath("insert-image", KIconLoader::Desktop)); + prev.findFirst("span a").setPlainText(i18n("Set a Preview...")); + prev.findFirst("a").setAttribute("href", QString("about:preview/modify/" + QVariant(index).toString())); + + setupPreview(prev, index); + //hideControls(prev); + + return prev; +} + + +QWebElement NewTabPage::loadingPreview(int index, const KUrl &url) +{ + QWebElement prev = markup(".thumbnail"); + + prev.findFirst(".preview img").setAttribute("src" , + QString("file:///") + KStandardDirs::locate("appdata", "pics/busywidget.gif")); + prev.findFirst("span a").setPlainText(i18n("Loading Preview...")); + prev.findFirst("a").setAttribute("href", url.toMimeDataString()); + + setupPreview(prev, index); + showControls(prev); + + new WebSnap(url, m_root.webFrame(), index); + + return prev; +} + + +QWebElement NewTabPage::validPreview(int index, const KUrl &url, const QString &title) +{ + QWebElement prev = markup(".thumbnail"); + KUrl previewPath = WebSnap::fileForUrl(url); + QString iString = QVariant(index).toString(); + + prev.findFirst(".preview img").setAttribute("src" , previewPath.toMimeDataString()); + prev.findFirst("a").setAttribute("href", url.toMimeDataString()); + prev.findFirst("span a").setAttribute("href", url.toMimeDataString()); + prev.findFirst("span a").setPlainText(checkTitle(title)); + + setupPreview(prev, index); + showControls(prev); + + return prev; +} + + +void NewTabPage::hideControls(QWebElement e) +{ + e.findFirst(".remove").setStyleProperty("visibility", "hidden"); + e.findFirst(".modify").setStyleProperty("visibility", "hidden"); +} + + +void NewTabPage::showControls(QWebElement e) +{ + e.findFirst(".remove").setStyleProperty("visibility", "visible"); + e.findFirst(".modify").setStyleProperty("visibility", "visible"); +} + + +void NewTabPage::setupPreview(QWebElement e, int index) +{ + e.findFirst(".remove img").setAttribute("src", QString("file:///") + + KIconLoader::global()->iconPath("edit-delete", KIconLoader::DefaultState)); + e.findFirst(".remove").setAttribute("title", "Remove favorite"); + e.findFirst(".modify img").setAttribute("src", QString("file:///") + + KIconLoader::global()->iconPath("insert-image", KIconLoader::DefaultState)); + e.findFirst(".modify").setAttribute("title", "Set new favorite"); + + e.findFirst(".modify").setAttribute("href", QString("about:preview/modify/" + QVariant(index).toString())); + e.findFirst(".remove").setAttribute("href", QString("about:preview/remove/" + QVariant(index).toString())); + + e.setAttribute("id", "preview" + QVariant(index).toString()); +} + + +void NewTabPage::snapFinished(int index, const KUrl &url, const QString &title) +{ + // Update title if necessary + QStringList urls = ReKonfig::previewUrls(); + if(KUrl(urls.at(index)) == url) + { + QStringList names = ReKonfig::previewNames(); + names.replace(index, title); + ReKonfig::setPreviewNames(names); + + ReKonfig::self()->writeConfig(); + } + + // Update page, but only if open + if(m_root.document().findAll("#rekonq-newtabpage").count() == 0) + return; + if(m_root.findAll(".favorites").count() == 0 && m_root.findAll(".closedTabs").count() == 0) + return; + + QWebElement prev = m_root.findFirst("#preview" + QVariant(index).toString()); + if(KUrl(prev.findFirst("a").attribute("href")) == url) + { + QWebElement newPrev = validPreview(index, url, title); + + if(m_root.findAll(".closedTabs").count() != 0) + hideControls(newPrev); + + prev.replace(newPrev); + } +} + + +void NewTabPage::removePreview(int index) +{ + QStringList names = ReKonfig::previewNames(); + QStringList urls = ReKonfig::previewUrls(); + + urls.removeAt(index); + names.removeAt(index); + + ReKonfig::setPreviewNames(names); + ReKonfig::setPreviewUrls(urls); + + generate(KUrl("about:favorites")); + + ReKonfig::self()->writeConfig(); +} + + +void NewTabPage::browsingMenu(const KUrl ¤tUrl) +{ + QList<QWebElement> navItems; + + KIconLoader *loader = KIconLoader::global(); + + QWebElement nav = markup(".link"); // Favorites + nav.findFirst("a").setAttribute("href", "about:favorites"); + nav.findFirst("img").setAttribute("src" , QString("file:///" + + loader->iconPath("emblem-favorite", KIconLoader::Desktop ||KIconLoader::SizeSmall))); + nav.findFirst("span").appendInside(i18n("Favorites")); + navItems.append(nav); + + nav = markup(".link"); // Closed Tabs + nav.findFirst("a").setAttribute("href", "about:closedTabs"); + nav.findFirst("img").setAttribute("src" , QString("file:///" + + loader->iconPath("tab-close", KIconLoader::Desktop ||KIconLoader::SizeSmall))); + nav.findFirst("span").appendInside(i18n("Closed Tabs")); + navItems.append(nav); + + nav = markup(".link"); // Bookmarks + nav.findFirst("a").setAttribute("href", "about:bookmarks"); + nav.findFirst("img").setAttribute("src" , QString("file:///" + + loader->iconPath("bookmarks", KIconLoader::Desktop ||KIconLoader::SizeSmall))); + nav.findFirst("span").appendInside(i18n("Bookmarks")); + navItems.append(nav); + + nav = markup(".link"); // History + nav.findFirst("a").setAttribute("href", "about:history"); + nav.findFirst("img").setAttribute("src" , QString("file:///" + + loader->iconPath("view-history", KIconLoader::Desktop ||KIconLoader::SizeSmall))); + nav.findFirst("span").appendInside(i18n("History")); + navItems.append(nav); + + nav = markup(".link"); // Downloads + nav.findFirst("a").setAttribute("href", "about:downloads"); + nav.findFirst("img").setAttribute("src" , QString("file:///" + + loader->iconPath("download", KIconLoader::Desktop ||KIconLoader::SizeSmall))); + nav.findFirst("span").appendInside(i18n("Downloads")); + navItems.append(nav); + + QWebElement it; + foreach(it, navItems) + { + if(it.findFirst("a").attribute("href") == currentUrl.toMimeDataString()) + it.addClass("current"); + else if(currentUrl == "about:home" && it.findFirst("a").attribute("href") == "about:favorites") + it.addClass("current"); + m_root.document().findFirst("#navigation").appendInside(it); + } +} + + +void NewTabPage::historyPage() +{ + m_root.addClass("history"); + + QWebElement clearData = markup(".link"); + clearData.findFirst("a").setAttribute("href", "about:history/clear"); + QString iconPath = QString("file:///" + KIconLoader::global()->iconPath("edit-clear", KIconLoader::SizeSmall || KIconLoader::Small)); + clearData.findFirst("img").setAttribute("src" , iconPath ); + clearData.findFirst("span").appendInside(i18n("Clear Private Data")); + m_root.document().findFirst("#actions").appendInside(clearData); + + HistoryTreeModel *model = Application::historyManager()->historyTreeModel(); + + if(model->rowCount() == 0) + { + m_root.addClass("empty"); + m_root.setPlainText(i18n("Your browsing history is empty")); + return; + } + + int i = 0; + do + { + QModelIndex index = model->index(i, 0, QModelIndex() ); + if(model->hasChildren(index)) + { + m_root.appendInside(markup("h3")); + m_root.lastChild().setPlainText(index.data().toString()); + + for(int j=0; j< model->rowCount(index); ++j) + { + QModelIndex son = model->index(j, 0, index ); + m_root.appendInside(son.data(HistoryModel::DateTimeRole).toDateTime().toString("hh:mm")); + m_root.appendInside(" "); + m_root.appendInside(markup("a")); + m_root.lastChild().setAttribute("href" , son.data(HistoryModel::UrlStringRole).toString()); + m_root.lastChild().appendInside(son.data().toString()); + m_root.appendInside("<br/>"); + } + } + i++; + } + while( model->hasIndex( i , 0 , QModelIndex() ) ); +} + + +void NewTabPage::bookmarksPage() +{ + m_root.addClass("bookmarks"); + + QWebElement editBookmarks = markup(".link"); + editBookmarks.findFirst("a").setAttribute("href", "about:bookmarks/edit"); + QString iconPath = QString("file:///" + KIconLoader::global()->iconPath("bookmarks-organize", KIconLoader::SizeSmall || KIconLoader::Small)); + editBookmarks.findFirst("img").setAttribute("src" , iconPath); + editBookmarks.findFirst("span").appendInside(i18n("Edit Bookmarks")); + m_root.document().findFirst("#actions").appendInside(editBookmarks); + + KBookmarkGroup bookGroup = Application::bookmarkProvider()->rootGroup(); + if (bookGroup.isNull()) + { + m_root.addClass("empty"); + m_root.setPlainText(i18n("You have no bookmarks")); + return; + } + + KBookmark bookmark = bookGroup.first(); + while (!bookmark.isNull()) + { + createBookItem(bookmark, m_root); + bookmark = bookGroup.next(bookmark); + } +} + + +void NewTabPage::createBookItem(const KBookmark &bookmark, QWebElement parent) +{ + if (bookmark.isGroup()) + { + KBookmarkGroup group = bookmark.toGroup(); + KBookmark bm = group.first(); + parent.appendInside(markup("h3")); + parent.lastChild().setPlainText(group.text()); + parent.appendInside(markup(".bookfolder")); + while (!bm.isNull()) + { + createBookItem(bm, parent.lastChild()); // it is .bookfolder + bm = group.next(bm); + } + } + else if(bookmark.isSeparator()) + { + parent.appendInside("<hr/>"); + } + else + { + parent.appendInside(markup("a")); + parent.lastChild().setAttribute("href" , bookmark.url().prettyUrl()); + parent.lastChild().setPlainText(bookmark.text()); + parent.appendInside("<br/>"); + } +} + + +void NewTabPage::closedTabsPage() +{ + m_root.addClass("closedTabs"); + + QList<HistoryItem> links = Application::instance()->mainWindow()->mainView()->recentlyClosedTabs(); + + if(links.isEmpty()) + { + m_root.addClass("empty"); + m_root.setPlainText(i18n("There are no recently closed tabs")); + return; + } + + for(int i=0; i < links.count(); ++i) + { + HistoryItem item = links.at(i); + QWebElement prev; + + if(item.url.isEmpty()) + continue; + else if(!QFile::exists(WebSnap::fileForUrl(item.url).toLocalFile())) + prev = loadingPreview(i, item.url); + else + prev = validPreview(i, item.url, item.title); + + prev.setAttribute("id", "preview" + QVariant(i).toString()); + hideControls(prev); + m_root.appendInside(prev); + } +} + + +QString NewTabPage::checkTitle(const QString &title) +{ + QString t(title); + if(t.length() > 23) + { + t.truncate(20); + t += "..."; + } + return t; +} + + +void NewTabPage::downloadsPage() +{ + m_root.addClass("downloads"); + + QWebElement clearData = markup(".link"); + clearData.findFirst("a").setAttribute("href", "about:downloads/clear"); + QString iconPath = QString("file:///" + KIconLoader::global()->iconPath("edit-clear", KIconLoader::SizeSmall || KIconLoader::Small)); + clearData.findFirst("img").setAttribute("src" , iconPath ); + clearData.findFirst("span").appendInside(i18n("Clear Private Data")); + m_root.document().findFirst("#actions").appendInside(clearData); + + DownloadList list = Application::historyManager()->downloads(); + + if(list.isEmpty()) + { + m_root.addClass("empty"); + m_root.setPlainText(i18n("There are no recently downloaded files to show")); + return; + } + + foreach(const DownloadItem &item, list) + { + m_root.prependInside(markup("div")); + + QWebElement div = m_root.firstChild(); + div.addClass("download"); + + KUrl u = KUrl(item.destUrlString); + QString fName = u.fileName(); + QString dir = QL1S("file://") + u.directory(); + + KIconLoader *loader = KIconLoader::global(); + QString iconPath = "file://" + loader->iconPath(KMimeType::iconNameForUrl(u), KIconLoader::Desktop); + + div.appendInside(markup("img")); + div.lastChild().setAttribute("src", iconPath ); + + div.appendInside("<strong>" + fName + "</strong>"); + div.appendInside(" - "); + QString date = KGlobal::locale()->formatDateTime(item.dateTime, KLocale::FancyLongDate); + div.appendInside("<em>" + date + "</em>"); + div.appendInside("<br/>"); + + div.appendInside(item.srcUrlString); + div.appendInside("<br/>"); + + div.appendInside(markup("a")); + div.lastChild().setAttribute("href" , dir); + div.lastChild().setPlainText("Browse dir"); + + /* TODO : make this link work + div.appendInside(" - "); + div.appendInside(markup("a")); + div.lastChild().setAttribute("href" , u.toMimeDataString()); + div.lastChild().setPlainText("Open file");*/ + } +} diff --git a/src/rekonqpage/newtabpage.h b/src/newtabpage.h index 003aa84e..6604e4df 100644 --- a/src/rekonqpage/newtabpage.h +++ b/src/newtabpage.h @@ -2,7 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -28,58 +29,91 @@ #define REKONQ_NEW_TAB_PAGE -// rekonq Includes -#include <webpage.h> +// Local Includes +#include "rekonqprivate_export.h" // KDE Includes #include <KUrl> // Qt Includes -#include <QtCore/QObject> -#include <QtCore/QString> +#include <QObject> +#include <QString> #include <QWebElement> // Forward Includes class KBookmark; +class WebPage; -class NewTabPage +class REKONQ_TESTS_EXPORT NewTabPage : public QObject { - +Q_OBJECT + public: NewTabPage(QWebFrame *frame); ~NewTabPage(); /** - * This is the unique NewTabPage public method. It takes an - * about: url and loads the corresponding part of the - * new tab page + * This method takes an about: url and loads + * the corresponding part of the new tab page */ void generate(const KUrl &url = KUrl("about:home")); + + void snapFinished(int index, const KUrl &url, const QString &title); + -protected: // these are the function to build the new tab page +private: + // these are the "high-level" functions to build the new tab page. + // Basically, you call browsingMenu + one of the *Page methods + // to load a page void browsingMenu(const KUrl ¤tUrl); void favoritesPage(); - //QString lastVisitedPage(); void historyPage(); void bookmarksPage(); void closedTabsPage(); + void downloadsPage(); + + // -------------------------------------------------------------------------- + // "low-level" functions + // we use these to create the pages over + + // Previews handling + QWebElement emptyPreview(int index); + QWebElement loadingPreview(int index, const KUrl &url); + QWebElement validPreview(int index, const KUrl &url, const QString &title); -private: + void removePreview(int index); + + /** + * This function takes a QwebElement with the .thumbnail structure, + * hiding the "remove" and "modify" buttons + * + */ + void hideControls(QWebElement e); + void showControls(QWebElement e); + void setupPreview(QWebElement e, int index); + void createBookItem(const KBookmark &bookmark, QWebElement parent); - /** This function helps to get faster a new markup of one type,it isn't easy to create one with QWebElement. - It gets it in the #models div of home.html. - It works for all elements defined here. - */ - inline QWebElement markup(QString selector) + /** + * This function helps to get faster a new markup of one type, + * it isn't easy to create one with QWebElement. + * + * It gets it in the #models div of home.html. + * It works for all elements defined here. + * + */ + inline QWebElement markup(const QString &selector) { return m_root.document().findFirst("#models > " + selector).clone(); } + + QString checkTitle(const QString &title); - QString m_html; +private: + QString m_html; QWebElement m_root; }; diff --git a/src/paneltreeview.cpp b/src/paneltreeview.cpp new file mode 100644 index 00000000..c13caf4d --- /dev/null +++ b/src/paneltreeview.cpp @@ -0,0 +1,196 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Yoann Laissus <yoann dot laissus at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "paneltreeview.h" +#include "paneltreeview.moc" + +// Local Includes +#include "application.h" + +// Qt Includes +#include <QMouseEvent> +#include <QClipboard> + + +PanelTreeView::PanelTreeView(QWidget *parent) + : QTreeView(parent) +{ + connect(this, SIGNAL(itemHovered(const QString &)), parent, SIGNAL(itemHovered(const QString &))); + connect(this, SIGNAL(openUrl(const KUrl &, Rekonq::OpenType)), parent, SIGNAL(openUrl(const KUrl &, Rekonq::OpenType))); + setMouseTracking(true); + setExpandsOnDoubleClick(false); +} + + +PanelTreeView::~PanelTreeView() +{ +} + + +void PanelTreeView::mousePressEvent(QMouseEvent *event) +{ + const QModelIndex index = indexAt(event->pos()); + bool expanded = isExpanded(index); + + QTreeView::mousePressEvent(event); + + // A change of an item expansion is handle by mouseReleaseEvent() + // So toggle again the item + if(expanded != isExpanded(index)) + setExpanded(index, !isExpanded(index)); + + if(!index.isValid()) + { + clearSelection(); + setCurrentIndex(QModelIndex()); + + if(event->button() == Qt::RightButton) + emit contextMenuEmptyRequested(event->pos()); + return; + } + + if(event->button() == Qt::RightButton) + { + if(model()->rowCount(index) == 0) + { + // An empty group needs to be handle by the panels + emit contextMenuItemRequested(event->pos()); + } + else + { + emit contextMenuGroupRequested(event->pos()); + } + } +} + + +void PanelTreeView::mouseReleaseEvent(QMouseEvent *event) +{ + QTreeView::mouseReleaseEvent(event); + + const QModelIndex index = indexAt(event->pos()); + if(!index.isValid()) + return; + + if(event->button() == Qt::MidButton || event->modifiers() == Qt::ControlModifier) + validOpenUrl(qVariantValue< KUrl >(index.data(Qt::UserRole)), Rekonq::SettingOpenTab); + + else if(event->button() == Qt::LeftButton) + { + if(model()->rowCount(index) == 0) + validOpenUrl(qVariantValue< KUrl >(index.data(Qt::UserRole))); + else + setExpanded(index, !isExpanded(index)); + } +} + + +void PanelTreeView::keyPressEvent(QKeyEvent *event) +{ + QTreeView::keyPressEvent(event); + QModelIndex index = currentIndex(); + + if(!index.isValid()) + return; + + if(event->key() == Qt::Key_Return) + { + if(model()->rowCount(index) == 0) + validOpenUrl(qVariantValue< KUrl >(index.data(Qt::UserRole))); + else + setExpanded(index, !isExpanded(index)); + } + + else if(event->key() == Qt::Key_Delete) + { + emit delKeyPressed(); + } +} + + +void PanelTreeView::validOpenUrl(const KUrl &url, Rekonq::OpenType openType) +{ + // To workaround a crash when the url is about:blank + if(url.url() == "about:blank") + emit openUrl(KUrl("about:home"), openType); + else + emit openUrl(url, openType); +} + + +void PanelTreeView::mouseMoveEvent(QMouseEvent *event) +{ + QTreeView::mouseMoveEvent(event); + const QModelIndex index = indexAt(event->pos()); + if(!index.isValid()) + { + emit itemHovered(""); + return; + } + emit itemHovered(qVariantValue< KUrl >(index.data(Qt::UserRole)).url()); +} + + +void PanelTreeView::openInCurrentTab() +{ + QModelIndex index = currentIndex(); + if(!index.isValid()) + return; + + validOpenUrl(qVariantValue< KUrl >(index.data(Qt::UserRole))); +} + + +void PanelTreeView::copyToClipboard() +{ + QModelIndex index = currentIndex(); + if(!index.isValid()) + return; + + QClipboard *cb = QApplication::clipboard(); + cb->setText(qVariantValue< KUrl >(index.data(Qt::UserRole)).url()); +} + + +void PanelTreeView::openInNewTab() +{ + QModelIndex index = currentIndex(); + if(!index.isValid()) + return; + + validOpenUrl(qVariantValue< KUrl >(index.data(Qt::UserRole)), Rekonq::SettingOpenTab); +} + + +void PanelTreeView::openInNewWindow() +{ + QModelIndex index = currentIndex(); + if(!index.isValid()) + return; + + validOpenUrl( qVariantValue< KUrl >(index.data(Qt::UserRole)), Rekonq::NewWindow); +} diff --git a/src/paneltreeview.h b/src/paneltreeview.h new file mode 100644 index 00000000..93d7a33e --- /dev/null +++ b/src/paneltreeview.h @@ -0,0 +1,69 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Yoann Laissus <yoann dot laissus at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef PANELTREEVIEW_H +#define PANELTREEVIEW_H + +// Local Includes +#include "application.h" + +// Qt Includes +#include <QTreeView> + + +class PanelTreeView : public QTreeView +{ + Q_OBJECT + +public: + PanelTreeView(QWidget *parent = 0); + ~PanelTreeView(); + +signals: + void openUrl(const KUrl &, const Rekonq::OpenType &); + void itemHovered(const QString &); + void delKeyPressed(); + void contextMenuItemRequested(const QPoint &pos); + void contextMenuGroupRequested(const QPoint &pos); + void contextMenuEmptyRequested(const QPoint &pos); + +public slots: + void copyToClipboard(); + void openInCurrentTab(); + void openInNewTab(); + void openInNewWindow(); + +protected: + void mouseReleaseEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void keyPressEvent(QKeyEvent *event); + +private: + void validOpenUrl(const KUrl &url, Rekonq::OpenType openType = Rekonq::CurrentTab); +}; + +#endif // PANELTREEVIEW_H diff --git a/src/previewimage.cpp b/src/previewimage.cpp deleted file mode 100644 index 9c8bb194..00000000 --- a/src/previewimage.cpp +++ /dev/null @@ -1,430 +0,0 @@ -/* ============================================================ -* -* This file is a part of the rekonq project -* -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> -* -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation; either version 2 of -* the License or (at your option) version 3 or any later version -* accepted by the membership of KDE e.V. (or its successor approved -* by the membership of KDE e.V.), which shall act as a proxy -* defined in Section 14 of version 3 of the license. -* -* This program 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 General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -* -* ============================================================ */ - - -// Self Includes -#include "previewimage.h" -#include "previewimage.moc" - -// Local Includes -#include "historymanager.h" -#include "rekonq.h" -#include "mainwindow.h" -#include "mainview.h" - -// KDE Includes -#include <KUrl> -#include <KStandardDirs> -#include <KDebug> -#include <KMenu> -#include <KAction> -#include <KLocale> - -// Qt Includes -#include <QFile> -#include <QMovie> -#include <QMouseEvent> -#include <QHBoxLayout> -#include <QVBoxLayout> -#include <QPainter> - - -PreviewImage::PreviewImage(const QUrl &url, const QString &title, int index, bool isFavorite) - : QWidget() - , ws(0) - , loadingSnapshot(false) - , m_url(url) - , m_title(title) - , m_isFavorite(isFavorite) - , m_index(index) - , m_button(0) - , m_imageLabel(new QLabel) - , m_textLabel(new QLabel) - , m_backgroundLabel(new QLabel) - , m_previewLabel(new QLabel) -{ - - int borderTop = 14; - int borderRight = 16; - int borderBottom = 14; - int borderLeft = 16; - - int previewWidth = 200; - int previewHeight = 150; - - int urlHeight = 18; - - m_size = QSize(borderLeft+previewWidth+borderRight, borderTop+previewHeight+borderBottom+urlHeight); - - setFixedSize(m_size); - m_previewLabel->setFixedSize(m_size); - - m_backgroundLabel->setPixmap(renderBackground(previewWidth,previewHeight, borderTop, borderBottom, borderLeft, borderRight)); - - m_previewLabel->setAlignment(Qt::AlignCenter); - m_backgroundLabel->setAlignment(Qt::AlignCenter); - m_imageLabel->setAlignment(Qt::AlignCenter); - m_textLabel->setAlignment(Qt::AlignCenter); - - m_previewLabel->setLayout(new QVBoxLayout); - m_previewLabel->layout()->setMargin(0); - m_previewLabel->layout()->addWidget(m_backgroundLabel); - m_previewLabel->layout()->addWidget(m_textLabel); - m_previewLabel->setCursor(Qt::PointingHandCursor); - - m_backgroundLabel->setLayout(new QVBoxLayout); - m_backgroundLabel->layout()->addWidget(m_imageLabel); - - setLayout(new QHBoxLayout); - layout()->setMargin(0); - layout()->setAlignment(Qt::AlignCenter); - layout()->addWidget(m_previewLabel); - - connect(this, SIGNAL(loadUrl(const KUrl &, const Rekonq::OpenType &)), - Application::instance(), SLOT(loadUrl(const KUrl &, const Rekonq::OpenType &))); - - loadUrlPreview(url); -} - - -PreviewImage::~PreviewImage() -{ - delete ws; - delete m_textLabel; - delete m_imageLabel; - delete m_backgroundLabel; - delete m_previewLabel; -} - - -QPixmap PreviewImage::renderBackground(int w, int h, int t, int b, int l, int r) -{ - QImage backImage(KStandardDirs::locate("appdata", "pics/bg.png")); - QImage resultImage(QSize(w + l + r, h + t + b), QImage::Format_ARGB32_Premultiplied); - - if (!backImage.isNull()) - { - int sw = backImage.width() - l - r; - int sh = backImage.height() - t - b; - QPainter pt(&resultImage); - pt.setCompositionMode(QPainter::CompositionMode_Source); - pt.fillRect(resultImage.rect(), Qt::transparent); - pt.drawImage(QRect(0, 0, l, t), backImage, QRect(0, 0, l, t)); - pt.drawImage(QRect(l, 0, w, t), backImage, QRect(l, 0, sw, t)); - pt.drawImage(QRect(l + w, 0, r, t), backImage, QRect(l + sw, 0, r, t)); - pt.drawImage(QRect(0, t, l, h), backImage, QRect(0, t, l, sh)); - pt.drawImage(QRect(l, t, w, h), backImage, QRect(l, t, sw, sh)); - pt.drawImage(QRect(l + w, t, r, h), backImage, QRect(l + sw, t, r, sh)); - pt.drawImage(QRect(0, t + h, l , b), backImage, QRect(0, t + sh, l , b)); - pt.drawImage(QRect(l, t + h, w, b), backImage, QRect(l, t + sh, sw, b)); - pt.drawImage(QRect(l + w, t + h, w, b), backImage, QRect(l + sw, t + sh, sw, b)); - pt.end(); - } - - return QPixmap::fromImage(resultImage); -} - - -void PreviewImage::loadUrlPreview(const QUrl& url) -{ - m_url = url; - - if(url.isEmpty()) - { - showEmptyPreview(); - return; - } - - m_previewLabel->setFixedSize(m_size); //unhide - - m_savePath = KStandardDirs::locateLocal("cache", QString("thumbs/") + guessNameFromUrl(m_url) + ".png", true); - - if(QFile::exists(m_savePath)) - { - m_pixmap.load(m_savePath); - m_imageLabel->setPixmap(m_pixmap); - checkTitle(); - m_textLabel->setText(m_title); - } - else - { - loadingSnapshot = true; - ws = new WebSnap( url ); - connect(ws, SIGNAL(finished()), this, SLOT(snapFinished())); - - QString path = KStandardDirs::locate("appdata", "pics/busywidget.gif"); - - // load an animation waiting for site preview - QMovie *movie = new QMovie(path, QByteArray(), this); - movie->setSpeed(50); - m_imageLabel->setMovie(movie); - movie->start(); - m_textLabel->setText( i18n("Loading preview...") ); - setCursor(Qt::BusyCursor); - } -} - - -void PreviewImage::snapFinished() -{ - loadingSnapshot = false; - QMovie *m = m_imageLabel->movie(); - delete m; - m_imageLabel->setMovie(0); - - m_pixmap = ws->previewImage(); - m_imageLabel->setPixmap(m_pixmap); - checkTitle(); - m_textLabel->setText(m_title); - - setCursor(Qt::PointingHandCursor); - - m_pixmap.save(m_savePath); - - if(m_index > -1) - { - // Update title - QStringList names = ReKonfig::previewNames(); - // update url (for added thumbs) - QStringList urls = ReKonfig::previewUrls(); - - // stripTrailingSlash to be sure to get the same string for same address - urls.replace(m_index, ws->snapUrl().toString(QUrl::StripTrailingSlash)); - names.replace(m_index, ws->snapTitle()); - - ReKonfig::setPreviewNames(names); - ReKonfig::setPreviewUrls(urls); - - ReKonfig::self()->writeConfig(); - } -} - - -void PreviewImage::showEmptyPreview() -{ - if(!m_isFavorite) - return; - - m_imageLabel->clear(); - m_textLabel->clear(); - - m_previewLabel->setFixedSize(0,0); //hide - - - m_button = new QToolButton(); - m_button->setDefaultAction(historyMenu()); - m_button->setPopupMode(QToolButton::InstantPopup); - m_button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - m_button->setText(i18n("Add Preview")); - m_button->setAutoRaise(true); - m_button->setIconSize(QSize(48, 48)); - layout()->addWidget(m_button); -} - - -void PreviewImage::mouseDoubleClickEvent(QMouseEvent *event) -{ - kDebug() << "no double click over here, thanks :D"; - Q_UNUSED(event); -} - - -void PreviewImage::mouseMoveEvent(QMouseEvent *event) -{ - kDebug() << "moving mouse over preview image"; - Q_UNUSED(event) -} - - -void PreviewImage::mousePressEvent(QMouseEvent *event) -{ - if(event->button() == Qt::LeftButton) - { - emit loadUrl(m_url, Rekonq::CurrentTab); - return; - } - else if(event->button() == Qt::MidButton) - { - emit loadUrl(m_url, Rekonq::SettingOpenTab); - return; - } - - QWidget::mousePressEvent(event); -} - - -void PreviewImage::mouseReleaseEvent(QMouseEvent *event) -{ - kDebug() << "NO000... don't leave your finger from the button!!"; - Q_UNUSED(event) -} - - -void PreviewImage::contextMenuEvent(QContextMenuEvent* event) -{ - if(!m_isFavorite) - return; - - if(loadingSnapshot) - return; - - KMenu menu(this); - KAction *a; - - if(!m_url.isEmpty()) - { - a = new KAction(KIcon("edit-delete"), i18n("Remove Thumbnail"), this); - connect(a, SIGNAL(triggered(bool)), this, SLOT(removeMe())); - menu.addAction(a); - - a = new KAction(KIcon("view-refresh"), i18n("Refresh Thumbnail"), &menu); - connect(a, SIGNAL(triggered(bool)), this, SLOT(refreshPreview())); - menu.addAction(a); - } - menu.addAction(historyMenu()); - - menu.exec(mapToGlobal(event->pos())); -} - - -KActionMenu* PreviewImage::historyMenu() -{ - KActionMenu *histMenu = new KActionMenu(KIcon("insert-image"), i18n("Set Page to Preview"), this); - QList<HistoryItem> history = Application::historyManager()->history(); - - if(history.isEmpty()) - { - KAction *a = new KAction(i18n("History is Empty"), this); - a->setEnabled(false); - histMenu->addAction(a); - return histMenu; - } - - int maxItems = 15; - for (int i = 0; i < maxItems && i < history.size() ; ++i) - { - HistoryItem it = history.at(i); - KAction *a = new KAction(Application::icon(it.url), it.title, this); - QStringList urlData; - urlData << it.url << it.title; - a->setData(urlData); - connect(a, SIGNAL(triggered(bool)), this, SLOT(setUrlFromAction())); - histMenu->addAction(a); - } - - return histMenu; -} - - -void PreviewImage::removeMe() -{ - QStringList names = ReKonfig::previewNames(); - QStringList urls = ReKonfig::previewUrls(); - - int index = urls.indexOf(QRegExp(m_url.toString(QUrl::StripTrailingSlash), Qt::CaseSensitive, QRegExp::FixedString)); - - urls.replace(index, QString("")); - names.replace(index, QString("")); - - ReKonfig::setPreviewNames(names); - ReKonfig::setPreviewUrls(urls); - - // sync file data - ReKonfig::self()->writeConfig(); - - showEmptyPreview(); - - m_url = ""; -} - - -void PreviewImage::setUrlFromAction() -{ - KAction *a = qobject_cast<KAction*>(sender()); - QStringList urlData = a->data().toStringList(); - - m_url = KUrl(urlData.at(0)); - m_title = urlData.at(1); - checkTitle(); - - if(m_button) - { - m_imageLabel->layout()->deleteLater(); - m_button->menu()->deleteLater(); - m_button->deleteLater(); - } - loadUrlPreview(m_url); - - // Update title - QStringList names = ReKonfig::previewNames(); - // update url (for added thumbs) - QStringList urls = ReKonfig::previewUrls(); - - // stripTrailingSlash to be sure to get the same string for same address - urls.replace(m_index, m_url.toString(QUrl::StripTrailingSlash)); - names.replace(m_index, m_title); - - ReKonfig::setPreviewNames(names); - ReKonfig::setPreviewUrls(urls); - - ReKonfig::self()->writeConfig(); -} - - -void PreviewImage::refreshPreview() -{ - QString path = KStandardDirs::locateLocal("cache", QString("thumbs/") + guessNameFromUrl(m_url) + ".png", true); - QFile::remove(path); - loadUrlPreview(m_url); -} - - -QString PreviewImage::guessNameFromUrl(QUrl url) -{ - QString name = url.toString( QUrl::RemoveScheme | QUrl::RemoveUserInfo | QUrl::StripTrailingSlash ); - - // TODO learn Regular Expressions :) - // and implement something better here.. - name.remove('/'); - name.remove('&'); - name.remove('.'); - name.remove('-'); - name.remove('_'); - name.remove('?'); - name.remove('='); - name.remove('+'); - - return name; -} - - -void PreviewImage::checkTitle() -{ - if(m_title.length() > 23) - { - m_title.truncate(20); - m_title += "..."; - } -} diff --git a/src/previewimage.h b/src/previewimage.h deleted file mode 100644 index 4dd8df3b..00000000 --- a/src/previewimage.h +++ /dev/null @@ -1,101 +0,0 @@ -/* ============================================================ -* -* This file is a part of the rekonq project -* -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> -* -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation; either version 2 of -* the License or (at your option) version 3 or any later version -* accepted by the membership of KDE e.V. (or its successor approved -* by the membership of KDE e.V.), which shall act as a proxy -* defined in Section 14 of version 3 of the license. -* -* This program 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 General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -* -* ============================================================ */ - - -#ifndef PREVIEW_IMAGE_H -#define PREVIEW_IMAGE_H - -// Local Includes -#include "websnap.h" -#include "application.h" - -// KDE Includes -#include <KActionMenu> - -// Qt Includes -#include <QLabel> -#include <QFrame> -#include <QImage> -#include <QUrl> -#include <QToolButton> -#include <QSize> - - -class PreviewImage : public QWidget -{ - Q_OBJECT - -public: - PreviewImage(const QUrl &url, const QString &title, int index, bool isFavorite); - ~PreviewImage(); - - QString guessNameFromUrl(QUrl url); - -public slots: - void snapFinished(); - void removeMe(); - void setUrlFromAction(); - void refreshPreview(); - -signals: - void loadUrl(const KUrl &, const Rekonq::OpenType &); - -protected: - void contextMenuEvent(QContextMenuEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - - void loadUrlPreview(const QUrl &url); - KActionMenu *historyMenu(); - void showEmptyPreview(); - -private: - void checkTitle(); - QPixmap renderBackground(int w, int h, int t, int b, int l, int r); - - QPixmap m_pixmap; - WebSnap *ws; - - QString m_savePath; - bool loadingSnapshot; - - QUrl m_url; - QString m_title; - bool m_isFavorite; - int m_index; - - QToolButton *m_button; - - QLabel *m_imageLabel; - QLabel *m_textLabel; - QLabel *m_backgroundLabel; - QLabel *m_previewLabel; - - QSize m_size; -}; - -#endif // PREVIEW_IMAGE_H diff --git a/src/previewselectorbar.cpp b/src/previewselectorbar.cpp new file mode 100644 index 00000000..924a5439 --- /dev/null +++ b/src/previewselectorbar.cpp @@ -0,0 +1,152 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Auto Includes +#include "previewselectorbar.h" +#include "previewselectorbar.moc" + +// Local Include +#include "rekonq.h" +#include "websnap.h" +#include "application.h" +#include "mainwindow.h" +#include "webtab.h" + +// KDE Includes +#include <KIcon> +#include <KLocalizedString> + +// Qt Includes +#include <QToolButton> +#include <QHBoxLayout> +#include <QString> + + +PreviewSelectorBar::PreviewSelectorBar(int index, QWidget* parent) + : QWidget(parent) + , m_button(0) + , m_label(0) + , m_previewIndex(index) +{ + m_label = new QLabel(i18n("Please open up the webpage you want to add as favorite"), this); + m_label->setWordWrap(true); + + QToolButton *closeButton = new QToolButton(this); + closeButton->setAutoRaise(true); + closeButton->setIcon(KIcon("dialog-close")); + connect(closeButton, SIGNAL(clicked(bool)), this, SLOT(destroy())); + + m_button = new QPushButton(KIcon("insert-image"), i18n("Set to This Page"), this); + m_button->setMaximumWidth(250); + connect(m_button, SIGNAL(clicked(bool)), this, SLOT(clicked())); + + // layout + QHBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(closeButton); + layout->addWidget(m_label); + layout->addWidget(m_button); + + layout->setContentsMargins(2, 0, 2, 0); + + setLayout(layout); +} + + +PreviewSelectorBar::~PreviewSelectorBar() +{ +} + + +void PreviewSelectorBar::verifyUrl() +{ + + if(Application::instance()->mainWindow()->currentTab()->page()->mainFrame()->url().scheme() != "about") + { + m_button->setEnabled(true); + m_button->setToolTip(""); + } + else + { + m_button->setEnabled(false); + m_button->setToolTip(i18n("You can not add this webpage as favorite")); + } +} + + +void PreviewSelectorBar::loadProgress() +{ + m_button->setEnabled(false); + m_button->setToolTip(i18n("Page is loading...")); +} + + +void PreviewSelectorBar::loadFinished() +{ + m_button->setEnabled(true); + m_button->setToolTip(""); + + verifyUrl(); +} + + +void PreviewSelectorBar::clicked() +{ + WebPage *page = Application::instance()->mainWindow()->currentTab()->page(); + + if(page) + { + // this is done just lo let the render process being faster.. + WebSnap::renderPreview(*page); + + KUrl url = page->mainFrame()->url(); + QStringList names = ReKonfig::previewNames(); + QStringList urls = ReKonfig::previewUrls(); + + urls.replace(m_previewIndex, url.toMimeDataString()); + names.replace(m_previewIndex, page->mainFrame()->title()); + + ReKonfig::setPreviewNames(names); + ReKonfig::setPreviewUrls(urls); + + ReKonfig::self()->writeConfig(); + + + page->mainFrame()->load(KUrl("about:favorites")); + } + + destroy(); +} + + +void PreviewSelectorBar::destroy() +{ + if (parentWidget() && parentWidget()->layout()) + { + parentWidget()->layout()->removeWidget(this); + } + this->deleteLater(); +} diff --git a/src/previewselectorbar.h b/src/previewselectorbar.h new file mode 100644 index 00000000..bb9f26c4 --- /dev/null +++ b/src/previewselectorbar.h @@ -0,0 +1,66 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef PREVIEWSELECTORBAR_H +#define PREVIEWSELECTORBAR_H + +// Local Includes +#include "rekonqprivate_export.h" +#include "webpage.h" + +// Qt Includes +#include <QWidget> +#include <QPushButton> +#include <QLabel> + + +class REKONQ_TESTS_EXPORT PreviewSelectorBar : public QWidget +{ +Q_OBJECT + +public: + PreviewSelectorBar(int index, QWidget *parent); + ~PreviewSelectorBar(); + +private slots: + void clicked(); + + void loadProgress(); + void loadFinished(); + + void verifyUrl(); + + void destroy(); + +private: + QPushButton *m_button; + QLabel *m_label; + + int m_previewIndex; +}; + +#endif // PREVIEWSELECTORBAR_H diff --git a/src/protocolhandler.cpp b/src/protocolhandler.cpp index c90afd19..c97bc475 100644 --- a/src/protocolhandler.cpp +++ b/src/protocolhandler.cpp @@ -2,7 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -36,7 +36,9 @@ #include "mainwindow.h" #include "mainview.h" #include "urlbar.h" +#include "webtab.h" #include "historymanager.h" +#include "adblockmanager.h" // KDE Includes #include <klocalizedstring.h> @@ -51,6 +53,7 @@ #include <KFileItem> #include <KJob> #include <kio/udsentry.h> +#include <KMessageBox> // Qt Includes #include <QLatin1String> @@ -60,13 +63,15 @@ #include <QFile> #include <QDateTime> +// Defines +#define QL1S(x) QLatin1String(x) + ProtocolHandler::ProtocolHandler(QObject *parent) : QObject(parent) - , _lister(new KDirLister) + , _lister(0) , _frame(0) { - connect( _lister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(showResults(const KFileItemList &))); } @@ -80,18 +85,16 @@ bool ProtocolHandler::preHandling(const QNetworkRequest &request, QWebFrame *fra _url = request.url(); _frame = frame; - kDebug() << "URL PROTOCOL: " << _url; - + // "http(s)" (fast) handling + if( _url.protocol() == QL1S("http") || _url.protocol() == QL1S("https") ) + return false; + // relative urls if(_url.isRelative()) return false; - - // "http(s)" (fast) handling - if( _url.protocol() == QLatin1String("http") || _url.protocol() == QLatin1String("https") ) - return false; - + // javascript handling - if( _url.protocol() == QLatin1String("javascript") ) + if( _url.protocol() == QL1S("javascript") ) { QString scriptSource = _url.authority(); QVariant result = frame->evaluateJavaScript(scriptSource); @@ -99,15 +102,28 @@ bool ProtocolHandler::preHandling(const QNetworkRequest &request, QWebFrame *fra } // "mailto" handling - if ( _url.protocol() == QLatin1String("mailto") ) + if ( _url.protocol() == QL1S("mailto") ) { KToolInvocation::invokeMailer(_url); return true; } + // "abp" handling + if ( _url.protocol() == QL1S("abp") ) + { + abpHandling(); + return true; + } + // "about" handling - if ( _url.protocol() == QLatin1String("about") ) + if ( _url.protocol() == QL1S("about") ) { + // let webkit manage the about:blank url... + if( _url == KUrl("about:blank") ) + { + return false; + } + if( _url == KUrl("about:home") ) { switch(ReKonfig::newTabStartPage()) @@ -118,26 +134,22 @@ bool ProtocolHandler::preHandling(const QNetworkRequest &request, QWebFrame *fra case 1: // closed tabs _url = KUrl("about:closedTabs"); break; - case 2: // history - _url = KUrl("about:history"); - break; - case 3: // bookmarks + case 2: // bookmarks _url = KUrl("about:bookmarks"); break; + case 3: // history + _url = KUrl("about:history"); + break; + case 4: // downloads + _url = KUrl("about:downloads"); default: // unuseful break; } } - if( _url == KUrl("about:closedTabs") - || _url == KUrl("about:history") - || _url == KUrl("about:bookmarks") - || _url == KUrl("about:favorites") - ) - { - NewTabPage p(frame); - p.generate(_url); - return true; - } + + NewTabPage p(frame); + p.generate(_url); + return true; } return false; @@ -152,12 +164,12 @@ bool ProtocolHandler::postHandling(const QNetworkRequest &request, QWebFrame *fr kDebug() << "URL PROTOCOL: " << _url; // "http(s)" (fast) handling - if( _url.protocol() == QLatin1String("http") || _url.protocol() == QLatin1String("https") ) + if( _url.protocol() == QL1S("http") || _url.protocol() == QL1S("https") ) return false; // "mailto" handling: It needs to be handled both here(mail links clicked) // and in prehandling (mail url launched) - if ( _url.protocol() == QLatin1String("mailto") ) + if ( _url.protocol() == QL1S("mailto") ) { KToolInvocation::invokeMailer(_url); return true; @@ -168,7 +180,7 @@ bool ProtocolHandler::postHandling(const QNetworkRequest &request, QWebFrame *fr // My idea is: webkit cannot handle in any way ftp. So we have surely to return true here. // We start trying to guess what the url represent: it's a dir? show its contents (and download them). // it's a file? download it. It's another thing? beat me, but I don't know what to do... - if( _url.protocol() == QLatin1String("ftp") ) + if( _url.protocol() == QL1S("ftp") ) { KIO::StatJob *job = KIO::stat(_url); connect(job, SIGNAL(result(KJob*)), this, SLOT( slotMostLocalUrlResult(KJob*) )); @@ -176,13 +188,15 @@ bool ProtocolHandler::postHandling(const QNetworkRequest &request, QWebFrame *fr } // "file" handling. This is quite trivial :) - if(_url.protocol() == QLatin1String("file") ) + if( _url.protocol() == QL1S("file") ) { QFileInfo fileInfo( _url.path() ); if(fileInfo.isDir()) { + _lister = new KDirLister; + connect( _lister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(showResults(const KFileItemList &))); _lister->openUrl(_url); - Application::instance()->mainWindow()->mainView()->urlBar()->setUrl(_url); + return true; } } @@ -193,6 +207,10 @@ bool ProtocolHandler::postHandling(const QNetworkRequest &request, QWebFrame *fr QString ProtocolHandler::dirHandling(const KFileItemList &list) { + if (!_lister) + { + return QString("rekonq error, sorry :("); + } KFileItem mainItem = _lister->rootItem(); KUrl rootUrl = mainItem.url(); @@ -263,7 +281,7 @@ QString ProtocolHandler::dirHandling(const KFileItemList &list) msg += "</table>"; - QString html = QString(QLatin1String(file.readAll())) + QString html = QString(QL1S(file.readAll())) .arg(title) .arg(msg) ; @@ -281,14 +299,13 @@ void ProtocolHandler::showResults(const KFileItemList &list) return; } - if ( list.isEmpty() ) - return; - QString html = dirHandling(list); - _frame->setHtml(html); + _frame->setHtml( html, _url ); - Application::instance()->mainWindow()->mainView()->urlBar()->setUrl(_url); + Application::instance()->mainWindow()->currentTab()->setFocus(); Application::historyManager()->addHistoryEntry( _url.prettyUrl() ); + + delete _lister; } @@ -304,8 +321,66 @@ void ProtocolHandler::slotMostLocalUrlResult(KJob *job) KIO::StatJob *statJob = static_cast<KIO::StatJob*>(job); KIO::UDSEntry entry = statJob->statResult(); if( entry.isDir() ) + { + _lister = new KDirLister; + connect( _lister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(showResults(const KFileItemList &))); _lister->openUrl(_url); + } else emit downloadUrl(_url); } } + + +/** + * abp scheme (easy) explanation + * + */ +void ProtocolHandler::abpHandling() +{ + kDebug() << _url; + + QString path = _url.path(); + if( path != QL1S("subscribe") ) + return; + + QMap<QString, QString> map = _url.queryItems( KUrl::CaseInsensitiveKeys ); + + QString location = map.value( QL1S("location") ); + kDebug() << location; + + QString title = map.value( QL1S("title") ); + kDebug() << title; + + QString requireslocation = map.value( QL1S("requireslocation") ); + kDebug() << requireslocation; + + QString requirestitle = map.value( QL1S("requirestitle") ); + kDebug() << requirestitle; + + QString info; + if( requirestitle.isEmpty() || requireslocation.isEmpty() ) + { + info = title; + } + else + { + info = i18n("\n %1,\n %2 (required by %3)\n", title, requirestitle, title); + } + + if ( KMessageBox::questionYesNo( 0, + i18n("Do you want to add the following subscriptions to your adblock settings?\n") + info, + i18n("Add automatic subscription to the adblock"), + KGuiItem(i18n("Add")), + KGuiItem(i18n("Discard")) + ) + ) + { + if( !requireslocation.isEmpty() && !requirestitle.isEmpty() ) + { + Application::adblockManager()->addSubscription( requirestitle, requireslocation ); + } + Application::adblockManager()->addSubscription( title, location ); + Application::adblockManager()->loadSettings(false); + } +} diff --git a/src/protocolhandler.h b/src/protocolhandler.h index 6ae47b74..99aec70a 100644 --- a/src/protocolhandler.h +++ b/src/protocolhandler.h @@ -2,7 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -27,6 +27,10 @@ #ifndef PROTOCOL_HANDLER_H #define PROTOCOL_HANDLER_H + +// Local Includes +#include "rekonqprivate_export.h" + // KDE Includes #include <KDirLister> @@ -41,7 +45,7 @@ class KUrl; class KJob; -class ProtocolHandler : public QObject +class REKONQ_TESTS_EXPORT ProtocolHandler : public QObject { Q_OBJECT @@ -70,7 +74,8 @@ private slots: private: QString dirHandling(const KFileItemList &list); - + void abpHandling(); + KDirLister *_lister; QWebFrame *_frame; KUrl _url; diff --git a/src/rekonq.kcfg b/src/rekonq.kcfg index a24508fc..860809cd 100644 --- a/src/rekonq.kcfg +++ b/src/rekonq.kcfg @@ -7,17 +7,37 @@ <!-- Includes --> <include>QtWebKit</include> +<include>QDateTime</include> <include>KUrl</include> <kcfgfile name="rekonqrc" /> +<!-- Miscellaneuos (not config UI) settins --> +<group name="misc"> + <entry name="FirstExecution" type="Bool"> + <default>true</default> + </entry> + <entry name="showHistoryPanel" type="Bool"> + <default>false</default> + </entry> + <entry name="showBookmarksPanel" type="Bool"> + <default>false</default> + </entry> + <entry name="walletBlackList" type="StringList"> + <default></default> + </entry> + <entry name="recoverOnCrash" type="Int"> + <default>0</default> + </entry> +</group> + <!-- New Tab Page Settings --> <group name="NewTabPage"> <entry name="previewNames" type="StringList"> - <default>KDE Homepage,KDE-Apps,KDE-Look,UserBase,KDE Community Forums,TechBase,Planet KDE,rekonq</default> + <default>KDE Homepage,UserBase,rekonq site</default> </entry> <entry name="previewUrls" type="StringList"> - <default>http://www.kde.org,http://kde-apps.org,http://kde-look.org,http://userbase.kde.org,http://forum.kde.org,http://techbase.kde.org,http://planetkde.org,http://rekonq.sourceforge.net</default> + <default>http://www.kde.org,http://userbase.kde.org,http://rekonq.sourceforge.net</default> </entry> </group> @@ -35,19 +55,16 @@ <entry name="homePage" type="String"> <default>http://www.kde.org/</default> </entry> - <entry name="showHistoryPanel" type="Bool"> - <default>false</default> - </entry> - <entry name="showBookmarksPanel" type="Bool"> - <default>false</default> - </entry> <entry name="kgetDownload" type="Bool"> <default>false</default> </entry> <entry name="kgetList" type="Bool"> <default>false</default> </entry> - </group> + <entry name="searchEngine" type="Int"> + <default>0</default> + </entry> + </group> <!-- Tabs Settings --> <group name="Tabs"> @@ -93,12 +110,6 @@ <entry name="expireHistory" type="Int"> <default>1</default> </entry> - <entry name="acceptCookies" type="Int"> - <default>2</default> - </entry> - <entry name="keepCookiesUntil" type="Int"> - <default>0</default> - </entry> </group> <!-- WebKit Settings --> @@ -144,4 +155,27 @@ </entry> </group> + +<!-- AdBlock Settings --> + <group name="AdBlock"> + <entry name="adBlockEnabled" type="Bool"> + <default>true</default> + </entry> + <entry name="hideAdsEnabled" type="Bool"> + <default>true</default> + </entry> + <entry name="subscriptionTitles" type="StringList"> + <default>EasyList</default> + </entry> + <entry name="subscriptionLocations" type="StringList"> + <default>https://easylist-downloads.adblockplus.org/easylist.txt</default> + </entry> + <entry name="lastUpdate" type="DateTime"> + <default>QDateTime(QDate(2009,03,13))</default> + </entry> + <entry name="updateInterval" type="Int"> + <default>7</default> + </entry> + </group> + </kcfg> diff --git a/src/rekonqpage/newtabpage.cpp b/src/rekonqpage/newtabpage.cpp deleted file mode 100644 index 66f74b86..00000000 --- a/src/rekonqpage/newtabpage.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/* ============================================================ -* -* This file is a part of the rekonq project -* -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> -* -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation; either version 2 of -* the License or (at your option) version 3 or any later version -* accepted by the membership of KDE e.V. (or its successor approved -* by the membership of KDE e.V.), which shall act as a proxy -* defined in Section 14 of version 3 of the license. -* -* This program 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 General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -* -* ============================================================ */ - - -// Self Includes -#include "newtabpage.h" - -// Auto Includes -#include "rekonq.h" - -// Local Includes -#include "historymodels.h" -#include "bookmarksmanager.h" -#include "application.h" -#include "mainwindow.h" -#include "mainview.h" - -// KDE Includes -#include <KStandardDirs> -#include <KIconLoader> -#include <KDebug> -#include <KConfig> -#include <KConfigGroup> - -// Qt Includes -#include <QFile> - - -NewTabPage::NewTabPage(QWebFrame *frame) - : m_root(frame->documentElement()) -{ - QString htmlFilePath = KStandardDirs::locate("data", "rekonq/htmls/home.html"); - - QFile file(htmlFilePath); - bool isOpened = file.open(QIODevice::ReadOnly); - if (!isOpened) - kWarning() << "Couldn't open the home.html file"; - - QString imagesPath = QString("file://") + KGlobal::dirs()->findResourceDir("data", "rekonq/pics/bg.png") + QString("rekonq/pics"); - - m_html = file.readAll(); - m_html.replace(QString("%2"), imagesPath); -} - - -NewTabPage::~NewTabPage() -{ -} - - -void NewTabPage::generate(const KUrl &url) -{ - QWebPage *page = m_root.webFrame()->page(); - page->mainFrame()->setHtml(m_html); - - m_root = page->mainFrame()->documentElement().findFirst("#content"); - - browsingMenu(url); - - QString title; - if(url == KUrl("about:closedTabs")) - { - closedTabsPage(); - title = i18n("Closed Tabs"); - } - if(url == KUrl("about:history")) - { - historyPage(); - title = i18n("History"); - } - if(url == KUrl("about:bookmarks")) - { - bookmarksPage(); - title = i18n("Bookmarks"); - } - if(url == KUrl("about:home") || url == KUrl("about:favorites")) - { - favoritesPage(); - title = i18n("Favorites"); - } - - m_root.document().findFirst("title").setPlainText(title); -} - - -void NewTabPage::favoritesPage() -{ - QStringList names = ReKonfig::previewNames(); - QStringList urls = ReKonfig::previewUrls(); - - m_root.addClass("favorites"); - - for(int i=0; i<8; ++i) - { - QWebElement speed = markup(".thumbnail"); - speed.findFirst("object").setAttribute("data" , urls.at(i)); - speed.findFirst("param[name=title]").setAttribute("value", names.at(i)); - speed.findFirst("param[name=index]").setAttribute("value", QString::number(i)); - speed.findFirst("param[name=isFavorite]").setAttribute("value", "true"); - m_root.appendInside(speed); - } -} - - -// FIXME : port to new PreviewImage API to use... -/*QString NewTabPage::lastVisitedPage() -{ - QString last; - QList<HistoryItem> history = Application::historyManager()->history(); - for (int i = 0; i < 8 && i < history.size(); ++i) - { - HistoryItem it = history.at(i); - last += "<div class=\"thumbnail\">"; - last += "<object type=\"application/image-preview\" data=\"" + it.url + "\" >"; - last += "</object>"; - last += "<br />"; - last += "<a href=\"" + it.url + "\">" + it.title + "</a></div>"; - } - - return last; - -}*/ - - -void NewTabPage::browsingMenu(const KUrl ¤tUrl) -{ - QList<QWebElement> navItems; - - KIconLoader *loader = KIconLoader::global(); - - QWebElement nav = markup(".link"); // Favorites - nav.findFirst("a").setAttribute("href", "about:favorites"); - nav.findFirst("img").setAttribute("src" , QString("file:///" + - loader->iconPath("emblem-favorite", KIconLoader::Desktop ||KIconLoader::SizeSmall))); - nav.findFirst("a").appendInside(i18n("Favorites")); - navItems.append(nav); - - nav = markup(".link"); // Closed Tabs - nav.findFirst("a").setAttribute("href", "about:closedTabs"); - nav.findFirst("img").setAttribute("src" , QString("file:///" + - loader->iconPath("tab-close", KIconLoader::Desktop ||KIconLoader::SizeSmall))); - nav.findFirst("a").appendInside(i18n("Closed Tabs")); - navItems.append(nav); - - nav = markup(".link"); // Bookmarks - nav.findFirst("a").setAttribute("href", "about:bookmarks"); - nav.findFirst("img").setAttribute("src" , QString("file:///" + - loader->iconPath("bookmarks", KIconLoader::Desktop ||KIconLoader::SizeSmall))); - nav.findFirst("a").appendInside(i18n("Bookmarks")); - navItems.append(nav); - - nav = markup(".link"); // History - nav.findFirst("a").setAttribute("href", "about:history"); - nav.findFirst("img").setAttribute("src" , QString("file:///" + - loader->iconPath("view-history", KIconLoader::Desktop ||KIconLoader::SizeSmall))); - nav.findFirst("a").appendInside(i18n("History")); - navItems.append(nav); - - QWebElement it; - foreach(it, navItems) - { - if(it.findFirst("a").attribute("href") == currentUrl.toMimeDataString()) - it.addClass("current"); - else if(currentUrl == "about:home" && it.findFirst("a").attribute("href") == "about:favorites") - it.addClass("current"); - m_root.document().findFirst("#navigation").appendInside(it); - } -} - - -void NewTabPage::historyPage() -{ - HistoryTreeModel *model = Application::historyManager()->historyTreeModel(); - - int i = 0; - do - { - QModelIndex index = model->index(i, 0, QModelIndex() ); - if(model->hasChildren(index)) - { - m_root.appendInside(markup("h3")); - m_root.lastChild().setPlainText(index.data().toString()); - - for(int j=0; j< model->rowCount(index); ++j) - { - QModelIndex son = model->index(j, 0, index ); - m_root.appendInside(son.data(HistoryModel::DateTimeRole).toDateTime().toString("hh:mm")); - m_root.appendInside(" "); - m_root.appendInside(markup("a")); - m_root.lastChild().setAttribute("href" , son.data(HistoryModel::UrlStringRole).toString()); - m_root.lastChild().appendInside(son.data().toString()); - m_root.appendInside("<br/>"); - } - } - i++; - } - while( model->hasIndex( i , 0 , QModelIndex() ) ); -} - - -void NewTabPage::bookmarksPage() -{ - KBookmarkGroup bookGroup = Application::bookmarkProvider()->rootGroup(); - if (bookGroup.isNull()) - { - return; - } - - KBookmark bookmark = bookGroup.first(); - while (!bookmark.isNull()) - { - createBookItem(bookmark, m_root); - bookmark = bookGroup.next(bookmark); - } -} - - -void NewTabPage::createBookItem(const KBookmark &bookmark, QWebElement parent) -{ - if (bookmark.isGroup()) - { - KBookmarkGroup group = bookmark.toGroup(); - KBookmark bm = group.first(); - parent.appendInside(markup("h3")); - parent.lastChild().setPlainText(group.text()); - parent.appendInside(markup(".bookfolder")); - while (!bm.isNull()) - { - createBookItem(bm, parent.lastChild()); // it is .bookfolder - bm = group.next(bm); - } - } - else if(bookmark.isSeparator()) - { - parent.appendInside("<hr/>"); - } - else - { - parent.appendInside(markup("a")); - parent.lastChild().setAttribute("href" , bookmark.url().prettyUrl()); - parent.lastChild().setPlainText(bookmark.text()); - parent.appendInside("<br/>"); - } -} - - -void NewTabPage::closedTabsPage() -{ - QList<HistoryItem> links = Application::instance()->mainWindow()->mainView()->recentlyClosedTabs(); - - foreach(const HistoryItem &item, links) - { - QWebElement closed = markup(".thumbnail"); - closed.findFirst("object").setAttribute("data" , item.url); - closed.findFirst("param[name=title]").setAttribute("value", item.title); - m_root.appendInside(closed); - } -} diff --git a/src/sessionmanager.cpp b/src/sessionmanager.cpp index f4e7cd3e..9e1f7baf 100644 --- a/src/sessionmanager.cpp +++ b/src/sessionmanager.cpp @@ -2,9 +2,9 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Yoram Bar-Haim <<yoram.b at zend dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -66,15 +66,15 @@ void SessionManager::saveSession() QFile sessionFile(m_sessionFilePath); if (!sessionFile.open(QFile::WriteOnly | QFile::Truncate)) { - kWarning() << "Unable to open session file" << sessionFile.fileName(); + kDebug() << "Unable to open session file" << sessionFile.fileName(); return; } QTextStream out(&sessionFile); MainWindowList wl = Application::instance()->mainWindowList(); - Q_FOREACH(QPointer<MainWindow> w, wl) + Q_FOREACH(QWeakPointer<MainWindow> w, wl) { out << "window\n"; - MainView *mv = w->mainView(); + MainView *mv = w.data()->mainView(); for (int i = 0 ; i < mv->count() ; i++) { out << mv->webTab(i)->url().toEncoded() << "\n"; @@ -93,7 +93,7 @@ bool SessionManager::restoreSession() return false; if (!sessionFile.open(QFile::ReadOnly)) { - kWarning() << "Unable to open session file" << sessionFile.fileName(); + kDebug() << "Unable to open session file" << sessionFile.fileName(); return false; } @@ -104,16 +104,17 @@ bool SessionManager::restoreSession() line = in.readLine(); if(line == QString("window")) { - Application::instance()->newMainWindow(); line = in.readLine(); - Application::instance()->loadUrl(line); + kDebug() << "New Window line: " << line; + Application::instance()->loadUrl(line, Rekonq::NewWindow); } else { + kDebug() << "New Current Tab line: " << line; Application::instance()->loadUrl(line, Rekonq::NewCurrentTab); } } - while(!line.isNull()); + while(!line.isEmpty()); return true; } diff --git a/src/sessionmanager.h b/src/sessionmanager.h index f1b7a71f..613b050f 100644 --- a/src/sessionmanager.h +++ b/src/sessionmanager.h @@ -2,9 +2,9 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Yoram Bar-Haim <<yoram.b at zend dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -30,6 +30,9 @@ #define SESSION_MANAGER_H +// Local Includes +#include "rekonqprivate_export.h" + // Qt Includes #include <QtCore/QObject> #include <QtCore/QString> @@ -38,7 +41,7 @@ /** * Session Management */ -class SessionManager : public QObject +class REKONQ_TESTS_EXPORT SessionManager : public QObject { Q_OBJECT public: diff --git a/src/settings/adblockwidget.cpp b/src/settings/adblockwidget.cpp new file mode 100644 index 00000000..2f431c1e --- /dev/null +++ b/src/settings/adblockwidget.cpp @@ -0,0 +1,193 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "adblockwidget.h" +#include "adblockwidget.moc" + +// Auto Includes +#include "rekonq.h" + +// KDE Includes +#include <KSharedConfig> +#include <KIcon> +#include <KDebug> + +// Qt Includes +#include <QString> +#include <QWhatsThis> +#include <QListWidgetItem> + + +AdBlockWidget::AdBlockWidget(QWidget *parent) + : QWidget(parent) + , _changed(false) +{ + setupUi(this); + + hintLabel->setText( i18n("<qt>Filter expression (e.g. <tt>http://www.example.com/ad/*</tt>, <a href=\"filterhelp\">more information</a>):") ); + connect( hintLabel, SIGNAL(linkActivated(const QString &)), this, SLOT(slotInfoLinkActivated(const QString &)) ); + + listWidget->setSortingEnabled(true); + listWidget->setSelectionMode(QAbstractItemView::SingleSelection); + + searchLine->setListWidget(listWidget); + + insertButton->setIcon( KIcon("list-add") ); + connect( insertButton, SIGNAL( clicked() ), this, SLOT( insertRule() ) ); + + removeButton->setIcon( KIcon("list-remove") ); + connect( removeButton, SIGNAL( clicked() ), this, SLOT( removeRule() ) ); + + load(); + + // emit changed signal + connect( insertButton, SIGNAL( clicked() ), this, SLOT( hasChanged() ) ); + connect( removeButton, SIGNAL( clicked() ), this, SLOT( hasChanged() ) ); + connect( checkEnableAdblock, SIGNAL( stateChanged(int) ), this, SLOT( hasChanged() ) ); + connect( checkHideAds, SIGNAL( stateChanged(int) ), this, SLOT( hasChanged() ) ); + connect( spinBox, SIGNAL( valueChanged(int) ), this, SLOT( hasChanged() ) ); +} + + +void AdBlockWidget::slotInfoLinkActivated(const QString &url) +{ + Q_UNUSED(url) + + QString hintHelpString = i18n("<qt><p>Enter an expression to filter. Filters can be defined as either:" + "<ul><li>a shell-style wildcard, e.g. <tt>http://www.example.com/ads*</tt>, the wildcards <tt>*?[]</tt> may be used</li>" + "<li>a full regular expression by surrounding the string with '<tt>/</tt>', e.g. <tt>/\\/(ad|banner)\\./</tt></li></ul>" + "<p>Any filter string can be preceded by '<tt>@@</tt>' to whitelist (allow) any matching URL, " + "which takes priority over any blacklist (blocking) filter."); + + QWhatsThis::showText( QCursor::pos(), hintHelpString ); +} + + +void AdBlockWidget::insertRule() +{ + QString rule = addFilterLineEdit->text(); + if(rule.isEmpty()) + return; + + listWidget->addItem( rule ); + addFilterLineEdit->clear(); +} + + +void AdBlockWidget::removeRule() +{ + listWidget->takeItem( listWidget->currentRow() ); +} + + +void AdBlockWidget::load() +{ + bool isAdBlockEnabled = ReKonfig::adBlockEnabled(); + checkEnableAdblock->setChecked(isAdBlockEnabled); + + bool areImageFiltered = ReKonfig::hideAdsEnabled(); + checkHideAds->setChecked(areImageFiltered); + + int days = ReKonfig::updateInterval(); + spinBox->setValue( days ); + + QStringList subscriptions = ReKonfig::subscriptionTitles(); + + // load automatic rules + foreach(QString sub, subscriptions) + { + QTreeWidgetItem *subItem = new QTreeWidgetItem(treeWidget); + subItem->setText(0, sub); + loadRules(subItem); + } + + // load local rules + KSharedConfig::Ptr config = KGlobal::config(); + KConfigGroup localGroup( config, "rules" ); + QStringList rules = localGroup.readEntry( "local-rules" , QStringList() ); + foreach(const QString &rule, rules) + { + listWidget->addItem( rule ); + } +} + + +void AdBlockWidget::loadRules(QTreeWidgetItem *item) +{ + KSharedConfig::Ptr config = KGlobal::config(); + KConfigGroup localGroup( config, "rules" ); + + QString str = item->text(0) + "-rules"; + kDebug() << str; + QStringList rules = localGroup.readEntry( str , QStringList() ); + + foreach(const QString &rule, rules) + { + QTreeWidgetItem *subItem = new QTreeWidgetItem(item); + subItem->setText(0, rule); + } +} + + +void AdBlockWidget::save() +{ + int n; + + // local rules + KSharedConfig::Ptr config = KGlobal::config(); + KConfigGroup localGroup( config , "rules" ); + + QStringList localRules; + + n = listWidget->count(); + for(int i = 0; i < n; ++i) + { + QListWidgetItem *item = listWidget->item(i); + localRules << item->text(); + } + localGroup.writeEntry( "local-rules" , localRules ); + + ReKonfig::setAdBlockEnabled( checkEnableAdblock->isChecked() ); + ReKonfig::setHideAdsEnabled( checkHideAds->isChecked() ); + ReKonfig::setUpdateInterval( spinBox->value() ); + + _changed = false; + emit changed(false); +} + + +void AdBlockWidget::hasChanged() +{ + _changed = true; + emit changed(true); +} + + +bool AdBlockWidget::changed() +{ + return _changed; +} diff --git a/src/settings/adblockwidget.h b/src/settings/adblockwidget.h new file mode 100644 index 00000000..7e641f3e --- /dev/null +++ b/src/settings/adblockwidget.h @@ -0,0 +1,66 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef ADBLOCK_WIDGET_H +#define ADBLOCK_WIDGET_H + + +// Ui Includes +#include "ui_settings_adblock.h" + +// Qt Includes +#include <QWidget> +#include <QTreeWidgetItem> + + +class AdBlockWidget : public QWidget, private Ui::adblock +{ +Q_OBJECT + +public: + AdBlockWidget(QWidget *parent = 0); + + void save(); + bool changed(); + +signals: + void changed(bool); + +private slots: + void hasChanged(); + + void slotInfoLinkActivated(const QString &); + void insertRule(); + void removeRule(); + +private: + void load(); + void loadRules(QTreeWidgetItem *item); + + bool _changed; +}; + +#endif // ADBLOCK_WIDGET_H diff --git a/src/settings/networkwidget.cpp b/src/settings/networkwidget.cpp new file mode 100644 index 00000000..54f6e068 --- /dev/null +++ b/src/settings/networkwidget.cpp @@ -0,0 +1,101 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "networkwidget.h" +#include "networkwidget.moc" + +// KDE Includes +#include <KTabWidget> +#include <KCModuleInfo> +#include <KDebug> + +// Qt Includes +#include <QVBoxLayout> + + +NetworkWidget::NetworkWidget(QWidget *parent) + : QWidget(parent) + , _cacheModule(0) + , _cookiesModule(0) + , _proxyModule(0) + , _changed(false) +{ + QVBoxLayout *l = new QVBoxLayout(this); + l->setMargin(0); + l->setSpacing(0); + + KTabWidget *tabWidget = new KTabWidget(this); + l->addWidget(tabWidget); + + KCModuleInfo cacheInfo("cache.desktop"); + _cacheModule = new KCModuleProxy(cacheInfo,parent); + tabWidget->addTab( _cacheModule, i18n(cacheInfo.moduleName().toLocal8Bit()) ); + + KCModuleInfo cookiesInfo("cookies.desktop"); + _cookiesModule = new KCModuleProxy(cookiesInfo,parent); + tabWidget->addTab( _cookiesModule, i18n(cookiesInfo.moduleName().toLocal8Bit()) ); + + KCModuleInfo proxyInfo("proxy.desktop"); + _proxyModule = new KCModuleProxy(proxyInfo,parent); + tabWidget->addTab( _proxyModule, i18n(proxyInfo.moduleName().toLocal8Bit()) ); + + connect(_cacheModule, SIGNAL( changed(bool) ), this, SLOT( hasChanged() ) ); + connect(_cookiesModule, SIGNAL( changed(bool) ), this, SLOT( hasChanged() ) ); + connect(_proxyModule, SIGNAL( changed(bool) ), this, SLOT( hasChanged() ) ); +} + + +NetworkWidget::~NetworkWidget() +{ + delete _cacheModule; + delete _cookiesModule; + delete _proxyModule; +} + + +void NetworkWidget::save() +{ + _cookiesModule->save(); + _proxyModule->save(); + _cacheModule->save(); + + _changed = false; + emit changed(false); +} + + +void NetworkWidget::hasChanged() +{ + _changed = true; + emit changed(true); +} + + +bool NetworkWidget::changed() +{ + return _changed; +} diff --git a/src/settings/networkwidget.h b/src/settings/networkwidget.h new file mode 100644 index 00000000..efdd1807 --- /dev/null +++ b/src/settings/networkwidget.h @@ -0,0 +1,63 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef NETWORK_WIDGET_H +#define NETWORK_WIDGET_H + + +// KDE Includes +#include <KCModuleProxy> + +// Qt Includes +#include <QWidget> + + +class NetworkWidget : public QWidget +{ +Q_OBJECT + +public: + NetworkWidget(QWidget *parent = 0); + ~NetworkWidget(); + + void save(); + bool changed(); + +signals: + void changed(bool); + +private slots: + void hasChanged(); + +private: + KCModuleProxy *_cacheModule; + KCModuleProxy *_cookiesModule; + KCModuleProxy *_proxyModule; + + bool _changed; +}; + +#endif // NETWORK_WIDGET_H diff --git a/src/settings/settings_adblock.ui b/src/settings/settings_adblock.ui new file mode 100644 index 00000000..445431c5 --- /dev/null +++ b/src/settings/settings_adblock.ui @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>adblock</class> + <widget class="QWidget" name="adblock"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>601</width> + <height>507</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QCheckBox" name="checkEnableAdblock"> + <property name="text"> + <string>&Enable AdBlock</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkHideAds"> + <property name="text"> + <string>&Hide filtered Elements</string> + </property> + </widget> + </item> + <item> + <widget class="KTabWidget" name="tabWidget"> + <property name="toolTip"> + <string/> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab_3"> + <attribute name="title"> + <string>Automatic Filters</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QTreeWidget" name="treeWidget"> + <column> + <property name="text"> + <string notr="true">1</string> + </property> + </column> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Automatic update interval:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="spinBox"> + <property name="value"> + <number>7</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Manual Filters</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Search:</string> + </property> + </widget> + </item> + <item> + <widget class="KListWidgetSearchLine" name="searchLine"/> + </item> + </layout> + </item> + <item> + <widget class="KListWidget" name="listWidget"/> + </item> + <item> + <widget class="QLabel" name="hintLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="KLineEdit" name="addFilterLineEdit"/> + </item> + <item> + <widget class="QToolButton" name="insertButton"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="removeButton"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KListWidget</class> + <extends>QListWidget</extends> + <header>klistwidget.h</header> + </customwidget> + <customwidget> + <class>KLineEdit</class> + <extends>QLineEdit</extends> + <header>klineedit.h</header> + </customwidget> + <customwidget> + <class>KTabWidget</class> + <extends>QTabWidget</extends> + <header>ktabwidget.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>KListWidgetSearchLine</class> + <extends>KLineEdit</extends> + <header>klistwidgetsearchline.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/settings/settings_general.ui b/src/settings/settings_general.ui index a4503d4a..00277133 100644 --- a/src/settings/settings_general.ui +++ b/src/settings/settings_general.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>751</width> - <height>523</height> + <width>552</width> + <height>512</height> </rect> </property> <property name="windowTitle"> @@ -150,11 +150,11 @@ <item> <widget class="QGroupBox" name="groupBox_3"> <property name="title"> - <string>New Tabs Behaviour</string> + <string>Search Engine</string> </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QLabel" name="label_4"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLabel" name="label_3"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -169,20 +169,20 @@ </property> <property name="baseSize"> <size> - <width>120</width> + <width>0</width> <height>0</height> </size> </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> <property name="text"> - <string>New tab opens:</string> + <string>Default search engine:</string> </property> </widget> </item> - <item row="0" column="1"> - <widget class="KComboBox" name="kcfg_newTabsBehaviour"> - <property name="enabled"> - <bool>true</bool> - </property> + <item> + <widget class="KComboBox" name="kcfg_searchEngine"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -191,75 +191,27 @@ </property> <item> <property name="text"> - <string>New Tab Page</string> + <string>google</string> </property> </item> <item> <property name="text"> - <string>Blank Page</string> + <string>altavista</string> </property> </item> <item> <property name="text"> - <string comment="@item:inlistbox">Home Page</string> - </property> - </item> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_5"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>120</width> - <height>0</height> - </size> - </property> - <property name="baseSize"> - <size> - <width>120</width> - <height>0</height> - </size> - </property> - <property name="text"> - <string>New tab page starts with:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="KComboBox" name="kcfg_newTabStartPage"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <item> - <property name="text"> - <string>Favorites</string> + <string>lycos</string> </property> </item> <item> <property name="text"> - <string>Closed Tabs</string> + <string>wikipedia</string> </property> </item> <item> <property name="text"> - <string>Bookmarks</string> - </property> - </item> - <item> - <property name="text"> - <string>History</string> + <string>wolfram</string> </property> </item> </widget> @@ -272,21 +224,21 @@ <property name="title"> <string>Download Manager</string> </property> - <layout class="QHBoxLayout" name="horizontalLayout_5"> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QCheckBox" name="kcfg_kgetDownload"> + <widget class="QCheckBox" name="kcfg_kgetList"> + <property name="whatsThis"> + <string>If enabled, rekonq will display an additional context menu entry, which, when selected, lists all available links of the current website in KGet.</string> + </property> <property name="text"> - <string>Use KGet for downloading files</string> + <string>List links with KGet</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="kcfg_kgetList"> - <property name="whatsThis"> - <string>If enabled, rekonq will display an additional context menu entry, which, when selected, lists all available links of the current website in KGet.</string> - </property> + <widget class="QCheckBox" name="kcfg_kgetDownload"> <property name="text"> - <string>List links with KGet</string> + <string>Use KGet for downloading files</string> </property> </widget> </item> @@ -301,7 +253,7 @@ <property name="sizeHint" stdset="0"> <size> <width>20</width> - <height>40</height> + <height>179</height> </size> </property> </spacer> diff --git a/src/settings/settings_tabs.ui b/src/settings/settings_tabs.ui index 9104843a..45579e90 100644 --- a/src/settings/settings_tabs.ui +++ b/src/settings/settings_tabs.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>456</width> - <height>329</height> + <width>483</width> + <height>427</height> </rect> </property> <property name="windowTitle"> @@ -15,6 +15,131 @@ </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>New Tabs Behaviour</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>120</width> + <height>0</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>120</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>New tab opens:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="KComboBox" name="kcfg_newTabsBehaviour"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <item> + <property name="text"> + <string>New Tab Page</string> + </property> + </item> + <item> + <property name="text"> + <string>Blank Page</string> + </property> + </item> + <item> + <property name="text"> + <string comment="@item:inlistbox">Home Page</string> + </property> + </item> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_5"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>120</width> + <height>0</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>120</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>New tab page starts with:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="KComboBox" name="kcfg_newTabStartPage"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <item> + <property name="text"> + <string>Favorites</string> + </property> + </item> + <item> + <property name="text"> + <string>Closed Tabs</string> + </property> + </item> + <item> + <property name="text"> + <string>Bookmarks</string> + </property> + </item> + <item> + <property name="text"> + <string>History</string> + </property> + </item> + <item> + <property name="text"> + <string>Downloads</string> + </property> + </item> + </widget> + </item> + </layout> + </widget> + </item> + <item> <widget class="QGroupBox" name="groupBox_4"> <property name="title"> <string>Tabbed Browsing</string> @@ -79,13 +204,20 @@ <property name="sizeHint" stdset="0"> <size> <width>20</width> - <height>142</height> + <height>120</height> </size> </property> </spacer> </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>KComboBox</class> + <extends>QComboBox</extends> + <header>kcombobox.h</header> + </customwidget> + </customwidgets> <resources/> <connections/> </ui> diff --git a/src/settings/settings_webkit.ui b/src/settings/settings_webkit.ui index 5074522b..e424fd9c 100644 --- a/src/settings/settings_webkit.ui +++ b/src/settings/settings_webkit.ui @@ -148,13 +148,7 @@ </widget> </item> <item> - <widget class="QComboBox" name="kcfg_pluginsEnabled"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> + <widget class="KComboBox" name="kcfg_pluginsEnabled"> <item> <property name="text"> <string>Autoload Plugins</string> @@ -219,6 +213,11 @@ <extends>QFrame</extends> <header>kurlrequester.h</header> </customwidget> + <customwidget> + <class>KComboBox</class> + <extends>QComboBox</extends> + <header>kcombobox.h</header> + </customwidget> </customwidgets> <resources/> <connections/> diff --git a/src/settings/settingsdialog.cpp b/src/settings/settingsdialog.cpp index e37481aa..35f753d3 100644 --- a/src/settings/settingsdialog.cpp +++ b/src/settings/settingsdialog.cpp @@ -2,9 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -37,6 +36,8 @@ #include "application.h" #include "mainwindow.h" #include "webtab.h" +#include "adblockwidget.h" +#include "networkwidget.h" //Ui Includes #include "ui_settings_general.h" @@ -53,7 +54,6 @@ #include <KCModuleProxy> // Qt Includes -#include <QtCore/QPointer> #include <QtGui/QWidget> @@ -65,12 +65,12 @@ private: Ui::tabs tabsUi; Ui::fonts fontsUi; Ui::webkit webkitUi; + + AdBlockWidget *adBlockWidg; + NetworkWidget *networkWidg; - KCModuleProxy *proxyModule; KCModuleProxy *ebrowsingModule; - KCModuleProxy *cookiesModule; - KCModuleProxy *cacheModule; - KCModuleProxy *adblockModule; + KShortcutsEditor *shortcutsEditor; Private(SettingsDialog *parent); @@ -101,21 +101,6 @@ Private::Private(SettingsDialog *parent) widget->layout()->setMargin(0); pageItem = parent->addPage(widget , i18n("Fonts")); pageItem->setIcon(KIcon("preferences-desktop-font")); - - KCModuleInfo cookiesInfo("cookies.desktop"); - cookiesModule = new KCModuleProxy(cookiesInfo,parent); - pageItem = parent->addPage(cookiesModule, i18n(cookiesInfo.moduleName().toLocal8Bit())); - pageItem->setIcon(KIcon(cookiesInfo.icon())); - - KCModuleInfo proxyInfo("proxy.desktop"); - proxyModule = new KCModuleProxy(proxyInfo,parent); - pageItem = parent->addPage(proxyModule, i18n(proxyInfo.moduleName().toLocal8Bit())); - pageItem->setIcon(KIcon(proxyInfo.icon())); - - KCModuleInfo cacheInfo("cache.desktop"); - cacheModule = new KCModuleProxy(cacheInfo,parent); - pageItem = parent->addPage(cacheModule, i18n(cacheInfo.moduleName().toLocal8Bit())); - pageItem->setIcon(KIcon(cacheInfo.icon())); widget = new QWidget; webkitUi.setupUi(widget); @@ -125,10 +110,15 @@ Private::Private(SettingsDialog *parent) KIcon webkitIcon = KIcon(QIcon(webkitIconPath)); pageItem->setIcon(webkitIcon); - KCModuleInfo adblockInfo("khtml_filter.desktop"); - adblockModule = new KCModuleProxy(adblockInfo,parent); - pageItem = parent->addPage(adblockModule, i18n(adblockInfo.moduleName().toLocal8Bit())); - pageItem->setIcon(KIcon(adblockInfo.icon())); + networkWidg = new NetworkWidget(parent); + networkWidg->layout()->setMargin(0); + pageItem = parent->addPage(networkWidg , i18n("Network")); + pageItem->setIcon( KIcon("preferences-system-network") ); + + adBlockWidg = new AdBlockWidget(parent); + adBlockWidg->layout()->setMargin(0); + pageItem = parent->addPage(adBlockWidg , i18n("Ad Block")); + pageItem->setIcon( KIcon("preferences-web-browser-adblock") ); shortcutsEditor = new KShortcutsEditor(Application::instance()->mainWindow()->actionCollection(), parent); pageItem = parent->addPage(shortcutsEditor , i18n("Shortcuts")); @@ -139,8 +129,8 @@ Private::Private(SettingsDialog *parent) pageItem = parent->addPage(ebrowsingModule, i18n(ebrowsingInfo.moduleName().toLocal8Bit())); pageItem->setIcon(KIcon(ebrowsingInfo.icon())); - // WARNING remember wheh changing here that the smaller netbooks - // have a 1024x576 resolution. So DONT bother that limits!! + // WARNING remember wheh changing here that the smallest netbooks + // have a 1024x576 resolution. So DON'T bother that limits!! parent->setMinimumSize(700,525); } @@ -153,23 +143,23 @@ SettingsDialog::SettingsDialog(QWidget *parent) , d(new Private(this)) { showButtonSeparator(false); - setWindowTitle(i18n("Configure - rekonq")); + setWindowTitle(i18nc("Window title of the settings dialog", "Configure – rekonq")); setModal(true); readConfig(); connect(d->generalUi.setHomeToCurrentPageButton, SIGNAL(clicked()), this, SLOT(setHomeToCurrentPage())); + // update buttons + connect(d->adBlockWidg, SIGNAL(changed(bool)), this, SLOT(updateButtons())); + connect(d->networkWidg, SIGNAL(changed(bool)), this, SLOT(updateButtons())); connect(d->ebrowsingModule, SIGNAL(changed(bool)), this, SLOT(updateButtons())); - connect(d->cookiesModule, SIGNAL(changed(bool)), this, SLOT(updateButtons())); - connect(d->proxyModule, SIGNAL(changed(bool)), this, SLOT(updateButtons())); - connect(d->cacheModule, SIGNAL(changed(bool)), this, SLOT(updateButtons())); - connect(d->adblockModule, SIGNAL(changed(bool)), this, SLOT(updateButtons())); - connect(d->shortcutsEditor, SIGNAL(keyChange()), this, SLOT(updateButtons())); - + connect(d->shortcutsEditor, SIGNAL(keyChange()), this, SLOT(updateButtons())); + + // save settings connect(this, SIGNAL(applyClicked()), this, SLOT(saveSettings())); - connect(this, SIGNAL(okClicked()), this, SLOT(saveSettings())); + connect(this, SIGNAL(okClicked()), this, SLOT(saveSettings())); setWebSettingsToolTips(); } @@ -209,24 +199,26 @@ void SettingsDialog::readConfig() // we need this function to SAVE settings in rc file.. void SettingsDialog::saveSettings() { + if (!hasChanged()) + return; + ReKonfig::self()->writeConfig(); d->ebrowsingModule->save(); - d->cookiesModule->save(); - d->proxyModule->save(); - d->cacheModule->save(); d->shortcutsEditor->save(); - d->adblockModule->save(); + d->adBlockWidg->save(); + d->networkWidg->save(); + + updateButtons(); + emit settingsChanged("ReKonfig"); } bool SettingsDialog::hasChanged() { return KConfigDialog::hasChanged() - || d->ebrowsingModule->changed() - || d->cookiesModule->changed() - || d->proxyModule->changed() - || d->cacheModule->changed() - || d->adblockModule->changed() + || d->adBlockWidg->changed() + || d->networkWidg->changed() + || d->ebrowsingModule->changed() || d->shortcutsEditor->isModified(); ; } diff --git a/src/settings/settingsdialog.h b/src/settings/settingsdialog.h index 360fe246..54494a00 100644 --- a/src/settings/settingsdialog.h +++ b/src/settings/settingsdialog.h @@ -2,9 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -30,6 +29,9 @@ #define SETTINGS_DIALOG_H +// Local Includes +#include "rekonqprivate_export.h" + // KDE Includes #include <KConfigDialog> @@ -38,7 +40,7 @@ class QWidget; class Private; -class SettingsDialog : public KConfigDialog +class REKONQ_TESTS_EXPORT SettingsDialog : public KConfigDialog { Q_OBJECT diff --git a/src/sslinfodialog_p.h b/src/sslinfodialog_p.h new file mode 100644 index 00000000..44d3ab7c --- /dev/null +++ b/src/sslinfodialog_p.h @@ -0,0 +1,107 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2000-2003 George Staikos <staikos@kde.org> + * Copyright (C) 2000 Malte Starostik <malte@kde.org> + * + * 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 SSLINFODIALOG_P_H +#define SSLINFODIALOG_P_H + +#include <kdemacros.h> + +#include <KDE/KDialog> +#include <ktcpsocket.h> + +// NOTE: We need a copy of this header file is needed here because it +// is never installed by default by KIO. + +/** + * KDE SSL Information Dialog + * + * This class creates a dialog that can be used to display information about + * an SSL session. + * + * There are NO GUARANTEES that KSslInfoDialog will remain binary compatible/ + * Contact staikos@kde.org for details if needed. + * + * @author George Staikos <staikos@kde.org> + * @see KSSL + * @short KDE SSL Information Dialog + */ +class KDE_EXPORT KSslInfoDialog : public KDialog +{ +Q_OBJECT + +public: + /** + * Construct a KSSL Information Dialog + * + * @param parent the parent widget + */ + explicit KSslInfoDialog(QWidget *parent = 0); + + /** + * Destroy this dialog + */ + virtual ~KSslInfoDialog(); + + /** + * Tell the dialog if the connection has portions that may not be + * secure (ie. a mixture of secure and insecure frames) + * + * @param isIt true if security is in question + */ + void setSecurityInQuestion(bool isIt); + + /** + * Set information to display about the SSL connection. + * + * @param certificateChain the certificate chain leading from the certificate + * authority to the peer. + * @param ip the ip of the remote host + * @param host the remote hostname + * @param sslProtocol the version of SSL in use (SSLv2, SSLv3, TLSv1) + * @param cipher the cipher in use + * @param usedBits the used bits of the key + * @param bits the key size of the cipher in use + * @param validationErrors errors validating the certificates, if any + */ + void setSslInfo(const QList<QSslCertificate> &certificateChain, + const QString &ip, const QString &host, + const QString &sslProtocol, const QString &cipher, + int usedBits, int bits, + const QList<QList<KSslError::Error> > &validationErrors); + + void setMainPartEncrypted(bool); + void setAuxiliaryPartsEncrypted(bool); + + static QList<QList<KSslError::Error> > errorsFromString(const QString &s); + +private Q_SLOTS: + void launchConfig(); + void displayFromChain(int); + +private: + void updateWhichPartsEncrypted(); + + class KSslInfoDialogPrivate; + KSslInfoDialogPrivate* const d; +}; + +#endif // SSLINFODIALOG_P_H diff --git a/src/tabbar.cpp b/src/tabbar.cpp index 460a2464..f8da57b1 100644 --- a/src/tabbar.cpp +++ b/src/tabbar.cpp @@ -3,9 +3,9 @@ * This file is a part of the rekonq project * * Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -93,13 +93,13 @@ QSize TabBar::tabSizeHint(int index) const int minWidth = view->sizeHint().width()/MIN_WIDTH_DIVISOR; int w; - if (baseWidth*count()<tabBarWidth) + if (baseWidth*count() < tabBarWidth) { w = baseWidth; } else { - if (count() > 0 && tabBarWidth/count()>minWidth) + if (count() > 0 && tabBarWidth/count() > minWidth) { w = tabBarWidth/count(); } @@ -150,40 +150,49 @@ void TabBar::showTabPreview(int tab) { MainView *mv = qobject_cast<MainView *>(parent()); - WebTab *view = mv->webTab(tab); - WebTab *currentView = mv->webTab(currentIndex()); + WebTab *indexedTab = mv->webTab(tab); + WebTab *currentTab = mv->webTab(currentIndex()); // check if view && currentView exist before using them :) - if(!currentView || !view) + if(!currentTab || !indexedTab) return; int w = tabSizeHint(tab).width(); - int h = w*((0.0 + currentView->height())/currentView->width()); + int h = w * ( (0.0 + currentTab->height()) / currentTab->width() ); //delete previous tab preview - if (m_previewPopup) - { - delete m_previewPopup; - } - + delete m_previewPopup.data(); + m_previewPopup.clear(); + + if (indexedTab->progress() != 0) + return; + m_previewPopup = new KPassivePopup(this); - m_previewPopup->setFrameShape(QFrame::StyledPanel); - m_previewPopup->setFrameShadow(QFrame::Plain); - m_previewPopup->setFixedSize(w, h); + m_previewPopup.data()->setFrameShape(QFrame::StyledPanel); + m_previewPopup.data()->setFrameShadow(QFrame::Plain); + m_previewPopup.data()->setFixedSize(w, h); + QLabel *l = new QLabel(); - view->page()->setViewportSize(currentView->page()->viewportSize()); - l->setPixmap(WebSnap::renderPreview(*(view->page()), w, h)); - m_previewPopup->setView(l); - m_previewPopup->layout()->setAlignment(Qt::AlignTop); - m_previewPopup->layout()->setMargin(0); - - QPoint pos( tabRect(tab).x() , tabRect(tab).y() + tabRect(tab).height() ); - m_previewPopup->show(mapToGlobal(pos)); + l->setPixmap( WebSnap::renderPreview( *indexedTab->page(), w, h, true) ); + + m_previewPopup.data()->setView(l); + m_previewPopup.data()->layout()->setAlignment(Qt::AlignTop); + m_previewPopup.data()->layout()->setMargin(0); + + QPoint pos( tabRect(tab).x() , tabRect(tab).y() + tabRect(tab).height()); + m_previewPopup.data()->show(mapToGlobal(pos)); } void TabBar::mouseMoveEvent(QMouseEvent *event) { + if (event->buttons() & Qt::LeftButton) + { + // hide addNewTabButton when moving tabs + MainView *view = qobject_cast<MainView *>(parent()); + QTimer::singleShot(200, view->addTabButton(), SLOT(hide())); + } + if (ReKonfig::alwaysShowTabPreviews()) { //Find the tab under the mouse @@ -208,9 +217,9 @@ void TabBar::mouseMoveEvent(QMouseEvent *event) //if current tab or not found then hide previous tab preview if (tab==currentIndex() || tab==-1) { - if ( m_previewPopup) + if ( !m_previewPopup.isNull() ) { - m_previewPopup->hide(); + m_previewPopup.data()->hide(); } m_currentTabPreview = -1; } @@ -225,9 +234,9 @@ void TabBar::leaveEvent(QEvent *event) if (ReKonfig::alwaysShowTabPreviews()) { //if leave tabwidget then hide previous tab preview - if ( m_previewPopup) + if ( !m_previewPopup.isNull() ) { - m_previewPopup->hide(); + m_previewPopup.data()->hide(); } m_currentTabPreview = -1; } @@ -238,6 +247,15 @@ void TabBar::leaveEvent(QEvent *event) void TabBar::mousePressEvent(QMouseEvent *event) { + if (ReKonfig::alwaysShowTabPreviews()) + { + if ( !m_previewPopup.isNull() ) + { + m_previewPopup.data()->hide(); + } + m_currentTabPreview = -1; + } + // just close tab on middle mouse click if (event->button() == Qt::MidButton) return; @@ -278,3 +296,26 @@ void TabBar::emptyAreaContextMenu(const QPoint &pos) menu.exec(pos); } + + +void TabBar::mouseReleaseEvent(QMouseEvent *event) +{ + MainView *mv = qobject_cast<MainView *>(parent()); + QTimer::singleShot(200, mv->addTabButton(), SLOT(show())); + + KTabBar::mouseReleaseEvent(event); +} + + +void TabBar::tabRemoved(int index) +{ + Q_UNUSED(index) + if (ReKonfig::alwaysShowTabPreviews()) + { + if ( !m_previewPopup.isNull() ) + { + m_previewPopup.data()->hide(); + } + m_currentTabPreview = -1; + } +} diff --git a/src/tabbar.h b/src/tabbar.h index f0476cbd..97c320fc 100644 --- a/src/tabbar.h +++ b/src/tabbar.h @@ -3,9 +3,9 @@ * This file is a part of the rekonq project * * Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> * Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -35,7 +35,7 @@ #include "rekonqprivate_export.h" // Qt Includes -#include <QPointer> +#include <QWeakPointer> // KDE Includes #include <KTabBar> @@ -80,6 +80,8 @@ protected: virtual void mouseMoveEvent(QMouseEvent *event); virtual void leaveEvent(QEvent *event); virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void tabRemoved(int); private slots: void cloneTab(); @@ -99,7 +101,7 @@ private: */ int m_actualIndex; - QPointer<KPassivePopup> m_previewPopup; + QWeakPointer<KPassivePopup> m_previewPopup; int m_currentTabPreview; }; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 5df23e24..3bc9a27f 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -2,16 +2,34 @@ SET( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) -INCLUDE_DIRECTORIES ( ${CMAKE_CURRENT_BINARY_DIR}/.. +INCLUDE_DIRECTORIES ( ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../adblock + ${CMAKE_CURRENT_SOURCE_DIR}/../bookmarks + ${CMAKE_CURRENT_SOURCE_DIR}/../history + ${CMAKE_CURRENT_SOURCE_DIR}/../settings + ${CMAKE_CURRENT_SOURCE_DIR}/../urlbar ${KDE4_INCLUDES} ${QT4_INCLUDES} ) -##### ------------- tabbar test +##### ------------- findbar test -kde4_add_unit_test( tabbar_test tabbar_test.cpp ) +kde4_add_unit_test( findbar_test findbar_test.cpp ) -target_link_libraries( tabbar_test +target_link_libraries( findbar_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${QT_QTGUI_LIBRARY} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- mainwindow test + +kde4_add_unit_test( mainwindow_test mainwindow_test.cpp ) + +target_link_libraries( mainwindow_test kdeinit_rekonq ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBS} @@ -29,4 +47,122 @@ target_link_libraries( mainview_test ${QT_QTTEST_LIBRARY} ) +##### ------------- networkaccessmanager test + +kde4_add_unit_test( networkaccessmanager_test networkaccessmanager_test.cpp ) + +target_link_libraries( networkaccessmanager_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- protocolhandler test + +kde4_add_unit_test( protocolhandler_test protocolhandler_test.cpp ) + +target_link_libraries( protocolhandler_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KDEWEBKIT_LIBS} + ${QT_QTNETWORK_LIBRARY} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- sessionmanager test + +kde4_add_unit_test( sessionmanager_test sessionmanager_test.cpp ) + +target_link_libraries( sessionmanager_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- tabbar test + +kde4_add_unit_test( tabbar_test tabbar_test.cpp ) + +target_link_libraries( tabbar_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- walletbar test + +kde4_add_unit_test( walletbar_test walletbar_test.cpp ) + +target_link_libraries( walletbar_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KDEWEBKIT_LIBS} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- webpage test + +kde4_add_unit_test( webpage_test webpage_test.cpp ) + +target_link_libraries( webpage_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KDEWEBKIT_LIBS} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- websnap test + +kde4_add_unit_test( websnap_test websnap_test.cpp ) + +target_link_libraries( websnap_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KDEWEBKIT_LIBS} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- webtab test + +kde4_add_unit_test( webtab_test webtab_test.cpp ) + +target_link_libraries( webtab_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KDEWEBKIT_LIBS} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- webview test + +kde4_add_unit_test( webview_test webview_test.cpp ) + +target_link_libraries( webview_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KDEWEBKIT_LIBS} + ${QT_QTTEST_LIBRARY} +) + +##### ------------- urlbar test + +kde4_add_unit_test( urlbar_test urlbar_test.cpp ) + +target_link_libraries( urlbar_test + kdeinit_rekonq + ${KDE4_KDECORE_LIBS} + ${KDE4_KDEUI_LIBS} + ${KDE4_KDEWEBKIT_LIBS} + ${QT_QTTEST_LIBRARY} +) + ############################################################ diff --git a/src/tests/HTTP_tests.html b/src/tests/HTTP_tests.html new file mode 100644 index 00000000..7a5ac00d --- /dev/null +++ b/src/tests/HTTP_tests.html @@ -0,0 +1,601 @@ +<html> + +<head> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +<title>Test Cases for HTTP Content-Disposition header and RFC 2231/2047 Encoding</title> + +<style type="text/css"> +a.plain { + color: black; + text-decoration: none; +} +body { + color: black; + font-family: verdana, helvetica, arial, sans-serif; + font-size: 10pt; + margin-left: 2em; +} +h1 { + font-size: 18pt; +} +h2 { + font-size: 14pt; +} +h3 { + font-size: 12pt; +} +h4 { + font-size: 10pt; +} +pre { + border-style: dotted; + border-width: 1px; + background-color: #f0f0f0; +} +pre.invalid { + border-style: dotted; + border-width: 1px; + background-color: #ff8080; +} +table { + font-size: 9pt; +} +table.aside { + float: right; + margin: 4px; + border-style: dotted; + border-width: 1px; + background-color: #f0f0f0; +} +q { + font-style: italic; +} +th { + text-align: right; + vertical-align: top; +} +h2, h3, h4 { + clear: both; +} +.fail { + background-color: #ffd0d0; +} +.warn { + background-color: #ffff80; +} +.pass { + background-color: #d0ffd0; +} +.unsupported { + background-color: #e0e0e0; +} + +</style> + +</head> + +<body> + +<h1>Test Cases for HTTP Content-Disposition header and RFC 2231/2047 Encoding</h1> + + +<h2>Test Cases</h2><div id="c-d-inline"><h3><a href="#c-d-inline" class="plain">Content-Disposition: Disposition-Type Inline</a></h3> + <p> + Various tests relating to the "inline" disposition type, see + <a href="http://greenbytes.de/tech/webdav/rfc2183.html#rfc.section.2.1">Section 2.1 of RFC 2183</a>. + </p> + <div id="inlonly"><h4><a href="#inlonly" class="plain">inlonly</a> + [<a href="http://greenbytes.de/tech/tc2231/inlonly.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>inline</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p>'inline' only</p><p><em>This should be equivalent to not including the header at all.</em></p></div><div id="inlwithasciifilename"><h4><a href="#inlwithasciifilename" class="plain">inlwithasciifilename</a> + [<a href="http://greenbytes.de/tech/tc2231/inlwithasciifilename.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>inline; filename="<b>foo.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass + (uses the filename in subsequent 'save' operation) + </td></tr><tr class="pass"><td>MSIE8</td><td>pass + (filename information not used) + </td></tr><tr class="pass"><td>Op10</td><td>pass + (filename information not used) + </td></tr><tr class="pass"><td>Saf4</td><td>pass + (filename information not used) + </td></tr><tr class="pass"><td>Konq</td><td>pass + (filename information not used) + </td></tr><tr class="pass"><td>Chrome</td><td>pass + (filename information not used) + </td></tr></tbody></table><p> + 'inline', specifying a filename of <code>foo.html</code> + </p><p><em> + Some UAs use this filename in a subsequent "save" operation. + </em></p></div><div id="inlwithasciifilenamepdf"><h4><a href="#inlwithasciifilenamepdf" class="plain">inlwithasciifilenamepdf</a> + [<a href="http://greenbytes.de/tech/tc2231/inlwithasciifilenamepdf.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>inline; filename="<b>foo.pdf</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass + (filename information not used) + </td></tr><tr class="pass"><td>MSIE8</td><td>pass + (filename information not used) + </td></tr><tr class="pass"><td>Op10</td><td>pass + (filename information not used) + </td></tr><tr class="pass"><td>Saf4</td><td>pass + (filename information not used) + </td></tr><tr class="pass"><td>Konq</td><td>pass + (filename information not used) + </td></tr><tr class="pass"><td>Chrome</td><td>pass + (filename information not used) + </td></tr></tbody></table><p> + 'inline', specifying a filename of <code>foo.pdf</code> + </p><p><em> + Some UAs use this filename in a subsequent "save" operation. + This variation of the test checks whether whatever handles PDF display + receives the filename information, and acts upon it + (this was tested with the latest Acrobat Reader plugin). + </em></p></div></div><div id="c-d-attachment"><h3><a href="#c-d-attachment" class="plain">Content-Disposition: Disposition-Type Attachment</a></h3> + <p> + Various tests relating to the "attchment" disposition type, see + <a href="http://greenbytes.de/tech/webdav/rfc2183.html#rfc.section.2.2">Section 2.2 of RFC 2183</a>. + </p> + <div id="attonly"><h4><a href="#attonly" class="plain">attonly</a> + [<a href="http://greenbytes.de/tech/tc2231/attonly.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p>'attachment' only</p><p><em>UA should offer to download the resource.</em></p></div><div id="attonlyucase"><h4><a href="#attonlyucase" class="plain">attonlyucase</a> + [<a href="http://greenbytes.de/tech/tc2231/attonlyucase.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>ATTACHMENT</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="fail"><td>Konq</td><td>fail</td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p>'ATTACHMENT' only</p><p><em>UA should offer to download the resource.</em></p></div><div id="attwithasciifilename"><h4><a href="#attwithasciifilename" class="plain">attwithasciifilename</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithasciifilename.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename="<b>foo.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo.html</code> + </p><p><em>UA should offer to download the resource as "foo.html".</em></p></div><div id="attwithasciifnescapedchar"><h4><a href="#attwithasciifnescapedchar" class="plain">attwithasciifnescapedchar</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithasciifnescapedchar.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename="<b>f\oo.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="fail"><td>FF3</td><td>fail + (apparently does not treat the backslash as escape character, replaces it with '_') + </td></tr><tr class="fail"><td>MSIE8</td><td>fail + (apparently does not treat the backslash as escape character, replaces it with '_') + </td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="fail"><td>Saf4</td><td>fail + (apparently does not treat the backslash as escape character, replaces it with '-') + </td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="fail"><td>Chrome</td><td>fail + (saves "oo.html" (what's going on here?)) + </td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>f\oo.html</code> (the first 'o' being escaped) + </p><p><em>UA should offer to download the resource as "foo.html".</em></p></div><div id="attwithfilenameandextparam"><h4><a href="#attwithfilenameandextparam" class="plain">attwithfilenameandextparam</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfilenameandextparam.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; foo="bar"; filename="<b>foo.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo.html</code> + and an extension parameter "foo" which should be ignored + (see <a href="http://greenbytes.de/tech/webdav/rfc2183.html#rfc.section.2.8">Section 2.8 of RFC 2183</a>.). + </p><p><em>UA should offer to download the resource as "foo.html".</em></p></div><div id="attwithasciifilenameucase"><h4><a href="#attwithasciifilenameucase" class="plain">attwithasciifilenameucase</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithasciifilenameucase.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; FILENAME="<b>foo.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="fail"><td>Konq</td><td>fail + (filename parameter is ignored) + </td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo.html</code> + </p><p><em>UA should offer to download the resource as "foo.html".</em></p></div><div id="attwithasciifilenamenq"><h4><a href="#attwithasciifilenamenq" class="plain">attwithasciifilenamenq</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithasciifilenamenq.asis">TEST</a>] + </h4><pre class="invalid"><b>Content-Disposition: </b>attachment; filename=<b>foo.html</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="warn"><td>FF3</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>MSIE8</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>Op10</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>Saf4</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>Konq</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>Chrome</td><td>warn + (accepts the unquoted value) + </td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo.html</code>, but missing + the quotes. + </p><p><em>This is invalid according to <a href="http://greenbytes.de/tech/webdav/rfc2616.html#rfc.section.19.5.1">Section 19.5.1 of RFC2616</a>, so UAs should + ignore it.</em></p></div><div id="attwithisofnplain"><h4><a href="#attwithisofnplain" class="plain">attwithisofnplain</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithisofnplain.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename="<b>foo-ä.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, using plain ISO-8859-1 + </p><p><em>UA should offer to download the resource as "foo-ä.html".</em></p></div><div id="attwithutf8fnplain"><h4><a href="#attwithutf8fnplain" class="plain">attwithutf8fnplain</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithutf8fnplain.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename="<b>foo-ä.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="fail"><td>FF3</td><td>fail + (decodes as UTF-8) + </td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="fail"><td>Chrome</td><td>fail + (decodes as UTF-8) + </td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, + which happens to be <code>foo-ä.html</code> using UTF-8 encoding. + </p><p><em>UA should offer to download the resource as "foo-ä.html". + Displaying "foo-ä.html" instead indicates that the UA tried to be smart by detecting + something that happens to look like UTF-8.</em></p></div><div id="attwithfnrawpctenca"><h4><a href="#attwithfnrawpctenca" class="plain">attwithfnrawpctenca</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfnrawpctenca.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename="<b>foo-%41.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="fail"><td>MSIE8</td><td>fail + (displays "foo-A.html") + </td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="fail"><td>Chrome</td><td>fail + (displays "foo-A.html" (see <a href="http://code.google.com/p/chromium/issues/detail?id=118">Chrome Issue 118</a>)) + </td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-%41.html</code> + </p><p><em>UA should offer to download the resource as "foo-%41.html". + Displaying "foo-A.html" instead would indicate that the UA has attempted + to percent-decode the parameter. + </em></p></div><div id="attwithfnrawpctenclong"><h4><a href="#attwithfnrawpctenclong" class="plain">attwithfnrawpctenclong</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfnrawpctenclong.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename="<b>foo-%c3%a4-%e2%82%ac.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="fail"><td>MSIE8</td><td>fail + (displays "foo-ä-€.html") + </td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="fail"><td>Chrome</td><td>fail + (displays "foo-ä-€.html" (see <a href="http://code.google.com/p/chromium/issues/detail?id=118">Chrome Issue 118</a>)) + </td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-%c3%a4-%e2%82%ac.html</code>, using raw percent encoded UTF-8 + to represent <code>foo-ä-€.html</code> + </p><p><em>UA should offer to download the resource as "foo-%c3%a4-%e2%82%ac.html". + Displaying "foo-ä-€.html" instead would indicate that the UA has attempted + to percent-decode the parameter (using UTF-8). Displaying something else + would indicate that the UA tried to percent-decode, but used a different encoding. + </em></p></div><div id="attwithasciifilenamews1"><h4><a href="#attwithasciifilenamews1" class="plain">attwithasciifilenamews1</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithasciifilenamews1.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename ="<b>foo.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo.html</code>, with one + blank space <em>before</em> the equals character. + </p><p><em>UA should offer to download the resource as "foo.html".</em></p></div><div id="attwithasciifilenamews2"><h4><a href="#attwithasciifilenamews2" class="plain">attwithasciifilenamews2</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithasciifilenamews2.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename= "<b>foo.html</b>"</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="pass"><td>MSIE8</td><td>pass</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="pass"><td>Saf4</td><td>pass</td></tr><tr class="pass"><td>Konq</td><td>pass</td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo.html</code>, with one + blank space <em>after</em> the equals character. + </p><p><em>UA should offer to download the resource as "foo.html".</em></p></div><div id="attfnbrokentoken"><h4><a href="#attfnbrokentoken" class="plain">attfnbrokentoken</a> + [<a href="http://greenbytes.de/tech/tc2231/attfnbrokentoken.asis">TEST</a>] + </h4><pre class="invalid"><b>Content-Disposition: </b>attachment; filename=<b>foo[1](2).html</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="warn"><td>FF3</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>MSIE8</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>Op10</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>Saf4</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>Konq</td><td>warn + (accepts the unquoted value) + </td></tr><tr class="warn"><td>Chrome</td><td>warn + (accepts the unquoted value) + </td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo[1](2).html</code>, but missing + the quotes. Also, "[", "]", "(" and ")" are not allowed in the HTTP <a href="http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p1-messaging-latest.html#rfc.section.1.2.2">token</a> + production. + </p><p><em>This is invalid according to <a href="http://greenbytes.de/tech/webdav/rfc2616.html#rfc.section.19.5.1">Section 19.5.1 of RFC2616</a>, + so UAs should ignore it.</em></p></div></div><div id="c-d-parms"><h3><a href="#c-d-parms" class="plain">Content-Disposition: Additional Parameters</a></h3> + <p> + Various tests relating to the additional parameters defined in + <a href="http://greenbytes.de/tech/webdav/rfc2183.html#rfc.section.2">Section 2 of RFC 2183</a>. + </p> + <div id="attcdate"><h4><a href="#attcdate" class="plain">attcdate</a> + [<a href="http://greenbytes.de/tech/tc2231/attcdate.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; <b>creation-date="Wed, 12 Feb 1997 16:29:51 -0500"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="unsupported"><td>FF3</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>Op10</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>Konq</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported + (seems to ignore the parameter) + </td></tr></tbody></table><p>'attachment', plus creation-date (see <a href="http://greenbytes.de/tech/webdav/rfc2183.html#rfc.section.2.4">Section 2.4 of RFC 2183</a>)</p><p><em>UA should offer to download the resource. When doing so, + the creation date should be set to 12 Feb 1997.</em></p></div><div id="attmdate"><h4><a href="#attmdate" class="plain">attmdate</a> + [<a href="http://greenbytes.de/tech/tc2231/attmdate.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; <b>modification-date="Wed, 12 Feb 1997 16:29:51 -0500"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="unsupported"><td>FF3</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>Op10</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>Konq</td><td>unsupported + (seems to ignore the parameter) + </td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported + (seems to ignore the parameter) + </td></tr></tbody></table><p>'attachment', plus modification-date (see <a href="http://greenbytes.de/tech/webdav/rfc2183.html#rfc.section.2.5">Section 2.5 of RFC 2183</a>)</p><p><em>UA should offer to download the resource. When doing so, + the modification date should be set to 12 Feb 1997.</em></p></div></div><div id="c-d-extension"><h3><a href="#c-d-extension" class="plain">Content-Disposition: Disposition-Type Extension</a></h3> + <p> + A test checking behavior for disposition type extensions, + which should be treated as "attachment", see + <a href="http://greenbytes.de/tech/webdav/rfc2183.html#rfc.section.2.8">Section 2.8 of RFC 2183</a>. + </p> + <div id="dispext"><h4><a href="#dispext" class="plain">dispext</a> + [<a href="http://greenbytes.de/tech/tc2231/dispext.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>foobar</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="fail (does not treat it as 'attachment')"><td>MSIE8</td><td>fail (does not treat it as 'attachment')</td></tr><tr class="fail (does not treat it as 'attachment')"><td>Op10</td><td>fail (does not treat it as 'attachment')</td></tr><tr class="fail (does not treat it as 'attachment')"><td>Saf4</td><td>fail (does not treat it as 'attachment')</td></tr><tr class="fail (does not treat it as 'attachment')"><td>Konq</td><td>fail (does not treat it as 'attachment')</td></tr><tr class="pass"><td>Chrome</td><td>pass</td></tr></tbody></table><p>'foobar' only</p><p><em>This should be equivalent to using "attachment".</em></p></div></div><div id="encoding-2231-char"><h3><a href="#encoding-2231-char" class="plain">RFC2231 Encoding: Character Sets</a></h3> + <p> + Various tests using the parameter value encoding defined + in <a href="http://greenbytes.de/tech/webdav/rfc2231.html#rfc.section.4">Section 4 of RFC 2231</a>. + </p> + <div id="attwithisofn2231iso"><h4><a href="#attwithisofn2231iso" class="plain">attwithisofn2231iso</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithisofn2231iso.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*=<b>iso-8859-1''foo-%E4.html</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, using RFC2231 encoded ISO-8859-1 + </p><p><em>UA should offer to download the resource as "foo-ä.html". + </em></p></div><div id="attwithfn2231utf8"><h4><a href="#attwithfn2231utf8" class="plain">attwithfn2231utf8</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfn2231utf8.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*=<b>UTF-8''foo-%c3%a4-%e2%82%ac.html</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä-€.html</code>, using RFC2231 encoded UTF-8 + </p><p><em>UA should offer to download the resource as "foo-ä-€.html". + </em></p></div><div id="attwithfn2231noc"><h4><a href="#attwithfn2231noc" class="plain">attwithfn2231noc</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfn2231noc.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*=<b>''foo-%c3%a4-%e2%82%ac.html</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="warn"><td>FF3</td><td>warn + (decodes as UTF-8) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="warn"><td>Op10</td><td>warn + (decodes as 8bit encoding (ISO-8859-1?)) + </td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + Behavior is undefined in RFC 2231, the charset part is missing, although UTF-8 was used. + </p></div><div id="attwithfn2231utf8comp"><h4><a href="#attwithfn2231utf8comp" class="plain">attwithfn2231utf8comp</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfn2231utf8comp.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*=<b>UTF-8''foo-a%cc%88.html</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="warn"><td>Op10</td><td>warn + (displays "foo-ä.html") + </td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, using RFC2231 encoded UTF-8, but + choosing the decomposed form (lowercase a plus COMBINING DIAERESIS) -- + on a Windows target system, this should be translated to the preferred + Unicode normal form (composed). + </p><p><em>UA should offer to download the resource as "foo-ä.html". + </em></p></div><div id="attwithfn2231utf8-bad"><h4><a href="#attwithfn2231utf8-bad" class="plain">attwithfn2231utf8-bad</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfn2231utf8-bad.asis">TEST</a>] + </h4><pre class="invalid"><b>Content-Disposition: </b>attachment; filename*=<b>iso-8859-1''foo-%c3%a4-%e2%82%ac.html</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="fail"><td>FF3</td><td>fail + (falls back to UTF-8) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="warn"><td>Op10</td><td>warn + (displays the raw octet sequence as if it was ISO-8859-1 (which is internally + treated as windows-1252, which <em>does</em> allow %82)) + </td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä-€.html</code>, using RFC2231 encoded UTF-8, but declaring ISO-8859-1 + </p><p><em> + The octet %82 does not represent a valid ISO-8859-1 code point, so + the UA should really ignore the parameter. + </em></p></div><div id="attwithfn2231ws1"><h4><a href="#attwithfn2231ws1" class="plain">attwithfn2231ws1</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfn2231ws1.asis">TEST</a>] + </h4><pre class="invalid"><b>Content-Disposition: </b>attachment; filename<b> *=</b>UTF-8''foo-%c3%a4.html</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="fail"><td>FF3</td><td>fail + (displays garbage) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, using RFC2231 encoded UTF-8, with whitespace before "*=" + </p><p><em> + The parameter is invalid, thus should be ignored. + </em></p></div><div id="attwithfn2231ws2"><h4><a href="#attwithfn2231ws2" class="plain">attwithfn2231ws2</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfn2231ws2.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename<b>*= </b>UTF-8''foo-%c3%a4.html</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, using RFC2231 encoded UTF-8, with whitespace after "*=" + </p><p><em> + UA should offer to download the resource as "foo-ä.html". + </em></p></div><div id="attwithfn2231ws3"><h4><a href="#attwithfn2231ws3" class="plain">attwithfn2231ws3</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfn2231ws3.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename<b>* =</b>UTF-8''foo-%c3%a4.html</pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, using RFC2231 encoded UTF-8, with whitespace inside "* =" + </p><p><em> + UA should offer to download the resource as "foo-ä.html". + </em></p></div><div id="attwithfn2231quot"><h4><a href="#attwithfn2231quot" class="plain">attwithfn2231quot</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfn2231quot.asis">TEST</a>] + </h4><pre class="invalid"><b>Content-Disposition: </b>attachment; filename*=<b>"</b>UTF-8''foo-%c3%a4.html<b>"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="fail"><td>FF3</td><td>fail + (tries to be helpful by removing the quotes) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, using RFC2231 encoded UTF-8, with double quotes + around the parameter value. + </p><p><em> + The parameter is invalid, thus should be ignored. + </em></p></div><div id="attwithfn2231encmissing"><h4><a href="#attwithfn2231encmissing" class="plain">attwithfn2231encmissing</a> + [<a href="http://greenbytes.de/tech/tc2231/attwithfn2231encmissing.asis">TEST</a>] + </h4><pre class="invalid"><b>Content-Disposition: </b>attachment; filename*=<b>''foo-%c3%a4.html</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="fail"><td>FF3</td><td>fail + (sniffs the encoding as UTF-8) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="fail"><td>Op10</td><td>fail + (assumes a default of ISO-8859-1) + </td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, using RFC2231 encoded UTF-8, but + leaving out the charset field. + </p><p><em> + The parameter is invalid, thus should be ignored. + </em></p></div></div><div id="encoding-2231-cont"><h3><a href="#encoding-2231-cont" class="plain">RFC2231 Encoding: Continuations</a></h3> + <p> + Various tests using the parameter value continuation efined + in <a href="http://greenbytes.de/tech/webdav/rfc2231.html#rfc.section.3">Section 3 of RFC 2231</a>. + </p> + <div id="attfncont"><h4><a href="#attfncont" class="plain">attfncont</a> + [<a href="http://greenbytes.de/tech/tc2231/attfncont.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*0=<b>"foo."</b>; filename*1=<b>"html"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo.html</code>, using RFC2231-style parameter continuations. + </p><p><em> + UA should offer to download the resource as "foo.html". + </em></p></div><div id="attfncontenc"><h4><a href="#attfncontenc" class="plain">attfncontenc</a> + [<a href="http://greenbytes.de/tech/tc2231/attfncontenc.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*0*=<b>UTF-8''foo-%c3%a4</b>; filename*1=<b>".html"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ä.html</code>, using both RFC2231-style parameter continuations + and UTF-8 encoding. + </p><p><em> + UA should offer to download the resource as "foo-ä.html". + </em></p></div><div id="attfncontlz"><h4><a href="#attfncontlz" class="plain">attfncontlz</a> + [<a href="http://greenbytes.de/tech/tc2231/attfncontlz.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*0=<b>"foo"</b>; filename*01=<b>"bar"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="warn"><td>FF3</td><td>warn + (accepts leading zeros) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="warn"><td>Op10</td><td>warn + (accepts leading zeros) + </td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo</code> (the parameter filename*01 should be ignored because of the leading zero) + </p><p><em> + UA should offer to download the resource as "foo". + </em></p></div><div id="attfncontnc"><h4><a href="#attfncontnc" class="plain">attfncontnc</a> + [<a href="http://greenbytes.de/tech/tc2231/attfncontnc.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*0=<b>"foo"</b>; filename*2=<b>"bar"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="warn"><td>FF3</td><td>warn + (accepts gaps) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo</code> (the parameter filename*2 because there's no filename*1 parameter) + </p><p><em> + UA should offer to download the resource as "foo". + </em></p></div><div id="attfnconts1"><h4><a href="#attfnconts1" class="plain">attfnconts1</a> + [<a href="http://greenbytes.de/tech/tc2231/attfnconts1.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*1=<b>"foo."</b>; filename*2=<b>"html"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass</td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment' (the filename* parameters should be ignored because filename*0 is missing) + </p><p><em> + UA should offer to download, not getting the filename from the header. + </em></p></div><div id="attfncontord"><h4><a href="#attfncontord" class="plain">attfncontord</a> + [<a href="http://greenbytes.de/tech/tc2231/attfncontord.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*1=<b>"bar"</b>; filename*0=<b>"foo"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="fail"><td>FF3</td><td>fail + (parameters are expected to be ordered) + </td></tr><tr class="unsupported"><td>MSIE8</td><td>unsupported</td></tr><tr class="pass"><td>Op10</td><td>pass</td></tr><tr class="unsupported"><td>Saf4</td><td>unsupported</td></tr><tr class="unsupported"><td>Konq</td><td>unsupported</td></tr><tr class="unsupported"><td>Chrome</td><td>unsupported</td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foobar</code> + </p><p><em> + UA should offer to download the resource as "foobar". + </em></p></div></div><div id="encoding-2231-fb"><h3><a href="#encoding-2231-fb" class="plain">RFC2231 Encoding: Fallback Behaviour</a></h3> + <p> + This tests how the UA behaves when the same parameter name appear + both in traditional and RFC 2231 extended format. + </p> + <div id="attfnboth"><h4><a href="#attfnboth" class="plain">attfnboth</a> + [<a href="http://greenbytes.de/tech/tc2231/attfnboth.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename="<b>foo-ae.html</b>"; filename*=<b>UTF-8''foo-%c3%a4.html</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass + (picks the traditionally encoded value -- the first of both) + </td></tr><tr class="pass"><td>MSIE8</td><td>pass + (picks the traditionally encoded value -- the first of both) + </td></tr><tr class="pass"><td>Op10</td><td>pass + (picks the traditionally encoded value -- the first of both) + </td></tr><tr class="pass"><td>Saf4</td><td>pass + (picks the traditionally encoded value -- the first of both) + </td></tr><tr class="pass"><td>Konq</td><td>pass + (picks the traditionally encoded value -- the first of both) + </td></tr><tr class="pass"><td>Chrome</td><td>pass + (picks the traditionally encoded value -- the first of both) + </td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ae.html</code> in + the traditional format, and <code>foo-ä.html</code> in RFC2231 format. + </p><p><em> + The behaviour of this undefined. Thus UAs should one of the two values. + </em></p></div><div id="attfnboth2"><h4><a href="#attfnboth2" class="plain">attfnboth2</a> + [<a href="http://greenbytes.de/tech/tc2231/attfnboth2.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename*=<b>UTF-8''foo-%c3%a4.html</b>; filename=<b>"foo-ae.html"</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="pass"><td>FF3</td><td>pass + (picks the RFC2231 encoded value -- the first of both) + </td></tr><tr class="fail"><td>MSIE8</td><td>fail + (ignores the parameter (this indicates a parsing bug)) + </td></tr><tr class="pass"><td>Op10</td><td>pass + (picks the RFC2231 encoded value -- the first of both) + </td></tr><tr class="pass"><td>Saf4</td><td>pass + (picks the traditionally encoded value -- the one it understands) + </td></tr><tr class="pass"><td>Konq</td><td>pass + (picks the traditionally encoded value -- the one it understands) + </td></tr><tr class="fail"><td>Chrome</td><td>fail + (ignores the parameter (this indicates a parsing bug)) + </td></tr></tbody></table><p> + 'attachment', specifying a filename of <code>foo-ae.html</code> in + the traditional format, and <code>foo-ä.html</code> in RFC2231 format. + </p><p><em> + The behaviour of this undefined. Thus UAs should one of the two values. + </em></p></div></div><div id="encoding-2047"><h3><a href="#encoding-2047" class="plain">RFC2047 Encoding</a></h3> + <p> + These tests RFC 2047 style encoding. + </p> + <p> + Note that according to <a href="http://greenbytes.de/tech/webdav/rfc2047.html#rfc.section.5">Section 5 of RFC 2047</a>, + this encoding does not apply here: <q cite="http://greenbytes.de/tech/webdav/rfc2047.html#rfc.section.5">An 'encoded-word' MUST NOT appear within a 'quoted-string'.</q>, and + <q cite="http://greenbytes.de/tech/webdav/rfc2047.html#rfc.section.5">An 'encoded-word' MUST NOT be used in parameter of a MIME + Content-Type or Content-Disposition field, or in any structured + field body except within a 'comment' or 'phrase'.</q> + </p> + <p> + Therefore, these tests are only be present in order to check + whether the UA by mistake tries to implement RFC2047. + </p> + <div id="attrfc2047token"><h4><a href="#attrfc2047token" class="plain">attrfc2047token</a> + [<a href="http://greenbytes.de/tech/tc2231/attrfc2047token.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename=<b>=?ISO-8859-1?Q?foo-=E4.html?=</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="fail"><td>FF3</td><td>fail + (decodes it anyway to "foo-ä.html") + </td></tr><tr class="pass"><td>MSIE8</td><td>pass + (takes the whole value as filename, but does not decode it (replacing question marks by underscores)) + </td></tr><tr class="fail"><td>Op10</td><td>fail + (displays garbage ("=.htm")) + </td></tr><tr class="pass"><td>Saf4</td><td>pass + (takes the whole value as filename, but does not decode it (replacing question marks by underscores)) + </td></tr><tr class="fail"><td>Konq</td><td>fail + (decodes it anyway to "foo-ä.html") + </td></tr><tr class="fail"><td>Chrome</td><td>fail + (decodes it anyway to "foo-ä.html") + </td></tr></tbody></table><p> + Uses RFC 2047 style encoded word. "=" is invalid inside the <code>token</code> + production, so this is invalid. + </p></div><div id="attrfc2047quoted"><h4><a href="#attrfc2047quoted" class="plain">attrfc2047quoted</a> + [<a href="http://greenbytes.de/tech/tc2231/attrfc2047quoted.asis">TEST</a>] + </h4><pre><b>Content-Disposition: </b>attachment; filename=<b>"=?ISO-8859-1?Q?foo-=E4.html?="</b></pre><table class="aside"><thead><tr><th colspan="2"> + Test Results + </th></tr></thead><tbody><tr class="fail"><td>FF3</td><td>fail + (decodes it anyway to "foo-ä.html") + </td></tr><tr class="pass"><td>MSIE8</td><td>pass + (takes the whole value as filename, but does not decode it) + </td></tr><tr class="fail"><td>Op10</td><td>fail + (displays garbage ("=.htm")) + </td></tr><tr class="pass"><td>Saf4</td><td>pass + (takes the whole value as filename, but does not decode it) + </td></tr><tr class="fail"><td>Konq</td><td>fail + (decodes it anyway to "foo-ä.html") + </td></tr><tr class="fail"><td>Chrome</td><td>fail + (decodes it anyway to "foo-ä.html") + </td></tr></tbody></table><p> + Uses RFC 2047 style encoded word, using the <code>quoted-string</code> production. + </p></div></div> +</body></html>
\ No newline at end of file diff --git a/src/tests/findbar_test.cpp b/src/tests/findbar_test.cpp new file mode 100644 index 00000000..a79f44a2 --- /dev/null +++ b/src/tests/findbar_test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtGui> +#include <QtTest/QtTest> + +#include "findbar.h" +#include "mainwindow.h" + + +class FindBarTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + void matchCase(); + void notifyMatch(); + +private: + FindBar *bar; + MainWindow *w; +}; + + +// ------------------------------------------- + + +void FindBarTest::initTestCase() +{ + w = new MainWindow; + bar = new FindBar(w); +} + + +void FindBarTest::cleanupTestCase() +{ + delete bar; +} + +void FindBarTest::matchCase() +{ + +} + +void FindBarTest::notifyMatch() +{ +} + +// ------------------------------------------- + +QTEST_KDEMAIN(FindBarTest, GUI) +#include "findbar_test.moc" diff --git a/src/tests/link_test.html b/src/tests/link_test.html index 7dd1470d..5ca3cd41 100644 --- a/src/tests/link_test.html +++ b/src/tests/link_test.html @@ -135,6 +135,13 @@ <td><a href="http://ads.cnn.com/" target="_blank">link</a></td> </tr> + +<tr> +<td>http://ja.wikipedia.org/wiki/特別:最近の更新</td> +<td>KGet import links with particular encoding</td> +<td><a href="http://ja.wikipedia.org/wiki/特別:最近の更新">link</a></td> +</tr> + <tr> <td></td> <td></td> diff --git a/src/tests/mainview_test.cpp b/src/tests/mainview_test.cpp index f56d73ab..596ac4e1 100644 --- a/src/tests/mainview_test.cpp +++ b/src/tests/mainview_test.cpp @@ -27,12 +27,13 @@ #include <qtest_kde.h> -#include <QtTest> #include <QtCore> #include <QtGui> +#include <QtTest> -#include "../mainview.h" -#include "../webview.h" +#include "mainwindow.h" +#include "mainview.h" +#include "webview.h" class MainViewTest : public QObject @@ -42,8 +43,6 @@ class MainViewTest : public QObject public slots: void initTestCase(); void cleanupTestCase(); - void init(); - void cleanup(); private slots: void tabwidget_data(); @@ -75,38 +74,29 @@ private slots: void currentChanged_data(); void currentChanged(); + +private: + MainWindow *window; + MainView *view; }; -// Subclass that exposes the protected functions. -class SubMainView : public MainView -{ -public: - void call_resizeEvent(QResizeEvent *event) - { return SubMainView::resizeEvent(event); } -}; +// ------------------------------------------------------------------------------- // This will be called before the first test function is executed. // It is only called once. void MainViewTest::initTestCase() { + window = new MainWindow; + view = window->mainView(); } // This will be called after the last test function is executed. // It is only called once. void MainViewTest::cleanupTestCase() { -} - -// This will be called before each test function is executed. -void MainViewTest::init() -{ -} - -// This will be called after every test function. -void MainViewTest::cleanup() -{ +// delete window; // FIXME: this let the test fail. Why?? } // ------------------------------------------- @@ -117,14 +107,16 @@ void MainViewTest::tabwidget_data() void MainViewTest::tabwidget() { - SubMainView widget; -// widget.currentWebView(); -// QCOMPARE(widget.currentIndex(), 0); -// widget.newTab(); -// widget.nextTab(); -// QCOMPARE(widget.currentIndex(), 1); -// widget.previousTab(); -// QCOMPARE(widget.currentIndex(), 0); + QCOMPARE(view->currentIndex(), -1); + +// view->newTab(); +// QCOMPARE(view->currentIndex(), 1); +// view->newTab(); +// view->nextTab(); +// QCOMPARE(view->currentIndex(), 0); +// +// view->previousTab(); +// QCOMPARE(view->currentIndex(), 0); } // ------------------------------------------- @@ -135,33 +127,30 @@ void MainViewTest::closeTab_data() QTest::newRow("null") << 0; } -// public void closeTab(int index = -1) + void MainViewTest::closeTab() { - QFETCH(int, index); - - SubMainView widget; -/* - QSignalSpy spy0(&widget, SIGNAL(linkHovered(const QString &))); - QSignalSpy spy3(&widget, SIGNAL(setCurrentTitle(const QString &))); -QSignalSpy spy5(&widget, SIGNAL(tabsChanged())); - QSignalSpy spy6(&widget, SIGNAL(lastTabClosed())); - - widget.newTab(); - widget.slotCloseTab(index); - widget.newTab(); - widget.slotCloseTab(index); - widget.newTab(); - - QCOMPARE(spy0.count(), 0); - QCOMPARE(spy3.count(), 2); - QCOMPARE(spy5.count(), 0); - QCOMPARE(spy6.count(), 0);*/ +// QFETCH(int, index); +// +// QSignalSpy spy1(view, SIGNAL(linkHovered(const QString &))); +// QSignalSpy spy2(view, SIGNAL(setCurrentTitle(const QString &))); +// QSignalSpy spy3(view, SIGNAL(tabsChanged())); +// QSignalSpy spy4(view, SIGNAL(lastTabClosed())); +// +// view->newTab(); +// view->closeTab(index); +// view->newTab(); +// view->closeTab(index); +// view->newTab(); +// +// QCOMPARE(spy1.count(), 0); +// QCOMPARE(spy2.count(), 2); +// QCOMPARE(spy3.count(), 0); +// QCOMPARE(spy4.count(), 0); } // ------------------------------------------- -Q_DECLARE_METATYPE(WebView*) void MainViewTest::currentWebView_data() { /* @@ -170,7 +159,6 @@ void MainViewTest::currentWebView_data() */ } -// public WebView *currentWebView() const void MainViewTest::currentWebView() { /* @@ -178,12 +166,12 @@ void MainViewTest::currentWebView() SubMainView widget; - QSignalSpy spy0(&widget, SIGNAL(linkHovered(const QString &))); - QSignalSpy spy2(&widget, SIGNAL(loadProgress(int))); - QSignalSpy spy3(&widget, SIGNAL(setCurrentTitle(const QString &))); - QSignalSpy spy4(&widget, SIGNAL(showStatusBarMessage(const QString &))); - QSignalSpy spy5(&widget, SIGNAL(tabsChanged())); - QSignalSpy spy6(&widget, SIGNAL(lastTabClosed())); + QSignalSpy spy0(view, SIGNAL(linkHovered(const QString &))); + QSignalSpy spy2(view, SIGNAL(loadProgress(int))); + QSignalSpy spy3(view, SIGNAL(setCurrentTitle(const QString &))); + QSignalSpy spy4(view, SIGNAL(showStatusBarMessage(const QString &))); + QSignalSpy spy5(view, SIGNAL(tabsChanged())); + QSignalSpy spy6(view, SIGNAL(lastTabClosed())); QCOMPARE(widget.currentWebView(), currentWebView); @@ -205,31 +193,24 @@ void MainViewTest::newTab_data() QTest::newRow("null") << 0; } -// public void newTab() + void MainViewTest::newTab() { - /* - QFETCH(int, foo); - - SubMainView widget; - - QSignalSpy spy0(&widget, SIGNAL(linkHovered(const QString &))); - QSignalSpy spy2(&widget, SIGNAL(loadProgress(int))); - QSignalSpy spy3(&widget, SIGNAL(setCurrentTitle(const QString &))); - QSignalSpy spy4(&widget, SIGNAL(showStatusBarMessage(const QString &))); - QSignalSpy spy5(&widget, SIGNAL(tabsChanged())); - QSignalSpy spy6(&widget, SIGNAL(lastTabClosed())); - - widget.newTab(); - - QCOMPARE(spy0.count(), 0); - QCOMPARE(spy2.count(), 0); - QCOMPARE(spy3.count(), 0); - QCOMPARE(spy4.count(), 0); - QCOMPARE(spy5.count(), 0); - QCOMPARE(spy6.count(), 0); - */ - QSKIP("Test is not implemented.", SkipAll); +// QFETCH(int, foo); +// +// QSignalSpy spy0(view, SIGNAL(linkHovered(const QString &))); +// QSignalSpy spy1(view, SIGNAL(setCurrentTitle(const QString &))); +// QSignalSpy spy2(view, SIGNAL(showStatusBarMessage(const QString &))); +// QSignalSpy spy3(view, SIGNAL(tabsChanged())); +// QSignalSpy spy4(view, SIGNAL(lastTabClosed())); +// +// view->newTab(); +// +// QCOMPARE(spy0.count(), 0); +// QCOMPARE(spy1.count(), 0); +// QCOMPARE(spy2.count(), 0); +// QCOMPARE(spy3.count(), 0); +// QCOMPARE(spy4.count(), 0); } // ------------------------------------------- @@ -248,12 +229,12 @@ void MainViewTest::nextTab() SubMainView widget; - QSignalSpy spy0(&widget, SIGNAL(linkHovered(const QString &))); - QSignalSpy spy2(&widget, SIGNAL(loadProgress(int))); - QSignalSpy spy3(&widget, SIGNAL(setCurrentTitle(const QString &))); - QSignalSpy spy4(&widget, SIGNAL(showStatusBarMessage(const QString &))); - QSignalSpy spy5(&widget, SIGNAL(tabsChanged())); - QSignalSpy spy6(&widget, SIGNAL(lastTabClosed())); + QSignalSpy spy0(view, SIGNAL(linkHovered(const QString &))); + QSignalSpy spy2(view, SIGNAL(loadProgress(int))); + QSignalSpy spy3(view, SIGNAL(setCurrentTitle(const QString &))); + QSignalSpy spy4(view, SIGNAL(showStatusBarMessage(const QString &))); + QSignalSpy spy5(view, SIGNAL(tabsChanged())); + QSignalSpy spy6(view, SIGNAL(lastTabClosed())); widget.nextTab(); @@ -284,12 +265,12 @@ void MainViewTest::previousTab() SubMainView widget; - QSignalSpy spy0(&widget, SIGNAL(linkHovered(const QString &))); - QSignalSpy spy2(&widget, SIGNAL(loadProgress(int))); - QSignalSpy spy3(&widget, SIGNAL(setCurrentTitle(const QString &))); - QSignalSpy spy4(&widget, SIGNAL(showStatusBarMessage(const QString &))); - QSignalSpy spy5(&widget, SIGNAL(tabsChanged())); - QSignalSpy spy6(&widget, SIGNAL(lastTabClosed())); + QSignalSpy spy0(view, SIGNAL(linkHovered(const QString &))); + QSignalSpy spy2(view, SIGNAL(loadProgress(int))); + QSignalSpy spy3(view, SIGNAL(setCurrentTitle(const QString &))); + QSignalSpy spy4(view, SIGNAL(showStatusBarMessage(const QString &))); + QSignalSpy spy5(view, SIGNAL(tabsChanged())); + QSignalSpy spy6(view, SIGNAL(lastTabClosed())); widget.previousTab(); @@ -314,12 +295,12 @@ void MainViewTest::recentlyClosedTabs() /* SubMainView widget; - QSignalSpy spy0(&widget, SIGNAL(linkHovered(const QString &))); - QSignalSpy spy2(&widget, SIGNAL(loadProgress(int))); - QSignalSpy spy3(&widget, SIGNAL(setCurrentTitle(const QString &))); - QSignalSpy spy4(&widget, SIGNAL(showStatusBarMessage(const QString &))); - QSignalSpy spy5(&widget, SIGNAL(tabsChanged())); - QSignalSpy spy6(&widget, SIGNAL(lastTabClosed())); + QSignalSpy spy0(view, SIGNAL(linkHovered(const QString &))); + QSignalSpy spy2(view, SIGNAL(loadProgress(int))); + QSignalSpy spy3(view, SIGNAL(setCurrentTitle(const QString &))); + QSignalSpy spy4(view, SIGNAL(showStatusBarMessage(const QString &))); + QSignalSpy spy5(view, SIGNAL(tabsChanged())); + QSignalSpy spy6(view, SIGNAL(lastTabClosed())); QCOMPARE(spy0.count(), 0); QCOMPARE(spy2.count(), 0); @@ -347,12 +328,12 @@ void MainViewTest::setCurrentTitle(const QString &) SubMainView widget; - QSignalSpy spy0(&widget, SIGNAL(linkHovered(const QString &))); - QSignalSpy spy2(&widget, SIGNAL(loadProgress(int))); - QSignalSpy spy3(&widget, SIGNAL(setCurrentTitle(const QString &))); - QSignalSpy spy4(&widget, SIGNAL(showStatusBarMessage(const QString &))); - QSignalSpy spy5(&widget, SIGNAL(tabsChanged())); - QSignalSpy spy6(&widget, SIGNAL(lastTabClosed())); + QSignalSpy spy0(view, SIGNAL(linkHovered(const QString &))); + QSignalSpy spy2(view, SIGNAL(loadProgress(int))); + QSignalSpy spy3(view, SIGNAL(setCurrentTitle(const QString &))); + QSignalSpy spy4(view, SIGNAL(showStatusBarMessage(const QString &))); + QSignalSpy spy5(view, SIGNAL(tabsChanged())); + QSignalSpy spy6(view, SIGNAL(lastTabClosed())); widget.call_setCurrentTitle(url); @@ -382,12 +363,12 @@ void MainViewTest::showStatusBarMessage(const QString &) SubMainView widget; - QSignalSpy spy0(&widget, SIGNAL(linkHovered(const QString &))); - QSignalSpy spy2(&widget, SIGNAL(loadProgress(int))); - QSignalSpy spy3(&widget, SIGNAL(setCurrentTitle(const QString &))); - QSignalSpy spy4(&widget, SIGNAL(showStatusBarMessage(const QString &))); - QSignalSpy spy5(&widget, SIGNAL(tabsChanged())); - QSignalSpy spy6(&widget, SIGNAL(lastTabClosed())); + QSignalSpy spy0(view, SIGNAL(linkHovered(const QString &))); + QSignalSpy spy2(view, SIGNAL(loadProgress(int))); + QSignalSpy spy3(view, SIGNAL(setCurrentTitle(const QString &))); + QSignalSpy spy4(view, SIGNAL(showStatusBarMessage(const QString &))); + QSignalSpy spy5(view, SIGNAL(tabsChanged())); + QSignalSpy spy6(view, SIGNAL(lastTabClosed())); widget.call_showStatusBarMessage(message); @@ -403,14 +384,12 @@ void MainViewTest::showStatusBarMessage(const QString &) // ------------------------------------------- -// void slotCurrentChanged(int index); void MainViewTest::currentChanged_data() { QTest::addColumn<int>("foo"); QTest::newRow("null") << 0; } -// private slotCurrentChanged void MainViewTest::currentChanged() { /* @@ -418,12 +397,12 @@ void MainViewTest::currentChanged() SubMainView widget; - QSignalSpy spy0(&widget, SIGNAL(linkHovered(const QString &))); - QSignalSpy spy2(&widget, SIGNAL(loadProgress(int))); - QSignalSpy spy3(&widget, SIGNAL(setCurrentTitle(const QString &))); - QSignalSpy spy4(&widget, SIGNAL(showStatusBarMessage(const QString &))); - QSignalSpy spy5(&widget, SIGNAL(tabsChanged())); - QSignalSpy spy6(&widget, SIGNAL(lastTabClosed())); + QSignalSpy spy0(view, SIGNAL(linkHovered(const QString &))); + QSignalSpy spy2(view, SIGNAL(loadProgress(int))); + QSignalSpy spy3(view, SIGNAL(setCurrentTitle(const QString &))); + QSignalSpy spy4(view, SIGNAL(showStatusBarMessage(const QString &))); + QSignalSpy spy5(view, SIGNAL(tabsChanged())); + QSignalSpy spy6(view, SIGNAL(lastTabClosed())); widget.call_tabsChanged(); diff --git a/src/tests/mainwindow_test.cpp b/src/tests/mainwindow_test.cpp new file mode 100644 index 00000000..d3ab6bef --- /dev/null +++ b/src/tests/mainwindow_test.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> + +#include "mainwindow.h" +#include "application.h" + + +class MainWindowTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + + +private: + MainWindow *window; +}; + + +// ------------------------------------------- + + +void MainWindowTest::initTestCase() +{ + window = new MainWindow; +} + + +void MainWindowTest::cleanupTestCase() +{ +// delete window; +} + +// ------------------------------------------- + +QTEST_KDEMAIN(MainWindowTest,GUI) +#include "mainwindow_test.moc" diff --git a/src/tests/networkaccessmanager_test.cpp b/src/tests/networkaccessmanager_test.cpp new file mode 100644 index 00000000..ac6cf89e --- /dev/null +++ b/src/tests/networkaccessmanager_test.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> + +#include "networkaccessmanager.h" + + +class NetworkAccessManagerTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + +private: + NetworkAccessManager *manager; +}; + + +// ------------------------------------------- + +void NetworkAccessManagerTest::initTestCase() +{ + manager = new NetworkAccessManager(this); +} + + +void NetworkAccessManagerTest::cleanupTestCase() +{ + delete manager; +} + + +// ------------------------------------------- + + + +// ------------------------------------------- + +QTEST_KDEMAIN(NetworkAccessManagerTest,GUI) +#include "networkaccessmanager_test.moc" diff --git a/src/tests/protocolhandler_test.cpp b/src/tests/protocolhandler_test.cpp new file mode 100644 index 00000000..a3c78c2f --- /dev/null +++ b/src/tests/protocolhandler_test.cpp @@ -0,0 +1,130 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> +#include <QtNetwork> +#include <QtWebKit> + +#include "protocolhandler.h" + + +class ProtocolhandlerTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + void preHandling_data(); + void preHandling(); + + void postHandling_data(); + void postHandling(); + +private: + ProtocolHandler *handler; +}; + + +// ------------------------------------------- + +void ProtocolhandlerTest::initTestCase() +{ + handler = new ProtocolHandler; +} + + +void ProtocolhandlerTest::cleanupTestCase() +{ + delete handler; +} + + +// ------------------------------------------- + + +void ProtocolhandlerTest::preHandling_data() +{ + QTest::addColumn<QString>("urlString"); + QTest::addColumn<bool>("result"); + + QTest::newRow("mailto") << "mailto:me@here.com" << true ; + QTest::newRow("relative") << "google.it" << false ; + QTest::newRow("javascript") << "javascript:alertbox('hello')" << true ; + QTest::newRow("aboutblank") << "about:blank" << false ; + QTest::newRow("abouthome") << "about:home" << true ; + QTest::newRow("ftp") << "ftp://ftp.kde.org" << false ; + QTest::newRow("file") << "file:///home" << false ; +} + + +void ProtocolhandlerTest::preHandling() +{ + QFETCH( QString, urlString ); + QFETCH( bool , result ); + + QWebView *view = new QWebView; + QWebFrame *frame = view->page()->mainFrame(); + + QNetworkRequest request = QNetworkRequest( QUrl(urlString) ); + + QCOMPARE( handler->preHandling( request, frame ) , result ); +} + + +void ProtocolhandlerTest::postHandling_data() +{ + QTest::addColumn<QString>("urlString"); + QTest::addColumn<bool>("result"); + + QTest::newRow("mailto") << "mailto:me@here.com" << true ; + QTest::newRow("relative") << "google.it" << false ; + QTest::newRow("javascript") << "javascript:alertbox('hello')" << false ; + QTest::newRow("aboutblank") << "about:blank" << false ; + QTest::newRow("abouthome") << "about:home" << false ; + QTest::newRow("ftp") << "ftp://ftp.kde.org" << true ; + QTest::newRow("file") << "file:///home" << true ; +} + + +void ProtocolhandlerTest::postHandling() +{ + QFETCH( QString, urlString ); + QFETCH( bool , result ); + + QWebView *view = new QWebView; + QWebFrame *frame = view->page()->mainFrame(); + + QNetworkRequest request = QNetworkRequest( QUrl(urlString) ); + + QCOMPARE( handler->postHandling( request, frame ) , result ); +} + +// ------------------------------------------- + +QTEST_KDEMAIN(ProtocolhandlerTest,GUI) +#include "protocolhandler_test.moc" diff --git a/src/tests/sessionmanager_test.cpp b/src/tests/sessionmanager_test.cpp new file mode 100644 index 00000000..e3e1b329 --- /dev/null +++ b/src/tests/sessionmanager_test.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> + + +#include "sessionmanager.h" + + +class SessionManagerTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + +private: + SessionManager *sessman; +}; + + +// ------------------------------------------- + + +void SessionManagerTest::initTestCase() +{ + sessman = new SessionManager; +} + + +void SessionManagerTest::cleanupTestCase() +{ + delete sessman; +} + + +// ------------------------------------------- + + + +// ------------------------------------------- + +QTEST_KDEMAIN(SessionManagerTest,GUI) +#include "sessionmanager_test.moc" diff --git a/src/tests/tabbar_test.cpp b/src/tests/tabbar_test.cpp index 08f295d1..560f2c9b 100644 --- a/src/tests/tabbar_test.cpp +++ b/src/tests/tabbar_test.cpp @@ -24,116 +24,115 @@ #include <QtCore> #include <QtGui> -#include "../tabbar.h" +#include "mainwindow.h" +#include "mainview.h" +#include "tabbar.h" -class TabBarTest : public QObject -{ - Q_OBJECT - -public slots: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - -private slots: - void tabbar_data(); - void tabbar(); - - void tabSizeHint_data(); - void tabSizeHint(); -}; - - -// Subclass that exposes the protected functions. +/** + * Subclass that exposes the protected functions. + */ class SubTabBar : public TabBar { public: - void call_cloneTab(int index) - { return SubTabBar::cloneTab(index); } - - void call_closeOtherTabs(int index) - { return SubTabBar::closeOtherTabs(index); } - - void call_closeTab(int index) - { return SubTabBar::closeTab(index); } + + SubTabBar(QWidget *parent) : TabBar(parent) {}; + QSize call_tabSizeHint(int index) const + { return SubTabBar::tabSizeHint(index); } + void call_mouseMoveEvent(QMouseEvent* event) { return SubTabBar::mouseMoveEvent(event); } - + + void call_leaveEvent(QEvent* event) + { return SubTabBar::leaveEvent(event); } + void call_mousePressEvent(QMouseEvent* event) { return SubTabBar::mousePressEvent(event); } + + void call_mouseReleaseEvent(QMouseEvent* event) + { return SubTabBar::mouseReleaseEvent(event); } +}; - void call_reloadAllTabs() - { return SubTabBar::reloadAllTabs(); } - void call_reloadTab(int index) - { return SubTabBar::reloadTab(index); } +// ------------------------------------------------------------------ - QSize call_tabSizeHint(int index) const - { return SubTabBar::tabSizeHint(index); } - void call_showTabPreview(int tab) - { return SubTabBar::showTabPreview(tab); } +class TabBarTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + void tabSizeHint_data(); + void tabSizeHint(); + + void mousePress_data(); + void mousePress(); + +private: + SubTabBar *_bar; }; -// This will be called before the first test function is executed. -// It is only called once. +// ------------------------------------------- + void TabBarTest::initTestCase() { + MainWindow *w = new MainWindow; + MainView *mv = new MainView(w); + _bar = new SubTabBar(mv); } - -// This will be called after the last test function is executed. -// It is only called once. void TabBarTest::cleanupTestCase() { + delete _bar; } +// ------------------------------------------- -// This will be called before each test function is executed. -void TabBarTest::init() +void TabBarTest::tabSizeHint_data() { + QTest::addColumn<int>("index"); + + QTest::newRow("1th") << 0; + QTest::newRow("2nd") << 1; + QTest::newRow("3rd") << 2; + QTest::newRow("4th") << 3; + QTest::newRow("5th") << 4; + QTest::newRow("6th") << 5; + QTest::newRow("7th") << 6; + QTest::newRow("8th") << 7; + QTest::newRow("9th") << 8; + QTest::newRow("10th") << 9; } -// This will be called after every test function. -void TabBarTest::cleanup() +void TabBarTest::tabSizeHint() { -} + QFETCH(int, index); -// ------------------------------------------- - -void TabBarTest::tabbar_data() -{ + QVERIFY(_bar->call_tabSizeHint(index).width() > 0); } -void TabBarTest::tabbar() +void TabBarTest::mousePress_data() { - SubTabBar widget; } -// ------------------------------------------- -void TabBarTest::tabSizeHint_data() +void TabBarTest::mousePress() { -// QTest::addColumn<int>("index"); -// QTest::newRow("0") << 0; +// QTest::mousePress(_bar, Qt::MidButton); +// // QCOMPARE(); ? +// +// QTest::mousePress(_bar, Qt::LeftButton); +// // QCOMPARE(); ? } - -// protected QSize tabSizeHint(int index) const -void TabBarTest::tabSizeHint() -{ - // Need fixes as our function uses MainView methods to determine size -// QFETCH(int, index); -// SubTabBar bar; -// QVERIFY(bar.call_tabSizeHint(index).width() <= 250); -} - // ------------------------------------------- QTEST_KDEMAIN(TabBarTest, GUI) diff --git a/src/tests/urlbar_test.cpp b/src/tests/urlbar_test.cpp new file mode 100644 index 00000000..7a1fb40b --- /dev/null +++ b/src/tests/urlbar_test.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> + +#include "webpage.h" +#include "webview.h" +#include "webtab.h" + +#include "urlbar.h" + + +class UrlBarTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + +private: + UrlBar *bar; + WebTab *tab; +}; + + +// ------------------------------------------- + +void UrlBarTest::initTestCase() +{ + tab = new WebTab; + bar = new UrlBar(tab); +} + + +void UrlBarTest::cleanupTestCase() +{ + delete bar; + delete tab; +} + + +// ------------------------------------------- + + + +// ------------------------------------------- + +QTEST_KDEMAIN(UrlBarTest,GUI) +#include "urlbar_test.moc" diff --git a/src/tests/walletbar_test.cpp b/src/tests/walletbar_test.cpp new file mode 100644 index 00000000..ec9c3559 --- /dev/null +++ b/src/tests/walletbar_test.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> + +#include "walletbar.h" + + +class WalletBarTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + +private: + WalletBar *bar; +}; + + +// ------------------------------------------- + + +void WalletBarTest::initTestCase() +{ + QWidget *w = new QWidget; + bar = new WalletBar(w); +} + + +void WalletBarTest::cleanupTestCase() +{ + delete bar; +} + + +// ------------------------------------------- + + + +// ------------------------------------------- + +QTEST_KDEMAIN(WalletBarTest,GUI) +#include "walletbar_test.moc" diff --git a/src/tests/webpage_test.cpp b/src/tests/webpage_test.cpp new file mode 100644 index 00000000..3051b8bf --- /dev/null +++ b/src/tests/webpage_test.cpp @@ -0,0 +1,112 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> +#include <QtWebKit> + +#include "webpage.h" +#include "webview.h" +#include "webtab.h" + + +class WebPageTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + void manageNetworkErrors(); + void downloadRequest(); + void downloadAllContentsWithKGet(); + + void createWindow(); + void acceptNavigationRequest(); + + void handleUnsupportedContent(); + + void loadFinished(); + +private: + WebTab *tab; + WebPage *page; + WebView *view; +}; + + +// ------------------------------------------- + + +void WebPageTest::initTestCase() +{ + tab = new WebTab; + view = tab->view(); + page = tab->page(); +} + + +void WebPageTest::cleanupTestCase() +{ + delete tab; +} + + +// ------------------------------------------- + + +void WebPageTest::manageNetworkErrors() +{ +} + +void WebPageTest::downloadRequest() +{ +} + +void WebPageTest::downloadAllContentsWithKGet() +{ +} + +void WebPageTest::createWindow() +{ +} + +void WebPageTest::acceptNavigationRequest() +{ +} + +void WebPageTest::handleUnsupportedContent() +{ +} + +void WebPageTest::loadFinished() +{ +} + +// ------------------------------------------- + +QTEST_KDEMAIN(WebPageTest,GUI) +#include "webpage_test.moc" diff --git a/src/tests/websnap_test.cpp b/src/tests/websnap_test.cpp new file mode 100644 index 00000000..53fc1d4f --- /dev/null +++ b/src/tests/websnap_test.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> +#include <QtWebKit> + +#include "websnap.h" + + +class WebSnapTest : public QObject +{ + Q_OBJECT + + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + +private: + WebSnap *snap; +}; + + +// ------------------------------------------- + + +void WebSnapTest::initTestCase() +{ +} + + +void WebSnapTest::cleanupTestCase() +{ + delete snap; +} + + +// ------------------------------------------- + + + +// ------------------------------------------- + +QTEST_KDEMAIN(WebSnapTest,GUI) +#include "websnap_test.moc" diff --git a/src/tests/webtab_test.cpp b/src/tests/webtab_test.cpp new file mode 100644 index 00000000..2c6edf35 --- /dev/null +++ b/src/tests/webtab_test.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> +#include <QtWebKit> + +#include "webpage.h" +#include "webview.h" +#include "webtab.h" + + +class WebTabTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private: + WebTab *tab; +}; + + +// ------------------------------------------- + + +void WebTabTest::initTestCase() +{ + tab = new WebTab; +} + + +void WebTabTest::cleanupTestCase() +{ + delete tab; +} + + +// ------------------------------------------- + + +// ------------------------------------------- + +QTEST_KDEMAIN(WebTabTest,GUI) +#include "webtab_test.moc" diff --git a/src/tests/webview_test.cpp b/src/tests/webview_test.cpp new file mode 100644 index 00000000..11d1a46c --- /dev/null +++ b/src/tests/webview_test.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2010 Andrea Diamantini <adjam7@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + + + +#include <qtest_kde.h> + +#include <QtCore> +#include <QtGui> +#include <QtTest> +#include <QtWebKit> + +#include "webview.h" +#include "webtab.h" + + +class WebViewTest : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + +private: + WebView *view; + WebTab *tab; +}; + + +// ------------------------------------------- + + +void WebViewTest::initTestCase() +{ + tab = new WebTab; + view = tab->view(); +} + + +void WebViewTest::cleanupTestCase() +{ + delete tab; +} + + +// ------------------------------------------- + + +// ------------------------------------------- + +QTEST_KDEMAIN(WebViewTest,GUI) +#include "webview_test.moc" diff --git a/src/urlbar/completionwidget.cpp b/src/urlbar/completionwidget.cpp new file mode 100644 index 00000000..8307940b --- /dev/null +++ b/src/urlbar/completionwidget.cpp @@ -0,0 +1,314 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "completionwidget.h" +#include "completionwidget.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "application.h" +#include "urlresolver.h" + +// KDE Includes +#include <KGlobalSettings> +#include <KDebug> +#include <KUrl> + +// Qt Includes +#include <QPoint> +#include <QSize> +#include <QVBoxLayout> +#include <QString> +#include <QEvent> +#include <QKeyEvent> + +// Defines +#define QL1S(x) QLatin1String(x) + + +CompletionWidget::CompletionWidget(QWidget *parent) + : QFrame(parent, Qt::ToolTip) + , _parent(parent) + , _currentIndex(-1) + , _searchEngine( defaultSearchEngine() ) +{ + setFrameStyle(QFrame::Panel); + setLayoutDirection(Qt::LeftToRight); + QVBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + setLayout(layout); +} + + +void CompletionWidget::insertSearchList(const UrlSearchList &list, const QString& text) +{ + _list = list; + int i = 0; + foreach(UrlSearchItem item, _list) + { + ListItem *suggestion = ListItemFactory::create(item, text, this); + suggestion->setBackgroundRole(i%2 ? QPalette::AlternateBase : QPalette::Base); + connect(suggestion, SIGNAL(itemClicked(ListItem *, Qt::MouseButton)), this, SLOT(itemChosen(ListItem *, Qt::MouseButton))); + connect(this, SIGNAL(nextItemSubChoice()), suggestion, SLOT(nextItemSubChoice())); + suggestion->setObjectName( QString::number(i++) ); + layout()->addWidget( suggestion ); + } +} + + +void CompletionWidget::sizeAndPosition() +{ + setFixedWidth( _parent->width() ); + adjustSize(); + + // position + QPoint p = _parent->mapToGlobal( QPoint(0,0) ); + move(p.x(), p.y() + _parent->height()); +} + + +void CompletionWidget::popup() +{ + down(); + sizeAndPosition(); + if (!isVisible()) + show(); +} + + +void CompletionWidget::up() +{ + // deactivate previous + if(_currentIndex != -1) + { + ListItem *widget = findChild<ListItem *>( QString::number(_currentIndex) ); + widget->deactivate(); + } + + if(_currentIndex > 0) + _currentIndex--; + else + _currentIndex=layout()->count()-1; + + // activate "new" current + ListItem *widget = findChild<ListItem *>( QString::number(_currentIndex) ); + widget->activate(); +} + + +void CompletionWidget::down() +{ + // deactivate previous + if(_currentIndex != -1) + { + ListItem *widget = findChild<ListItem *>( QString::number(_currentIndex) ); + widget->deactivate(); + } + + if(_currentIndex < _list.count() -1) + _currentIndex++; + else + _currentIndex=0; + + // activate "new" current + ListItem *widget = findChild<ListItem *>( QString::number(_currentIndex) ); + widget->activate(); +} + + +void CompletionWidget::clear() +{ + QLayoutItem *child; + while ((child = layout()->takeAt(0)) != 0) + { + delete child->widget(); + delete child; + } + _currentIndex = -1; +} + + +bool CompletionWidget::eventFilter( QObject *o, QEvent *e ) +{ + int type = e->type(); + QWidget *wid = qobject_cast<QWidget*>(o); + + if (o == this) + { + return false; + } + + //hide conditions of the CompletionWidget + if (wid + && ((wid == _parent && (type == QEvent::Move || type == QEvent::Resize)) + || ((wid->windowFlags() & Qt::Window) + && (type == QEvent::Move || type == QEvent::Hide || type == QEvent::WindowDeactivate) + && wid == _parent->window()) + || (type == QEvent::MouseButtonPress && !isAncestorOf(wid))) + ) + { + hide(); + return false; + } + + //actions on the CompletionWidget + if (wid && wid->isAncestorOf(_parent) && isVisible()) + { + ListItem *child; + + if ( type == QEvent::KeyPress ) + { + QKeyEvent *ev = static_cast<QKeyEvent *>( e ); + switch ( ev->key() ) + { + case Qt::Key_Up: + case Qt::Key_Backtab: + if (ev->modifiers() == Qt::NoButton || (ev->modifiers() & Qt::ShiftModifier)) + { + up(); + ev->accept(); + return true; + } + break; + + case Qt::Key_Down: + case Qt::Key_Tab: + if (ev->modifiers() == Qt::NoButton) + { + down(); + ev->accept(); + return true; + } + if (ev->modifiers() & Qt::ControlModifier) + { + emit nextItemSubChoice(); + ev->accept(); + return true; + } + break; + + case Qt::Key_Enter: + case Qt::Key_Return: + child = findChild<ListItem *>( QString::number(_currentIndex) ); + emit chosenUrl( child->url(), Rekonq::CurrentTab); + ev->accept(); + hide(); + return true; + + case Qt::Key_Escape: + hide(); + return true; + } + } + } + + return QFrame::eventFilter(o,e); +} + + +void CompletionWidget::setVisible( bool visible ) +{ + if (visible) + { + Application::instance()->installEventFilter(this); + } + else + { + Application::instance()->removeEventFilter(this); + } + + + QFrame::setVisible(visible); +} + + +void CompletionWidget::itemChosen(ListItem *item, Qt::MouseButton button) +{ + if(button == Qt::MidButton) + emit chosenUrl( item->url(), Rekonq::NewCurrentTab); + else + emit chosenUrl( item->url(), Rekonq::CurrentTab); + hide(); +} + + + + +void CompletionWidget::suggestUrls(const QString &text) +{ + QWidget *w = qobject_cast<QWidget *>(parent()); + if(!w->hasFocus()) + return; + + if(text.isEmpty()) + { + hide(); + return; + } + + UrlResolver res(text); + UrlSearchList list = res.orderedSearchItems(); + if(list.count() > 0) + { + clear(); + insertSearchList(list, text); + popup(); + } +} + + +QString CompletionWidget::defaultSearchEngine() +{ + int n = ReKonfig::searchEngine(); + QString engine; + switch(n) + { + case 0: + engine = QL1S("google"); + break; + case 1: + engine = QL1S("altavista"); + break; + case 2: + engine = QL1S("lycos"); + break; + case 3: + engine = QL1S("wikipedia"); + break; + case 4: + engine = QL1S("wolfram"); + break; + default: + engine = QL1S("google"); + break; + } + + return engine; +} diff --git a/src/urlbar/completionwidget.h b/src/urlbar/completionwidget.h new file mode 100644 index 00000000..e9851484 --- /dev/null +++ b/src/urlbar/completionwidget.h @@ -0,0 +1,82 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef COMPLETION_WIDGET_H +#define COMPLETION_WIDGET_H + + +// Local Includes +#include "application.h" +#include "listitem.h" + +// KDE Includes +#include <KLineEdit> + +// Qt Includes +#include <QFrame> + + +class CompletionWidget : public QFrame +{ + Q_OBJECT + +public: + CompletionWidget(QWidget *parent); + + virtual bool eventFilter(QObject *obj, QEvent *ev); + void setVisible(bool visible); + + QString searchEngine() { return _searchEngine; }; + void setCurrentEngine(const QString &engine) { _searchEngine = engine; }; + +private slots: + void itemChosen(ListItem *item, Qt::MouseButton = Qt::LeftButton); + void suggestUrls(const QString &text); + +signals: + void chosenUrl(const KUrl &, Rekonq::OpenType); + void nextItemSubChoice(); + +private: + QString defaultSearchEngine(); + + void insertSearchList(const UrlSearchList &list, const QString& text); + void popup(); + void clear(); + + void sizeAndPosition(); + void up(); + void down(); + + QWidget *_parent; + + UrlSearchList _list; + int _currentIndex; + + QString _searchEngine; +}; + +#endif // COMPLETION_WIDGET_H diff --git a/src/urlbar/lineedit.cpp b/src/urlbar/lineedit.cpp index f3c93e8e..6236512f 100644 --- a/src/urlbar/lineedit.cpp +++ b/src/urlbar/lineedit.cpp @@ -30,24 +30,64 @@ #include "lineedit.h" #include "lineedit.moc" +// KDE Includes +#include <klocalizedstring.h> +#include <KDebug> +#include <KStandardDirs> +#include <KIconLoader> + // Qt Includes #include <QtGui/QContextMenuEvent> #include <QtGui/QFocusEvent> #include <QtGui/QKeyEvent> +#include <QStyleOptionFrameV2> +#include <QPainter> + + +IconButton::IconButton(QWidget *parent) + : QToolButton(parent) +{ + setToolButtonStyle(Qt::ToolButtonIconOnly); + setStyleSheet("IconButton { background-color:transparent; border: none; padding: 0px}"); + setCursor(Qt::ArrowCursor); +} + + +// ----------------------------------------------------------------------------------------------------------- LineEdit::LineEdit(QWidget* parent) - : KLineEdit(parent) + : KLineEdit(parent) + , _icon( new IconButton(this) ) { + // cosmetic + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); setMinimumWidth(200); + setMinimumHeight(26); + + // initial style + setStyleSheet( QString("LineEdit { padding: 0 0 0 %1px;} ").arg(_icon->sizeHint().width()) ); + + // doesn't show the clear button + setClearButtonShown(false); + + // trap Key_Enter & Key_Return events, while emitting the returnPressed signal + setTrapReturnKey(true); + + // insert decoded URLs + setUrlDropsEnabled(true); + + // accept focus, via tabbing, clicking & wheeling setFocusPolicy(Qt::WheelFocus); - setHandleSignals(true); - setClearButtonShown(true); + + // disable completion object (we have our own :) ) + setCompletionObject(0); } LineEdit::~LineEdit() { + delete _icon; } @@ -67,3 +107,87 @@ void LineEdit::mouseDoubleClickEvent(QMouseEvent *) { selectAll(); } + + +IconButton *LineEdit::iconButton() const +{ + return _icon; +} + + +void LineEdit::paintEvent(QPaintEvent *event) +{ + // you need this before our code to draw inside the line edit.. + KLineEdit::paintEvent(event); + + if (text().isEmpty()) + { + QStyleOptionFrame option; + initStyleOption(&option); + QRect textRect = style()->subElementRect(QStyle::SE_LineEditContents, &option, this); + QPainter painter(this); + painter.setPen(Qt::gray); + painter.drawText( textRect, + Qt::AlignCenter, + i18n("Search Bookmarks, History, Web.. just start typing here!") + ); + } +} + + +IconButton *LineEdit::addRightIcon(LineEdit::icon ic) +{ + IconButton *rightIcon = new IconButton(this); + + switch(ic) + { + case LineEdit::KGet: + rightIcon->setIcon( KIcon("download") ); + rightIcon->setToolTip( i18n("List all links with KGet") ); + break; + case LineEdit::RSS: + rightIcon->setIcon( KIcon("application-rss+xml") ); + rightIcon->setToolTip( i18n("List all available RSS feeds") ); + break; + case LineEdit::SSL: + rightIcon->setIcon( KIcon("object-locked") ); + rightIcon->setToolTip( i18n("Show SSL Infos") ); + break; + default: + kDebug() << "ERROR.. default non extant case!!"; + break; + } + + _rightIconsList << rightIcon; + int iconsCount = _rightIconsList.count(); + rightIcon->move( width() - 23*iconsCount, 6); + rightIcon->show(); + + return rightIcon; +} + + +void LineEdit::clearRightIcons() +{ + qDeleteAll(_rightIconsList); + _rightIconsList.clear(); +} + + +void LineEdit::resizeEvent(QResizeEvent *event) +{ + int newHeight = ( height() - 19 )/2; + _icon->move(4, newHeight ); + + int iconsCount = _rightIconsList.count(); + int w = width(); + + for(int i = 0; i < iconsCount; ++i) + { + IconButton *bt = _rightIconsList.at(i); + bt->move( w - 25*(i+1), newHeight ); + } + + KLineEdit::resizeEvent(event); + +} diff --git a/src/urlbar/lineedit.h b/src/urlbar/lineedit.h index 67ded052..68cdc7d1 100644 --- a/src/urlbar/lineedit.h +++ b/src/urlbar/lineedit.h @@ -32,11 +32,32 @@ // KDE Includes #include <KLineEdit> +#include <KIcon> + +// Qt Includes +#include <QToolButton> // Forward Declarations class QContextMenuEvent; class QFocusEvent; class QKeyEvent; +class QStyleOptionFrameV2; + + +class IconButton : public QToolButton +{ + Q_OBJECT + +public: + IconButton(QWidget *parent = 0); +}; + + +// ------------------------------------------------------------------------------------ + + +// Definitions +typedef QList<IconButton *> IconButtonPointerList; class LineEdit : public KLineEdit @@ -44,12 +65,33 @@ class LineEdit : public KLineEdit Q_OBJECT public: + + enum icon + { + KGet = 0x00000001, + RSS = 0x00000010, + SSL = 0x00000100, + }; + explicit LineEdit(QWidget *parent = 0); virtual ~LineEdit(); + + IconButton *iconButton() const; protected: - virtual void keyPressEvent(QKeyEvent*); + virtual void keyPressEvent(QKeyEvent *); virtual void mouseDoubleClickEvent(QMouseEvent *); + virtual void paintEvent(QPaintEvent *); + virtual void resizeEvent(QResizeEvent *); + + IconButton *addRightIcon(LineEdit::icon ); + +private slots: + void clearRightIcons(); + +private: + IconButton *_icon; + IconButtonPointerList _rightIconsList; }; #endif // LINEEDIT_H diff --git a/src/urlbar/listitem.cpp b/src/urlbar/listitem.cpp new file mode 100644 index 00000000..a182c1a2 --- /dev/null +++ b/src/urlbar/listitem.cpp @@ -0,0 +1,437 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "listitem.h" +#include "listitem.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "urlresolver.h" +#include "application.h" +#include "websnap.h" +#include "completionwidget.h" + +// KDE Includes +#include <KIcon> +#include <KStandardDirs> +#include <KDebug> +#include <QActionGroup> +#include <KConfigGroup> +#include <KIcon> + +// Qt Includes +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QLabel> +#include <QSizePolicy> +#include <QPixmap> +#include <QStylePainter> +#include <QMouseEvent> +#include <QWebSettings> +#include <QFile> + +// Defines +#define QL1S(x) QLatin1String(x) + + +ListItem::ListItem(const UrlSearchItem &item, QWidget *parent) + : QWidget(parent) + , m_option() + , m_url(item.url) +{ + setAutoFillBackground(true); + + m_option.initFrom(this); + m_option.direction = Qt::LeftToRight; + + QPalette p(palette()); + p.setColor(QPalette::Base, Qt::white); // TODO: choose the correct color + + p.setColor(QPalette::AlternateBase, QColor(247,247,247)); // TODO: choose the correct color + setPalette(p); + + QHBoxLayout *hLayout = new QHBoxLayout(this); + hLayout->setSpacing(4); + setLayout(hLayout); + + deactivate(); +} + + +ListItem::~ListItem() +{ + disconnect(); +} + + + +void ListItem::activate() +{ + m_option.state |= QStyle::State_Selected; + update(); +} + + +void ListItem::deactivate() +{ + m_option.state &= ~QStyle::State_Selected; + update(); +} + + +void ListItem::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + + if( m_option.state.testFlag(QStyle::State_Selected) || m_option.state.testFlag(QStyle::State_MouseOver)) + { + QPainter painter(this); + m_option.rect=QRect(QPoint(),size()); + style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &m_option, &painter, this); + } + + QWidget::paintEvent(event); +} + + +void ListItem::enterEvent(QEvent *e) +{ + m_option.state |= QStyle::State_MouseOver; + update(); + QWidget::enterEvent(e); +} + + +void ListItem::leaveEvent(QEvent *e) +{ + m_option.state &= ~QStyle::State_MouseOver; + update(); + QWidget::enterEvent(e); +} + + +void ListItem::mousePressEvent(QMouseEvent *e) +{ + emit itemClicked(this, e->button()); + QWidget::mousePressEvent(e); +} + + +KUrl ListItem::url() +{ + return m_url; +} + +void ListItem::nextItemSubChoice() +{ + //will be override +} + + +// --------------------------------------------------------------- + + +TypeIconLabel::TypeIconLabel(int type, QWidget *parent) + : QLabel(parent) +{ + setMinimumWidth(40); + QHBoxLayout *hLayout = new QHBoxLayout(this); + hLayout->setMargin(0); + hLayout->setAlignment(Qt::AlignRight); + setLayout(hLayout); + + if (type & UrlSearchItem::Search) hLayout->addWidget(getIcon("edit-find")); + if (type & UrlSearchItem::Browse) hLayout->addWidget(getIcon("applications-internet")); + if (type & UrlSearchItem::Bookmark) hLayout->addWidget(getIcon("rating")); + if (type & UrlSearchItem::History) hLayout->addWidget(getIcon("view-history")); +} + + +QLabel *TypeIconLabel::getIcon(QString icon) +{ + QLabel *iconLabel = new QLabel(this); + iconLabel->setFixedSize(16,16); + QPixmap pixmap = KIcon(icon).pixmap(16); + iconLabel->setPixmap(pixmap); + return iconLabel; +} + + +// --------------------------------------------------------------- + + +IconLabel::IconLabel(const QString &icon, QWidget *parent) + : QLabel(parent) +{ + QPixmap pixmapIcon = Application::icon( KUrl(icon) ).pixmap(16); + setFixedSize(16,16); + setPixmap(pixmapIcon); +} + + +// --------------------------------------------------------------- + + +TextLabel::TextLabel(const QString &text, const QString &textToPointOut, QWidget *parent) + : QLabel(parent) +{ + QString t = text; + if (!textToPointOut.isEmpty()) + t = t.replace(QRegExp("(" + textToPointOut + ")", Qt::CaseInsensitive), "<b>\\1</b>"); + + setText(t); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); +} + + +//-------------------------------------------------------------------------------------------- + + +PreviewListItem::PreviewListItem(const UrlSearchItem &item, const QString &text, QWidget *parent) + : ListItem(item, parent) +{ + QLabel *previewLabelIcon = new QLabel(this); + previewLabelIcon->setFixedSize(45,33); + new PreviewLabel(item.url.url(), 38, 29, previewLabelIcon); + IconLabel* icon = new IconLabel(item.url.url(), previewLabelIcon); + icon->move(27, 16); + layout()->addWidget(previewLabelIcon); + + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setMargin(0); + vLayout->addWidget( new TextLabel(item.title, text, this) ); + vLayout->addWidget( new TextLabel("<i>" + item.url.url() + "</i>", text, this) ); + ((QHBoxLayout *)layout())->addLayout(vLayout); + + layout()->addWidget( new TypeIconLabel(item.type, this) ); +} + + +// --------------------------------------------------------------- + + +PreviewLabel::PreviewLabel(const QString &url, int width, int height, QWidget *parent) + : QLabel(parent) +{ + setFixedSize(width, height); + setFrameStyle(QFrame::StyledPanel | QFrame::Raised); + + KUrl u = WebSnap::fileForUrl( QUrl(url) ); + QString path = u.pathOrUrl(); + if(QFile::exists(path)) + { + QPixmap preview; + preview.load(path); + setPixmap(preview.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + } +} + + +// --------------------------------------------------------------- + + +SearchListItem::SearchListItem(const UrlSearchItem &item, const QString &text, QWidget *parent) + : ListItem(item, parent) + , m_text(text) +{ + CompletionWidget *w = qobject_cast<CompletionWidget *>(parent); + QString currentEngine = w->searchEngine(); + kDebug() << currentEngine; + + m_iconLabel = new IconLabel("edit-find", this); //TODO: get the default engine icon + m_titleLabel = new TextLabel( searchItemTitle(currentEngine, text), QString(), this); + m_engineBar = new EngineBar(text, currentEngine, parent); + + // without this it will not work :) + m_url = m_engineBar->url(); + + layout()->addWidget( m_iconLabel ); + layout()->addWidget( m_titleLabel ); + layout()->addWidget( new QLabel( i18n("Engines: "), this ) ); + layout()->addWidget( m_engineBar ); + layout()->addWidget( new TypeIconLabel(item.type, this) ); + + connect(m_engineBar, SIGNAL(searchEngineChanged(QString, QString)), this, SLOT(changeSearchEngine(QString, QString))); +} + + +QString SearchListItem::searchItemTitle(QString engine, QString text) +{ + return QString("Search "+ engine +" for <b>"+text+"</b>"); +} + + +void SearchListItem::changeSearchEngine(QString url, QString engine) +{ + m_titleLabel->setText(searchItemTitle(engine,m_text)); + m_iconLabel->setPixmap(Application::icon( KUrl(url) ).pixmap(16)); + QString url2 = url.replace( QL1S("\\{@}"), m_text); + m_url = KUrl(url2); + + CompletionWidget *w = qobject_cast<CompletionWidget *>(parent()); + w->setCurrentEngine( engine ); +} + + +void SearchListItem::nextItemSubChoice() +{ + m_engineBar->selectNextEngine(); +} + + +// ----------------------------------------------------------------------------------------------- + + +EngineBar::EngineBar(const QString &text, const QString &selectedEngine, QWidget *parent) + : KToolBar(parent) +{ + setIconSize(QSize(16,16)); + setToolButtonStyle(Qt::ToolButtonIconOnly); + + m_engineGroup = new QActionGroup(this); + m_engineGroup->setExclusive(true); + + KConfig config("kuriikwsfilterrc"); //Share with konqueror + KConfigGroup cg = config.group("General"); + QStringList favoriteEngines; + favoriteEngines << "wikipedia" << "google"; //defaults + favoriteEngines = cg.readEntry("FavoriteSearchEngines", favoriteEngines); + + // default engine + CompletionWidget *w = qobject_cast<CompletionWidget *>(parent); + QString defaultEngine = w->searchEngine(); + KService::Ptr service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(defaultEngine)); + + m_engineGroup->addAction(newEngineAction(service, selectedEngine)); + + // set url; + QString url = service->property("Query").toString(); + url = url.replace("\\{@}",text); + m_url = KUrl(url); + + Q_FOREACH(const QString &engine, favoriteEngines) + { + if(!engine.isEmpty()) + { + service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(engine)); + if(service && service->desktopEntryName() != defaultEngine) + { + m_engineGroup->addAction(newEngineAction(service, selectedEngine)); + } + } + } + + addActions(m_engineGroup->actions()); +} + + +KAction *EngineBar::newEngineAction(KService::Ptr service, QString selectedEngine) +{ + KAction *a = new KAction(Application::icon(m_url), service->name(), this); + a->setCheckable(true); + if (service->name()==selectedEngine) + a->setChecked(true); + + QString url = service->property("Query").toString(); + + a->setData( QStringList() << url << service->desktopEntryName() ); + connect(a, SIGNAL(triggered(bool)), this, SLOT(changeSearchEngine())); + + return a; +} + + +void EngineBar::changeSearchEngine() +{ + KAction *a = qobject_cast<KAction*>(sender()); + QStringList list = a->data().toStringList(); + emit searchEngineChanged(list.first(), list.last()); +} + + +void EngineBar::selectNextEngine() +{ + QList<QAction *> e = m_engineGroup->actions(); + int i = 0; + while(i<e.count() && !e.at(i)->isChecked()) + { + i++; + } + + if (i+1 == e.count()) + { + e.at(0)->setChecked(true); + e.at(0)->trigger(); + } + else + { + e.at(i+1)->setChecked(true); + e.at(i+1)->trigger(); + } +} + + +// --------------------------------------------------------------- + + +BrowseListItem::BrowseListItem(const UrlSearchItem &item, const QString &text, QWidget *parent) + : ListItem(item, parent) +{ + QString url = text; + layout()->addWidget( new IconLabel(item.url.url(), this) ); + layout()->addWidget( new TextLabel( QL1S("Browse <i>http://<b>") + url.remove("http://") + QL1S("</b></i>"), QString(), this) ); + layout()->addWidget( new TypeIconLabel(item.type, this) ); +} + + +// --------------------------------------------------------------- + + +ListItem *ListItemFactory::create(const UrlSearchItem &item, const QString &text, QWidget *parent) +{ + ListItem *newItem; + + if(item.type & UrlSearchItem::Browse) + { + newItem = new BrowseListItem(item, text, parent); + } + else + { + if(item.type & UrlSearchItem::Search) + { + newItem = new SearchListItem(item, text, parent); + } + else + { + newItem = new PreviewListItem(item, text, parent); + } + } + + return newItem; +} diff --git a/src/urlbar/listitem.h b/src/urlbar/listitem.h new file mode 100644 index 00000000..de42fd03 --- /dev/null +++ b/src/urlbar/listitem.h @@ -0,0 +1,221 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef LISTITEM_H +#define LISTITEM_H + + +// Local Includes +#include "urlresolver.h" + +// KDE Includes +#include <KToolBar> +#include <KAction> +#include <KService> + +// Qt Includes +#include <QWidget> +#include <QLayout> +#include <QStyleOptionViewItemV4> +#include <QLabel> + +// Forward Declarations +class UrlSearchItem; + + +class ListItem : public QWidget +{ + Q_OBJECT + +public: + ListItem(const UrlSearchItem &item, QWidget *parent = 0); + virtual ~ListItem(); + + void activate(); + void deactivate(); + + KUrl url(); + +public slots: + virtual void nextItemSubChoice(); + +signals: + void itemClicked(ListItem *item, Qt::MouseButton); + +protected: + virtual void paintEvent(QPaintEvent *event); + virtual void enterEvent(QEvent *); + virtual void leaveEvent(QEvent *); + virtual void mousePressEvent(QMouseEvent *e); + +private: + QStyleOptionViewItemV4 m_option; + +protected: + KUrl m_url; +}; + + +// ------------------------------------------------------------------------- + + +class TypeIconLabel : public QLabel +{ + Q_OBJECT + +public: + TypeIconLabel(int type, QWidget *parent = 0); + +private: + QLabel *getIcon(QString icon); +}; + + +// ------------------------------------------------------------------------- + + +class IconLabel : public QLabel +{ + Q_OBJECT + +public: + IconLabel(const QString &icon, QWidget *parent = 0); +}; + + +// ------------------------------------------------------------------------- + + +class TextLabel : public QLabel +{ + Q_OBJECT + +public: + TextLabel(const QString &text, const QString &textToPointOut = QString(), QWidget *parent = 0); +}; + + +// ------------------------------------------------------------------------- + + +class EngineBar : public KToolBar +{ + Q_OBJECT + +public: + EngineBar(const QString &text, const QString &selectedEngine, QWidget *parent = 0); + + void selectNextEngine(); + KUrl url() { return m_url; }; + +signals: + void searchEngineChanged(QString url, QString engine); + +private slots: + void changeSearchEngine(); + +private: + KAction *newEngineAction(KService::Ptr service, QString selectedEngine); + + QActionGroup *m_engineGroup; + KUrl m_url; +}; + + +// ------------------------------------------------------------------------- + + +class SearchListItem : public ListItem +{ + Q_OBJECT + +public: + SearchListItem(const UrlSearchItem &item, const QString &text, QWidget *parent = 0); + +public slots: + virtual void nextItemSubChoice(); + +private slots: + void changeSearchEngine(QString url, QString engine); + +private: + QString searchItemTitle(QString engine, QString text); + + TextLabel* m_titleLabel; + IconLabel* m_iconLabel; + EngineBar* m_engineBar; + + QString m_text; +}; + + +// ------------------------------------------------------------------------- + + +class PreviewListItem : public ListItem +{ + Q_OBJECT + +public: + PreviewListItem(const UrlSearchItem &item, const QString &text, QWidget *parent = 0); +}; + + +// ------------------------------------------------------------------------- + + +class PreviewLabel : public QLabel +{ + Q_OBJECT + +public: + PreviewLabel(const QString &url, int width, int height, QWidget *parent = 0); +}; + + +// ------------------------------------------------------------------------- + + +class BrowseListItem : public ListItem +{ + Q_OBJECT + +public: + BrowseListItem(const UrlSearchItem &item, const QString &text, QWidget *parent = 0); +}; + + +//------------------------------------------------------------------------------------------------- + + +class ListItemFactory +{ +public: + static ListItem *create(const UrlSearchItem &item, const QString &text, QWidget *parent); +}; + + +#endif diff --git a/src/urlbar/urlbar.cpp b/src/urlbar/urlbar.cpp index adeba6ae..6d1b19c9 100644 --- a/src/urlbar/urlbar.cpp +++ b/src/urlbar/urlbar.cpp @@ -31,12 +31,16 @@ #include "urlbar.h" #include "urlbar.moc" +// Auto Includes +#include "rekonq.h" + // Local Includes #include "application.h" #include "lineedit.h" #include "mainwindow.h" +#include "webtab.h" #include "webview.h" -#include "historymanager.h" +#include "completionwidget.h" // KDE Includes #include <KDebug> @@ -48,299 +52,219 @@ #include <QPaintEvent> #include <QPalette> #include <QTimer> +#include <QVBoxLayout> - -QColor UrlBar::s_defaultBaseColor; +// Defines +#define QL1S(x) QLatin1String(x) UrlBar::UrlBar(QWidget *parent) - : KHistoryComboBox(true, parent) - , m_lineEdit(new LineEdit) - , m_progress(0) + : LineEdit(parent) + , _tab(0) + , _privateMode(false) { - setUrlDropsEnabled(true); - setAutoDeleteCompletionObject(true); - - //cosmetic - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - setMinimumWidth(180); + _tab = qobject_cast<WebTab *>(parent); - setTrapReturnKey(true); - - setupLineEdit(); - - // add every item to history - connect(this, SIGNAL(returnPressed(const QString&)), SLOT(activated(const QString&))); - connect(completionBox(), SIGNAL(activated(const QString&)), SLOT(activated(const QString&))); - - connect(this, SIGNAL(cleared()), SLOT(cleared())); - - // setup completion box - setCompletionObject( Application::historyManager()->completionObject() ); + connect(_tab->view(), SIGNAL(urlChanged(const QUrl &)), this, SLOT(setQUrl(const QUrl &))); + connect(_tab->view(), SIGNAL(loadFinished(bool)), this, SLOT(loadFinished())); + connect(_tab->view(), SIGNAL(loadStarted()), this, SLOT(clearRightIcons())); - // set dropdown list background - QPalette p = view()->palette(); - p.setColor(QPalette::Base, palette().color(QPalette::Base)); - view()->setPalette(p); + // load typed urls + connect(this, SIGNAL(returnPressed(const QString &)), this, SLOT(loadTyped(const QString &))); - // load urls on activated urlbar signal - connect(this, SIGNAL(activated(const KUrl&)), Application::instance(), SLOT(loadUrl(const KUrl&))); + activateSuggestions(true); } UrlBar::~UrlBar() { + activateSuggestions(false); + _box.clear(); } -void UrlBar::selectAll() const -{ - lineEdit()->selectAll(); -} - - -KUrl UrlBar::url() const -{ - return m_currentUrl; -} - - -KLineEdit *UrlBar::lineEdit() const -{ - return m_lineEdit; -} - - -void UrlBar::setupLineEdit() -{ - // Make m_lineEdit background transparent - QPalette p = m_lineEdit->palette(); - p.setColor(QPalette::Base, Qt::transparent); - m_lineEdit->setPalette(p); - - if (!s_defaultBaseColor.isValid()) - { - s_defaultBaseColor = palette().color(QPalette::Base); - } - - setLineEdit(m_lineEdit); - - // Make the lineedit consume the Qt::Key_Enter event... - lineEdit()->setTrapReturnKey(true); - - lineEdit()->setHandleSignals(true); - - // clear the URL bar - lineEdit()->clear(); -} - - -void UrlBar::setUrl(const QUrl& url) +void UrlBar::setQUrl(const QUrl& url) { - if(url.scheme() == "about") + if(url.scheme() == QL1S("about") ) { - m_currentUrl = KUrl(); - updateUrl(); // updateUrl before setFocus + iconButton()->setIcon( KIcon("arrow-right") ); + clear(); setFocus(); } else { - m_currentUrl = KUrl(url); - updateUrl(); + clearFocus(); + LineEdit::setUrl(url); + setCursorPosition(0); + iconButton()->setIcon( Application::icon(url) ); } - } -void UrlBar::setProgress(int progress) +void UrlBar::activated(const KUrl& url, Rekonq::OpenType type) { - m_progress = progress; - repaint(); + activateSuggestions(false); + + clearFocus(); + setUrl(url); + Application::instance()->loadUrl(url, type); } -void UrlBar::updateUrl() +void UrlBar::paintEvent(QPaintEvent *event) { - // Don't change my typed url... - // FIXME this is not a proper solution (also if it works...) - if(hasFocus()) - { - kDebug() << "Don't change my typed url..."; - return; - } - - KIcon icon; - if(m_currentUrl.isEmpty()) - { - icon = KIcon("arrow-right"); - } - else - { - icon = Application::icon(m_currentUrl); - } - - if (count()) + QColor backgroundColor; + if( _privateMode ) { - changeUrl(0, icon, m_currentUrl); + backgroundColor = QColor(220, 220, 220); // light gray } else { - insertUrl(0, icon, m_currentUrl); + backgroundColor = Application::palette().color(QPalette::Base); } + + // set background color of UrlBar + QPalette p = palette(); - setCurrentIndex(0); - - // important security consideration: always display the beginning - // of the url rather than its end to prevent spoofing attempts. - // Must be AFTER setCurrentIndex - if (!hasFocus()) + int progr = _tab->progress(); + if (progr == 0) + { + if( _tab->url().scheme() == QL1S("https") ) + { + backgroundColor = QColor(255, 255, 171); // light yellow + } + p.setBrush(QPalette::Base, backgroundColor); + } + else { - lineEdit()->setCursorPosition(0); + QColor loadingColor = QColor(116, 192, 250); + + QLinearGradient gradient(0, 0, width(), 0); + gradient.setColorAt(0, loadingColor); + gradient.setColorAt(((double)progr)/100, backgroundColor); + p.setBrush(QPalette::Base, gradient); } + setPalette(p); + + LineEdit::paintEvent(event); } -void UrlBar::activated(const QString& urlString) -{ - if (urlString.isEmpty()) - return; - - setUrl(urlString); - emit activated(m_currentUrl); -} - - -void UrlBar::cleared() -{ - // clear the history on user's request from context menu - clear(); -} - - -void UrlBar::loadFinished(bool) -{ - // reset progress bar after small delay - m_progress = 0; - QTimer::singleShot(200, this, SLOT(repaint())); -} - - -void UrlBar::updateProgress(int progress) -{ - m_progress = progress; - repaint(); -} - - -void UrlBar::paintEvent(QPaintEvent *event) +void UrlBar::keyPressEvent(QKeyEvent *event) { - // set background color of UrlBar - QPalette p = palette(); - p.setColor(QPalette::Base, s_defaultBaseColor); - setPalette(p); - - KHistoryComboBox::paintEvent(event); - - if (!hasFocus()) + // this handles the Modifiers + Return key combinations + QString currentText = text().trimmed(); + if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) + && !currentText.startsWith(QLatin1String("http://"), Qt::CaseInsensitive)) { - QPainter painter(this); - - QColor loadingColor; - if (m_currentUrl.scheme() == QLatin1String("https")) + QString append; + if (event->modifiers() == Qt::ControlModifier) + { + append = QLatin1String(".com"); + } + else if (event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { - loadingColor = QColor(248, 248, 100); + append = QLatin1String(".org"); } - else + else if (event->modifiers() == Qt::ShiftModifier) + { + append = QLatin1String(".net"); + } + + QUrl url(QLatin1String("http://www.") + currentText); + QString host = url.host(); + if (!host.endsWith(append, Qt::CaseInsensitive)) { - loadingColor = QColor(116, 192, 250); + host += append; + url.setHost(host); + setText(url.toString()); } - painter.setBrush(generateGradient(loadingColor, height())); - painter.setPen(Qt::transparent); - - QRect backgroundRect = lineEdit()->frameGeometry(); - int mid = backgroundRect.width() * m_progress / 100; - QRect progressRect(backgroundRect.x(), backgroundRect.y(), mid, backgroundRect.height()); - painter.drawRect(progressRect); - painter.end(); } + + LineEdit::keyPressEvent(event); } -QSize UrlBar::sizeHint() const +void UrlBar::focusInEvent(QFocusEvent *event) { - return lineEdit()->sizeHint(); + activateSuggestions(true); + + LineEdit::focusInEvent(event); } -QLinearGradient UrlBar::generateGradient(const QColor &color, int height) +void UrlBar::setPrivateMode(bool on) { - QColor base = s_defaultBaseColor; - base.setAlpha(0); - QColor barColor = color; - barColor.setAlpha(200); - QLinearGradient gradient(0, 0, 0, height); - gradient.setColorAt(0, base); - gradient.setColorAt(0.25, barColor.lighter(120)); - gradient.setColorAt(0.5, barColor); - gradient.setColorAt(0.75, barColor.lighter(120)); - gradient.setColorAt(1, base); - return gradient; + _privateMode = on; } -void UrlBar::setBackgroundColor(QColor c) +void UrlBar::dropEvent(QDropEvent *event) { - s_defaultBaseColor = c; - repaint(); + LineEdit::dropEvent(event); + activated(text()); } -bool UrlBar::isLoading() +void UrlBar::loadFinished() { - if(m_progress == 0) + if(_tab->progress() != 0) + return; + + if(_tab->url().scheme() == QL1S("about") ) + { + update(); + return; + } + + // show KGet downloads?? + if(ReKonfig::kgetList()) + { + IconButton *bt = addRightIcon(LineEdit::KGet); + connect(bt, SIGNAL(clicked()), _tab->page(), SLOT(downloadAllContentsWithKGet())); + } + + // show RSS + if(_tab->hasRSSInfo()) + { + IconButton *bt = addRightIcon(LineEdit::RSS); + connect(bt, SIGNAL(clicked()), _tab, SLOT(showRSSInfo())); + } + + // show SSL + if(_tab->url().scheme() == QL1S("https") ) { - return false; + IconButton *bt = addRightIcon(LineEdit::SSL); + connect(bt, SIGNAL(clicked()), _tab->page(), SLOT(showSSLInfo())); } - return true; + + update(); } -void UrlBar::keyPressEvent(QKeyEvent *event) +void UrlBar::loadTyped(const QString &text) { - QString currentText = m_lineEdit->text().trimmed(); - if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) + activated(KUrl(text)); +} + + +void UrlBar::activateSuggestions(bool b) +{ + if(b) { - if( !currentText.startsWith(QLatin1String("http://"), Qt::CaseInsensitive) ) + if(_box.isNull()) { - QString append; - if (event->modifiers() == Qt::ControlModifier) - { - append = QLatin1String(".com"); - } - else if (event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) - { - append = QLatin1String(".org"); - } - else if (event->modifiers() == Qt::ShiftModifier) - { - append = QLatin1String(".net"); - } - - QUrl url(QLatin1String("http://www.") + currentText); - QString host = url.host(); - if (!host.endsWith(append, Qt::CaseInsensitive)) - { - host += append; - url.setHost(host); - m_lineEdit->setText(url.toString()); - } - } - else - { - // fill lineEdit with its stripped contents to remove trailing spaces - m_lineEdit->setText(currentText); + _box = new CompletionWidget(this); + installEventFilter(_box.data()); + connect(_box.data(), SIGNAL(chosenUrl(const KUrl &, Rekonq::OpenType)), this, SLOT(activated(const KUrl &, Rekonq::OpenType))); + + // activate suggestions on edit text + connect(this, SIGNAL(textChanged(const QString &)), _box.data(), SLOT(suggestUrls(const QString &))); } } - - KHistoryComboBox::keyPressEvent(event); + else + { + removeEventFilter(_box.data()); + _box.data()->deleteLater(); + } } diff --git a/src/urlbar/urlbar.h b/src/urlbar/urlbar.h index 8d267b2c..28afc21e 100644 --- a/src/urlbar/urlbar.h +++ b/src/urlbar/urlbar.h @@ -32,22 +32,24 @@ // Local Includes +#include "rekonqprivate_export.h" #include "lineedit.h" +#include "application.h" // KDE Includes #include <KUrl> -#include <KHistoryComboBox> // Qt Includes -#include <QUrl> +#include <QWeakPointer> // Forward Declarations class QLinearGradient; class QWidget; -class KCompletion; +class CompletionWidget; +class WebTab; -class UrlBar : public KHistoryComboBox +class REKONQ_TESTS_EXPORT UrlBar : public LineEdit { Q_OBJECT @@ -55,44 +57,27 @@ public: UrlBar(QWidget *parent = 0); ~UrlBar(); - void selectAll() const; - KUrl url() const; - QSize sizeHint() const; - void setBackgroundColor(QColor); - bool isLoading(); - - void setProgress(int progress); - -signals: - void activated(const KUrl&); + void setPrivateMode(bool on); -public slots: - void setUrl(const QUrl &url); - void updateProgress(int progress); - void updateUrl(); - private slots: - void activated(const QString& url); - void loadFinished(bool); - void cleared(); + void activated(const KUrl& url, Rekonq::OpenType = Rekonq::CurrentTab); + void setQUrl(const QUrl &url); + void loadFinished(); + void loadTyped(const QString &); + protected: virtual void paintEvent(QPaintEvent *event); virtual void keyPressEvent(QKeyEvent *event); + virtual void focusInEvent(QFocusEvent *event); + virtual void dropEvent(QDropEvent *event); private: - void setupLineEdit(); - - KLineEdit *lineEdit() const; - - static QLinearGradient generateGradient(const QColor &color, int height); - - static QColor s_defaultBaseColor; - - LineEdit *m_lineEdit; - - KUrl m_currentUrl; - int m_progress; + void activateSuggestions(bool); + + QWeakPointer<CompletionWidget> _box; + WebTab *_tab; + bool _privateMode; }; #endif diff --git a/src/urlbar/urlresolver.cpp b/src/urlbar/urlresolver.cpp new file mode 100644 index 00000000..5b4b1625 --- /dev/null +++ b/src/urlbar/urlresolver.cpp @@ -0,0 +1,230 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "urlresolver.h" + +// Local Includes +#include "application.h" +#include "historymanager.h" +#include "bookmarksmanager.h" + +// KDE Includes +#include <KUriFilter> +#include <KCompletion> +#include <KDebug> +#include <KService> +#include <KConfig> +#include <KConfigGroup> + +// Qt Includes +#include <QString> +#include <QByteArray> +#include <QUrl> + +// defines +#define MAX_ELEMENTS 9 + + +// NOTE default kurifilter plugin list (at least in my box) +// 1. "kshorturifilter" +// 2. "kurisearchfilter" +// 3. "localdomainurifilter" +// 4 ."kuriikwsfilter" +// 5. "fixhosturifilter" + + +bool UrlSearchItem::operator==(UrlSearchItem i) +{ + return url==i.url; +} + + +UrlResolver::UrlResolver(const QString &typedUrl) + : _typedString(typedUrl.trimmed()) +{ +} + + +UrlSearchList UrlResolver::orderedSearchItems() +{ + // NOTE: the logic here is : "we wanna suggest (at least) 9 elements" + // so we have (more or less) 3 from first results (1 from QUrl Resolutions, 2 from + // default search engines). + // There are 6 remaining: if bookmarkResults + historyResults <= 6, catch all, else + // catch first 3 results from the two resulting lists :) + + UrlSearchList list; + +// if(isHttp()) +// { +// list << qurlFromUserInputResolution(); +// } + + list << webSearchesResolution(); + + if (_typedString.length() >= 2) + { + list << qurlFromUserInputResolution(); + + int firstResults = list.count(); + int checkPoint = 9 - firstResults; + + UrlSearchList historyList = historyResolution(); + int historyResults = historyList.count(); + + UrlSearchList bookmarksList = bookmarksResolution(); + int bookmarkResults = bookmarksList.count(); + + if(historyResults + bookmarkResults > checkPoint) + { + historyList = historyList.mid(0,3); + bookmarksList = bookmarksList.mid(0,3); + } + + QList<UrlSearchItem> common; + + foreach (UrlSearchItem i, historyList) + { + if (!bookmarksList.contains(i)) + { + list << i; + } + else + { + i.type |= UrlSearchItem::Bookmark; + common << i; + } + } + + foreach (UrlSearchItem i, common) + { + list << i; + } + + foreach (UrlSearchItem i, bookmarksList) + { + if (!common.contains(i)) + list << i; + } + } + + return list; +} + + +bool UrlResolver::isHttp() +{ + QString ipv4 = "^0*([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.0*([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])"\ + "\\.0*([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.0*([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])"; + + QString ipv6 = "^([0-9a-fA-F]{4}|0)(\\:([0-9a-fA-F]{4}|0)){7}"; + + QString address = "[\\d\\w-.]+\\.(a[cdefgilmnoqrstuwz]|b[abdefghijmnorstvwyz]|"\ + "c[acdfghiklmnoruvxyz]|d[ejkmnoz]|e[ceghrst]|f[ijkmnor]|g[abdefghilmnpqrstuwy]|"\ + "h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|"\ + "m[acdghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eouw]|"\ + "s[abcdeghijklmnortuvyz]|t[cdfghjkmnoprtvwz]|u[augkmsyz]|v[aceginu]|w[fs]|"\ + "y[etu]|z[amw]|aero|arpa|biz|com|coop|edu|info|int|gov|mil|museum|name|net|org|"\ + "pro)"; + + return _typedString.startsWith("http://") + || _typedString.startsWith("https://") + || (QRegExp(address, Qt::CaseInsensitive).indexIn(_typedString) != -1) + || (QRegExp(ipv4, Qt::CaseInsensitive).indexIn(_typedString) != -1) + || (QRegExp(ipv6, Qt::CaseInsensitive).indexIn(_typedString) != -1); +} + + +////////////////////////////////////////////////////////////////////////// +// PRIVATE ENGINES + + +// STEP 1 = QUrl from User Input (easily the best solution... ) +UrlSearchList UrlResolver::qurlFromUserInputResolution() +{ + UrlSearchList list; + QString url2 = _typedString; + QUrl urlFromUserInput = QUrl::fromUserInput(url2); + if(urlFromUserInput.isValid()) + { + KUrl gUrl(urlFromUserInput); + QString gTitle = i18n("Browse"); + UrlSearchItem gItem(UrlSearchItem::Browse, gUrl, gTitle); + list << gItem; + } + + return list; +} + + +// STEP 2 = Web Searches +UrlSearchList UrlResolver::webSearchesResolution() +{ + UrlSearchList list; + + if(KUrl(_typedString).isRelative()) + { + UrlSearchItem gItem(UrlSearchItem::Search, KUrl(), QString() ); // others will find this url.. + list << gItem; + } + + return list; +} + + +// STEP 3 = history completion +UrlSearchList UrlResolver::historyResolution() +{ + UrlSearchList list; + + KCompletion *historyCompletion = Application::historyManager()->completionObject(); + QStringList historyResults = historyCompletion->substringCompletion(_typedString); + Q_FOREACH(const QString &s, historyResults) + { + UrlSearchItem it(UrlSearchItem::History, KUrl(s), Application::historyManager()->titleForHistoryUrl(s)); + list << it; + } + + return list; +} + + +// STEP 4 = bookmarks completion +UrlSearchList UrlResolver::bookmarksResolution() +{ + UrlSearchList list; + + KCompletion *bookmarkCompletion = Application::bookmarkProvider()->completionObject(); + QStringList bookmarkResults = bookmarkCompletion->substringCompletion(_typedString); + Q_FOREACH(const QString &s, bookmarkResults) + { + UrlSearchItem it(UrlSearchItem::Bookmark, KUrl(s), Application::bookmarkProvider()->titleForBookmarkUrl(s)); + list << it; + } + + return list; +} diff --git a/src/urlbar/urlresolver.h b/src/urlbar/urlresolver.h new file mode 100644 index 00000000..22a9de4f --- /dev/null +++ b/src/urlbar/urlresolver.h @@ -0,0 +1,85 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy +* defined in Section 14 of version 3 of the license. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +#ifndef URL_RESOLVER_H +#define URL_RESOLVER_H + +// KDE Includes +#include <KUrl> + +// Qt Includes +#include <QString> +#include <QList> + + +class UrlSearchItem +{ + + public: + + enum types + { + Search = 0x00000001, + Browse = 0x00000010, + History = 0x00000100, + Bookmark = 0x00001000, + }; + + int type; + KUrl url; + QString title; + + UrlSearchItem(const int &_type, const KUrl &_url, const QString &_title = QString()) + : type(_type), url(_url), title(_title) + {}; + + bool operator==(UrlSearchItem i); +}; + +typedef QList <UrlSearchItem> UrlSearchList; + + +// ---------------------------------------------------------------------- + + +class UrlResolver +{ +public: + UrlResolver(const QString &typedUrl); + + UrlSearchList orderedSearchItems(); + +private: + QString _typedString; + + UrlSearchList webSearchesResolution(); + UrlSearchList historyResolution(); + UrlSearchList qurlFromUserInputResolution(); + UrlSearchList bookmarksResolution(); + bool isHttp(); +}; + +#endif // URL_RESOLVER_H diff --git a/src/walletbar.cpp b/src/walletbar.cpp index c5d705e0..5b911585 100644 --- a/src/walletbar.cpp +++ b/src/walletbar.cpp @@ -28,6 +28,9 @@ #include "walletbar.h" #include "walletbar.moc" +// Auto Includes +#include "rekonq.h" + // KDE Includes #include <klocalizedstring.h> #include <KIcon> @@ -85,7 +88,11 @@ void WalletBar::rememberData() void WalletBar::neverRememberData() { - // TODO: store site url (to remember never bother about) + // add url to the blacklist + QStringList list = ReKonfig::walletBlackList(); + list << m_url.toString(); + ReKonfig::setWalletBlackList( list ); + notNowRememberData(); } diff --git a/src/walletbar.h b/src/walletbar.h index d2e39373..efb28a8f 100644 --- a/src/walletbar.h +++ b/src/walletbar.h @@ -24,10 +24,13 @@ * ============================================================ */ -#ifndef WALLET_WIDGET_H -#define WALLET_WIDGET_H +#ifndef WALLET_BAR_H +#define WALLET_BAR_H +// Local Includes +#include "rekonqprivate_export.h" + // Qt Includes #include <QWidget> #include <QString> @@ -35,7 +38,7 @@ #include <QLabel> -class WalletBar : public QWidget +class REKONQ_TESTS_EXPORT WalletBar : public QWidget { Q_OBJECT @@ -65,4 +68,4 @@ private: QLabel *m_label; }; -#endif // WALLET_WIDGET_H +#endif // WALLET_BAR_H diff --git a/src/webinspectorpanel.cpp b/src/webinspectorpanel.cpp index a038d280..6f8e48a0 100644 --- a/src/webinspectorpanel.cpp +++ b/src/webinspectorpanel.cpp @@ -2,7 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Matthieu Gicquel<matgic78@gmail.com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -10,9 +10,9 @@ * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved -* by the membership of KDE e.V.), which shall act as a proxy +* by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. -* +* * This program 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 diff --git a/src/webinspectorpanel.h b/src/webinspectorpanel.h index 8f65b48a..bb196b5c 100644 --- a/src/webinspectorpanel.h +++ b/src/webinspectorpanel.h @@ -2,7 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Matthieu Gicquel<matgic78@gmail.com> +* Copyright (C) 2010 by Matthieu Gicquel<matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -29,6 +29,9 @@ // Local Includes +#include "rekonqprivate_export.h" + +// Local Includes #include "mainwindow.h" // Qt Includes @@ -38,7 +41,7 @@ Docked web inspector behaviour : hide/show by tab, not globally */ -class WebInspectorPanel : public QDockWidget +class REKONQ_TESTS_EXPORT WebInspectorPanel : public QDockWidget { Q_OBJECT public: diff --git a/src/webpage.cpp b/src/webpage.cpp index b2bedffc..a75272cd 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -6,7 +6,8 @@ * Copyright (C) 2008 Dirk Mueller <mueller@kde.org> * Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org> * Copyright (C) 2008 Michael Howell <mhowell123@gmail.com> -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -44,6 +45,8 @@ #include "networkaccessmanager.h" #include "adblockmanager.h" +#include "sslinfodialog_p.h" + // KDE Includes #include <KStandardDirs> #include <KUrl> @@ -68,32 +71,72 @@ #include <QtGui/QMouseEvent> #include <QtGui/QClipboard> #include <QtGui/QKeyEvent> +#include <QWebFrame> + +// Defines +#define QL1S(x) QLatin1String(x) +#define QL1C(x) QLatin1Char(x) + + +// 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); +} + + +// --------------------------------------------------------------------------------- -WebPage::WebPage(QObject *parent) - : KWebPage(parent, KWalletIntegration) +WebPage::WebPage(QWidget *parent) + : KWebPage(parent, KWalletIntegration) { + // ----- handling unsupported content... setForwardUnsupportedContent(true); + connect(this, SIGNAL(unsupportedContent(QNetworkReply *)), this, SLOT(handleUnsupportedContent(QNetworkReply *))); - // rekonq Network Manager + // ----- rekonq Network Manager NetworkAccessManager *manager = new NetworkAccessManager(this); + manager->setCache(0); // disable QtWebKit cache to just use KIO one.. - // disable QtWebKit cache to just use KIO one.. - manager->setCache(0); - + // set cookieJar window ID.. + if (parent && parent->window()) + manager->setCookieJarWindowId(parent->window()->winId()); + setNetworkAccessManager(manager); - // Web Plugin Factory - setPluginFactory(new WebPluginFactory(this)); + // activate ssl warnings + setSessionMetaData("ssl_activate_warnings", "TRUE"); - - connect(networkAccessManager(), SIGNAL(finished(QNetworkReply*)), this, SLOT(manageNetworkErrors(QNetworkReply*))); + // Override the 'Accept' header sent by QtWebKit which favors XML over HTML! + // Setting the accept meta-data to null will force kio_http to use its own + // default settings for this header. + setSessionMetaData(QL1S("accept"), QString()); - connect(this, SIGNAL(unsupportedContent(QNetworkReply *)), this, SLOT(handleUnsupportedContent(QNetworkReply *))); + // ----- Web Plugin Factory + setPluginFactory(new WebPluginFactory(this)); + + // ----- last stuffs + connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(manageNetworkErrors(QNetworkReply*))); connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool))); // protocol handler signals - connect(&m_protHandler, SIGNAL(downloadUrl(const KUrl &)), this, SLOT(downloadUrl(const KUrl &))); + connect(&_protHandler, SIGNAL(downloadUrl(const KUrl &)), this, SLOT(downloadUrl(const KUrl &))); } @@ -105,23 +148,66 @@ WebPage::~WebPage() bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type) { - // advise users on resubmitting data - if(type == QWebPage::NavigationTypeFormResubmitted) + KIO::AccessManager *manager = qobject_cast<KIO::AccessManager*>(networkAccessManager()); + KIO::MetaData metaData = manager->requestMetaData(); + + // Get the SSL information sent, if any... + if( metaData.contains(QL1S("ssl_in_use")) ) { - int risp = KMessageBox::warningContinueCancel(view(), - i18n("Are you sure you want to send your data again?"), - i18n("Resend form data") ); - if(risp == KMessageBox::Cancel) - return false; + WebSslInfo info; + info.fromMetaData(metaData.toVariant()); + info.setUrl(request.url()); + _sslInfo = info; } - - if (frame && m_protHandler.preHandling( request, frame )) + + if(frame) { - return false; + if ( _protHandler.preHandling(request, frame) ) + { + return false; + } + + switch (type) + { + case QWebPage::NavigationTypeLinkClicked: + if (_sslInfo.isValid() ) + { + setRequestMetaData("ssl_was_in_use", "TRUE"); + } + break; + + case QWebPage::NavigationTypeFormSubmitted: + break; + + case QWebPage::NavigationTypeFormResubmitted: + if( KMessageBox::warningContinueCancel(view(), + i18n("Are you sure you want to send your data again?"), + i18n("Resend form data") + ) + == KMessageBox::Cancel) + { + return false; + } + break; + + case QWebPage::NavigationTypeReload: + case QWebPage::NavigationTypeBackOrForward: + case QWebPage::NavigationTypeOther: + break; + + default: + break; + } + + if(frame == mainFrame()) + { + setRequestMetaData("main_frame_request", "TRUE"); + } + else + { + setRequestMetaData("main_frame_request", "FALSE"); + } } - - m_requestedUrl = request.url(); - return KWebPage::acceptNavigationRequest(frame, request, type); } @@ -137,7 +223,7 @@ WebPage *WebPage::createWindow(QWebPage::WebWindowType type) WebTab *w = 0; if(ReKonfig::openTabNoWindow()) { - w = Application::instance()->mainWindow()->mainView()->newWebTab(!ReKonfig::openTabsBack()); + w = Application::instance()->mainWindow()->mainView()->newWebTab(!ReKonfig::openTabsBack(), ReKonfig::openTabsNearCurrent()); } else { @@ -160,7 +246,12 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply) if( offer.isNull() ) // no service can handle this. We can just download it.. { - isLocal ? KMessageBox::sorry(view(), i18n("No service can handle this :(") ) : downloadRequest(reply->request()); + kDebug() << "no service can handle this. We can just download it.."; + + isLocal + ? KMessageBox::sorry(view(), i18n("No service can handle this :(") ) + : downloadRequest( reply->request() ); + return; } @@ -171,18 +262,35 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply) switch ( dlg.askEmbedOrSave() ) { case KParts::BrowserOpenOrSaveQuestion::Save: - downloadRequested(reply->request()); - return; + kDebug() << "service handling: download!"; + downloadRequest( reply->request() ); + return; + case KParts::BrowserOpenOrSaveQuestion::Cancel: - return; + return; + default: // non extant case break; } } // case KParts::BrowserRun::Embed - KUrl::List list; - list.append(url); - KRun::run(*offer,url,0); + QString html; + html += "<html>"; + html += "<head>"; + html += "<title>"; + html += url.pathOrUrl(); + html += "</title>"; + html += "<style type=\"text/css\">"; + html += "* { border: 0; padding: 0; margin: 0; }"; + html += "</style>"; + html += "</head>"; + html += "<body>"; + html += "<embed src=\"" + url.pathOrUrl() + "\" width=\"100%\" height=\"100%\" />"; + html += "</body>"; + html += "</html>"; + + mainFrame()->setHtml(html, url); + return; } } @@ -191,53 +299,80 @@ void WebPage::loadFinished(bool) { Application::adblockManager()->applyHidingRules(this); + QStringList list = ReKonfig::walletBlackList(); + // KWallet Integration - // TODO: Add check for sites exempt from automatic form filling... - if (wallet()) + if ( wallet() + && !list.contains( mainFrame()->url().toString() ) + ) { wallet()->fillFormData(mainFrame()); } } -void WebPage::manageNetworkErrors(QNetworkReply* reply) +void WebPage::manageNetworkErrors(QNetworkReply *reply) { - if( reply->error() == QNetworkReply::NoError ) - return; - - if(m_protHandler.postHandling( reply->request(), mainFrame() )) - return; - - // don't bother on adblocked urls - if( reply->error() == QNetworkReply::ContentAccessDenied ) - return; - - if( reply->url() != m_requestedUrl ) // prevent favicon loading - return; + Q_ASSERT(reply); + WebView *v = 0; + QWebFrame* frame = qobject_cast<QWebFrame *>(reply->request().originatingObject()); + const bool isMainFrameRequest = (frame == mainFrame()); - if( reply->error() == QNetworkReply::ContentNotFoundError ) + if ( isMainFrameRequest + && _sslInfo.isValid() + && !domainSchemeMatch(reply->url(), _sslInfo.url()) + ) { - QList<QWebFrame*> frames; - frames.append(mainFrame()); - while (!frames.isEmpty()) - { - QWebFrame *firstFrame = frames.takeFirst(); - - if (firstFrame->url() == reply->url()) - { - firstFrame->setHtml(errorPage(reply), reply->url()); - return; - } - QList<QWebFrame *> children = firstFrame->childFrames(); - Q_FOREACH(QWebFrame *frame, children) - { - frames.append(frame); - } - } + //kDebug() << "Reseting cached SSL info..."; + _sslInfo = WebSslInfo(); } - else + + // NOTE: These are not all networkreply errors, + // but just that supported directly by KIO + switch( reply->error() ) { - mainFrame()->setHtml(errorPage(reply), reply->url()); + + case QNetworkReply::NoError: // no error. Simple :) + if ( isMainFrameRequest && !_sslInfo.isValid() ) + { + // Obtain and set the SSL information if any... + _sslInfo.fromMetaData(reply->attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData))); + _sslInfo.setUrl(reply->url()); + } + break; + + case QNetworkReply::UnknownNetworkError: // unknown network-related error detected + + if( _protHandler.postHandling(reply->request(), mainFrame()) ) + break; + + case QNetworkReply::ContentAccessDenied: // access to remote content denied (similar to HTTP error 401) + kDebug() << "We (hopefully) are managing this through the adblock :)"; + break; + + case QNetworkReply::ConnectionRefusedError: // remote server refused connection + case QNetworkReply::HostNotFoundError: // invalid hostname + case QNetworkReply::TimeoutError: // connection time out + case QNetworkReply::OperationCanceledError: // operation canceled via abort() or close() calls + case QNetworkReply::ProxyNotFoundError: // invalid proxy hostname + case QNetworkReply::ContentOperationNotPermittedError: // operation requested on remote content not permitted + case QNetworkReply::ContentNotFoundError: // remote content not found on server (similar to HTTP error 404) + case QNetworkReply::ProtocolUnknownError: // Unknown protocol + case QNetworkReply::ProtocolInvalidOperationError: // requested operation is invalid for this protocol + + // don't bother on elements loading errors: + // we'll manage just main url page ones + v = qobject_cast<WebView *>(view()); + if( reply->url() != v->url() ) + break; + + mainFrame()->setHtml( errorPage(reply), reply->url() ); + break; + + default: + kDebug() << "Nothing to do here.."; + break; + } } @@ -275,68 +410,97 @@ QString WebPage::errorPage(QNetworkReply *reply) } +// WARNING +// this code is actually copied from KWebPage::downloadRequest to save +// downloads data before. If you have some better ideas about, +// feel free to let us know about :) void WebPage::downloadRequest(const QNetworkRequest &request) { - if (ReKonfig::kgetDownload()) - { - //*Copy of kwebpage code (Shouldn't be done in kwepage ?) - - KUrl destUrl; - KUrl srcUrl (request.url()); - int result = KIO::R_OVERWRITE; - - do - { - destUrl = KFileDialog::getSaveFileName(srcUrl.fileName(), QString(), view()); - - if (destUrl.isLocalFile()) - { - QFileInfo finfo (destUrl.toLocalFile()); - if (finfo.exists()) - { - QDateTime now = QDateTime::currentDateTime(); - KIO::RenameDialog dlg (view(), i18n("Overwrite File?"), srcUrl, destUrl, - KIO::RenameDialog_Mode(KIO::M_OVERWRITE | KIO::M_SKIP), - -1, finfo.size(), - now.toTime_t(), finfo.created().toTime_t(), - now.toTime_t(), finfo.lastModified().toTime_t()); - result = dlg.exec(); - } - } - } - while (result == KIO::R_CANCEL && destUrl.isValid()); - - if (result == KIO::R_OVERWRITE && destUrl.isValid()) + KUrl destUrl; + KUrl srcUrl (request.url()); + int result = KIO::R_OVERWRITE; + + do + { + destUrl = KFileDialog::getSaveFileName(srcUrl.fileName(), QString(), view()); + + if (destUrl.isLocalFile()) + { + QFileInfo finfo( destUrl.toLocalFile() ); + if ( finfo.exists() ) + { + QDateTime now = QDateTime::currentDateTime(); + QPointer<KIO::RenameDialog> dlg = new KIO::RenameDialog( view(), + i18n("Overwrite File?"), + srcUrl, + destUrl, + KIO::RenameDialog_Mode(KIO::M_OVERWRITE | KIO::M_SKIP), + -1, + finfo.size(), + now.toTime_t(), + finfo.created().toTime_t(), + now.toTime_t(), + finfo.lastModified().toTime_t() + ); + result = dlg->exec(); + delete dlg; + } + } + } + while ( result == KIO::R_CANCEL && destUrl.isValid() ); + + if ( result == KIO::R_OVERWRITE && destUrl.isValid() ) + { + // now store data + // now, destUrl, srcUrl + Application::historyManager()->addDownload( srcUrl.pathOrUrl() , destUrl.pathOrUrl() ); + + if ( ReKonfig::kgetDownload() ) { - //*End of copy code - //KGet integration: if(!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) { KToolInvocation::kdeinitExecWait("kget"); } QDBusInterface kget("org.kde.kget", "/KGet", "org.kde.kget.main"); - kget.call("addTransfer", srcUrl.prettyUrl(), destUrl.prettyUrl(), true); + if( kget.isValid() ) + { + kget.call("addTransfer", srcUrl.prettyUrl(), destUrl.prettyUrl(), true); + return; + } } - } - else KWebPage::downloadRequest(request); + + // else, use KIO or fallback to it + KIO::Job *job = KIO::file_copy(srcUrl, destUrl, -1, KIO::Overwrite); + QVariant attr = request.attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData)); + if (attr.isValid() && attr.type() == QVariant::Map) + job->setMetaData(KIO::MetaData(attr.toMap())); + + job->addMetaData(QL1S("MaxCacheSize"), QL1S("0")); // Don't store in http cache. + job->addMetaData(QL1S("cache"), QL1S("cache")); // Use entry from cache if available. + job->uiDelegate()->setAutoErrorHandlingEnabled(true); + } } void WebPage::downloadAllContentsWithKGet() { - QList<QString> contentList; + QSet<QString> contents; + KUrl baseUrl( currentFrame()->url() ); + KUrl relativeUrl; QWebElementCollection images = mainFrame()->documentElement().findAll("img"); foreach(QWebElement img, images) { - contentList.append(img.attribute("src")); + relativeUrl.setEncodedUrl(img.attribute("src").toUtf8(),KUrl::TolerantMode); + contents << baseUrl.resolved(relativeUrl).toString(); } QWebElementCollection links = mainFrame()->documentElement().findAll("a"); foreach(QWebElement link, links) { - contentList.append(link.attribute("href")); + relativeUrl.setEncodedUrl(link.attribute("href").toUtf8(),KUrl::TolerantMode); + contents << baseUrl.resolved(relativeUrl).toString(); } if(!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) @@ -344,5 +508,46 @@ void WebPage::downloadAllContentsWithKGet() KToolInvocation::kdeinitExecWait("kget"); } QDBusInterface kget("org.kde.kget", "/KGet", "org.kde.kget.main"); - kget.call("importLinks", QVariant(contentList)); + if( kget.isValid() ) + { + kget.call("importLinks", QVariant(contents.toList())); + } +} + + +void WebPage::showSSLInfo() +{ + if (_sslInfo.isValid()) + { + QPointer<KSslInfoDialog> dlg = new KSslInfoDialog ( view() ); + dlg->setSslInfo( _sslInfo.certificateChain(), + _sslInfo.peerAddress().toString(), + mainFrame()->url().host(), + _sslInfo.protocol(), + _sslInfo.ciphers(), + _sslInfo.usedChiperBits(), + _sslInfo.supportedChiperBits(), + KSslInfoDialog::errorsFromString( _sslInfo.certificateErrors() ) + ); + + dlg->exec(); + delete dlg; + + return; + } + + if( mainFrame()->url().scheme() == QL1S("https") ) + { + KMessageBox::error( view(), + i18n("The SSL information for this site appears to be corrupt."), + i18nc("Secure Sockets Layer", "SSL") + ); + } + else + { + KMessageBox::information( view(), + i18n("This site doesn't contain SSL information."), + i18nc("Secure Sockets Layer", "SSL") + ); + } } diff --git a/src/webpage.h b/src/webpage.h index 9169ad60..9583cc22 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -6,7 +6,8 @@ * Copyright (C) 2008 Dirk Mueller <mueller@kde.org> * Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org> * Copyright (C) 2008 Michael Howell <mhowell123@gmail.com> -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -33,7 +34,10 @@ // Local Includes +#include "rekonqprivate_export.h" #include "protocolhandler.h" +#include "newtabpage.h" +#include "websslinfo.h" // KDE Includes #include <KWebPage> @@ -46,18 +50,18 @@ class QWebFrame; class QNetworkReply; -class WebPage : public KWebPage +class REKONQ_TESTS_EXPORT WebPage : public KWebPage { Q_OBJECT public: - explicit WebPage(QObject *parent = 0); + explicit WebPage(QWidget *parent = 0); ~WebPage(); public slots: - void manageNetworkErrors(QNetworkReply *reply); virtual void downloadRequest(const QNetworkRequest &request); void downloadAllContentsWithKGet(); + protected: WebPage *createWindow(WebWindowType type); @@ -69,13 +73,15 @@ protected Q_SLOTS: virtual void handleUnsupportedContent(QNetworkReply *reply); private slots: + void manageNetworkErrors(QNetworkReply *reply); void loadFinished(bool); - + void showSSLInfo(); + private: QString errorPage(QNetworkReply *); - - QUrl m_requestedUrl; - ProtocolHandler m_protHandler; + + ProtocolHandler _protHandler; + WebSslInfo _sslInfo; }; #endif diff --git a/src/webpluginfactory.cpp b/src/webpluginfactory.cpp index aec4e18d..79a36aa0 100644 --- a/src/webpluginfactory.cpp +++ b/src/webpluginfactory.cpp @@ -2,7 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -32,7 +33,6 @@ #include "rekonq.h" #include "application.h" #include "mainwindow.h" -#include "previewimage.h" #include "clicktoflash.h" // KDE Includes @@ -41,21 +41,15 @@ WebPluginFactory::WebPluginFactory(QObject *parent) : KWebPluginFactory(parent) + , _loadClickToFlash(false) { - loadClickToFlash = false; connect(this, SIGNAL(signalLoadClickToFlash(bool)), SLOT(setLoadClickToFlash(bool))); } -WebPluginFactory::~WebPluginFactory() -{ -} - - - void WebPluginFactory::setLoadClickToFlash(bool load) { - loadClickToFlash = load; + _loadClickToFlash = load; } @@ -66,61 +60,36 @@ QObject *WebPluginFactory::create(const QString &mimeType, { kDebug() << "loading mimeType: " << mimeType; - if(mimeType == QString("application/image-preview") ) + switch( ReKonfig::pluginsEnabled() ) { - QString title; - int number = -1; - bool isFavorite = false; - - int i; - i = argumentNames.indexOf( QString("title") ); - if(i > -1) - title = argumentValues.at(i); - i = argumentNames.indexOf( QString("isFavorite") ); - if(i > -1) - isFavorite = true; - i = argumentNames.indexOf( QString("index") ); - if(i > -1) - number = argumentValues.at(i).toInt(); - - return new PreviewImage(url, title, number, isFavorite); - } - - if(ReKonfig::pluginsEnabled() == 0) // plugins are enabled - { - kDebug() << "No plugins found for" << mimeType << ". Falling back to QtWebKit ones..."; + case 0: + kDebug() << "No plugins found for" << mimeType << ". Falling back to KDEWebKit ones..."; + return KWebPluginFactory::create(mimeType, url, argumentNames, argumentValues); + + case 1: + if( mimeType != QString("application/x-shockwave-flash") ) + break; + + if( _loadClickToFlash ) + { + emit signalLoadClickToFlash(false); + return 0; //KWebPluginFactory::create(mimeType, url, argumentNames, argumentValues); + } + else + { + ClickToFlash* ctf = new ClickToFlash(url); + connect(ctf, SIGNAL(signalLoadClickToFlash(bool)), this, SLOT(setLoadClickToFlash(bool))); + return ctf; + } + break; + + case 2: return 0; + + default: + kDebug() << "oh oh.. this should NEVER happen.."; + break; } - if(mimeType == QString("application/x-shockwave-flash") - && !loadClickToFlash) - { - ClickToFlash* ctf = new ClickToFlash(url); - connect(ctf, SIGNAL(signalLoadClickToFlash(bool)), this, SLOT(setLoadClickToFlash(bool))); - return ctf; - } - - // this let QtWebKit using builtin plugins - // to load in example flash contents and so on.. - kDebug() << "No plugins found for" << mimeType << ". Falling back to QtWebKit ones..."; - emit signalLoadClickToFlash(false); return KWebPluginFactory::create(mimeType, url, argumentNames, argumentValues); } - - -QList<QWebPluginFactory::Plugin> WebPluginFactory::plugins() const -{ - QList<KWebPluginFactory::Plugin> plugins = KWebPluginFactory::plugins(); - - QWebPluginFactory::Plugin p; - p.name = "application/image-preview"; - p.description = "plugin for embedding Web snapped images"; - plugins.append(p); - - p.name = "application/x-shockwave-flash"; - p.description = "Plugin for flash animations"; - plugins.append(p); - - - return plugins; -} diff --git a/src/webpluginfactory.h b/src/webpluginfactory.h index c1e4c28f..85122d56 100644 --- a/src/webpluginfactory.h +++ b/src/webpluginfactory.h @@ -2,7 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -28,6 +29,9 @@ #define WEB_PLUGIN_FACTORY_H +// Local Includes +#include "rekonqprivate_export.h" + // KDE Includes #include <KWebPluginFactory> @@ -36,23 +40,19 @@ #include <QtGui/QWidget> -class WebPluginFactory : public KWebPluginFactory +class REKONQ_TESTS_EXPORT WebPluginFactory : public KWebPluginFactory { Q_OBJECT public: WebPluginFactory(QObject *parent); - ~WebPluginFactory(); virtual QObject *create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const; - virtual QList<Plugin> plugins() const; - signals: - void signalLoadClickToFlash(bool) const; public slots: @@ -63,7 +63,7 @@ private: When true, force loading of next flash animation (don't show clicktoflash) We use signals/slots to set this property because QWebPluginFactory::create is const */ - bool loadClickToFlash; + bool _loadClickToFlash; }; #endif // WEB_PLUGIN_FACTORY_H diff --git a/src/websnap.cpp b/src/websnap.cpp index 7dcbb836..612fdf4e 100644 --- a/src/websnap.cpp +++ b/src/websnap.cpp @@ -3,7 +3,8 @@ * This file is a part of the rekonq project * * Copyright (C) 2009 Nokia Corporation <qt-info@nokia.com> -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -29,6 +30,9 @@ #include "websnap.h" #include "websnap.moc" +// Local Includes +#include "newtabpage.h" + // KDE Includes #include <KDebug> #include <KStandardDirs> @@ -42,15 +46,12 @@ #include <QFile> -#define WIDTH 200 -#define HEIGHT 150 - - -WebSnap::WebSnap(const QUrl &url) +WebSnap::WebSnap(const QUrl& url, QWebFrame *frame, int index) : QObject() + , m_url(url) + , m_frame(frame) + , m_previewIndex(index) { - m_url = url; - // this to not register websnap history m_page.settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, true); @@ -59,46 +60,40 @@ WebSnap::WebSnap(const QUrl &url) m_page.settings()->setAttribute(QWebSettings::JavascriptEnabled, false); connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(saveResult(bool))); + QTimer::singleShot(0, this, SLOT(load())); } -WebSnap::~WebSnap() -{ -} - - void WebSnap::load() { m_page.mainFrame()->load(m_url); } -QPixmap WebSnap::renderPreview(const QWebPage &page,int w, int h) +// NOTE please, be careful modifying this. +// You are playing with fire.. +QPixmap WebSnap::renderPreview(const QWebPage &page, int w, int h, bool save) { // prepare page - page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); // Why it doesn't work with one setScrollBarPolicy? - page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); // bug in qtwebkit ? + page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); - page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); - + QSize oldSize = page.viewportSize(); + // find the best size QSize size; - if (page.viewportSize().width() && page.viewportSize().height()) + int width = page.mainFrame()->contentsSize().width(); + if (width < 640) { - size = page.viewportSize(); - } - else - { - int width = page.mainFrame()->contentsSize().width(); - if (width < 640) width = 640; - size = QSize(width,width*((0.0+h)/w)); - page.setViewportSize(size); + width = 640; } + size = QSize(width,width*((0.0+h)/w)); + page.setViewportSize(size); // create the page image QImage pageImage = QImage(size, QImage::Format_ARGB32_Premultiplied); - pageImage.fill(Qt::transparent); + pageImage.fill(Qt::transparent); + // render it QPainter p(&pageImage); page.mainFrame()->render(&p); @@ -107,42 +102,75 @@ QPixmap WebSnap::renderPreview(const QWebPage &page,int w, int h) // restore page settings page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded); - page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded); - page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded); page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded); + page.setViewportSize(oldSize); + + QPixmap pm = QPixmap::fromImage(pageImage); + if(save) + { + KUrl url( page.mainFrame()->url() ); + kDebug() << "saving preview"; + QFile::remove( fileForUrl(url).toLocalFile() ); + pm.save(fileForUrl(url).toLocalFile()); + } + + return pm; +} + - return QPixmap::fromImage(pageImage); +KUrl WebSnap::fileForUrl(KUrl url) +{ + QString filePath = KStandardDirs::locateLocal("cache", QString("thumbs/") + WebSnap::guessNameFromUrl(url) + ".png", true); + return KUrl(filePath); +} + + +QString WebSnap::guessNameFromUrl(QUrl url) +{ + QString name = url.toString( QUrl::RemoveScheme | QUrl::RemoveUserInfo | QUrl::StripTrailingSlash ); + + // TODO learn Regular Expressions :) + // and implement something better here.. + name.remove('/'); + name.remove('&'); + name.remove('.'); + name.remove('-'); + name.remove('_'); + name.remove('?'); + name.remove('='); + name.remove('+'); + + return name; } void WebSnap::saveResult(bool ok) { + QPixmap image = QPixmap(); + // crude error-checking if (!ok) { kDebug() << "Error loading site.."; - return; + m_snapTitle = "Error..."; + } - - m_image = renderPreview(m_page, WIDTH, HEIGHT); - emit finished(); + else + { + image = renderPreview(m_page, WIDTH, HEIGHT); + m_snapTitle = m_page.mainFrame()->title(); + } + QFile::remove(fileForUrl(m_url).toLocalFile()); + image.save(fileForUrl(m_url).toLocalFile()); + + NewTabPage p( m_frame ); + p.snapFinished(m_previewIndex, m_url, m_snapTitle); + + this->deleteLater(); } - QString WebSnap::snapTitle() { return m_page.mainFrame()->title(); } - - -QUrl WebSnap::snapUrl() -{ - return m_url; -} - - -QPixmap WebSnap::previewImage() -{ - return m_image; -} diff --git a/src/websnap.h b/src/websnap.h index 6c5b4af9..9773b4cc 100644 --- a/src/websnap.h +++ b/src/websnap.h @@ -3,7 +3,8 @@ * This file is a part of the rekonq project * * Copyright (C) 2009 Nokia Corporation <qt-info@nokia.com> -* Copyright (C) 2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -28,6 +29,9 @@ #ifndef WEB_SNAP_H #define WEB_SNAP_H +// Local Includes +#include "rekonqprivate_export.h" + // KDE Includes #include <KUrl> @@ -37,39 +41,49 @@ #include <QImage> #include <QWebPage> +#define WIDTH 200 +#define HEIGHT 150 + /** - * This class renders a site producing an image based - * on that. + * This class is used in many classes of rekonq to produce an image + * based on the site corresponding to the url passed as argument. + * It also cached the images to not retrieve them every time :) + * * Heavily based on Graphics-Dojo WebSnap example (thanks!) + * + * We use this in the following rekonq classes: + * - TabBar class: to show a tab preview (given a page, you show WITHOUT saving an image) + * - NewTabPage class: to show the favorites page "preview" (given an url, you show AND save an image) + * - PreviewSelector class: to save new favorite selection (given a page, you show AND save an image) + * */ -class WebSnap : public QObject +class REKONQ_TESTS_EXPORT WebSnap : public QObject { Q_OBJECT public: - WebSnap(const QUrl &url); - ~WebSnap(); - - QPixmap previewImage(); - static QPixmap renderPreview(const QWebPage &page, int w, int h); + WebSnap(const QUrl &url, QWebFrame *frame, int index); + + static QPixmap renderPreview(const QWebPage &page, int w = WIDTH, int h = HEIGHT, bool save = true); + + static KUrl fileForUrl(KUrl url); + static QString guessNameFromUrl(QUrl url); QString snapTitle(); - QUrl snapUrl(); - -signals: - void finished(); private slots: void load(); - void saveResult(bool ok); + void saveResult(bool ok = true); private: QWebPage m_page; - QPixmap m_image; QUrl m_url; QString m_snapTitle; + + QWebFrame *m_frame; + int m_previewIndex; }; #endif // WEB_SNAP_H diff --git a/src/websslinfo.cpp b/src/websslinfo.cpp new file mode 100644 index 00000000..ffc4918f --- /dev/null +++ b/src/websslinfo.cpp @@ -0,0 +1,211 @@ +/* + * 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 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 "websslinfo.h" + +#include <QtCore/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->peerAddress.isNull(); +} + +QUrl WebSslInfo::url() const +{ + return d->url; +} + +QHostAddress WebSslInfo::parentAddress() const +{ + return d->parentAddress; +} + +QHostAddress WebSslInfo::peerAddress() const +{ + return d->peerAddress; +} + +QString WebSslInfo::protocol() const +{ + return d->protocol; +} + +QString WebSslInfo::ciphers() const +{ + return d->ciphers; +} + +QString WebSslInfo::certificateErrors() const +{ + return d->certErrors; +} + +int WebSslInfo::supportedChiperBits () const +{ + return d->supportedCipherBits; +} + +int WebSslInfo::usedChiperBits () const +{ + return d->usedCipherBits; +} + +QList<QSslCertificate> WebSslInfo::certificateChain() const +{ + return d->certificateChain; +} + +WebSslInfo& WebSslInfo::operator=(const WebSslInfo& other) +{ + 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; +} + +QVariant WebSslInfo::toMetaData() const +{ + if (isValid()) { + QMap<QString, QVariant> data; + data.insert("ssl_in_use", true); + data.insert("ssl_peer_ip", d->peerAddress.toString()); + data.insert("ssl_parent_ip", d->parentAddress.toString()); + data.insert("ssl_protocol_version", d->protocol); + data.insert("ssl_cipher", d->ciphers); + data.insert("ssl_cert_errors", d->certErrors); + data.insert("ssl_cipher_used_bits", d->usedCipherBits); + data.insert("ssl_cipher_bits", d->supportedCipherBits); + QByteArray certChain; + Q_FOREACH(const QSslCertificate& cert, d->certificateChain) + certChain += cert.toPem(); + data.insert("ssl_peer_chain", certChain); + return data; + } + + return QVariant(); +} + +void WebSslInfo::fromMetaData(const QVariant& value) +{ + if (value.isValid() && value.type() == QVariant::Map) { + QMap<QString,QVariant> metaData = value.toMap(); + if (metaData.value("ssl_in_use", false).toBool()) { + setCertificateChain(metaData.value("ssl_peer_chain").toByteArray()); + setPeerAddress(metaData.value("ssl_peer_ip").toString()); + setParentAddress(metaData.value("ssl_parent_ip").toString()); + setProtocol(metaData.value("ssl_protocol_version").toString()); + setCiphers(metaData.value("ssl_cipher").toString()); + setCertificateErrors(metaData.value("ssl_cert_errors").toString()); + setUsedCipherBits(metaData.value("ssl_cipher_used_bits").toString()); + setSupportedCipherBits(metaData.value("ssl_cipher_bits").toString()); + } + } +} + +void WebSslInfo::setUrl (const QUrl &url) +{ + d->url = url; +} + +void WebSslInfo::setPeerAddress(const QString& address) +{ + d->peerAddress = address; +} + +void WebSslInfo::setParentAddress(const QString& address) +{ + d->parentAddress = address; +} + +void WebSslInfo::setProtocol(const QString& protocol) +{ + d->protocol = protocol; +} + +void WebSslInfo::setCertificateChain(const QByteArray& chain) +{ + d->certificateChain = QSslCertificate::fromData(chain); +} + +void WebSslInfo::setCiphers(const QString& ciphers) +{ + d->ciphers = ciphers; +} + +void WebSslInfo::setUsedCipherBits(const QString& bits) +{ + d->usedCipherBits = bits.toInt(); +} + +void WebSslInfo::setSupportedCipherBits(const QString& bits) +{ + d->supportedCipherBits = bits.toInt(); +} + +void WebSslInfo::setCertificateErrors(const QString& certErrors) +{ + d->certErrors = certErrors; +} diff --git a/src/websslinfo.h b/src/websslinfo.h new file mode 100644 index 00000000..433cf053 --- /dev/null +++ b/src/websslinfo.h @@ -0,0 +1,73 @@ +/* + * 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 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 WEBSSLINFO_H +#define WEBSSLINFO_H + +#include <kdemacros.h> + +#include <QtCore/QUrl> +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtNetwork/QHostAddress> +#include <QtNetwork/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; + + QVariant toMetaData() const; + void fromMetaData (const QVariant &); + + 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/src/webtab.cpp b/src/webtab.cpp index b1f2cdfc..6bafd04a 100644 --- a/src/webtab.cpp +++ b/src/webtab.cpp @@ -2,8 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -39,6 +39,7 @@ #include "webpage.h" #include "bookmarksmanager.h" #include "walletbar.h" +#include "previewselectorbar.h" // KDE Includes #include <KService> @@ -48,6 +49,7 @@ #include <KActionMenu> #include <KWebView> #include <kwebwallet.h> +#include <KDE/KMessageBox> // Qt Includes #include <QContextMenuEvent> @@ -58,28 +60,34 @@ #include <QAction> #include <QVBoxLayout> +// Defines +#define QL1S(x) QLatin1String(x) -WebTab::WebTab(QWidget* parent) + +WebTab::WebTab(QWidget *parent) : QWidget(parent) - , m_view( new WebView(this) ) , m_progress(0) { - QVBoxLayout* l = new QVBoxLayout(this); + QVBoxLayout *l = new QVBoxLayout(this); l->setMargin(0); l->setSpacing(0); - QWidget* messageBar = new QWidget(this); + QWidget *messageBar = new QWidget(this); l->addWidget(messageBar); messageBar->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Minimum); - QVBoxLayout* l2 = new QVBoxLayout(messageBar); + QVBoxLayout *l2 = new QVBoxLayout(messageBar); l2->setMargin(0); l2->setSpacing(0); - l->addWidget(m_view); - m_view->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); - - KWebWallet *wallet = page()->wallet(); + WebView *view = new WebView(this); + l->addWidget(view); + view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + // fix focus handling + setFocusProxy( view ); + + KWebWallet *wallet = view->page()->wallet(); if(wallet) { @@ -87,34 +95,32 @@ WebTab::WebTab(QWidget* parent) this, SLOT(createWalletBar(const QString &, const QUrl &))); } - connect(page(), SIGNAL(statusBarMessage(const QString&)), this, SLOT(setStatusBarText(const QString&))); - - connect(m_view, SIGNAL(loadProgress(int)), this, SLOT(updateProgress(int))); - connect(m_view, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool))); + connect(view, SIGNAL(loadProgress(int)), this, SLOT(updateProgress(int))); + connect(view, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool))); } WebTab::~WebTab() { - delete m_view; } WebView *WebTab::view() { - return m_view; + WebView *view = qobject_cast<WebView *>( layout()->itemAt(1)->widget() ); + return view; } WebPage *WebTab::page() { - return m_view->page(); // FIXME + return view()->page(); } -KUrl WebTab::url() const -{ - return KUrl(m_view->url()); +KUrl WebTab::url() +{ + return KUrl( view()->url() ); } @@ -124,18 +130,6 @@ int WebTab::progress() } -QString WebTab::lastStatusBarText() const -{ - return m_statusBarText; -} - - -void WebTab::setStatusBarText(const QString &string) -{ - m_statusBarText = string; -} - - void WebTab::updateProgress(int p) { m_progress = p; @@ -149,7 +143,13 @@ void WebTab::loadFinished(bool) void WebTab::createWalletBar(const QString &key, const QUrl &url) -{ +{ + // check if the url is in the wallet blacklist + QString urlString = url.toString(); + QStringList blackList = ReKonfig::walletBlackList(); + if( blackList.contains( urlString ) ) + return; + KWebWallet *wallet = page()->wallet(); QWidget *messageBar = layout()->itemAt(0)->widget(); @@ -162,3 +162,60 @@ void WebTab::createWalletBar(const QString &key, const QUrl &url) connect(walletBar, SIGNAL(saveFormDataRejected(const QString &)), wallet, SLOT(rejectSaveFormDataRequest(const QString &))); } + + +void WebTab::createPreviewSelectorBar(int index) +{ + QWidget *messageBar = layout()->itemAt(0)->widget(); + PreviewSelectorBar *bar = new PreviewSelectorBar(index, messageBar); + messageBar->layout()->addWidget(bar); + + connect(page(), SIGNAL(loadStarted()), bar, SLOT(loadProgress())); + connect(page(), SIGNAL(loadProgress(int)), bar, SLOT(loadProgress())); + connect(page(), SIGNAL(loadFinished(bool)), bar, SLOT(loadFinished())); + connect(page()->mainFrame(), SIGNAL(urlChanged(QUrl)), bar, SLOT(verifyUrl())); +} + + +bool WebTab::hasRSSInfo() +{ + _rssList.clear(); + QWebElementCollection col = page()->mainFrame()->findAllElements("link"); + foreach(QWebElement el, col) + { + if( el.attribute("type") == QL1S("application/rss+xml") || el.attribute("type") == QL1S("application/rss+xml") ) + { + if( el.attribute("href").startsWith( QL1S("http") ) ) + { + _rssList << KUrl( el.attribute("href") ); + } + else + { + KUrl u = url(); + // NOTE + // cd() is probably better than setPath() here, + // for all those url sites just having a path + if(u.cd( el.attribute("href") )) + _rssList << u; + } + } + } + + return !_rssList.isEmpty(); +} + + +void WebTab::showRSSInfo() +{ + QString urlList = QString("Here are the rss link found: <br /><br />"); + foreach(const KUrl &url, _rssList) + { + urlList += QString("<a href=\"") + url.url() + QString("\">") + url.url() + QString("</a><br />"); + } + urlList += QString("<br />Enough for now.. waiting for some cool akonadi based feeds management :)"); + + KMessageBox::information( view(), + urlList, + "RSS Management" + ); +} diff --git a/src/webtab.h b/src/webtab.h index ecf8e5b3..9054a7c1 100644 --- a/src/webtab.h +++ b/src/webtab.h @@ -2,8 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -29,16 +29,21 @@ #define WEBTAB_H +// Local Includes +#include "rekonqprivate_export.h" + // KDE Includes #include <KUrl> -#include <KWebView> + +// Qt Includes +#include <QWidget> // Forward Declarations class WebPage; class WebView; -class WebTab : public QWidget +class REKONQ_TESTS_EXPORT WebTab : public QWidget { Q_OBJECT @@ -48,21 +53,24 @@ public: WebView *view(); WebPage *page(); - KUrl url() const; - QString lastStatusBarText() const; + KUrl url(); + int progress(); + void createPreviewSelectorBar(int index); + bool hasRSSInfo(); + private slots: - void setStatusBarText(const QString &string); void updateProgress(int progress); void loadFinished(bool); void createWalletBar(const QString &, const QUrl &); + void showRSSInfo(); private: - WebView *const m_view; int m_progress; - QString m_statusBarText; + + KUrl::List _rssList; }; #endif diff --git a/src/webview.cpp b/src/webview.cpp index 232a2633..f48afffb 100644 --- a/src/webview.cpp +++ b/src/webview.cpp @@ -2,8 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -62,16 +62,21 @@ WebView::WebView(QWidget* parent) : KWebView(parent, false) - , m_page( new WebPage(this) ) - , m_mousePos(QPoint(0,0)) + , _mousePos( QPoint(0,0) ) + , _scrollTimer( new QTimer(this) ) + , _VScrollSpeed(0) + , _HScrollSpeed(0) + , _canEnableAutoScroll(true) + , _isAutoScrollEnabled(false) { - setPage(m_page); + WebPage *page = new WebPage(this); + setPage(page); // download system connect(this, SIGNAL(linkShiftClicked(const KUrl &)), - m_page, SLOT(downloadUrl(const KUrl &))); - connect(m_page, SIGNAL(downloadRequested(const QNetworkRequest &)), - m_page, SLOT(downloadRequest(const QNetworkRequest &))); + page, SLOT(downloadUrl(const KUrl &))); + connect(page, SIGNAL(downloadRequested(const QNetworkRequest &)), + page, SLOT(downloadRequest(const QNetworkRequest &))); // middle click || ctrl + click signal connect(this, SIGNAL(linkMiddleOrCtrlClicked(const KUrl &)), @@ -80,12 +85,24 @@ WebView::WebView(QWidget* parent) // loadUrl signal connect(this, SIGNAL(loadUrl(const KUrl &, const Rekonq::OpenType &)), Application::instance(), SLOT(loadUrl(const KUrl &, const Rekonq::OpenType &))); + + // scrolling timer + connect(_scrollTimer, SIGNAL(timeout()), this, SLOT(scrollFrameChanged())); + _scrollTimer->setInterval(100); } WebView::~WebView() { - disconnect(); + delete _scrollTimer; + disconnect(); +} + + +WebPage *WebView::page() +{ + WebPage *page = qobject_cast<WebPage *>( KWebView::page() ); + return page; } @@ -164,7 +181,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) const QString searchProviderPrefix = *(service->property("Keys").toStringList().begin()) + keywordDelimiter; data.setData(searchProviderPrefix + "some keyword"); a = new KAction(service->name(), this); - a->setIcon(Application::icon(KUrl(data.uri()))); + a->setIcon( Application::icon( data.uri() ) ); a->setData(searchProviderPrefix); connect(a, SIGNAL(triggered(bool)), this, SLOT(search())); searchMenu->addAction(a); @@ -306,24 +323,60 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) void WebView::mousePressEvent(QMouseEvent *event) { + if(_isAutoScrollEnabled) + { + setCursor(Qt::ArrowCursor); + _VScrollSpeed = 0; + _HScrollSpeed = 0; + _scrollTimer->stop(); + _isAutoScrollEnabled = false; + return; + } + + QWebHitTestResult result = page()->mainFrame()->hitTestContent( event->pos() ); + _canEnableAutoScroll = !result.isContentEditable() && result.linkUrl().isEmpty(); + switch(event->button()) { case Qt::XButton1: triggerPageAction(KWebPage::Back); break; + case Qt::XButton2: triggerPageAction(KWebPage::Forward); break; + + case Qt::MidButton: + if(_canEnableAutoScroll && !_isAutoScrollEnabled) + { + setCursor( KIcon("transform-move").pixmap(32) ); + _clickPos = event->pos(); + _isAutoScrollEnabled = true; + } + break; + default: - KWebView::mousePressEvent(event); break; }; + KWebView::mousePressEvent(event); } void WebView::mouseMoveEvent(QMouseEvent *event) { - m_mousePos = event->pos(); + _mousePos = event->pos(); + + if(_isAutoScrollEnabled) + { + QPoint r = _mousePos - _clickPos; + _HScrollSpeed = r.x() / 2; // you are too fast.. + _VScrollSpeed = r.y() / 2; + if( !_scrollTimer->isActive() ) + _scrollTimer->start(); + + return; + } + if (Application::instance()->mainWindow()->isFullScreen()) { if (event->pos().y()>=0 && event->pos().y()<=4) @@ -341,7 +394,7 @@ void WebView::mouseMoveEvent(QMouseEvent *event) QPoint WebView::mousePos() { - return m_mousePos; + return _mousePos; } @@ -397,18 +450,73 @@ void WebView::openLinkInNewTab() void WebView::keyPressEvent(QKeyEvent *event) { - if ((event->modifiers() == Qt::ControlModifier) && (event->key() == Qt::Key_C)) + if ( event->modifiers() == Qt::ControlModifier ) { - triggerPageAction(KWebPage::Copy); - return; - } + if ( event->key() == Qt::Key_C ) + { + triggerPageAction(KWebPage::Copy); + return; + } - if ((event->modifiers() == Qt::ControlModifier) && (event->key() == Qt::Key_A)) + if ( event->key() == Qt::Key_A ) + { + triggerPageAction(KWebPage::SelectAll); + return; + } + } + + if(!_canEnableAutoScroll) { - triggerPageAction(KWebPage::SelectAll); + KWebView::keyPressEvent(event); return; } + // Auto Scrolling + if ( event->modifiers() == Qt::ShiftModifier ) + { + if( event->key() == Qt::Key_Up ) + { + _VScrollSpeed--; + if( !_scrollTimer->isActive() ) + _scrollTimer->start(); + return; + } + + if( event->key() == Qt::Key_Down ) + { + _VScrollSpeed++; + if( !_scrollTimer->isActive() ) + _scrollTimer->start(); + return; + } + + if( event->key() == Qt::Key_Right ) + { + _HScrollSpeed++; + if( !_scrollTimer->isActive() ) + _scrollTimer->start(); + return; + } + + if( event->key() == Qt::Key_Left ) + { + _HScrollSpeed--; + if( !_scrollTimer->isActive() ) + _scrollTimer->start(); + return; + } + + if(_scrollTimer->isActive()) + { + _scrollTimer->stop(); + } + else + { + if(_VScrollSpeed || _HScrollSpeed) + _scrollTimer->start(); + } + } + KWebView::keyPressEvent(event); } @@ -418,6 +526,7 @@ void WebView::inspect() QAction *a = Application::instance()->mainWindow()->actionByName("web_inspector"); if(a && !a->isChecked()) a->trigger(); + pageAction(QWebPage::InspectElement)->trigger(); } @@ -425,3 +534,19 @@ void WebView::loadUrlInNewTab(const KUrl &url) { emit loadUrl(url, Rekonq::SettingOpenTab); } + + +void WebView::scrollFrameChanged() +{ + // do the scrolling + page()->currentFrame()->scroll( _HScrollSpeed, _VScrollSpeed ); + + // check if we reached the end + int y = page()->currentFrame()->scrollPosition().y(); + if (y == 0 || y == page()->currentFrame()->scrollBarMaximum(Qt::Vertical)) + _VScrollSpeed = 0; + + int x = page()->currentFrame()->scrollPosition().x(); + if (x == 0 || x == page()->currentFrame()->scrollBarMaximum(Qt::Horizontal)) + _HScrollSpeed = 0; +} diff --git a/src/webview.h b/src/webview.h index 263b2ec4..c6ca2688 100644 --- a/src/webview.h +++ b/src/webview.h @@ -2,8 +2,8 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> -* Copyright (C) 2009 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009-2010 by Lionel Chauvin <megabigbug@yahoo.fr> * * * This program is free software; you can redistribute it and/or @@ -29,6 +29,7 @@ #define WEBVIEW_H // Local Includes +#include "rekonqprivate_export.h" #include "application.h" // KDE Includes @@ -38,7 +39,7 @@ class WebPage; -class WebView : public KWebView +class REKONQ_TESTS_EXPORT WebView : public KWebView { Q_OBJECT @@ -46,12 +47,12 @@ public: explicit WebView(QWidget *parent); ~WebView(); - WebPage *page() { return m_page; } + WebPage *page(); QPoint mousePos(); protected: void contextMenuEvent(QContextMenuEvent *event); - void mousePressEvent(QMouseEvent *event);// need to be ported + void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void keyPressEvent(QKeyEvent *event); @@ -67,12 +68,20 @@ private slots: void viewImage(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers); void inspect(); + void scrollFrameChanged(); + signals: void loadUrl(const KUrl &, const Rekonq::OpenType &); private: - WebPage *const m_page; - QPoint m_mousePos; + QPoint _mousePos; + QPoint _clickPos; + + QTimer *_scrollTimer; + int _VScrollSpeed; + int _HScrollSpeed; + bool _canEnableAutoScroll; + bool _isAutoScrollEnabled; }; #endif |