diff options
138 files changed, 11953 insertions, 3964 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 661cc6e3..41be2608 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.33" ) +SET(REKONQ_VERSION "0.4.68" ) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/version.h ) @@ -21,10 +21,8 @@ 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) -FIND_PACKAGE(KDE4 REQUIRED) +FIND_PACKAGE(Qt4 4.6.0 COMPONENTS QtCore QtGui QtNetwork QtWebKit REQUIRED) +FIND_PACKAGE(KDE4 4.4.0 REQUIRED) INCLUDE(MacroOptionalFindPackage) INCLUDE(FindPackageHandleStandardArgs) @@ -46,16 +44,16 @@ SET(QT_VERS_STR "${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}" ) -IF(QT_FOUND) +IF(QT4_FOUND) MESSAGE(STATUS " Qt library found...................... YES") MESSAGE(STATUS " Qt version ${QT_VERS_STR} found! ") -ELSE(QT_FOUND) +ELSE(QT4_FOUND) MESSAGE(STATUS " Qt library found...................... NO") MESSAGE(STATUS "") MESSAGE(SEND_ERROR " rekonq needs at least Qt ${QT_MIN_VERSION}. Please install it and try compiling again.") MESSAGE(STATUS " Qt website is at http://qt.nokia.com") MESSAGE(STATUS "") -ENDIF(QT_FOUND) +ENDIF(QT4_FOUND) MESSAGE(STATUS "") @@ -78,13 +76,13 @@ ENDIF(KDE4_FOUND) ##### FINAL RESULTS ##### -IF(QT_FOUND AND KDE4_FOUND) +IF(QT4_FOUND AND KDE4_FOUND) MESSAGE(STATUS " rekonq will be compiled............... YES") SET(REKONQ_CAN_BE_COMPILED true) -ELSE(QT_FOUND AND KDE4_FOUND) +ELSE(QT4_FOUND AND KDE4_FOUND) MESSAGE(FATAL_ERROR " rekonq will NOT be compiled!") SET(REKONQ_CAN_BE_COMPILED false) -ENDIF(QT_FOUND AND KDE4_FOUND) +ENDIF(QT4_FOUND AND KDE4_FOUND) MESSAGE(STATUS "") MESSAGE(STATUS "-----------------------------------------------------------------------") @@ -97,6 +95,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 c98c0def..fc8d05ec 100644 --- a/docs/index.docbook +++ b/docs/index.docbook @@ -65,7 +65,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> @@ -555,8 +555,7 @@ Documentation copyright 2010 &Jonathan.Kolberg; &Jonathan.Kolberg.mail; <!--TRANS:CREDIT_FOR_TRANSLATORS--> &underFDL; <!-- FDL: do not remove --> -&underBSDLicense; <!-- BSD License --> -<!-- Still needed? --> +&underGPL; <!-- GPL License --> </chapter> 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..d13e84c0 100755..100644 --- a/scripts/codingstyle.sh +++ b/scripts/codingstyle.sh @@ -18,7 +18,7 @@ # ... # } # -# I like this way, for me more readable. +# I like this way, for me more readable. :) # # Kdelibs coding style is defined in http://techbase.kde.org/Policies/Kdelibs_Coding_Style @@ -42,7 +42,7 @@ astyle \ `find -type f -name '*.cpp'` `find -type f -name '*.h'` echo "Removing .orig files..." -rm *.orig +rm *.orig */*.orig echo "Done!" diff --git a/scripts/cppcheck.sh b/scripts/cppcheck.sh new file mode 100644 index 00000000..be081040 --- /dev/null +++ b/scripts/cppcheck.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# apply rekonq coding style to all cpp and header files in src directory +# +# requirements: installed astyle +# +# rekonq use kdelibs coding style, except for brackets, so while kdelibs coding style +# is +# +# void foo() { +# ... +# } +# +# rekonq uses +# +# void foo() +# { +# ... +# } +# +# I like this way, for me more readable. :) +# +# Kdelibs coding style is defined in http://techbase.kde.org/Policies/Kdelibs_Coding_Style + + +PWD=$(pwd) + +cd $PWD +cd .. +cd src + +echo "cppcheck(ing)..." +cppcheck \ +--enable=all \ +--force \ +--verbose \ +. 2>/tmp/cppcheck.out + +echo "DONE. read output in /tmp/cppcheck.out" 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..6926630e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,44 +8,55 @@ 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 + searchengine.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 adblock/adblockrule.cpp #---------------------------------------- urlbar/urlbar.cpp - urlbar/lineedit.cpp + urlbar/completionwidget.cpp + urlbar/urlresolver.cpp + urlbar/listitem.cpp + urlbar/rsswidget.cpp + #---------------------------------------- + analyzer/analyzerpanel.cpp + analyzer/networkanalyzer.cpp ) @@ -54,6 +65,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 ) @@ -69,6 +81,7 @@ INCLUDE_DIRECTORIES ( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/history ${CMAKE_CURRENT_SOURCE_DIR}/rekonqpage ${CMAKE_CURRENT_SOURCE_DIR}/settings + ${CMAKE_CURRENT_SOURCE_DIR}/analyzer ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES} ${QT4_INCLUDES} 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..e195c705 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 @@ -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 @@ -28,6 +28,9 @@ #include "adblockmanager.h" #include "adblockmanager.moc" +// Auto Includes +#include "rekonq.h" + // Local Includes #include "adblocknetworkreply.h" #include "webpage.h" @@ -35,7 +38,7 @@ // KDE Includes #include <KSharedConfig> #include <KConfigGroup> -#include <KDebug> +#include <KIO/TransferJob> // Qt Includes #include <QUrl> @@ -43,11 +46,11 @@ AdBlockManager::AdBlockManager(QObject *parent) - : QObject(parent) - , _isAdblockEnabled(false) - , _isHideAdsEnabled(false) + : QObject(parent) + , _isAdblockEnabled(false) + , _isHideAdsEnabled(false) + , _index(0) { - loadSettings(); } @@ -56,91 +59,144 @@ 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); - - // no need to load filters if adblock is not enabled :) - if(!_isAdblockEnabled) - return; - - _whiteList.clear(); - _blackList.clear(); - _hideList.clear(); - - QMap<QString,QString> entryMap = cg.entryMap(); - QMap<QString,QString>::ConstIterator it; - for( it = entryMap.constBegin(); it != entryMap.constEnd(); ++it ) + ReKonfig::setLastUpdate(today); + + updateNextSubscription(); + return; + } + + // else + QStringList titles = ReKonfig::subscriptionTitles(); + foreach(const QString &title, titles) + { + rules = rulesGroup.readEntry(title + "-rules" , QStringList()); + loadRules(rules); + } +} + + +void AdBlockManager::loadRules(const QStringList &rules) +{ + foreach(const QString &stringRule, rules) + { + // ! rules are comments + if (stringRule.startsWith('!')) + continue; + + // [ rules are ABP info + if (stringRule.startsWith('[')) + continue; + + // 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(QL1S("@@"))) { - QString name = it.key(); - QString url = it.value(); + AdBlockRule rule(stringRule.mid(2)); + _whiteList << rule; + continue; + } - 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; - } - } + // hide (CSS) rules + if (stringRule.startsWith(QL1S("##"))) + { + _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; - + // we (ad)block just http traffic - if(request.url().scheme() != QLatin1String("http")) + if (request.url().scheme() != QL1S("http")) return 0; - + QString urlString = request.url().toString(); // check white rules before :) foreach(const AdBlockRule &filter, _whiteList) { - if(filter.match(urlString)) + if (filter.match(urlString)) { - kDebug() << "****ADBLOCK: WHITE RULE (@@) Matched: ***********" << urlString; - return 0; + kDebug() << "****ADBLOCK: WHITE RULE (@@) Matched: ***********"; + kDebug() << "Filter exp: " << filter.pattern(); + kDebug() << "UrlString: " << urlString; + return 0; } } - + // then check the black ones :( foreach(const AdBlockRule &filter, _blackList) { - if(filter.match(urlString)) + 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(QL1S("visibility"), QL1S("hidden")); + el.setStyleProperty(QL1S("width"), QL1S("0")); + el.setStyleProperty(QL1S("height"), QL1S("0")); + } + } + AdBlockNetworkReply *reply = new AdBlockNetworkReply(request, urlString, this); - return reply; + return reply; } } - + // no match return 0; } @@ -148,24 +204,124 @@ QNetworkReply *AdBlockManager::block(const QNetworkRequest &request) void AdBlockManager::applyHidingRules(WebPage *page) { - if(!page || !page->mainFrame()) + if (!page) return; - + if (!_isAdblockEnabled) return; - + 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(QL1S("visibility"), QL1S("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..eae761e0 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 @@ -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 @@ -30,42 +30,42 @@ // NOTE: AdBlockPlus Filters (fast) summary -// +// // ### Basic Filter rules -// -// RULE = http://example.com/ads/* +// +// RULE = http://example.com/ads/* // this should block every link containing all things from that link -// +// // ### Exception rules (@@) -// +// // RULE = @@advice* -// +// // this will save every site, also that matched by other rules, cointaining words // that starts with "advice". Wildcards && regular expression allowed here. -// +// // ### Beginning/end matching rules (||) -// +// // RULE=||http://badsite.com -// +// // will stop all links starting with http://badsite.com -// +// // RULE=*swf|| -// +// // will stop all links to direct flash contents -// +// // ### Comments (!) -// +// // RULE=!azz.. -// +// // Every rule starting with a ! is commented out and should not be checked -// +// // ### Filter Options -// -// You can also specify a number of options to modify the behavior of a filter. +// +// You can also specify a number of options to modify the behavior of a filter. // You list these options separated with commas after a dollar sign ($) at the end of the filter -// +// // RULE=*/ads/*$element,match-case -// +// // where $element can be one of the following: // $script external scripts loaded via HTML script tag // $image regular images, typically loaded via HTML img tag @@ -80,37 +80,44 @@ // $subdocument embedded pages, usually included via HTML frames // $document the page itself (only exception rules can be applied to the page) // $other types of requests not covered in the list above -// +// // Inverse type options are allowed through the ~ sign, for example: -// +// // RULE=*/ads/*~$script,match-case -// +// // ### Regular expressions -// +// // They usually allow to check for (a lot of) sites, using just one rule, but be careful: // BASIC FILTERS ARE PROCESSED FASTER THAN REGULAR EXPRESSIONS (In ADP! In rekonq, I don't know...) -// -// +// +// // ### ELEMENT HIDING (##) -// -// This is quite different from usual adblock (but, for me, more powerful!). Sometimes you will find advertisements +// +// This is quite different from usual adblock (but, for me, more powerful!). Sometimes you will find advertisements // that can’t be blocked because they are embedded as text in the web page itself. // All you can do there is HIDE the element :) -// +// // RULE=##div.advise -// +// // The previous rule will hide every div whose class is named "advise". Usual CSS selectors apply here :) // // END NOTE ---------------------------------------------------------------------------------------------------------- +// Rekonq Includes +#include "rekonq_defines.h" + // Local Includes #include "adblockrule.h" +// KDE Includes +#include <KIO/Job> + // Qt Includes #include <QObject> #include <QNetworkReply> #include <QStringList> +#include <QByteArray> // Forward Includes class QNetworkRequest; @@ -120,18 +127,30 @@ class WebPage; typedef QList<AdBlockRule> AdBlockRuleList; -class AdBlockManager : public QObject +class REKONQ_TESTS_EXPORT AdBlockManager : public QObject { -Q_OBJECT - + Q_OBJECT + 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; bool _isHideAdsEnabled; @@ -139,6 +158,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..13677daa 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 @@ -36,9 +36,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 @@ -58,17 +58,19 @@ #include <klocalizedstring.h> // Qt Includes -#include <QNetworkRequest> -#include <QTimer> +#include <QtCore/QTimer> +#include <QtCore/QString> + +#include <QtNetwork/QNetworkRequest> AdBlockNetworkReply::AdBlockNetworkReply(const QNetworkRequest &request, const QString &urlString, QObject *parent) - : QNetworkReply(parent) + : QNetworkReply(parent) { 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..14a0672c 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 @@ -36,9 +36,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 @@ -54,15 +54,18 @@ #define ADBLOCK_NETWORK_REPLY_H +// Rekonq Includes +#include "rekonq_defines.h" + // Qt Includes #include <QNetworkReply> -#include <QString> // Forward Declarations class AdBlockRule; +class QString; -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..7c91a692 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 @@ -38,9 +38,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 @@ -57,44 +57,38 @@ // Qt Includes #include <QStringList> -#include <QDebug> -#include <QRegExp> #include <QUrl> -// Defines -#define QL1S(x) QLatin1String(x) -#define QL1C(x) QLatin1Char(x) - AdBlockRule::AdBlockRule(const QString &filter) - : m_optionMatchRule(false) + : m_optionMatchRule(false) { bool isRegExpRule = false; QString parsedLine = filter; - - if ( parsedLine.startsWith( QL1C('/') ) && parsedLine.endsWith( QL1C('/') ) ) + + if (parsedLine.startsWith(QL1C('/')) && parsedLine.endsWith(QL1C('/'))) { parsedLine = parsedLine.mid(1); parsedLine = parsedLine.left(parsedLine.size() - 1); isRegExpRule = true; } - - int optionsNumber = parsedLine.indexOf( QL1C('$'), 0); + + int optionsNumber = parsedLine.indexOf(QL1C('$'), 0); QStringList options; - - if (optionsNumber >= 0) + + if (optionsNumber >= 0) { options = parsedLine.mid(optionsNumber + 1).split(QL1C(',')); parsedLine = parsedLine.left(optionsNumber); } - if(!isRegExpRule) + if (!isRegExpRule) parsedLine = convertPatternToRegExp(parsedLine); - + m_regExp = QRegExp(parsedLine, Qt::CaseInsensitive, QRegExp::RegExp2); - if ( options.contains( QL1S("match-case") )) + if (options.contains(QL1S("match-case"))) { m_regExp.setCaseSensitivity(Qt::CaseSensitive); m_optionMatchRule = true; @@ -111,19 +105,19 @@ bool AdBlockRule::match(const QString &encodedUrl) const // TODO: Reimplement this in rekonq 0.5 :) // -// if (matched && !m_options.isEmpty()) +// if (matched && !m_options.isEmpty()) // { // // we only support domain right now // if (m_options.count() == 1) // { -// foreach (const QString &option, m_options) +// foreach (const QString &option, m_options) // { -// if (option.startsWith( QL1S("domain=") )) +// if (option.startsWith( QL1S("domain=") )) // { // QUrl url = QUrl::fromEncoded(encodedUrl.toUtf8()); // QString host = url.host(); // QStringList domainOptions = option.mid(7).split( QL1C('|') ); -// foreach (QString domainOption, domainOptions) +// foreach (QString domainOption, domainOptions) // { // bool negate = domainOption.at(0) == QL1C('~'); // if (negate) @@ -147,37 +141,43 @@ bool AdBlockRule::match(const QString &encodedUrl) const QString AdBlockRule::convertPatternToRegExp(const QString &wildcardPattern) { QString pattern = wildcardPattern; - + // remove multiple wildcards - pattern.replace(QRegExp( QL1S("\\*+") ), QL1S("*") ); - + pattern.replace(QRegExp(QL1S("\\*+")), QL1S("*")); + // remove anchors following separator placeholder - pattern.replace(QRegExp( QL1S("\\^\\|$") ), QL1S("^") ); - + pattern.replace(QRegExp(QL1S("\\^\\|$")), QL1S("^")); + // remove leading wildcards - pattern.replace(QRegExp( QL1S("^(\\*)") ), QL1S("") ); - + pattern.replace(QRegExp(QL1S("^(\\*)")), QL1S("")); + // remove trailing wildcards - pattern.replace(QRegExp( QL1S("(\\*)$") ), QL1S("") ); - + pattern.replace(QRegExp(QL1S("(\\*)$")), QL1S("")); + // escape special symbols - pattern.replace(QRegExp( QL1S("(\\W)") ), QL1S("\\\\1") ); - + pattern.replace(QRegExp(QL1S("(\\W)")), QL1S("\\\\1")); + // process extended anchor at expression start - pattern.replace(QRegExp( QL1S("^\\\\\\|\\\\\\|") ), QL1S("^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?") ); - + pattern.replace(QRegExp(QL1S("^\\\\\\|\\\\\\|")), QL1S("^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?")); + // process separator placeholders - pattern.replace(QRegExp( QL1S("\\\\\\^") ), QL1S("(?:[^\\w\\d\\-.%]|$)") ); - + pattern.replace(QRegExp(QL1S("\\\\\\^")), QL1S("(?:[^\\w\\d\\-.%]|$)")); + // process anchor at expression start - pattern.replace(QRegExp( QL1S("^\\\\\\|") ), QL1S("^") ); - + pattern.replace(QRegExp(QL1S("^\\\\\\|")), QL1S("^")); + // process anchor at expression end - pattern.replace(QRegExp( QL1S("\\\\\\|$") ), QL1S("$") ); - + pattern.replace(QRegExp(QL1S("\\\\\\|$")), QL1S("$")); + // replace wildcards by .* - pattern.replace(QRegExp( QL1S("\\\\\\*") ), QL1S(".*") ); + pattern.replace(QRegExp(QL1S("\\\\\\*")), QL1S(".*")); // 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..6f042fe2 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 @@ -37,9 +37,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 @@ -54,9 +54,13 @@ #ifndef ADBLOCKRULE_H #define ADBLOCKRULE_H + +// Rekonq Includes +#include "rekonq_defines.h" + // Qt Includes -#include <QRegExp> -#include <QString> +#include <QtCore/QRegExp> +#include <QtCore/QString> // Forward Includes class QUrl; @@ -69,11 +73,13 @@ public: bool match(const QString &encodedUrl) const; -private: + QString pattern() const; + +private: QString convertPatternToRegExp(const QString &wildcardPattern); - + QRegExp m_regExp; - + // Rule Options bool m_optionMatchRule; }; diff --git a/src/analyzer/analyzerpanel.cpp b/src/analyzer/analyzerpanel.cpp new file mode 100644 index 00000000..be346300 --- /dev/null +++ b/src/analyzer/analyzerpanel.cpp @@ -0,0 +1,103 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* 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 "analyzerpanel.h" +#include "analyzerpanel.moc" + +// Local Includes +#include "networkanalyzer.h" +#include "networkaccessmanager.h" +#include "webtab.h" +#include "webview.h" +#include "webpage.h" + +// KDE Includes +#include "KAction" + + +NetworkAnalyzerPanel::NetworkAnalyzerPanel(const QString &title, QWidget *parent) + : QDockWidget(title, parent) + , _viewer(new NetworkAnalyzer(this)) +{ + setObjectName("networkAnalyzerDock"); + setWidget(_viewer); +} + + +NetworkAnalyzerPanel::~NetworkAnalyzerPanel() +{ + delete _viewer; +} + + +void NetworkAnalyzerPanel::closeEvent(QCloseEvent *event) +{ + Q_UNUSED(event); + toggle(false); +} + + +MainWindow* NetworkAnalyzerPanel::mainWindow() +{ + return qobject_cast< MainWindow* >(parentWidget()); +} + + +void NetworkAnalyzerPanel::toggle(bool enable) +{ + mainWindow()->actionByName("net_analyzer")->setChecked(enable); + WebPage *page = mainWindow()->currentTab()->page(); + NetworkAccessManager *manager = qobject_cast<NetworkAccessManager *>(page->networkAccessManager()); + + if (enable) + { + connect(page, SIGNAL(loadStarted()), _viewer, SLOT(clear())); + connect(manager, SIGNAL(networkData(QNetworkAccessManager::Operation, const QNetworkRequest &, QNetworkReply *)), + _viewer, SLOT(addRequest(QNetworkAccessManager::Operation, const QNetworkRequest &, QNetworkReply *) ) ); + + +// mainWindow()->currentTab()->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); +// findChild<QWebInspector *>()->setPage(mainWindow()->currentTab()->page()); + show(); + } + else + { + disconnect(page, SIGNAL(loadStarted()), _viewer, SLOT(clear())); + disconnect(manager, SIGNAL(networkData(QNetworkAccessManager::Operation, const QNetworkRequest &, QNetworkReply *)), + _viewer, SLOT(addRequest(QNetworkAccessManager::Operation, const QNetworkRequest &, QNetworkReply *) ) ); + + hide(); +// mainWindow()->currentTab()->view()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, false); + } +} + + +void NetworkAnalyzerPanel::changeCurrentPage() +{ + bool enable = mainWindow()->currentTab()->view()->settings()->testAttribute(QWebSettings::DeveloperExtrasEnabled); + toggle(enable); +} diff --git a/src/urlbar/lineedit.cpp b/src/analyzer/analyzerpanel.h index f3c93e8e..d98206f1 100644 --- a/src/urlbar/lineedit.cpp +++ b/src/analyzer/analyzerpanel.h @@ -2,9 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 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) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -12,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 @@ -26,44 +24,46 @@ * ============================================================ */ -// Self Includes -#include "lineedit.h" -#include "lineedit.moc" +#ifndef ANALYZER_PANEL_H +#define ANALYZER_PANEL_H -// Qt Includes -#include <QtGui/QContextMenuEvent> -#include <QtGui/QFocusEvent> -#include <QtGui/QKeyEvent> +// Rekonq Includes +#include "rekonq_defines.h" -LineEdit::LineEdit(QWidget* parent) - : KLineEdit(parent) -{ - setMinimumWidth(200); - setFocusPolicy(Qt::WheelFocus); - setHandleSignals(true); - setClearButtonShown(true); -} +// Local Includes +#include "mainwindow.h" + +// Qt Includes +#include <QDockWidget> + +// Forward Declarations +class NetworkAnalyzer; -LineEdit::~LineEdit() +/** + Docked network analyzer + behaviour : hide/show by tab, not globally +*/ +class REKONQ_TESTS_EXPORT NetworkAnalyzerPanel : public QDockWidget { -} + Q_OBJECT +public: + NetworkAnalyzerPanel(const QString &title, QWidget *parent); + ~NetworkAnalyzerPanel(); + +public slots: + void toggle(bool enable); + void changeCurrentPage(); -void LineEdit::keyPressEvent(QKeyEvent *event) -{ - if (event->key() == Qt::Key_Escape) - { - clearFocus(); - event->accept(); - } +protected: + virtual void closeEvent(QCloseEvent *event); - KLineEdit::keyPressEvent(event); -} + MainWindow *mainWindow(); +private: + NetworkAnalyzer *_viewer; +}; -void LineEdit::mouseDoubleClickEvent(QMouseEvent *) -{ - selectAll(); -} +#endif // NET_ANALYZER_PANEL_H diff --git a/src/analyzer/networkanalyzer.cpp b/src/analyzer/networkanalyzer.cpp new file mode 100644 index 00000000..53972a9c --- /dev/null +++ b/src/analyzer/networkanalyzer.cpp @@ -0,0 +1,199 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009, 2010 by Richard J. Moore <rich@kde.org> +* 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 "networkanalyzer.h" +#include "networkanalyzer.moc" + +// KDE Includes +#include <klocalizedstring.h> +#include <KPassivePopup> + +// Qt Includes +#include <QtGui/QTreeWidget> +#include <QtGui/QVBoxLayout> +#include <QtGui/QHeaderView> +#include <QtGui/QLabel> + +#include <QSignalMapper> + + +NetworkAnalyzer::NetworkAnalyzer(QWidget *parent) + : QWidget(parent) + , _mapper(new QSignalMapper(this)) + , _requestList(new QTreeWidget(this)) +{ + QStringList headers; + headers << i18n("Method") << i18n("Url") << i18n("Response") << i18n("Length") << i18n("Content Type") << i18n("Info"); + _requestList->setHeaderLabels( headers ); + + _requestList->header()->setResizeMode(0, QHeaderView::ResizeToContents); + _requestList->header()->setResizeMode(1, QHeaderView::Stretch); + _requestList->header()->setResizeMode(2, QHeaderView::ResizeToContents); + _requestList->header()->setResizeMode(3, QHeaderView::ResizeToContents); + _requestList->header()->setResizeMode(4, QHeaderView::ResizeToContents); + + _requestList->setAlternatingRowColors(true); + + QVBoxLayout *lay = new QVBoxLayout(this); + lay->addWidget( _requestList ); + + connect( _mapper, SIGNAL(mapped(QObject *)), this, SLOT(requestFinished(QObject *)) ); + + connect( _requestList, SIGNAL(itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( showItemDetails( QTreeWidgetItem *) ) ); +} + + +NetworkAnalyzer::~NetworkAnalyzer() +{ +} + + +void NetworkAnalyzer::addRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QNetworkReply *reply ) +{ + // Add to list of requests + QStringList cols; + switch( op ) + { + case QNetworkAccessManager::HeadOperation: + cols << QL1S("HEAD"); + break; + case QNetworkAccessManager::GetOperation: + cols << QL1S("GET"); + break; + case QNetworkAccessManager::PutOperation: + cols << QL1S("PUT"); + break; + case QNetworkAccessManager::PostOperation: + cols << QL1S("POST"); + break; + default: + kDebug() << "Unknown network operation"; + } + cols << req.url().toString(); + cols << i18n("Pending"); + + QTreeWidgetItem *item = new QTreeWidgetItem( cols ); + _requestList->addTopLevelItem( item ); + + // Add to maps + _requestMap.insert( reply, req ); + _itemMap.insert( reply, item ); + _itemRequestMap.insert( item, req ); + + _mapper->setMapping( reply, reply ); + connect( reply, SIGNAL( finished() ), _mapper, SLOT( map() ) ); +} + + +void NetworkAnalyzer::clear() +{ + _requestMap.clear(); + _itemMap.clear(); + _itemReplyMap.clear(); + _itemRequestMap.clear(); + _requestList->clear(); +} + + +void NetworkAnalyzer::requestFinished( QObject *replyObject ) +{ + QNetworkReply *reply = qobject_cast<QNetworkReply *>( replyObject ); + if ( !reply ) { + kDebug() << "Failed to downcast reply"; + return; + } + + QTreeWidgetItem *item = _itemMap[reply]; + + // Record the reply headers + QList<QByteArray> headerValues; + foreach(const QByteArray &header, reply->rawHeaderList() ) + { + headerValues += reply->rawHeader( header ); + } + + QPair< QList<QByteArray>, QList<QByteArray> > replyHeaders; + replyHeaders.first = reply->rawHeaderList(); + replyHeaders.second = headerValues; + _itemReplyMap[item] = replyHeaders; + + // Display the request + int status = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt(); + QString reason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString(); + item->setText( 2, i18n("%1 %2", status, reason) ); + + QString length = reply->header( QNetworkRequest::ContentLengthHeader ).toString(); + item->setText( 3, length ); + + QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString(); + item->setText( 4, contentType ); + + if ( status == 302 ) { + QUrl target = reply->attribute( QNetworkRequest::RedirectionTargetAttribute ).toUrl(); + item->setText( 5, i18n("Redirect: %1", target.toString() ) ); + } +} + + +void NetworkAnalyzer::showItemDetails( QTreeWidgetItem *item ) +{ + // Show request details + QString details; + + QNetworkRequest req = _itemRequestMap[item]; + details += QL1S("<h3>Request Details</h3>"); + details += QL1S("<ul>"); + foreach(const QByteArray &header, req.rawHeaderList() ) + { + details += QL1S("<li>"); + details += QL1S( header ); + details += QL1S(": "); + details += QL1S( req.rawHeader( header ) ); + details += QL1S("</li>"); + } + details += QL1S("</ul>"); + + QPair< QList<QByteArray>, QList<QByteArray> > replyHeaders = _itemReplyMap[item]; + details += QL1S("<h3>Response Details</h3>"); + details += QL1S("<ul>"); + for ( int i = 0; i < replyHeaders.first.count(); i++ ) + { + details += QL1S("<li>"); + details += QL1S( replyHeaders.first[i] ); + details += QL1S(": "); + details += QL1S( replyHeaders.second[i] ); + details += QL1S("</li>"); + } + details += QL1S("</ul>"); + +// QLabel *label = new QLabel(details, this); +// KPassivePopup *popup = new KPassivePopup(this); +// popup->setView(label); +// popup->show(_requestList->mapToGlobal(_requestList->pos())); + KPassivePopup::message(details,this); +} diff --git a/src/analyzer/networkanalyzer.h b/src/analyzer/networkanalyzer.h new file mode 100644 index 00000000..9e38663f --- /dev/null +++ b/src/analyzer/networkanalyzer.h @@ -0,0 +1,77 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009, 2010 by Richard J. Moore <rich@kde.org> +* 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_ANALYZER_H +#define NETWORK_ANALYZER_H + + +// Rekonq Includes +#include "rekonq_defines.h" + +// Qt Includes +#include <QtCore/QMap> +#include <QtCore/QList> + +#include <QtGui/QWidget> + +#include <QtNetwork/QNetworkAccessManager> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkRequest> + +// Forward Declarations +class QTreeWidgetItem; +class QSignalMapper; +class QTreeWidget; + + +class NetworkAnalyzer : public QWidget +{ + Q_OBJECT + +public: + NetworkAnalyzer(QWidget *parent = 0); + ~NetworkAnalyzer(); + +private slots: + void addRequest( QNetworkAccessManager::Operation op, const QNetworkRequest &req, QNetworkReply *reply ); + + void clear(); + void requestFinished( QObject *replyObject ); + void showItemDetails( QTreeWidgetItem *item ); + +private: + QMap<QNetworkReply *, QNetworkRequest> _requestMap; + QMap<QTreeWidgetItem *, QNetworkRequest> _itemRequestMap; + QMap<QNetworkReply *, QTreeWidgetItem *> _itemMap; + QMap<QTreeWidgetItem *, QPair< QList<QByteArray>, QList<QByteArray> > > _itemReplyMap; + + QSignalMapper *_mapper; + QTreeWidget *_requestList; +}; + +#endif // NETWORK_ANALYZER_H diff --git a/src/application.cpp b/src/application.cpp index 05004f30..b1419d00 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 @@ -12,9 +12,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 @@ -44,48 +44,60 @@ #include "adblockmanager.h" #include "webview.h" #include "filterurljob.h" +#include "tabbar.h" // KDE Includes #include <KCmdLineArgs> #include <KStandardDirs> #include <kio/job.h> #include <kio/jobclasses.h> -#include <KToolInvocation> #include <KUriFilter> #include <KMessageBox> -#include <KWindowInfo> #include <KUrl> #include <ThreadWeaver/Weaver> // Qt Includes -#include <QRegExp> -#include <QFile> -#include <QFileInfo> #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() - : KUniqueApplication() + : KUniqueApplication() { - connect(Weaver::instance(), SIGNAL( jobDone(ThreadWeaver::Job*) ), - this, SLOT( loadResolvedUrl(ThreadWeaver::Job*) ) ); + connect(Weaver::instance(), SIGNAL(jobDone(ThreadWeaver::Job*)), + this, SLOT(loadResolvedUrl(ThreadWeaver::Job*))); } 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.data(); + s_bookmarkProvider.clear(); - delete s_bookmarkProvider; - delete s_historyManager; - delete s_sessionManager; - delete s_adblockManager; + delete s_historyManager.data(); + s_historyManager.clear(); + + delete s_sessionManager.data(); + s_sessionManager.clear(); + + delete s_adblockManager.data(); + s_adblockManager.clear(); } @@ -93,81 +105,69 @@ int Application::newInstance() { KCmdLineArgs::setCwd(QDir::currentPath().toUtf8()); KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); - - // we share one process for several mainwindows, - // so initialize only once - static bool first = true; - - if(args->count() == 0) + + 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()) + switch (ReKonfig::startupBehaviour()) { - case 0: // open home page - mainWindow()->homePage(); - break; - case 1: // open new tab page - loadUrl( KUrl("about:home") ); - break; - case 2: // restore session - if(sessionManager()->restoreSession()) - break; - default: - mainWindow()->homePage(); + case 0: // open home page + mainWindow()->homePage(); + break; + case 1: // open new tab page + loadUrl(KUrl("about:home")); + break; + case 2: // restore session + if (sessionManager()->restoreSession()) break; - } + default: + mainWindow()->homePage(); + break; + } } 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()) + else { - kDebug() << "session restored"; - return 1; - } - - // are there args? load them.. - if (args->count() > 0) - { - // 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; } @@ -180,18 +180,26 @@ Application *Application::instance() void Application::postLaunch() { + // updating rekonq configuration + updateConfiguration(); + setWindowIcon(KIcon("rekonq")); - + // set Icon Database Path to store "favicons" associated with web sites QString directory = KStandardDirs::locateLocal("cache" , "" , true); QWebSettings::setIconDatabasePath(directory); Application::historyManager(); Application::sessionManager(); - + // 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(); } @@ -203,14 +211,14 @@ void Application::saveConfiguration() const MainWindow *Application::mainWindow() { - if(m_mainWindows.isEmpty()) + if (m_mainWindows.isEmpty()) return newMainWindow(); - + MainWindow *active = qobject_cast<MainWindow*>(QApplication::activeWindow()); - - if(!active) + + 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"); - } - - if(url.isEmpty()) + // 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,23 +289,20 @@ 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; } // first, create the webview(s) to not let hangs UI.. WebTab *tab = 0; MainWindow *w = 0; - w = (type == Rekonq::NewWindow) + w = (type == Rekonq::NewWindow) ? newMainWindow() : mainWindow(); - - switch(type) + + switch (type) { case Rekonq::SettingOpenTab: tab = w->mainView()->newWebTab(!ReKonfig::openTabsBack(), ReKonfig::openTabsNearCurrent()); @@ -311,39 +318,34 @@ void Application::loadUrl(const KUrl& url, const Rekonq::OpenType& type) tab = w->mainView()->currentWebTab(); break; }; - + WebView *view = tab->view(); - + 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 *Application::newMainWindow(bool withTab) { MainWindow *w = new MainWindow(); - w->mainView()->newWebTab(); // remember using newWebTab and NOT newTab here!! - + + if (withTab) + w->mainView()->newWebTab(); // remember using newWebTab and NOT newTab here!! + m_mainWindows.prepend(w); w->show(); - + return w; } void Application::removeMainWindow(MainWindow *window) { - m_mainWindows.removeAt(m_mainWindows.indexOf(window, 0)); + m_mainWindows.removeOne(window); } @@ -355,11 +357,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(); } @@ -368,19 +370,101 @@ void Application::loadResolvedUrl(ThreadWeaver::Job *job) FilterUrlJob *threadedJob = static_cast<FilterUrlJob *>(job); KUrl url = threadedJob->url(); WebView *view = threadedJob->view(); - + + // Bye and thanks :) + delete threadedJob; + if (view) { - view->setFocus(); - view->load(url); - + view->load(url); + // we are sure of the url now, let's add it to history // anyway we store here just http sites because local and ftp ones are // added trough the protocol handler and the other are ignored - if( url.protocol() == QLatin1String("http") || url.protocol() == QLatin1String("https") ) - historyManager()->addHistoryEntry( url.prettyUrl() ); + if (url.protocol() == QL1S("http") || url.protocol() == QL1S("https")) + historyManager()->addHistoryEntry(url.prettyUrl()); } - - // Bye and thanks :) - delete threadedJob; +} + + +void Application::newWindow() +{ + loadUrl(KUrl("about:home"), Rekonq::NewWindow); + mainWindow()->mainView()->urlBarWidget()->setFocus(); +} + + +void Application::updateConfiguration() +{ + // FIXME: + // all things related to mainview can be + // improved/moved/replicated in all the mainwindows + MainView *view = mainWindow()->mainView(); + + // ============== General ================== + view->updateTabBar(); + + // ============== Tabs ================== + if (ReKonfig::closeTabSelectPrevious()) + view->tabBar()->setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab); + else + view->tabBar()->setSelectionBehaviorOnRemove(QTabBar::SelectRightTab); + + // =========== Encodings & Fonts ============== + QWebSettings *defaultSettings = QWebSettings::globalSettings(); + + defaultSettings->setDefaultTextEncoding(ReKonfig::defaultEncoding()); + + int fnSize = ReKonfig::fontSize(); + int minFnSize = ReKonfig::minFontSize(); + + QFont standardFont = ReKonfig::standardFont(); + defaultSettings->setFontFamily(QWebSettings::StandardFont, standardFont.family()); + defaultSettings->setFontSize(QWebSettings::DefaultFontSize, fnSize); + defaultSettings->setFontSize(QWebSettings::MinimumFontSize, minFnSize); + + QFont fixedFont = ReKonfig::fixedFont(); + defaultSettings->setFontFamily(QWebSettings::FixedFont, fixedFont.family()); + defaultSettings->setFontSize(QWebSettings::DefaultFixedFontSize, fnSize); + + // ================ WebKit ============================ + defaultSettings->setAttribute(QWebSettings::AutoLoadImages, ReKonfig::autoLoadImages()); + defaultSettings->setAttribute(QWebSettings::DnsPrefetchEnabled, ReKonfig::dnsPrefetch()); + defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, ReKonfig::javascriptEnabled()); + defaultSettings->setAttribute(QWebSettings::JavaEnabled, ReKonfig::javaEnabled()); + defaultSettings->setAttribute(QWebSettings::JavascriptCanOpenWindows, ReKonfig::javascriptCanOpenWindows()); + defaultSettings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, ReKonfig::javascriptCanAccessClipboard()); + defaultSettings->setAttribute(QWebSettings::LinksIncludedInFocusChain, ReKonfig::linksIncludedInFocusChain()); + defaultSettings->setAttribute(QWebSettings::ZoomTextOnly, ReKonfig::zoomTextOnly()); + defaultSettings->setAttribute(QWebSettings::PrintElementBackgrounds, ReKonfig::printElementBackgrounds()); + + if (ReKonfig::pluginsEnabled() == 2) + defaultSettings->setAttribute(QWebSettings::PluginsEnabled, false); + else + defaultSettings->setAttribute(QWebSettings::PluginsEnabled, true); + + // ===== HTML 5 features WebKit support ====== + defaultSettings->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, ReKonfig::offlineStorageDatabaseEnabled()); + defaultSettings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, ReKonfig::offlineWebApplicationCacheEnabled()); + defaultSettings->setAttribute(QWebSettings::LocalStorageEnabled, ReKonfig::localStorageEnabled()); + if (ReKonfig::localStorageEnabled()) + { + QString path = KStandardDirs::locateLocal("cache", QString("WebkitLocalStorage/rekonq"), true); + path.remove("rekonq"); + QWebSettings::setOfflineStoragePath(path); + QWebSettings::setOfflineStorageDefaultQuota(50000); + } + + // Applies user defined CSS to all open webpages. If there no longer is a + // user defined CSS removes it from all open webpages. + 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(); + Application::adblockManager()->loadSettings(); + + defaultSettings = 0; } diff --git a/src/application.h b/src/application.h index 4b951ded..7b58ab18 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 @@ -12,9 +12,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 @@ -30,15 +30,16 @@ #define APPLICATION_H +// Rekonq Includes +#include "rekonq_defines.h" + // KDE Includes #include <KUniqueApplication> #include <KIcon> -#include <kio/job.h> -#include <kio/jobclasses.h> #include <ThreadWeaver/Job> // Qt Includes -#include <QPointer> +#include <QWeakPointer> #include <QList> // Forward Declarations @@ -52,44 +53,13 @@ class AdBlockManager; class WebView; -typedef QList< QPointer<MainWindow> > MainWindowList; - - -namespace Rekonq -{ - /** - * @short notifying message status - * Different message status - */ - - enum Notify - { - Success, ///< url successfully (down)loaded - Error, ///< url failed to (down)load - Download, ///< downloading url - Info ///< information, (default) - }; - - /** - * @short Open link options - * Different modes of opening new tab - */ - enum OpenType - { - CurrentTab, ///< open url in current tab - SettingOpenTab, ///< open url according to users settings - NewCurrentTab, ///< open url in new tab and make it current - NewBackTab, ///< open url in new tab in background - NewWindow ///< open url in new window - }; - -} +typedef QList< QWeakPointer<MainWindow> > MainWindowList; /** * */ -class Application : public KUniqueApplication +class REKONQ_TESTS_EXPORT Application : public KUniqueApplication { Q_OBJECT @@ -100,15 +70,16 @@ public: static Application *instance(); MainWindow *mainWindow(); + MainWindow *newMainWindow(bool withTab = true); MainWindowList mainWindowList(); - + static KIcon icon(const KUrl &url); static HistoryManager *historyManager(); static BookmarkProvider *bookmarkProvider(); static SessionManager *sessionManager(); static AdBlockManager *adblockManager(); - + public slots: /** * Save application's configuration @@ -117,16 +88,11 @@ public slots: */ void saveConfiguration() const; - MainWindow *newMainWindow(); - - void loadUrl( const KUrl& url, - const Rekonq::OpenType& type = Rekonq::CurrentTab + 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: @@ -137,13 +103,15 @@ private slots: void postLaunch(); void loadResolvedUrl(ThreadWeaver::Job *); - + + void updateConfiguration(); + 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..47608710 --- /dev/null +++ b/src/bookmarks/bookmarkcontextmenu.cpp @@ -0,0 +1,331 @@ +/* ============================================================ +* +* 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(); +} + + +BookmarkContextMenu::~BookmarkContextMenu() +{ + delete m_ac; +} + + +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..ebbfd6e8 --- /dev/null +++ b/src/bookmarks/bookmarkcontextmenu.h @@ -0,0 +1,68 @@ +/* ============================================================ +* +* 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); + ~BookmarkContextMenu(); + + 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..bfa8d238 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 @@ -12,9 +13,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 @@ -34,25 +35,24 @@ #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() @@ -66,7 +66,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 +93,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; } @@ -112,26 +135,35 @@ BookmarkMenu::BookmarkMenu(KBookmarkManager *manager, KMenu *menu, KActionCollection* 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); + actionCollection->addAction(QL1S("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 +183,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 +262,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 +284,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 &))); @@ -194,40 +302,42 @@ BookmarkProvider::~BookmarkProvider() delete m_actionCollection; delete m_owner; delete m_manager; + + delete m_completion; } -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); + bookmarkToolBar->clear(); + fillBookmarkBar(bookmarkToolBar); } } } @@ -244,13 +354,19 @@ QAction *BookmarkProvider::actionByName(const QString &name) void BookmarkProvider::contextMenu(const QPoint &point) { - KAction* action = dynamic_cast<KAction*>(m_bookmarkToolBar->actionAt(point)); - if (!action) + if (m_bookmarkToolBars.isEmpty()) return; - KMenu *menu = m_bookmarkMenu->viewContextMenu(action); - if (!menu) + + KToolBar *bookmarkToolBar = m_bookmarkToolBars.at(0); + if (!bookmarkToolBar) return; - menu->popup(m_bookmarkToolBar->mapToGlobal(point)); + + KBookmarkActionInterface* action = dynamic_cast<KBookmarkActionInterface *>(bookmarkToolBar->actionAt(point)); + if (!action) + return; + + BookmarkContextMenu menu(action->bookmark(), bookmarkManager(), bookmarkOwner()); + menu.exec(bookmarkToolBar->mapToGlobal(point)); } @@ -265,36 +381,90 @@ KActionMenu* BookmarkProvider::bookmarkActionMenu(QWidget *parent) } -KAction *BookmarkProvider::fillBookmarkBar(const KBookmark &bookmark) +void BookmarkProvider::fillBookmarkBar(KToolBar *toolBar) { - if (bookmark.isGroup()) + KBookmarkGroup root = m_manager->toolbar(); + if (root.isNull()) + return; + + for (KBookmark bookmark = root.first(); !bookmark.isNull(); bookmark = root.next(bookmark)) { - KBookmarkGroup group = bookmark.toGroup(); - KBookmark bm = group.first(); - KActionMenu *menuAction = new KActionMenu(KIcon(bookmark.icon()), bookmark.text(), this); - menuAction->setDelayed(false); - while (!bm.isNull()) + if (bookmark.isGroup()) { - menuAction->addAction(fillBookmarkBar(bm)); - bm = group.next(bm); + KBookmarkActionMenu *menuAction = new KBookmarkActionMenu(bookmark.toGroup(), this); + menuAction->setDelayed(false); + new BookmarkMenu(bookmarkManager(), bookmarkOwner(), menuAction->menu(), bookmark.address()); + + toolBar->addAction(menuAction); } - return menuAction; + + else if (bookmark.isSeparator()) + { + toolBar->addSeparator(); + } + + else + { + toolBar->addAction(new KBookmarkAction(bookmark, m_owner, this)); + } + } +} + + +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; } - - if(bookmark.isSeparator()) + + KBookmark bookmark = bookGroup.first(); + while (!bookmark.isNull() && title.isEmpty()) { - KAction *a = new KAction(this); - a->setSeparator(true); - return a; + title = titleForBookmarkUrl(bookmark, url); + bookmark = bookGroup.next(bookmark); } - else + + if (title.isEmpty()) { - return new KBookmarkAction(bookmark, m_owner, this); + title = url; } + + return title; } -KBookmarkGroup BookmarkProvider::rootGroup() +QString BookmarkProvider::titleForBookmarkUrl(const KBookmark &bookmark, QString url) { - return m_manager->root(); + 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..ae12280b 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 @@ -30,6 +31,9 @@ #define BOOKMARKS_H +// Rekonq Includes +#include "rekonq_defines.h" + // Local Includes #include "application.h" @@ -38,6 +42,7 @@ // KDE Includes #include <KBookmarkOwner> +#include <KCompletion> // Forward Declarations class BookmarkProvider; @@ -55,7 +60,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 +115,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 +135,6 @@ signals: // KDE Includes #include <KBookmarkMenu> - /** * This class represent the rekonq bookmarks menu. * It's just a simple class inherited from KBookmarkMenu @@ -143,13 +149,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 +208,7 @@ public: */ void setupBookmarkBar(KToolBar *); + void removeToolBar(KToolBar*); /** * @short Get action by name @@ -209,7 +226,22 @@ 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 +268,18 @@ public slots: */ void slotBookmarksChanged(const QString &group, const QString &caller); + private: - KAction *fillBookmarkBar(const KBookmark &bookmark); + void fillBookmarkBar(KToolBar *toolBar); + 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..502af574 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) + : 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"); @@ -82,32 +81,144 @@ void BookmarksPanel::setup() KLineEdit *search = new KLineEdit; search->setClearButtonShown(true); searchLayout->addWidget(search); - searchLabel->setBuddy( search ); + 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); setWidget(ui); - BookmarksTreeModel *model = new BookmarksTreeModel( this ); + BookmarksTreeModel *model = new BookmarksTreeModel(this); BookmarksProxy *proxy = new BookmarksProxy(ui); - proxy->setSourceModel( model ); - treeView->setModel( proxy ); + proxy->setSourceModel(model); + 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); - connect(search, SIGNAL(textChanged(QString)), proxy, SLOT(setFilterFixedString(QString))); - connect(treeView, SIGNAL( activated(QModelIndex) ), this, SLOT( bookmarkActivated(QModelIndex) ) ); + 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; + + 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( selected, + Application::bookmarkProvider()->bookmarkManager(), + Application::bookmarkProvider()->bookmarkOwner(), + this + ); + + menu.exec(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..b2a9f264 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,26 @@ #ifndef BOOKMARKSPANEL_H #define BOOKMARKSPANEL_H + +// Rekonq Includes +#include "rekonq_defines.h" + +// Local Includes +#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 +57,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..4e4b4f06 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 @@ -29,27 +30,27 @@ #include "bookmarksproxy.moc" -BookmarksProxy::BookmarksProxy( QObject *parent ) - : QSortFilterProxyModel( parent ) +BookmarksProxy::BookmarksProxy(QObject *parent) + : QSortFilterProxyModel(parent) { } -bool BookmarksProxy::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const +bool BookmarksProxy::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { - QModelIndex idx = sourceModel()->index( source_row, 0, source_parent ); - return recursiveMatch( idx ); + QModelIndex idx = sourceModel()->index(source_row, 0, source_parent); + return recursiveMatch(idx); } -bool BookmarksProxy::recursiveMatch( const QModelIndex &index ) const +bool BookmarksProxy::recursiveMatch(const QModelIndex &index) const { - if( index.data().toString().contains( filterRegExp() ) ) + if (index.data().toString().contains(filterRegExp())) return true; - for( int childRow = 0; childRow < sourceModel()->rowCount( index ); ++childRow ) + for (int childRow = 0; childRow < sourceModel()->rowCount(index); ++childRow) { - if( recursiveMatch( sourceModel()->index( childRow, 0, index ) ) ) + if (recursiveMatch(sourceModel()->index(childRow, 0, index))) return true; } return false; diff --git a/src/bookmarks/bookmarksproxy.h b/src/bookmarks/bookmarksproxy.h index 99483331..e7b50d8e 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 + +// Rekonq Includes +#include "rekonq_defines.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..06732007 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,105 +33,124 @@ #include "application.h" #include "bookmarksmanager.h" +// Qt Includes +#include <QMimeData> + // KDE includes #include <KBookmarkGroup> #include <KLocalizedString> -class BookmarksTreeModel::BtmItem -{ -public: - BtmItem(const KBookmark &bm) +BtmItem::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; +} // ------------------------------------------------------------------------------------- BookmarksTreeModel::BookmarksTreeModel(QObject *parent) - : QAbstractItemModel(parent) - , m_root(0) + : QAbstractItemModel(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())); } @@ -143,13 +163,13 @@ BookmarksTreeModel::~BookmarksTreeModel() int BookmarksTreeModel::rowCount(const QModelIndex &parent) const { BtmItem *parentItem = 0; - if( !parent.isValid() ) + if (!parent.isValid()) { parentItem = m_root; } - else + else { - parentItem = static_cast< BtmItem* >( parent.internalPointer() ); + parentItem = static_cast< BtmItem* >(parent.internalPointer()); } return parentItem->childCount(); @@ -166,11 +186,11 @@ int BookmarksTreeModel::columnCount(const QModelIndex &parent) const QVariant BookmarksTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { - if( orientation == Qt::Horizontal - && role == Qt::DisplayRole - && section == 0 - ) - return i18n( "Bookmark" ); + if (orientation == Qt::Horizontal + && role == Qt::DisplayRole + && section == 0 + ) + return i18n("Bookmark"); return QVariant(); } @@ -178,33 +198,42 @@ 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; } QModelIndex BookmarksTreeModel::index(int row, int column, const QModelIndex &parent) const { - if( !hasIndex( row, column, parent ) ) + if (!hasIndex(row, column, parent)) { return QModelIndex(); } BtmItem *parentItem; - if( !parent.isValid() ) + if (!parent.isValid()) { parentItem = m_root; } - else + else { - parentItem = static_cast< BtmItem* >( parent.internalPointer() ); + parentItem = static_cast< BtmItem* >(parent.internalPointer()); } - BtmItem *childItem = parentItem->child( row ); - if( childItem ) + BtmItem *childItem = parentItem->child(row); + if (childItem) { - return createIndex( row, column, childItem ); + return createIndex(row, column, childItem); } return QModelIndex(); @@ -213,74 +242,52 @@ QModelIndex BookmarksTreeModel::index(int row, int column, const QModelIndex &pa QModelIndex BookmarksTreeModel::parent(const QModelIndex &index) const { - if( !index.isValid() ) + if (!index.isValid()) { return QModelIndex(); } - BtmItem *childItem = static_cast< BtmItem* >( index.internalPointer() ); + BtmItem *childItem = static_cast< BtmItem* >(index.internalPointer()); BtmItem *parentItem = childItem->parent(); - if( parentItem == m_root ) + if (parentItem == m_root) { return QModelIndex(); } - return createIndex( parentItem->row(), 0, parentItem ); + return createIndex(parentItem->row(), 0, parentItem); } QVariant BookmarksTreeModel::data(const QModelIndex &index, int role) const { - if( !index.isValid() ) + if (!index.isValid()) { return QVariant(); } - BtmItem *node = static_cast< BtmItem* >( index.internalPointer() ); - if( node && node == m_root ) + BtmItem *node = static_cast< BtmItem* >(index.internalPointer()); + if (node && node == m_root) { - if( role == Qt::DisplayRole ) - return i18n( "Bookmarks" ); - if( role == Qt::DecorationRole ) - return KIcon( "bookmarks" ); + if (role == Qt::DisplayRole) + return i18n("Bookmarks"); + if (role == Qt::DecorationRole) + return KIcon("bookmarks"); } - else + else { - if( node ) - return node->data( role ); + if (node) + return node->data(role); } return QVariant(); } -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(); } @@ -295,29 +302,126 @@ void BookmarksTreeModel::setRoot(KBookmarkGroup bmg) delete m_root; m_root = new BtmItem(KBookmark()); - if( bmg.isNull() ) + if (bmg.isNull()) return; - populate( m_root, bmg ); + populate(m_root, bmg); reset(); } -void BookmarksTreeModel::populate( BtmItem *node, KBookmarkGroup bmg) +void BookmarksTreeModel::populate(BtmItem *node, KBookmarkGroup bmg) { node->clear(); - if( bmg.isNull() ) + if (bmg.isNull()) return; KBookmark bm = bmg.first(); - while( !bm.isNull() ) + while (!bm.isNull()) { - BtmItem *newChild = new BtmItem( bm ); - if( bm.isGroup() ) - populate( newChild, bm.toGroup() ); + BtmItem *newChild = new BtmItem(bm); + if (bm.isGroup()) + populate(newChild, bm.toGroup()); + + node->appendChild(newChild); + 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); - node->appendChild( newChild ); - bm = bmg.next( bm ); + 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..8dd0923c 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> + +// Rekonq Includes +#include "rekonq_defines.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..e9174470 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 @@ -66,13 +41,13 @@ -ClickToFlash::ClickToFlash(QUrl pluginUrl, QWidget *parent) - : QWidget(parent) - , m_url(pluginUrl) +ClickToFlash::ClickToFlash(const QUrl &pluginUrl, QWidget *parent) + : QWidget(parent) + , m_url(pluginUrl) { QHBoxLayout *l = new QHBoxLayout(this); setLayout(l); - + QToolButton *button = new QToolButton(this); button->setPopupMode(QToolButton::InstantPopup); button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); @@ -84,12 +59,12 @@ ClickToFlash::ClickToFlash(QUrl pluginUrl, QWidget *parent) void ClickToFlash::load() -{ +{ QWidget *parent = parentWidget(); QWebView *view = 0; - while (parent) + while (parent) { - if (QWebView *aView = qobject_cast<QWebView*>(parent)) + if (QWebView *aView = qobject_cast<QWebView*>(parent)) { view = aView; break; @@ -99,54 +74,66 @@ void ClickToFlash::load() if (!view) return; - const QString selector = QLatin1String("%1[type=\"application/x-shockwave-flash\"]"); + const QString selector = QL1S("%1[type=\"application/x-shockwave-flash\"]"); hide(); - + QList<QWebFrame*> frames; frames.append(view->page()->mainFrame()); - while (!frames.isEmpty()) + while (!frames.isEmpty()) { QWebFrame *frame = frames.takeFirst(); QWebElement docElement = frame->documentElement(); QWebElementCollection elements; - elements.append(docElement.findAll(selector.arg(QLatin1String("object")))); - elements.append(docElement.findAll(selector.arg(QLatin1String("embed")))); - - bool isRightElement = false; - foreach (QWebElement element, elements) + elements.append(docElement.findAll(selector.arg(QL1S("object")))); + elements.append(docElement.findAll(selector.arg(QL1S("embed")))); + + 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..87c53587 100644 --- a/src/clicktoflash.h +++ b/src/clicktoflash.h @@ -1,77 +1,61 @@ -/* - * 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 + +// Rekonq Includes +#include "rekonq_defines.h" + +// Qt Includes #include <QWidget> #include <QUrl> +// Forward Declarations +class QWebElement; -class WebPluginFactory; -class ClickToFlash : public QWidget +class REKONQ_TESTS_EXPORT ClickToFlash : public QWidget { Q_OBJECT + public: - ClickToFlash(QUrl pluginUrl, QWidget *parent = 0); + explicit ClickToFlash(const QUrl &pluginUrl, QWidget *parent = 0); signals: void signalLoadClickToFlash(bool); - + 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..109b5505 100644 --- a/src/data/rekonq.desktop +++ b/src/data/rekonq.desktop @@ -1,16 +1,20 @@ [Desktop Entry] Name=rekonq +Name[cs]=rekonq +Name[da]=rekonq +Name[nds]=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[nds]=Webkit-KDE-Kieker +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[x-test]=xxWebkit KDE Browserxx Icon=rekonq 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..c887ac62 100644 --- a/src/filterurljob.cpp +++ b/src/filterurljob.cpp @@ -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 @@ -28,18 +28,14 @@ #include "filterurljob.h" // KDE Includes -#include <KUriFilter> #include <KUriFilterData> -// Qt Includes -#include <QUrl> - - FilterUrlJob::FilterUrlJob(WebView *view, const QString &urlString, QObject *parent) - : Job(parent) - , _view(view) - , _urlString(urlString) + : Job(parent) + , _view(view) + , _urlString(urlString) { + uriFilter = KUriFilter::self(); } @@ -61,7 +57,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 (uriFilter->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..c10c5e35 100644 --- a/src/filterurljob.h +++ b/src/filterurljob.h @@ -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 @@ -27,11 +27,15 @@ #ifndef FILTER_URL_JOB_H #define FILTER_URL_JOB_H +// Rekonq Includes +#include "rekonq_defines.h" + // Local Includes #include "webview.h" // KDE Includes #include <KUrl> +#include <KUriFilter> #include <ThreadWeaver/Job> // Qt Includes @@ -41,21 +45,23 @@ using namespace ThreadWeaver; -class FilterUrlJob : public Job +class REKONQ_TESTS_EXPORT FilterUrlJob : public Job { public: FilterUrlJob(WebView *view, const QString &urlString, QObject *parent = 0); WebView *view(); KUrl url(); - + protected: void run(); - + private: WebView *_view; QString _urlString; KUrl _url; + KUriFilter *uriFilter; + }; #endif // FILTER_URL_JOB_H diff --git a/src/findbar.cpp b/src/findbar.cpp index bd1a5137..f89cde60 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 @@ -11,9 +11,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 @@ -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,10 +69,11 @@ 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); - // hide timer + // hide timer connect(m_hideTimer, SIGNAL(timeout()), this, SLOT(hide())); // label @@ -77,27 +83,35 @@ 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(); setLayout(layout); - + // we start off hidden hide(); } @@ -105,6 +119,10 @@ FindBar::FindBar(KMainWindow *mainwindow) FindBar::~FindBar() { + delete m_lineEdit; + delete m_hideTimer; + delete m_matchCase; + delete m_highlightAll; } @@ -120,44 +138,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(); @@ -166,7 +169,7 @@ void FindBar::notifyMatch(bool match) { p.setColor(QPalette::Base, QColor(KApplication::palette().color(QPalette::Active, QPalette::Base))); } - else + else { if (match) { @@ -180,3 +183,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..39bb28c9 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 @@ -11,9 +11,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 @@ -29,46 +29,44 @@ #define FINDBAR_H +// Rekonq Includes +#include "rekonq_defines.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..83b3f6b0 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 @@ -11,9 +11,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 @@ -31,9 +31,6 @@ #include "autosaver.h" #include "autosaver.moc" -// KDE Includes -#include <KDebug> - // Qt Includes #include <QtCore/QMetaObject> @@ -52,7 +49,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 +91,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..6927dbe8 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 @@ -11,9 +11,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 @@ -29,6 +29,9 @@ #define AUTOSAVER_H +// Rekonq Includes +#include "rekonq_defines.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..e7e80841 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 @@ -12,9 +12,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 @@ -63,18 +63,17 @@ static const unsigned int HISTORY_VERSION = 23; HistoryManager::HistoryManager(QObject *parent) - : QWebHistoryInterface(parent) - , m_saveTimer(new AutoSaver(this)) - , m_historyLimit(30) - , m_historyModel(0) - , m_historyFilterModel(0) - , m_historyTreeModel(0) - , m_completion(0) + : QWebHistoryInterface(parent) + , m_saveTimer(new AutoSaver(this)) + , m_historyLimit(30) + , m_historyModel(0) + , m_historyFilterModel(0) + , m_historyTreeModel(0) + , m_completion(new KCompletion) { // take care of the completion object - m_completion = new KCompletion; - m_completion->setOrder( KCompletion::Weighted ); - + m_completion->setOrder(KCompletion::Weighted); + m_expiredTimer.setSingleShot(true); connect(&m_expiredTimer, SIGNAL(timeout()), this, SLOT(checkForExpired())); connect(this, SIGNAL(entryAdded(const HistoryItem &)), m_saveTimer, SLOT(changeOccurred())); @@ -95,6 +94,12 @@ HistoryManager::~HistoryManager() { m_saveTimer->saveIfNeccessary(); delete m_completion; + + delete m_saveTimer; + + delete m_historyModel; + delete m_historyFilterModel; + delete m_historyTreeModel; } @@ -113,11 +118,11 @@ bool HistoryManager::historyContains(const QString &url) const void HistoryManager::addHistoryEntry(const QString &url) { QUrl cleanUrl(url); - + // don't store about: urls (home page related) - if(cleanUrl.scheme() == QString("about")) + if (cleanUrl.scheme() == QString("about")) return; - + cleanUrl.setPassword(QString()); cleanUrl.setHost(cleanUrl.host().toLower()); HistoryItem item(cleanUrl.toString(), QDateTime::currentDateTime()); @@ -213,7 +218,7 @@ void HistoryManager::addHistoryEntry(const HistoryItem &item) m_history.prepend(item); emit entryAdded(item); - + if (m_history.count() == 1) checkForExpired(); } @@ -255,7 +260,7 @@ void HistoryManager::removeHistoryEntry(const KUrl &url, const QString &title) break; } } - + // Remove item from completion object QString _url = url.path(); _url.remove(QRegExp("^http://|/$")); @@ -317,7 +322,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 +368,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 +422,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 +442,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 +457,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..0f131782 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 @@ -12,9 +12,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 @@ -30,6 +30,9 @@ #define HISTORY_H +// Rekonq Includes +#include "rekonq_defines.h" + // KDE Includes #include <KUrl> @@ -51,10 +54,13 @@ class HistoryItem public: HistoryItem() {} explicit HistoryItem(const QString &u, - const QDateTime &d = QDateTime(), + 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..e68eac42 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 @@ -12,9 +12,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 @@ -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(); } @@ -688,7 +696,7 @@ QVariant HistoryTreeModel::data(const QModelIndex &index, int role) const QDate date = idx.data(HistoryModel::DateRole).toDate(); if (date == QDate::currentDate()) return i18n("Earlier Today"); - return date.toString(QLatin1String("dddd, MMMM d, yyyy")); + return date.toString(QL1S("dddd, MMMM d, yyyy")); } if (index.column() == 1) { diff --git a/src/history/historymodels.h b/src/history/historymodels.h index 08f3f63e..78691694 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 @@ -12,9 +12,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 @@ -30,6 +30,9 @@ #define HISTORYMODELS_H +// Rekonq Includes +#include "rekonq_defines.h" + // Local Includes #include "historymanager.h" @@ -37,15 +40,13 @@ #include <KUrl> // Qt Includes -#include <QDateTime> #include <QHash> #include <QObject> -#include <QTimer> #include <QSortFilterProxyModel> #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..c8009afd 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 @@ -11,9 +11,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 @@ -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) + : QDockWidget(title, parent, flags) + , m_treeView(new PanelTreeView(this)) { setup(); setShown(ReKonfig::showHistoryPanel()); @@ -67,14 +71,14 @@ void HistoryPanel::setup() { setObjectName("historyPanel"); setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - + 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,78 @@ 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); + int header = fm.width( QL1C('m') ) * 40; + 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::contextMenuItem(const QPoint &pos) +{ + KMenu menu; + 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); + + menu.exec(m_treeView->mapToGlobal(pos)); } -void HistoryPanel::itemActivated(const QModelIndex &item) +void HistoryPanel::contextMenuGroup(const QPoint &pos) { - emit openUrl( item.data(HistoryModel::UrlRole).toUrl() ); + KMenu menu; + KAction* action; + + action = new KAction(KIcon("tab-new"), i18n("Open Folder in Tabs"), this); + connect(action, SIGNAL(triggered()), this, SLOT(openAll())); + menu.addAction(action); + + menu.exec(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..1c86cfee 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 @@ -11,9 +11,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 @@ -29,6 +29,13 @@ #define HISTORYPANEL_H +// Rekonq Includes +#include "rekonq_defines.h" + +// Local Includes +#include "application.h" +#include "paneltreeview.h" + // Qt Includes #include <QDockWidget> @@ -38,22 +45,26 @@ class QWidget; class QModelIndex; -class HistoryPanel : public QDockWidget +class REKONQ_TESTS_EXPORT HistoryPanel : public QDockWidget { -Q_OBJECT + Q_OBJECT public: explicit HistoryPanel(const QString &title, QWidget *parent = 0, Qt::WindowFlags flags = 0); ~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..5551c55a 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 @@ -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 @@ -41,7 +41,7 @@ static const char description[] = I18N_NOOP("A lightweight Web Browser for KDE based on WebKit"); -extern "C" KDE_EXPORT int kdemain( int argc, char **argv ) +extern "C" KDE_EXPORT int kdemain(int argc, char **argv) { KAboutData about("rekonq", 0, @@ -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", @@ -89,8 +84,13 @@ extern "C" KDE_EXPORT int kdemain( int argc, char **argv ) ki18n("(Tons of ) patches, testing, bugfixing"), "ronny_scholz@web.de", ""); - - // --------------- about credits ----------------------------- + + // --------------- 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", @@ -120,7 +120,7 @@ extern "C" KDE_EXPORT int kdemain( int argc, char **argv ) ki18n("Handbook"), "rohan16garg@gmail.com", ""); - + about.addCredit(ki18n("Dario Freddi"), ki18n("Patches, hints, first KWallet support implementation (not yet included)"), "drf@kde.org", @@ -130,7 +130,7 @@ extern "C" KDE_EXPORT int kdemain( int argc, char **argv ) ki18n("first awesome bar implementation (wait next version and you'll see..)"), "jondeandres@gmail.com", ""); - + // Initialize command line args KCmdLineArgs::init(argc, argv, &about); diff --git a/src/mainview.cpp b/src/mainview.cpp index b26e7466..84b87956 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 @@ -12,9 +13,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 @@ -45,7 +46,6 @@ #include <KShortcut> #include <KStandardShortcut> #include <KMessageBox> -#include <KDebug> #include <KStandardDirs> #include <KPassivePopup> #include <KLocalizedString> @@ -63,51 +63,67 @@ MainView::MainView(MainWindow *parent) : KTabWidget(parent) - , m_urlBar(new UrlBar(this)) - , m_tabBar(new TabBar(this)) - , m_addTabButton(new QToolButton(this)) + , _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); - + // loading pixmap path 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(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(m_tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); - + 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(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(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))); - + QTimer::singleShot(0, this, SLOT(postLaunch())); } MainView::~MainView() { + delete _bars; + delete m_addTabButton; } void MainView::postLaunch() { - // Session Manager - connect (this, SIGNAL(tabsChanged()), Application::sessionManager(), SLOT(saveSession())); + QStringList list = Application::sessionManager()->closedSites(); + foreach(const QString &line, list) + { + if(line.startsWith( QL1S("about") )) + break; + QString title = line; + QString url = title; + HistoryItem item(url, QDateTime::currentDateTime(), title); + m_recentlyClosedTabs.removeAll(item); + m_recentlyClosedTabs.prepend(item); + } + // Session Manager + connect(this, SIGNAL(tabsChanged()), Application::sessionManager(), SLOT(saveSession())); + m_addTabButton->setDefaultAction(m_parentWindow->actionByName("new_tab")); m_addTabButton->setAutoRaise(true); @@ -117,23 +133,21 @@ 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) { - if(ButtonInCorner) + if (ButtonInCorner) return; setCornerWidget(m_addTabButton); ButtonInCorner = true; } else { - if(ButtonInCorner) + if (ButtonInCorner) { setCornerWidget(0); m_addTabButton->show(); @@ -141,16 +155,12 @@ void MainView::updateTabButtonPosition() } // detecting X position - int newPosX = tabBarWidth; - int tabWidthHint = m_tabBar->tabSizeHint(0).width(); - if (tabWidthHint < sizeHint().width()/4) + int newPosX = tabBarWidth; + 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); + m_addTabButton->move(newPosX, 0); } } @@ -163,13 +173,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 -{ - return m_urlBar; +QWidget *MainView::urlBarWidget() const +{ + return _bars; } @@ -185,9 +202,9 @@ void MainView::updateTabBar() { if (!isTabBarHidden()) { - if (m_tabBar->isHidden()) + if (tabBar()->isHidden()) { - m_tabBar->show(); + tabBar()->show(); m_addTabButton->show(); } updateTabButtonPosition(); @@ -195,16 +212,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()) { - if (m_tabBar->isHidden()) + if (tabBar()->isHidden()) { - m_tabBar->show(); + tabBar()->show(); m_addTabButton->show(); } updateTabButtonPosition(); @@ -235,17 +252,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) { @@ -268,17 +274,12 @@ void MainView::currentChanged(int index) // retrieve the old webview (that where we move from) WebTab *oldTab = this->webTab(m_currentTabIndex); - + // set current 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&))); @@ -286,36 +287,40 @@ void MainView::currentChanged(int index) 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(); } WebTab *MainView::webTab(int index) const { - WebTab *tab = qobject_cast<WebTab *>( this->widget(index) ); - if(tab) + WebTab *tab = qobject_cast<WebTab *>(this->widget(index)); + if (tab) { return tab; } @@ -328,6 +333,7 @@ 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())); @@ -339,21 +345,26 @@ WebTab *MainView::newWebTab(bool focused, bool nearParent) // connecting webPage signals with mainview connect(tab->view()->page(), SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested())); 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) { setCurrentWidget(tab); } emit tabsChanged(); - + return tab; } @@ -362,21 +373,21 @@ void MainView::newTab() { WebView *w = newWebTab()->view(); - switch(ReKonfig::newTabsBehaviour()) + switch (ReKonfig::newTabsBehaviour()) { case 0: // new tab page - w->load( KUrl("about:home") ); + w->load(KUrl("about:home")); break; case 1: // blank page - urlBar()->setUrl(KUrl("")); + urlBar()->clear(); break; case 2: // homepage - w->load( KUrl(ReKonfig::homePage()) ); + w->load(KUrl(ReKonfig::homePage())); break; default: break; } - urlBar()->setFocus(); + _bars->currentWidget()->setFocus(); } @@ -391,9 +402,9 @@ void MainView::reloadAllTabs() void MainView::windowCloseRequested() { - WebPage *page = qobject_cast<WebPage *>( sender() ); - WebView *view = qobject_cast<WebView *>( page->view() ); - int index = indexOf( view->parentWidget() ); + WebPage *page = qobject_cast<WebPage *>(sender()); + WebView *view = qobject_cast<WebView *>(page->view()); + int index = indexOf(view->parentWidget()); if (index >= 0) { @@ -437,10 +448,10 @@ void MainView::cloneTab(int index) index = currentIndex(); if (index < 0 || index >= count()) return; - + WebTab *tab = newWebTab(); KUrl url = webTab(index)->url(); - + // workaround against bug in webkit: // only set url if it is not empty // otherwise the current working directory will be used @@ -452,26 +463,25 @@ void MainView::cloneTab(int index) // When index is -1 index chooses the current tab -void MainView::closeTab(int index) +void MainView::closeTab(int index, bool del) { // open default homePage if just one tab is opened if (count() == 1) { WebView *w = currentWebTab()->view(); - urlBar()->setUrl(KUrl("")); - switch(ReKonfig::newTabsBehaviour()) + switch (ReKonfig::newTabsBehaviour()) { case 0: // new tab page case 1: // blank page - w->load( KUrl("about:home") ); + w->load(KUrl("about:home")); + urlBar()->setFocus(); break; case 2: // homepage - w->load( KUrl(ReKonfig::homePage()) ); + w->load(KUrl(ReKonfig::homePage())); break; default: break; } - urlBar()->setFocus(); return; } @@ -480,50 +490,50 @@ 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); - } + if (!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!! - if (hasFocus && count() > 0) - { - currentWebTab()->setFocus(); - } + QWidget *urlbar = _bars->widget(index); + _bars->removeWidget(urlbar); + + if (del) + { + tab->deleteLater(); // tab is scheduled for deletion. + urlbar->deleteLater(); } + + emit tabsChanged(); } void MainView::webViewLoadStarted() { - WebView *view = qobject_cast<WebView *>( sender() ); - int index = indexOf( view->parentWidget() ); + WebView *view = qobject_cast<WebView *>(sender()); + int index = indexOf(view->parentWidget()); if (-1 != index) { QLabel *label = animatedLoading(index, true); @@ -533,21 +543,20 @@ void MainView::webViewLoadStarted() } } - emit browserTabLoading(true); - if (index != currentIndex()) return; + emit browserTabLoading(true); emit showStatusBarMessage(i18n("Loading...")); } void MainView::webViewLoadFinished(bool ok) { - WebView *view = qobject_cast<WebView *>( sender() ); + WebView *view = qobject_cast<WebView *>(sender()); int index = -1; - if(view) - index = indexOf( view->parentWidget() ); + if (view) + index = indexOf(view->parentWidget()); if (-1 != index) { @@ -565,28 +574,26 @@ void MainView::webViewLoadFinished(bool ok) { return; } - + if (ok) emit showStatusBarMessage(i18n("Done"), Rekonq::Success); - else - emit showStatusBarMessage(i18n("Failed to load"), Rekonq::Error); +// else +// emit showStatusBarMessage(i18n("Failed to load"), Rekonq::Error); } void MainView::webViewIconChanged() { - WebView *view = qobject_cast<WebView *>( sender() ); - int index = indexOf( view->parentWidget() ); + WebView *view = qobject_cast<WebView *>(sender()); + 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(); } } @@ -598,15 +605,15 @@ void MainView::webViewTitleChanged(const QString &title) { tabTitle = i18n("(Untitled)"); } - WebView *view = qobject_cast<WebView *>( sender() ); - int index = indexOf( view->parentWidget() ); + WebView *view = qobject_cast<WebView *>(sender()); + int index = indexOf(view->parentWidget()); if (-1 != index) { setTabText(index, tabTitle); } if (currentIndex() == index) { - emit setCurrentTitle(tabTitle); + emit currentTitle(tabTitle); } Application::historyManager()->updateHistoryEntry(view->url(), tabTitle); } @@ -614,11 +621,11 @@ void MainView::webViewTitleChanged(const QString &title) void MainView::webViewUrlChanged(const QUrl &url) { - WebView *view = qobject_cast<WebView *>( sender() ); - int index = indexOf( view->parentWidget() ); + WebView *view = qobject_cast<WebView *>(sender()); + int index = indexOf(view->parentWidget()); if (-1 != index) { - m_tabBar->setTabData(index, url); + tabBar()->setTabData(index, url); } emit tabsChanged(); } @@ -641,13 +648,29 @@ void MainView::previousTab() setCurrentIndex(next); } +void MainView::openClosedTabs() +{ + foreach (const HistoryItem &item, recentlyClosedTabs()) + { + Application::instance()->loadUrl( KUrl(item.url), Rekonq::SettingOpenTab); + } +} + +void MainView::openClosedTab() +{ + KAction *action = qobject_cast<KAction *>(sender()); + if (action) + { + Application::instance()->loadUrl(action->data().toUrl(), Rekonq::SettingOpenTab); + } +} 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 +682,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; } @@ -685,8 +708,32 @@ void MainView::detachTab(int index) if (index < 0 || index >= count()) return; - KUrl url = webTab(index)->view()->url(); - closeTab(index); - - Application::instance()->loadUrl(url, Rekonq::NewWindow); + WebTab *tab = webTab(index); + KUrl u = tab->url(); + kDebug() << u; + if (u.scheme() == QL1S("about")) + { + closeTab(index); + Application::instance()->loadUrl(u, Rekonq::NewWindow); + } + else + { + QString label = tab->view()->title(); + QWidget *bar = _bars->widget(index); + closeTab(index, false); + + MainWindow *w = Application::instance()->newMainWindow(false); + w->mainView()->addTab(tab, Application::icon(u), label); + QStackedWidget *stack = qobject_cast<QStackedWidget *>(w->mainView()->urlBarWidget()); + stack->insertWidget(0, bar); + w->mainView()->updateTabBar(); + } +} + + +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..6edccc15 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 @@ -12,9 +13,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 @@ -30,8 +31,10 @@ #define MAINVIEW_H +// Rekonq Includes +#include "rekonq_defines.h" + // Local Includes -#include "rekonqprivate_export.h" #include "webview.h" #include "webpage.h" #include "application.h" @@ -43,6 +46,7 @@ // Qt Includes #include <QtGui/QToolButton> +#include <QStackedWidget> // Forward Declarations class QUrl; @@ -55,7 +59,7 @@ class UrlBar; /** - * This class represent rekonq Main View. + * This class represent rekonq Main View. * It contains all WebViews and the url bar. * */ @@ -68,8 +72,7 @@ public: MainView(MainWindow *parent); ~MainView(); -public: - + QWidget *urlBarWidget() const; UrlBar *urlBar() const; WebTab *webTab(int index) const; @@ -82,16 +85,15 @@ public: * */ void updateTabBar(); - + void setTabBarHidden(bool hide); - + QToolButton *addTabButton() const; - void clear(); /** * This function creates a new empty tab * with a webview inside - * @param focused decide if you wannna give focus + * @param focused decide if you wannna give focus * (or not) to this new tab (default true) * @param nearParent decide if you wanna create new tab near current or not * @return the webview embedded in the new tab @@ -106,7 +108,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); @@ -123,14 +125,16 @@ public slots: void newTab(); void cloneTab(int index = -1); - void closeTab(int index = -1); + void closeTab(int index = -1, bool del = true); void closeOtherTabs(int index); void reloadTab(int index = -1); void reloadAllTabs(); void nextTab(); void previousTab(); void detachTab(int index = -1); - + void openClosedTabs(); + void openClosedTab(); + // WEB slot actions void webReload(); void webStop(); @@ -147,7 +151,7 @@ private slots: void windowCloseRequested(); void postLaunch(); - + void movedTab(int, int); protected: virtual void resizeEvent(QResizeEvent *event); @@ -167,8 +171,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 d3c14d85..128648bf 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 @@ -46,12 +47,12 @@ #include "urlbar.h" #include "tabbar.h" #include "adblockmanager.h" +#include "analyzerpanel.h" // Ui Includes #include "ui_cleardata.h" // KDE Includes -#include <KUrl> #include <KShortcut> #include <KStandardAction> #include <KAction> @@ -64,23 +65,21 @@ #include <KTemporaryFile> #include <KPassivePopup> #include <KMenuBar> -#include <KToolBar> #include <KJobUiDelegate> #include <kdeprintdialog.h> #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> -#include <QtGui/QAction> #include <QtGui/QFont> #include <QtGui/QDesktopWidget> #include <QtGui/QPrinter> @@ -95,25 +94,24 @@ MainWindow::MainWindow() - : KMainWindow() - , m_view( new MainView(this) ) - , m_findBar( new FindBar(this) ) - , m_historyPanel(0) - , 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_popup( new KPassivePopup(this) ) - , m_hidePopup( new QTimer(this) ) - , m_ac( new KActionCollection(this) ) + : KMainWindow() + , m_view(new MainView(this)) + , m_findBar(new FindBar(this)) + , m_historyPanel(0) + , m_bookmarksPanel(0) + , m_webInspectorPanel(0) + , m_analyzerPanel(0) + , m_historyBackMenu(0) + , m_encodingMenu(new KMenu(this)) + , 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)) { // enable window size "auto-save" setAutoSaveSettings(); - // updating rekonq configuration - updateConfiguration(); - // creating a centralWidget containing panel, m_view and the hidden findbar QWidget *centralWidget = new QWidget; centralWidget->setContentsMargins(0, 0, 0, 0); @@ -148,7 +146,7 @@ MainWindow::MainWindow() // setting popup notification m_popup->setAutoDelete(false); - connect(Application::instance(), SIGNAL(focusChanged(QWidget*,QWidget*)), m_popup, SLOT(hide())); + connect(Application::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)), m_popup, SLOT(hide())); m_popup->setFrameShape(QFrame::NoFrame); m_popup->setLineWidth(0); connect(m_hidePopup, SIGNAL(timeout()), m_popup, SLOT(hide())); @@ -159,36 +157,68 @@ MainWindow::MainWindow() MainWindow::~MainWindow() { + Application::bookmarkProvider()->removeToolBar(m_bmBar); Application::instance()->removeMainWindow(this); + + delete m_view; + delete m_findBar; + + delete m_historyPanel; + delete m_bookmarksPanel; + delete m_webInspectorPanel; + + delete m_stopReloadAction; + delete m_historyBackMenu; + delete m_encodingMenu; + + delete m_mainBar; + delete m_bmBar; + + delete m_zoomSlider; + delete m_popup; + delete m_hidePopup; + + delete m_ac; } 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->addAction(actionByName(KStandardAction::name(KStandardAction::Back))); + m_mainBar->addAction(actionByName(KStandardAction::name(KStandardAction::Forward))); m_mainBar->addSeparator(); - m_mainBar->addAction( actionByName("stop_reload") ); - m_mainBar->addAction( actionByName(KStandardAction::name(KStandardAction::Home)) ); + m_mainBar->addAction(actionByName( QL1S("stop_reload") )); + m_mainBar->addAction(actionByName(KStandardAction::name(KStandardAction::Home))); // location bar KAction *urlBarAction = new KAction(this); - urlBarAction->setDefaultWidget(m_view->urlBar()); - m_mainBar->addAction( urlBarAction ); + urlBarAction->setDefaultWidget(m_view->urlBarWidget()); + m_mainBar->addAction(urlBarAction); - m_mainBar->addAction( actionByName("bookmarksActionMenu") ); - m_mainBar->addAction( actionByName("rekonq_tools") ); + m_mainBar->addAction(actionByName( QL1S("bookmarksActionMenu") )); + m_mainBar->addAction(actionByName( QL1S("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); + } } @@ -196,13 +226,13 @@ void MainWindow::postLaunch() { // KActionCollection read settings m_ac->readSettings(); - + // notification system connect(m_view, SIGNAL(showStatusBarMessage(const QString&, Rekonq::Notify)), this, SLOT(notifyMessage(const QString&, Rekonq::Notify))); 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 @@ -251,8 +281,8 @@ void MainWindow::setupActions() // new window action 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())); + actionCollection()->addAction(QL1S("new_window"), a); + connect(a, SIGNAL(triggered(bool)), Application::instance(), SLOT(newWindow())); // Standard Actions KStandardAction::open(this, SLOT(fileOpen()), actionCollection()); @@ -261,142 +291,167 @@ 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)); - actionCollection()->addAction(QLatin1String("stop"), a); + actionCollection()->addAction(QL1S("stop"), a); connect(a, SIGNAL(triggered(bool)), m_view, SLOT(webStop())); // stop reload Action m_stopReloadAction = new KAction(this); - actionCollection()->addAction(QLatin1String("stop_reload") , m_stopReloadAction); + actionCollection()->addAction(QL1S("stop_reload") , m_stopReloadAction); m_stopReloadAction->setShortcutConfigurable(false); connect(m_view, SIGNAL(browserTabLoading(bool)), this, SLOT(browserLoading(bool))); browserLoading(false); //first init for blank start page a = new KAction(i18n("Open Location"), this); a->setShortcut(Qt::CTRL + Qt::Key_L); - actionCollection()->addAction(QLatin1String("open_location"), a); + actionCollection()->addAction(QL1S("open_location"), a); connect(a, SIGNAL(triggered(bool)) , this, SLOT(openLocation())); // ============================= 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())); + actionCollection()->addAction(QL1S("zoom_in"), a); + connect(a, SIGNAL(triggered(bool)), this, SLOT(zoomIn())); - a = new KAction(KIcon("zoom-original"), i18n("&Normal Font"), this); + 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(QL1S("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(QL1S("zoom_out"), a); + connect(a, SIGNAL(triggered(bool)), this, SLOT(zoomOut())); // =============================== Tools Actions ================================= a = new KAction(i18n("Page S&ource"), this); a->setIcon(KIcon("application-xhtml+xml")); - actionCollection()->addAction(QLatin1String("page_source"), a); + actionCollection()->addAction(QL1S("page_source"), a); connect(a, SIGNAL(triggered(bool)), this, SLOT(viewPageSource())); a = new KAction(KIcon("view-media-artist"), i18n("Private &Browsing"), this); a->setCheckable(true); - actionCollection()->addAction(QLatin1String("private_browsing"), a); + actionCollection()->addAction(QL1S("private_browsing"), a); connect(a, SIGNAL(triggered(bool)), this, SLOT(privateBrowsing(bool))); a = new KAction(KIcon("edit-clear"), i18n("Clear Private Data..."), this); - actionCollection()->addAction(QLatin1String("clear_private_data"), a); + actionCollection()->addAction(QL1S("clear_private_data"), a); 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); a->setShortcut(KShortcut(Qt::CTRL + Qt::Key_T)); - actionCollection()->addAction(QLatin1String("new_tab"), a); + actionCollection()->addAction(QL1S("new_tab"), a); connect(a, SIGNAL(triggered(bool)), m_view, SLOT(newTab())); a = new KAction(KIcon("view-refresh"), i18n("Reload All Tabs"), this); - actionCollection()->addAction( QLatin1String("reload_all_tabs"), a); - connect(a, SIGNAL(triggered(bool)), m_view, SLOT(reloadAllTabs()) ); + actionCollection()->addAction(QL1S("reload_all_tabs"), a); + connect(a, SIGNAL(triggered(bool)), m_view, SLOT(reloadAllTabs())); a = new KAction(i18n("Show Next Tab"), this); a->setShortcuts(QApplication::isRightToLeft() ? KStandardShortcut::tabPrev() : KStandardShortcut::tabNext()); - actionCollection()->addAction(QLatin1String("show_next_tab"), a); + actionCollection()->addAction(QL1S("show_next_tab"), a); connect(a, SIGNAL(triggered(bool)), m_view, SLOT(nextTab())); a = new KAction(i18n("Show Previous Tab"), this); a->setShortcuts(QApplication::isRightToLeft() ? KStandardShortcut::tabNext() : KStandardShortcut::tabPrev()); - actionCollection()->addAction(QLatin1String("show_prev_tab"), a); + actionCollection()->addAction(QL1S("show_prev_tab"), a); connect(a, SIGNAL(triggered(bool)), m_view, SLOT(previousTab())); + + a = new KAction(KIcon("tab-new"), i18n("Open Closed Tabs"), this); + a->setShortcut(KShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_T)); + actionCollection()->addAction(QL1S("open_closed_tabs"), a); + connect(a, SIGNAL(triggered(bool)), m_view, SLOT(openClosedTabs())); + + // Closed Tabs Menu + KActionMenu *closedTabsMenu = new KActionMenu(KIcon("tab-new"), i18n("Closed Tabs"), this); + closedTabsMenu->setDelayed(false); + actionCollection()->addAction(QL1S("closed_tab_menu"), closedTabsMenu); // ============================== Indexed Tab Actions ==================================== a = new KAction(KIcon("tab-close"), i18n("&Close Tab"), this); - actionCollection()->addAction(QLatin1String("close_tab"), a); + actionCollection()->addAction(QL1S("close_tab"), a); connect(a, SIGNAL(triggered(bool)), m_view->tabBar(), SLOT(closeTab())); a = new KAction(KIcon("tab-duplicate"), i18n("Clone Tab"), this); - actionCollection()->addAction(QLatin1String("clone_tab"), a); - connect(a, SIGNAL(triggered(bool)), m_view->tabBar(), SLOT(cloneTab()) ); + actionCollection()->addAction(QL1S("clone_tab"), a); + connect(a, SIGNAL(triggered(bool)), m_view->tabBar(), SLOT(cloneTab())); a = new KAction(KIcon("tab-close-other"), i18n("Close &Other Tabs"), this); - actionCollection()->addAction( QLatin1String("close_other_tabs"), a); - connect(a, SIGNAL(triggered(bool)), m_view->tabBar(), SLOT(closeOtherTabs()) ); + actionCollection()->addAction(QL1S("close_other_tabs"), a); + connect(a, SIGNAL(triggered(bool)), m_view->tabBar(), SLOT(closeOtherTabs())); a = new KAction(KIcon("view-refresh"), i18n("Reload Tab"), this); - actionCollection()->addAction( QLatin1String("reload_tab"), a); - connect(a, SIGNAL(triggered(bool)), m_view->tabBar(), SLOT(reloadTab()) ); + actionCollection()->addAction(QL1S("reload_tab"), a); + connect(a, SIGNAL(triggered(bool)), m_view->tabBar(), SLOT(reloadTab())); a = new KAction(KIcon("tab-detach"), i18n("Detach Tab"), this); - actionCollection()->addAction( QLatin1String("detach_tab"), a); - connect(a, SIGNAL(triggered(bool)), m_view->tabBar(), SLOT(detachTab()) ); - + actionCollection()->addAction(QL1S("detach_tab"), a); + connect(a, SIGNAL(triggered(bool)), m_view->tabBar(), SLOT(detachTab())); + + // ----------------------- Bookmarks ToolBar Action -------------------------------------- QAction *qa; - + qa = m_mainBar->toggleViewAction(); - qa->setText( i18n("Main Toolbar") ); - qa->setIcon( KIcon("bookmark-toolbar") ); - actionCollection()->addAction(QLatin1String("main_bar"), qa); - + qa->setText(i18n("Main Toolbar")); + qa->setIcon(KIcon("bookmark-toolbar")); + actionCollection()->addAction(QL1S("main_bar"), qa); + qa = m_bmBar->toggleViewAction(); - qa->setText( i18n("Bookmarks Toolbar") ); - qa->setIcon( KIcon("bookmark-toolbar") ); - actionCollection()->addAction(QLatin1String("bm_bar"), qa); + qa->setText(i18n("Bookmarks Toolbar")); + qa->setIcon(KIcon("bookmark-toolbar")); + actionCollection()->addAction(QL1S("bm_bar"), qa); // Bookmark Menu KActionMenu *bmMenu = Application::bookmarkProvider()->bookmarkActionMenu(this); bmMenu->setIcon(KIcon("bookmarks")); bmMenu->setDelayed(false); - actionCollection()->addAction(QLatin1String("bookmarksActionMenu"), bmMenu); + actionCollection()->addAction(QL1S("bookmarksActionMenu"), bmMenu); + + + // ---------------- Encodings ----------------------------------- + a = new KAction(KIcon("character-set"), i18n("Set Encoding"), this); + actionCollection()->addAction(QL1S("encodings"), a); + a->setMenu(m_encodingMenu); + connect(m_encodingMenu, SIGNAL(aboutToShow()), this, SLOT(populateEncodingMenu())); + connect(m_encodingMenu, SIGNAL(triggered(QAction *)), this, SLOT(setEncoding(QAction *))); } @@ -410,159 +465,132 @@ void MainWindow::setupTools() 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(QL1S("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(QL1S("zoom_in"))); + zoomIn->setAutoRaise(true); + + QToolButton *zoomNormal = new QToolButton(zoomWidget); + zoomNormal->setDefaultAction(actionByName(QL1S("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"))); - toolsMenu->addAction(actionByName(QLatin1String("clear_private_data"))); + toolsMenu->addAction(actionByName(QL1S("private_browsing"))); + toolsMenu->addAction(actionByName(QL1S("clear_private_data"))); toolsMenu->addSeparator(); - KActionMenu *webMenu = new KActionMenu(KIcon("applications-development-web"), i18n("Web Development"), this); - webMenu->addAction(actionByName(QLatin1String("web_inspector"))); - webMenu->addAction(actionByName(QLatin1String("page_source"))); + KActionMenu *webMenu = new KActionMenu(KIcon("applications-development-web"), i18n("Development"), this); + webMenu->addAction(actionByName(QL1S("web_inspector"))); + webMenu->addAction(actionByName(QL1S("page_source"))); + webMenu->addAction(actionByName(QL1S("net_analyzer"))); toolsMenu->addAction(webMenu); toolsMenu->addSeparator(); - toolsMenu->addAction(actionByName(QLatin1String("bm_bar"))); - toolsMenu->addAction(actionByName(QLatin1String("show_history_panel"))); - toolsMenu->addAction(actionByName(QLatin1String("show_bookmarks_panel"))); + toolsMenu->addAction(actionByName(QL1S("bm_bar"))); + toolsMenu->addAction(actionByName(QL1S("show_history_panel"))); + toolsMenu->addAction(actionByName(QL1S("show_bookmarks_panel"))); toolsMenu->addAction(actionByName(KStandardAction::name(KStandardAction::FullScreen))); toolsMenu->addSeparator(); + toolsMenu->addAction(actionByName(QL1S("encodings"))); + helpMenu()->setIcon(KIcon("help-browser")); toolsMenu->addAction(helpMenu()->menuAction()); toolsMenu->addAction(actionByName(KStandardAction::name(KStandardAction::Preferences))); // adding rekonq_tools to rekonq actionCollection - actionCollection()->addAction(QLatin1String("rekonq_tools"), toolsMenu); + actionCollection()->addAction(QL1S("rekonq_tools"), toolsMenu); } void MainWindow::setupPanels() { KAction* a; - + // 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); + actionCollection()->addAction(QL1S("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); + actionCollection()->addAction(QL1S("show_bookmarks_panel"), a); // STEP 3 // Setup webinspector panel m_webInspectorPanel = new WebInspectorPanel(i18n("Web Inspector"), this); connect(mainView(), SIGNAL(currentChanged(int)), m_webInspectorPanel, SLOT(changeCurrentPage())); - + a = new KAction(KIcon("tools-report-bug"), i18n("Web &Inspector"), this); a->setCheckable(true); - actionCollection()->addAction(QLatin1String("web_inspector"), a); + actionCollection()->addAction(QL1S("web_inspector"), a); connect(a, SIGNAL(triggered(bool)), m_webInspectorPanel, SLOT(toggle(bool))); - + addDockWidget(Qt::BottomDockWidgetArea, m_webInspectorPanel); m_webInspectorPanel->hide(); -} - - - -void MainWindow::updateConfiguration() -{ - // ============== General ================== - m_view->updateTabBar(); - - // ============== Tabs ================== - if (ReKonfig::closeTabSelectPrevious()) - m_view->tabBar()->setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab); - else - m_view->tabBar()->setSelectionBehaviorOnRemove(QTabBar::SelectRightTab); - - // =========== Fonts ============== - QWebSettings *defaultSettings = QWebSettings::globalSettings(); - - int fnSize = ReKonfig::fontSize(); - int minFnSize = ReKonfig::minFontSize(); - - QFont standardFont = ReKonfig::standardFont(); - defaultSettings->setFontFamily(QWebSettings::StandardFont, standardFont.family()); - defaultSettings->setFontSize(QWebSettings::DefaultFontSize, fnSize); - defaultSettings->setFontSize(QWebSettings::MinimumFontSize, minFnSize); - - QFont fixedFont = ReKonfig::fixedFont(); - defaultSettings->setFontFamily(QWebSettings::FixedFont, fixedFont.family()); - defaultSettings->setFontSize(QWebSettings::DefaultFixedFontSize, fnSize); - - // ================ WebKit ============================ - defaultSettings->setAttribute(QWebSettings::AutoLoadImages, ReKonfig::autoLoadImages()); - defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, ReKonfig::javascriptEnabled()); - defaultSettings->setAttribute(QWebSettings::JavaEnabled, ReKonfig::javaEnabled()); - defaultSettings->setAttribute(QWebSettings::JavascriptCanOpenWindows, ReKonfig::javascriptCanOpenWindows()); - defaultSettings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, ReKonfig::javascriptCanAccessClipboard()); - defaultSettings->setAttribute(QWebSettings::LinksIncludedInFocusChain, ReKonfig::linksIncludedInFocusChain()); - defaultSettings->setAttribute(QWebSettings::ZoomTextOnly, ReKonfig::zoomTextOnly()); - defaultSettings->setAttribute(QWebSettings::PrintElementBackgrounds, ReKonfig::printElementBackgrounds()); - if(ReKonfig::pluginsEnabled() == 2) - defaultSettings->setAttribute(QWebSettings::PluginsEnabled, false); - else - defaultSettings->setAttribute(QWebSettings::PluginsEnabled, true); - - // ===== HTML 5 features WebKit support ====== - defaultSettings->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, ReKonfig::offlineStorageDatabaseEnabled()); - defaultSettings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, ReKonfig::offlineWebApplicationCacheEnabled()); - defaultSettings->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, ReKonfig::localStorageDatabaseEnabled()); - if(ReKonfig::localStorageDatabaseEnabled()) - { - QString path = KStandardDirs::locateLocal("cache", QString("WebkitLocalStorage/rekonq"), true); - path.remove("rekonq"); - QWebSettings::setOfflineStoragePath(path); - QWebSettings::setOfflineStorageDefaultQuota(50000); - } - - // 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()); - - // ====== load Settings on main classes - Application::historyManager()->loadSettings(); - Application::adblockManager()->loadSettings(); - - defaultSettings = 0; -} + // STEP 4 + // Setup Network analyzer panel + m_analyzerPanel = new NetworkAnalyzerPanel( i18n("Network Analyzer"), this); + connect(mainView(), SIGNAL(currentChanged(int)), m_analyzerPanel, SLOT(changeCurrentPage())); + a = new KAction(KIcon("document-edit-decrypt-verify"), i18n("Network Analyzer"), this); + a->setCheckable(true); + actionCollection()->addAction(QL1S("net_analyzer"), a); + connect(a, SIGNAL(triggered(bool)), this, SLOT(enableNetworkAnalysis(bool))); -void MainWindow::updateBrowser() -{ - updateConfiguration(); - mainView()->reloadAllTabs(); + addDockWidget(Qt::BottomDockWidgetArea, m_analyzerPanel); + m_analyzerPanel->hide(); } @@ -578,7 +606,7 @@ void MainWindow::fileSaveAs() KUrl srcUrl = currentTab()->url(); QString name = srcUrl.fileName(); - if(name.isNull()) + if (name.isNull()) { name = srcUrl.host() + QString(".html"); } @@ -602,7 +630,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&)), Application::instance(), SLOT(updateConfiguration())); s->exec(); delete s; @@ -616,6 +644,27 @@ void MainWindow::updateActions() QAction *historyForwardAction = actionByName(KStandardAction::name(KStandardAction::Forward)); historyForwardAction->setEnabled(currentTab()->view()->history()->canGoForward()); + + QAction *openClosedTabsAction = actionByName(QLatin1String("open_closed_tabs")); + openClosedTabsAction->setEnabled(mainView()->recentlyClosedTabs().size() > 0); + + // update closed tabs menu + KActionMenu *am = dynamic_cast<KActionMenu *>(actionByName(QLatin1String("closed_tab_menu"))); + if (!am) + return; + + am->setEnabled(mainView()->recentlyClosedTabs().size() > 0); + + if (am->menu()) + am->menu()->clear(); + + foreach (HistoryItem item, mainView()->recentlyClosedTabs()) + { + KAction *a = new KAction(Application::icon(item.url), item.title, this); + a->setData(item.url); + connect(a, SIGNAL(triggered()), m_view, SLOT(openClosedTab())); + am->addAction(a); + } } @@ -624,9 +673,9 @@ void MainWindow::updateWindowTitle(const QString &title) QWebSettings *settings = QWebSettings::globalSettings(); if (title.isEmpty()) { - if(settings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) + if (settings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) { - setWindowTitle("rekonq (" + i18n("Private Browsing") + ")"); + setWindowTitle(i18nc("Window title when private browsing is activated", "rekonq (Private Browsing)")); } else { @@ -635,13 +684,13 @@ void MainWindow::updateWindowTitle(const QString &title) } else { - if(settings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) + 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)); } } } @@ -651,7 +700,7 @@ void MainWindow::fileOpen() { QString filePath = KFileDialog::getOpenFileName(KUrl(), i18n("*.html *.htm *.svg *.png *.gif *.svgz|Web Resources (*.html *.htm *.svg *.png *.gif *.svgz)\n" - "*.*|All files (*.*)"), + "*.*|All files (*.*)"), this, i18n("Open Web Resource")); @@ -668,7 +717,7 @@ void MainWindow::printRequested(QWebFrame *frame) return; QWebFrame *printFrame = 0; - if(frame == 0) + if (frame == 0) { printFrame = currentTab()->page()->mainFrame(); } @@ -696,29 +745,27 @@ void MainWindow::privateBrowsing(bool enable) "<p>When private browsing is turned on," " web pages are not added to the history," " new cookies are not stored, current cookies cannot be accessed," - " site icons will not be stored, the session will not be saved, " - " and searches are not added to the pop-up menu in the Google search box." - " Until you close the window, you can still click the Back and Forward buttons" + " site icons will not be stored, the session will not be saved." + " Until you close the window, you can still click the Back and Forward buttons" " to return to the web pages you have opened.</p>", title); - int button = KMessageBox::questionYesNo(this, text, title); - if (button == KMessageBox::Yes) + int button = KMessageBox::warningContinueCancel(this, text, title); + 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 { - actionCollection()->action("private_browsing")->setChecked(false); + actionCollection()->action( QL1S("private_browsing") )->setChecked(false); } } 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(); } } @@ -729,57 +776,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::zoomOut() +{ + m_zoomSlider->setValue(m_zoomSlider->value() - 1); +} -void MainWindow::viewTextSmaller() +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); } @@ -806,10 +907,10 @@ void MainWindow::setWidgetsVisible(bool makeVisible) historyPanelFlag = m_historyPanel->isHidden(); bookmarksPanelFlag = m_bookmarksPanel->isHidden(); } - - m_bmBar->hide(); + + m_bmBar->hide(); m_view->setTabBarHidden(true); - m_historyPanel->hide(); + m_historyPanel->hide(); m_bookmarksPanel->hide(); // hide main toolbar @@ -828,7 +929,7 @@ void MainWindow::setWidgetsVisible(bool makeVisible) m_historyPanel->show(); if (!bookmarksPanelFlag) m_bookmarksPanel->show(); - } + } } @@ -856,13 +957,16 @@ void MainWindow::viewPageSource() isTempFile = true; } } - KRun::runUrl(url, QLatin1String("text/plain"), this, isTempFile); + KRun::runUrl(url, QL1S("text/plain"), this, isTempFile); } -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())); } @@ -903,19 +1007,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(); + } } @@ -925,6 +1051,7 @@ void MainWindow::keyPressEvent(QKeyEvent *event) if (event->key() == Qt::Key_Escape) { m_findBar->hide(); + currentTab()->setFocus(); // give focus to web pages return; } @@ -953,7 +1080,7 @@ void MainWindow::keyPressEvent(QKeyEvent *event) } -QAction *MainWindow::actionByName(const QString name) +QAction *MainWindow::actionByName(const QString &name) { QAction *ret = actionCollection()->action(name); @@ -961,7 +1088,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 } @@ -975,7 +1102,7 @@ void MainWindow::notifyMessage(const QString &msg, Rekonq::Notify status) } // deleting popus if empty msgs - if(msg.isEmpty()) + if (msg.isEmpty()) { m_hidePopup->start(250); return; @@ -984,7 +1111,7 @@ void MainWindow::notifyMessage(const QString &msg, Rekonq::Notify status) m_hidePopup->stop(); - switch(status) + switch (status) { case Rekonq::Info: break; @@ -1003,78 +1130,95 @@ void MainWindow::notifyMessage(const QString &msg, Rekonq::Notify status) // setting the popup QLabel *label = new QLabel(msg); m_popup->setView(label); - QSize labelSize(label->fontMetrics().width(msg)+2*margin, label->fontMetrics().height()+2*margin); + QSize labelSize(label->fontMetrics().width(msg) + 2*margin, label->fontMetrics().height() + 2*margin); if (labelSize.width() > width()) labelSize.setWidth(width()); m_popup->setFixedSize(labelSize); m_popup->layout()->setAlignment(Qt::AlignTop); m_popup->layout()->setMargin(margin); // useful values - + WebTab *tab = m_view->currentWebTab(); + // fix crash on window close - if(!m_view->currentWebTab()->page()->currentFrame()) + if (!tab) return; - - bool scrollbarIsVisible = m_view->currentWebTab()->page()->currentFrame()->scrollBarMaximum(Qt::Horizontal); + + // fix crash on window close + if (!tab->page()) + return; + + 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(); } - m_popup->show(QPoint(x,y)); + m_popup->show(QPoint(x, y)); } 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()) + if (clearWidget.clearHistory->isChecked()) { Application::historyManager()->clear(); } - if(clearWidget.clearCookies->isChecked()) + if (clearWidget.clearDownloads->isChecked()) + { + Application::historyManager()->clearDownloadsHistory(); + } + + if (clearWidget.clearCookies->isChecked()) { QDBusInterface kcookiejar("org.kde.kded", "/modules/kcookiejar", "org.kde.KCookieServer"); - QDBusReply<void> reply = kcookiejar.call( "deleteAllCookies" ); + QDBusReply<void> reply = kcookiejar.call("deleteAllCookies"); } - if(clearWidget.clearCachedPages->isChecked()) + if (clearWidget.clearCachedPages->isChecked()) { - // TODO implement me! + KProcess::startDetached(KStandardDirs::findExe("kio_http_cache_cleaner"), + QStringList(QL1S("--clear-all"))); } - if(clearWidget.clearWebIcons->isChecked()) + if (clearWidget.clearWebIcons->isChecked()) { QWebSettings::clearIconDatabase(); } - if(clearWidget.homePageThumbs->isChecked()) + if (clearWidget.homePageThumbs->isChecked()) { QString path = KStandardDirs::locateLocal("cache", QString("thumbs/rekonq"), true); path.remove("rekonq"); @@ -1087,6 +1231,8 @@ void MainWindow::clearPrivateData() } } } + + dialog->deleteLater(); } @@ -1100,19 +1246,17 @@ void MainWindow::aboutToShowBackMenu() int offset = 0; QList<QWebHistoryItem> historyList = history->backItems(8); //no more than 8 elements! int listCount = historyList.count(); - if(pivot >= 8) - offset = pivot - 8; - + if (pivot >= 8) + offset = pivot - 8; - - for(int i = listCount - 1; i>=0; --i) + for (int i = listCount - 1; i >= 0; --i) { QWebHistoryItem item = historyList.at(i); KAction *action = new KAction(this); action->setData(i + offset); - QIcon icon = Application::icon( item.url() ); - action->setIcon( icon ); - action->setText( item.title() ); + KIcon icon = Application::icon(item.url()); + action->setIcon(icon); + action->setText(item.title()); m_historyBackMenu->addAction(action); } } @@ -1121,13 +1265,54 @@ void MainWindow::aboutToShowBackMenu() void MainWindow::openActionUrl(QAction *action) { int index = action->data().toInt(); - - QWebHistory *history = currentTab()->view()->history(); - if(!history->itemAt(index).isValid()) + + QWebHistory *history = currentTab()->view()->history(); + if (!history->itemAt(index).isValid()) { - kDebug() << "Invalid Index!: "<< index; + kDebug() << "Invalid Index!: " << index; return; } - history->goToItem( history->itemAt(index) ); + history->goToItem(history->itemAt(index)); +} + + +void MainWindow::setEncoding(QAction *qa) +{ + QString currentCodec = qa->text().toLatin1(); + currentCodec = currentCodec.remove('&'); + kDebug() << currentCodec; + QWebSettings::globalSettings()->setDefaultTextEncoding(currentCodec); + ReKonfig::setDefaultEncoding(currentCodec); +} + + +void MainWindow::populateEncodingMenu() +{ + QList<QByteArray> byteCodecs = QTextCodec::availableCodecs(); + QStringList codecs; + Q_FOREACH(const QByteArray &b, byteCodecs) + { + codecs << QString(b); + } + codecs.sort(); + + QString currentCodec = ReKonfig::defaultEncoding(); + kDebug() << "Current Codec: " << currentCodec; + + m_encodingMenu->clear(); + Q_FOREACH(const QString &codec, codecs) + { + QAction *action = m_encodingMenu->addAction(codec); + action->setCheckable(true); + if (currentCodec == codec) + action->setChecked(true); + } +} + + +void MainWindow::enableNetworkAnalysis(bool b) +{ + currentTab()->page()->enableNetworkAnalyzer(b); + m_analyzerPanel->toggle(b); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 7083591d..55e3f8cf 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 @@ -29,9 +31,8 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H - -// Local Includes -#include "application.h" +// Rekonq Includes +#include "rekonq_defines.h" // KDE Includes #include <KMainWindow> @@ -40,17 +41,20 @@ #include <KUrl> // Forward Declarations -class QWebFrame; - -class KAction; -class KPassivePopup; - class FindBar; class HistoryPanel; class BookmarksPanel; class WebInspectorPanel; class WebTab; class MainView; +class NetworkAnalyzerPanel; + +class KAction; +class KPassivePopup; + +class QWebFrame; +class QSlider; + /** @@ -58,7 +62,7 @@ class MainView; * It handles the menus, toolbars, and status bars. * */ -class MainWindow : public KMainWindow +class REKONQ_TESTS_EXPORT MainWindow : public KMainWindow { Q_OBJECT @@ -68,20 +72,21 @@ public: MainView *mainView() const; WebTab *currentTab() const; - QAction *actionByName(const QString name); + QAction *actionByName(const QString &name); virtual QSize sizeHint() const; - virtual KActionCollection *actionCollection () const; + virtual KActionCollection *actionCollection() const; void setWidgetsVisible(bool makeFullScreen); - + + void setZoomSliderFactor(qreal factor); + private: void setupActions(); void setupTools(); void setupToolbars(); void setupPanels(); - + public slots: - void updateBrowser(); - void homePage(); + void homePage(Qt::MouseButtons = Qt::LeftButton, Qt::KeyboardModifiers = Qt::NoModifier); /** * Notifies a message in a popup @@ -94,7 +99,7 @@ public slots: void notifyMessage(const QString &msg, Rekonq::Notify status = Rekonq::Info); void printRequested(QWebFrame *frame = 0); - + signals: // switching tabs void ctrlTabPressed(); @@ -110,24 +115,26 @@ protected: private slots: void postLaunch(); - void updateConfiguration(); void browserLoading(bool); void updateActions(); 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(); @@ -149,20 +156,30 @@ private slots: void aboutToShowBackMenu(); void openActionUrl(QAction *action); + // encodings + void setEncoding(QAction *); + void populateEncodingMenu(); + + void enableNetworkAnalysis(bool); + private: MainView *m_view; FindBar *m_findBar; - + HistoryPanel *m_historyPanel; BookmarksPanel *m_bookmarksPanel; WebInspectorPanel *m_webInspectorPanel; - + NetworkAnalyzerPanel *m_analyzerPanel; + KAction *m_stopReloadAction; KMenu *m_historyBackMenu; + KMenu *m_encodingMenu; 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..e1d2e6eb 100644 --- a/src/networkaccessmanager.cpp +++ b/src/networkaccessmanager.cpp @@ -3,16 +3,17 @@ * 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 * 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 @@ -24,6 +25,7 @@ * ============================================================ */ + // Self Includes #include "networkaccessmanager.h" #include "networkaccessmanager.moc" @@ -31,23 +33,72 @@ // Local Includes #include "application.h" #include "adblockmanager.h" -#include <KDebug> +#include "webpage.h" + +// KDE Includes +#include <KLocale> +#include <KProtocolManager> + +// Qt Includes +#include <QtNetwork/QNetworkReply> + NetworkAccessManager::NetworkAccessManager(QObject *parent) - : AccessManager(parent) + : AccessManager(parent) { + QString c = KGlobal::locale()->country(); + if (c == QL1S("C")) + c = QL1S("en_US"); + if (c != QL1S("en_US")) + c.append(QL1S(", en_US")); + + _acceptLanguage = c.toLatin1(); } -QNetworkReply *NetworkAccessManager::createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData) +QNetworkReply *NetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) { - // Adblock + WebPage *parentPage = qobject_cast<WebPage *>(parent()); + + QNetworkReply *reply = 0; + + QNetworkRequest req = request; + req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); + req.setRawHeader("Accept-Language", _acceptLanguage); + + KIO::CacheControl cc = KProtocolManager::cacheControl(); + switch (cc) + { + case KIO::CC_CacheOnly: // Fail request if not in cache. + req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache); + break; + + case KIO::CC_Refresh: // Always validate cached entry with remote site. + req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork); + break; + + case KIO::CC_Reload: // Always fetch from remote site + req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); + break; + + case KIO::CC_Cache: // Use cached entry if available. + case KIO::CC_Verify: // Validate cached entry with remote site if expired. + default: + req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + break; + } + + if (op == QNetworkAccessManager::GetOperation) { - QNetworkReply *reply = Application::adblockManager()->block(req); - if (reply) - return reply; + reply = Application::adblockManager()->block(req, parentPage); } - return AccessManager::createRequest(op,req,outgoingData); + if(!reply) + reply = AccessManager::createRequest(op, req, outgoingData); + + if(parentPage->hasNetworkAnalyzerEnabled()) + emit networkData( op, req, reply ); + + return reply; } diff --git a/src/networkaccessmanager.h b/src/networkaccessmanager.h index 5c34ebd7..a012f0d5 100644 --- a/src/networkaccessmanager.h +++ b/src/networkaccessmanager.h @@ -3,16 +3,17 @@ * 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 * 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 @@ -28,6 +29,12 @@ #define NETWORKACCESSMANAGER_H +// Rekonq Includes +#include "rekonq_defines.h" + +// Local Includes +#include "webpage.h" + // KDE Includes #include <kio/accessmanager.h> @@ -35,15 +42,21 @@ 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); + virtual QNetworkReply *createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData = 0); + +signals: + void networkData(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QNetworkReply *reply); + +private: + QByteArray _acceptLanguage; }; #endif // NETWORKACCESSMANAGER_H diff --git a/src/newtabpage.cpp b/src/newtabpage.cpp new file mode 100644 index 00000000..f177cbf3 --- /dev/null +++ b/src/newtabpage.cpp @@ -0,0 +1,597 @@ +/* ============================================================ +* +* 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 <KConfig> +#include <KDialog> +#include <KCalendarSystem> + +// Qt Includes +#include <QtCore/QFile> + + +NewTabPage::NewTabPage(QWebFrame *frame) + : QObject(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 = KUrl(urls.at(i)); + QWebElement prev; + + if (url.isEmpty()) + prev = emptyPreview(i); + else if (!WebSnap::existsImage(url)) + 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); + + // NOTE: we need the page frame for two reasons + // 1) to link to the WebPage calling the snapFinished slot + // 2) to "auto-destroy" snaps on tab closing :) + QWebFrame *frame = qobject_cast<QWebFrame *>(parent()); + WebSnap *snap = new WebSnap(url, frame); + connect(snap, SIGNAL(snapDone(bool)), frame->page(), SLOT(updateImage(bool))); + return prev; +} + + +QWebElement NewTabPage::validPreview(int index, const KUrl &url, const QString &title) +{ + QWebElement prev = markup(".thumbnail"); + QString previewPath = QL1S("file://") + WebSnap::imagePathFromUrl(url); + QString iString = QVariant(index).toString(); + + prev.findFirst(".preview img").setAttribute("src" , previewPath); + prev.findFirst("a").setAttribute("href", url.toMimeDataString()); // NOTE ? + prev.findFirst("span a").setAttribute("href", url.toMimeDataString()); // NOTE ? + 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() +{ + // 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; + + QStringList urls = ReKonfig::previewUrls(); + QStringList names = ReKonfig::previewNames(); + + for (int i = 0; i < urls.count(); i++) + { + KUrl url = KUrl(urls.at(i)); + QString title = names.at(i); + + if (WebSnap::existsImage(url)) + { + QWebElement prev = m_root.findFirst("#preview" + QVariant(i).toString()); + if (KUrl(prev.findFirst("a").attribute("href")) == url) + { + QWebElement newPrev = validPreview(i, 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; + + prev = WebSnap::existsImage(KUrl(item.url)) + ? validPreview(i, item.url, item.title) + : loadingPreview(i, item.url); + + 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/newtabpage.h b/src/newtabpage.h new file mode 100644 index 00000000..ad4941d3 --- /dev/null +++ b/src/newtabpage.h @@ -0,0 +1,122 @@ +/* ============================================================ +* +* 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/>. +* +* ============================================================ */ + + +#ifndef REKONQ_NEW_TAB_PAGE +#define REKONQ_NEW_TAB_PAGE + + +// Rekonq Includes +#include "rekonq_defines.h" + +// KDE Includes +#include <KUrl> + +// Qt Includes +#include <QObject> +#include <QString> +#include <QWebElement> + +// Forward Includes +class KBookmark; +class WebPage; + + +class REKONQ_TESTS_EXPORT NewTabPage : public QObject +{ + Q_OBJECT + +public: + NewTabPage(QWebFrame *frame); + ~NewTabPage(); + + /** + * This method takes an about: url and loads + * the corresponding part of the new tab page + */ + void generate(const KUrl &url = KUrl("about:home")); + + /** + * This method updates thumbs, removing loading previews + * and providing a real picture + */ + void snapFinished(); + +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(); + 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); + + 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(const QString &selector) + { + return m_root.document().findFirst("#models > " + selector).clone(); + } + + QString checkTitle(const QString &title); + +private: + QString m_html; + QWebElement m_root; +}; + +#endif // REKONQ_NEW_TAB_PAGE diff --git a/src/paneltreeview.cpp b/src/paneltreeview.cpp new file mode 100644 index 00000000..58673d60 --- /dev/null +++ b/src/paneltreeview.cpp @@ -0,0 +1,200 @@ +/* ============================================================ +* +* 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" + +// KDE Includes +#include <KUrl> + +// Qt Includes +#include <QtGui/QMouseEvent> +#include <QtGui/QKeyEvent> +#include <QtGui/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 = Application::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..75aee8e7 --- /dev/null +++ b/src/paneltreeview.h @@ -0,0 +1,72 @@ +/* ============================================================ +* +* 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 + +// Rekonq Includes +#include "rekonq_defines.h" + +// Qt Includes +#include <QTreeView> + +// Forward Declarations +class KUrl; + + +class REKONQ_TESTS_EXPORT 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..cacf6968 --- /dev/null +++ b/src/previewselectorbar.cpp @@ -0,0 +1,157 @@ +/* ============================================================ +* +* 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" + +// Self Includes +#include "rekonq.h" + +// Local Include +#include "websnap.h" +#include "application.h" +#include "mainwindow.h" +#include "webtab.h" +#include "webpage.h" + +// KDE Includes +#include <KIcon> +#include <KLocalizedString> + +// Qt Includes +#include <QtCore/QString> + +#include <QtGui/QToolButton> +#include <QtGui/QHBoxLayout> + + + +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..6f2acd41 --- /dev/null +++ b/src/previewselectorbar.h @@ -0,0 +1,65 @@ +/* ============================================================ +* +* 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 + +// Rekonq Includes +#include "rekonq_defines.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 cd75d06f..d710c24c 100644 --- a/src/protocolhandler.cpp +++ b/src/protocolhandler.cpp @@ -2,16 +2,16 @@ * * 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 * 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 @@ -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> @@ -44,13 +46,13 @@ #include <KRun> #include <KToolInvocation> #include <KStandardDirs> -#include <KDebug> #include <KMimeType> #include <KIconLoader> #include <KDirLister> #include <KFileItem> #include <KJob> #include <kio/udsentry.h> +#include <KMessageBox> // Qt Includes #include <QLatin1String> @@ -62,11 +64,10 @@ ProtocolHandler::ProtocolHandler(QObject *parent) - : QObject(parent) - , _lister(new KDirLister) - , _frame(0) + : QObject(parent) + , _lister(0) + , _frame(0) { - connect( _lister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(showResults(const KFileItemList &))); } @@ -79,38 +80,52 @@ bool ProtocolHandler::preHandling(const QNetworkRequest &request, QWebFrame *fra { _url = request.url(); _frame = frame; - - kDebug() << "URL PROTOCOL: " << _url; - - // relative urls - if(_url.isRelative()) - return false; - + // "http(s)" (fast) handling - if( _url.protocol() == QLatin1String("http") || _url.protocol() == QLatin1String("https") ) + if (_url.protocol() == QL1S("http") || _url.protocol() == QL1S("https")) return false; - + + // relative urls + if (_url.isRelative()) + return false; + // javascript handling - if( _url.protocol() == QLatin1String("javascript") ) + if (_url.protocol() == QL1S("javascript")) { QString scriptSource = _url.authority(); + if(scriptSource.isEmpty()) + return false; + QVariant result = frame->evaluateJavaScript(scriptSource); return true; } - + // "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")) { - if( _url == KUrl("about:home") ) + // let webkit manage the about:blank url... + if (_url == KUrl("about:blank")) + { + return false; + } + + if (_url == KUrl("about:home")) { - switch(ReKonfig::newTabStartPage()) + switch (ReKonfig::newTabStartPage()) { case 0: // favorites _url = KUrl("about:favorites"); @@ -118,28 +133,24 @@ 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; } @@ -148,16 +159,16 @@ bool ProtocolHandler::postHandling(const QNetworkRequest &request, QWebFrame *fr { _url = request.url(); _frame = frame; - + 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,48 +179,67 @@ 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*) )); + connect(job, SIGNAL(result(KJob*)), this, SLOT(slotMostLocalUrlResult(KJob*))); return true; } - + // "file" handling. This is quite trivial :) - if(_url.protocol() == QLatin1String("file") ) + if (_url.protocol() == QL1S("file")) { - QFileInfo fileInfo( _url.path() ); - if(fileInfo.isDir()) + QFileInfo fileInfo(_url.path()); + if (fileInfo.isDir()) { + if(_lister) + delete _lister; + + _lister = new KDirLister(this); + connect(_lister, SIGNAL(newItems(const KFileItemList &)), this, SLOT(showResults(const KFileItemList &))); _lister->openUrl(_url); - Application::instance()->mainWindow()->mainView()->urlBar()->setUrl(_url); + return true; } } - + return false; } -QString ProtocolHandler::dirHandling(const KFileItemList &list) -{ +// --------------------------------------------------------------------------------------------------------------------------- - KFileItem mainItem = _lister->rootItem(); - KUrl rootUrl = mainItem.url(); - - if (mainItem.isNull()) + +void ProtocolHandler::showResults(const KFileItemList &list) +{ + if (!_lister->rootItem().isNull() && _lister->rootItem().isReadable() && _lister->rootItem().isFile()) { - QString errStr = i18n("Error opening: %1: No such file or directory", rootUrl.prettyUrl() ); - return errStr; + emit downloadUrl(_lister->rootItem().url()); } - - if (!mainItem.isReadable()) + else { - QString errStr = i18n("Unable to read %1", rootUrl.prettyUrl() ); - return errStr; + QString html = dirHandling(list); + _frame->setHtml(html, _url); + + Application::instance()->mainWindow()->currentTab()->setFocus(); + Application::historyManager()->addHistoryEntry(_url.prettyUrl()); } - // display "rekonq info" page + delete _lister; +} + + +QString ProtocolHandler::dirHandling(const KFileItemList &list) +{ + if (!_lister) + { + return QString("rekonq error, sorry :("); + } + + // let me modify it.. + KUrl rootUrl = _url; + + // display "rekonq info" page QString infoFilePath = KStandardDirs::locate("data", "rekonq/htmls/rekonqinfo.html"); QFile file(infoFilePath); @@ -219,18 +249,18 @@ QString ProtocolHandler::dirHandling(const KFileItemList &list) return QString("rekonq error, sorry :("); } - QString title = _url.prettyUrl(); - QString msg = "<h1>" + i18n("Index of ") + _url.prettyUrl() + "</h1>"; + QString title = _url.prettyUrl(); + QString msg = i18nc("%1=an URL", "<h1>Index of %1</h1>", _url.prettyUrl()); - if(rootUrl.cd("..")) + if (rootUrl.cd("..")) { QString path = rootUrl.prettyUrl(); - QString uparrow = KIconLoader::global()->iconPath( "arrow-up", KIconLoader::Small ); + QString uparrow = KIconLoader::global()->iconPath("arrow-up", KIconLoader::Small); msg += "<img src=\"file://" + uparrow + "\" alt=\"up-arrow\" />"; msg += "<a href=\"" + path + "\">" + i18n("Up to higher level directory") + "</a><br /><br />"; } - + msg += "<table width=\"100%\">"; msg += "<tr><th align=\"left\">" + i18n("Name") + "</th><th>" + i18n("Size") + "</th><th>" + i18n("Last Modified") + "</th></tr>"; @@ -238,63 +268,43 @@ QString ProtocolHandler::dirHandling(const KFileItemList &list) { msg += "<tr>"; QString fullPath = item.url().prettyUrl(); - + QString iconName = item.iconName(); - QString icon = QString("file://") + KIconLoader::global()->iconPath( iconName, KIconLoader::Small ); - + QString icon = QString("file://") + KIconLoader::global()->iconPath(iconName, KIconLoader::Small); + msg += "<td width=\"70%\">"; msg += "<img src=\"" + icon + "\" alt=\"" + iconName + "\" /> "; msg += "<a href=\"" + fullPath + "\">" + item.name() + "</a>"; msg += "</td>"; - + msg += "<td align=\"right\">"; - if(item.isFile()) + if (item.isFile()) { - msg += QString::number( item.size()/1024 ) + " KB"; + msg += QString::number(item.size() / 1024) + " KB"; } msg += "</td>"; - + msg += "<td align=\"right\">"; msg += item.timeString(); msg += "</td>"; - + msg += "</tr>"; } msg += "</table>"; - - - QString html = QString(QLatin1String(file.readAll())) - .arg(title) - .arg(msg) - ; - - return html; -} -void ProtocolHandler::showResults(const KFileItemList &list) -{ - if(_lister->rootItem().isFile()) - { - WebPage *page = qobject_cast<WebPage *>( _frame->page() ); - page->downloadUrl( _lister->rootItem().url() ); - return; - } - - if ( list.isEmpty() ) - return; - - QString html = dirHandling(list); - _frame->setHtml(html); + QString html = QString(QL1S(file.readAll())) + .arg(title) + .arg(msg) + ; - Application::instance()->mainWindow()->mainView()->urlBar()->setUrl(_url); - Application::historyManager()->addHistoryEntry( _url.prettyUrl() ); + return html; } void ProtocolHandler::slotMostLocalUrlResult(KJob *job) { - if(job->error()) + if (job->error()) { // TODO kDebug() << "error"; @@ -303,9 +313,72 @@ void ProtocolHandler::slotMostLocalUrlResult(KJob *job) { KIO::StatJob *statJob = static_cast<KIO::StatJob*>(job); KIO::UDSEntry entry = statJob->statResult(); - if( entry.isDir() ) + if (entry.isDir()) + { + if(_lister) + delete _lister; + + _lister = new KDirLister(this); + 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..a8661f81 100644 --- a/src/protocolhandler.h +++ b/src/protocolhandler.h @@ -2,16 +2,16 @@ * * 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 * 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 @@ -27,6 +27,10 @@ #ifndef PROTOCOL_HANDLER_H #define PROTOCOL_HANDLER_H + +// Rekonq Includes +#include "rekonq_defines.h" + // KDE Includes #include <KDirLister> @@ -41,12 +45,12 @@ class KUrl; class KJob; -class ProtocolHandler : public QObject +class REKONQ_TESTS_EXPORT ProtocolHandler : public QObject { -Q_OBJECT + Q_OBJECT public: - ProtocolHandler(QObject *parent = 0); + ProtocolHandler(QObject *parent = 0); ~ProtocolHandler(); /** @@ -60,17 +64,18 @@ public: * WebKit tried to */ bool postHandling(const QNetworkRequest &request, QWebFrame *frame); - + signals: - void downloadUrl( const KUrl &); - + void downloadUrl(const KUrl &); + private slots: void showResults(const KFileItemList &); void slotMostLocalUrlResult(KJob *); - + 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..3658b324 100644 --- a/src/rekonq.kcfg +++ b/src/rekonq.kcfg @@ -7,17 +7,40 @@ <!-- 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> + <entry name="defaultEncoding" type="String"> + <default>UTF-8</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 +58,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 +113,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 --> @@ -106,6 +120,9 @@ <entry name="autoLoadImages" type="Bool"> <default>true</default> </entry> + <entry name="dnsPrefetch" type="Bool"> + <default>true</default> + </entry> <entry name="javascriptEnabled" type="Bool"> <default>true</default> </entry> @@ -136,7 +153,7 @@ <entry name="offlineWebApplicationCacheEnabled" type="Bool"> <default>true</default> </entry> - <entry name="localStorageDatabaseEnabled" type="Bool"> + <entry name="localStorageEnabled" type="Bool"> <default>true</default> </entry> <entry name="userCSS" type="Url"> @@ -144,4 +161,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/rekonq_defines.h b/src/rekonq_defines.h new file mode 100644 index 00000000..c8755e03 --- /dev/null +++ b/src/rekonq_defines.h @@ -0,0 +1,98 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007 David Faure <faure@kde.org> +* 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 REKONQ_DEFINES_H +#define REKONQ_DEFINES_H + + +// ---------------------------------------------------------------------------------------------------- +// UNIT TESTS NEED + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include <kdemacros.h> + +/* Classes from the rekonq application, which are exported only for unit tests */ +#ifndef REKONQ_TESTS_EXPORT +/* We are building this library */ +#define REKONQ_TESTS_EXPORT KDE_EXPORT +#else +/* We are using this library */ +#define REKONQ_TESTS_EXPORT KDE_IMPORT +#endif + + +// ---------------------------------------------------------------------------------------------------- +// DEFINES + +#define QL1S(x) QLatin1String(x) +#define QL1C(x) QLatin1Char(x) + + + +// ---------------------------------------------------------------------------------------------------- +// ENUMS + +namespace Rekonq +{ + /** + * @short notifying message status + * Different message status + */ + + enum Notify + { + Success, ///< url successfully (down)loaded + Error, ///< url failed to (down)load + Download, ///< downloading url + Info ///< information, (default) + }; + + /** + * @short Open link options + * Different modes of opening new tab + */ + enum OpenType + { + CurrentTab, ///< open url in current tab + SettingOpenTab, ///< open url according to users settings + NewCurrentTab, ///< open url in new tab and make it current + NewBackTab, ///< open url in new tab in background + NewWindow ///< open url in new window + }; +} + + +// ---------------------------------------------------------------------------------------------------- +// INCLUDES + +#include <KDebug> + + + +// ---------------------------------------------------------------------------------------------------- + +#endif // REKONQ_DEFINES_H 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/rekonqpage/newtabpage.h b/src/rekonqpage/newtabpage.h deleted file mode 100644 index 003aa84e..00000000 --- a/src/rekonqpage/newtabpage.h +++ /dev/null @@ -1,86 +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 REKONQ_NEW_TAB_PAGE -#define REKONQ_NEW_TAB_PAGE - - -// rekonq Includes -#include <webpage.h> - -// KDE Includes -#include <KUrl> - -// Qt Includes -#include <QtCore/QObject> -#include <QtCore/QString> -#include <QWebElement> - -// Forward Includes -class KBookmark; - - -class NewTabPage -{ - -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 - */ - void generate(const KUrl &url = KUrl("about:home")); - -protected: // these are the function to build the new tab page - void browsingMenu(const KUrl ¤tUrl); - - void favoritesPage(); - //QString lastVisitedPage(); - void historyPage(); - void bookmarksPage(); - void closedTabsPage(); - -private: - 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) - { - return m_root.document().findFirst("#models > " + selector).clone(); - } - - QString m_html; - - QWebElement m_root; -}; - -#endif // REKONQ_NEW_TAB_PAGE diff --git a/src/searchengine.cpp b/src/searchengine.cpp new file mode 100644 index 00000000..0d2c6aea --- /dev/null +++ b/src/searchengine.cpp @@ -0,0 +1,167 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* 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 +* 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/>. +* +* ============================================================ */ + + +//local includes +#include "searchengine.h" + +// Auto Includes +#include "rekonq.h" + +//KDE includes +#include <KConfigGroup> +#include <KServiceTypeTrader> + + +QString SearchEngine::m_delimiter = ""; + + +QString SearchEngine::delimiter() +{ + if (m_delimiter == "") loadDelimiter(); + return m_delimiter; +} + + +void SearchEngine::loadDelimiter() +{ + KConfig config("kuriikwsfilterrc"); //Share with konqueror + KConfigGroup cg = config.group("General"); + m_delimiter = cg.readEntry("KeywordDelimiter", ":"); +} + + +KService::Ptr SearchEngine::m_defaultWS; + + +KService::Ptr SearchEngine::defaultWS() +{ + if (!m_defaultWS) loadDefaultWS(); + return m_defaultWS; +} + + +void SearchEngine::loadDefaultWS() +{ + KConfig config("kuriikwsfilterrc"); //Share with konqueror + KConfigGroup cg = config.group("General"); + QString d = cg.readEntry("DefaultSearchEngine", "google"); + m_defaultWS = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(d)); +} + + +KService::Ptr SearchEngine::fromString(QString text) +{ + KService::List providers = KServiceTypeTrader::self()->query("SearchProvider"); + int i = 0; + bool found = false; + KService::Ptr service; + while (!found && i < providers.size()) + { + QStringList list = providers.at(i)->property("Keys").toStringList(); + foreach(const QString &key, list) + { + const QString searchPrefix = key + delimiter(); + if (text.startsWith(searchPrefix)) + { + service = providers.at(i); + found = true; + } + } + i++; + } + + return service; +} + + +QString SearchEngine::buildQuery(KService::Ptr engine, QString text) +{ + QString query = engine->property("Query").toString(); + query = query.replace("\\{@}", KUrl::toPercentEncoding(text)); + return query; +} + + +KService::List SearchEngine::m_favorites; + + +KService::List SearchEngine::favorites() +{ + if (m_favorites.isEmpty()) loadFavorites(); + return m_favorites; +} + + +void SearchEngine::loadFavorites() +{ + KConfig config("kuriikwsfilterrc"); //Share with konqueror + KConfigGroup cg = config.group("General"); + QStringList favoriteEngines; + favoriteEngines << "wikipedia" << "google"; //defaults + favoriteEngines = cg.readEntry("FavoriteSearchEngines", favoriteEngines); + + KService::List favorites; + KService::Ptr service; + foreach(const QString &engine, favoriteEngines) + { + service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(engine)); + if (service) + favorites << service; + } + + m_favorites = favorites; +} + + +KService::Ptr SearchEngine::defaultEngine() +{ + 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 KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(engine)); +} diff --git a/src/searchengine.h b/src/searchengine.h new file mode 100644 index 00000000..2e30e056 --- /dev/null +++ b/src/searchengine.h @@ -0,0 +1,62 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* 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 +* 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 SEARCHENGINE_H +#define SEARCHENGINE_H + + +// Rekonq Includes +#include "rekonq_defines.h" + +// KDE Includes +#include <KService> + +//Qt Includes +#include <QString> + + +class SearchEngine +{ +public: + + static QString delimiter(); + static KService::Ptr defaultEngine(); + static KService::List favorites(); + static KService::Ptr fromString(QString text); + static QString buildQuery(KService::Ptr engine, QString text); + static KService::Ptr defaultWS(); + + static void loadDelimiter(); + static void loadFavorites(); + static void loadDefaultWS(); + +private: + static QString m_delimiter; + static KService::List m_favorites; + static KService::Ptr m_defaultWS; +}; + +#endif diff --git a/src/sessionmanager.cpp b/src/sessionmanager.cpp index f4e7cd3e..6aada509 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 @@ -38,16 +38,16 @@ // KDE Includes #include <KStandardDirs> -#include <KDebug> // Qt Includes -#include <QFile> -#include <QTextStream> +#include <QtCore/QFile> +#include <QtCore/QTextStream> + SessionManager::SessionManager(QObject *parent) - : QObject(parent) - , m_safe(true) + : QObject(parent) + , m_safe(true) { m_sessionFilePath = KStandardDirs::locateLocal("appdata" , "session"); } @@ -60,21 +60,21 @@ SessionManager::~SessionManager() void SessionManager::saveSession() { - if(!m_safe) + if (!m_safe) return; m_safe = false; 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(const 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; } @@ -102,18 +102,48 @@ bool SessionManager::restoreSession() do { line = in.readLine(); - if(line == QString("window")) + if (line == QString("window")) { - Application::instance()->newMainWindow(); line = in.readLine(); - Application::instance()->loadUrl(line); + kDebug() << "New Window line: " << line; + Application::instance()->loadUrl( KUrl(line), Rekonq::NewWindow); } else { - Application::instance()->loadUrl(line, Rekonq::NewCurrentTab); + kDebug() << "New Current Tab line: " << line; + Application::instance()->loadUrl( KUrl(line), Rekonq::NewCurrentTab); } } - while(!line.isNull()); - + while (!line.isEmpty()); + return true; } + + +QStringList SessionManager::closedSites() +{ + QStringList list; + + QFile sessionFile(m_sessionFilePath); + if (!sessionFile.exists()) + return list; + if (!sessionFile.open(QFile::ReadOnly)) + { + kDebug() << "Unable to open session file" << sessionFile.fileName(); + return list; + } + + QTextStream in(&sessionFile); + QString line; + do + { + line = in.readLine(); + if (line != QString("window")) + { + list << QString(line); + } + } + while (!line.isEmpty()); + + return list; +} diff --git a/src/sessionmanager.h b/src/sessionmanager.h index f1b7a71f..a446b530 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 +// Rekonq Includes +#include "rekonq_defines.h" + // Qt Includes #include <QtCore/QObject> #include <QtCore/QString> @@ -38,13 +41,15 @@ /** * Session Management */ -class SessionManager : public QObject +class REKONQ_TESTS_EXPORT SessionManager : public QObject { Q_OBJECT public: SessionManager(QObject *parent = 0); ~SessionManager(); bool restoreSession(); + + QStringList closedSites(); private slots: void saveSession(); diff --git a/src/settings/adblockwidget.cpp b/src/settings/adblockwidget.cpp new file mode 100644 index 00000000..59cb8a81 --- /dev/null +++ b/src/settings/adblockwidget.cpp @@ -0,0 +1,192 @@ +/* ============================================================ +* +* 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(const 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"; + 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/rekonqprivate_export.h b/src/settings/adblockwidget.h index 8f996a1f..1ed9aaa6 100644 --- a/src/rekonqprivate_export.h +++ b/src/settings/adblockwidget.h @@ -2,8 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2007 David Faure <faure@kde.org> -* 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 @@ -11,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 @@ -25,19 +24,43 @@ * ============================================================ */ -#ifndef REKONQPRIVATE_EXPORT_H -#define REKONQPRIVATE_EXPORT_H +#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(); -/* needed for KDE_EXPORT and KDE_IMPORT macros */ -#include <kdemacros.h> +private: + void load(); + void loadRules(QTreeWidgetItem *item); -/* Classes from the rekonq application, which are exported only for unit tests */ -#ifndef REKONQ_TESTS_EXPORT - /* We are building this library */ - #define REKONQ_TESTS_EXPORT KDE_EXPORT -#else - /* We are using this library */ - #define REKONQ_TESTS_EXPORT KDE_IMPORT -#endif + bool _changed; +}; -#endif // REKONQPRIVATE_EXPORT_H +#endif // ADBLOCK_WIDGET_H diff --git a/src/settings/networkwidget.cpp b/src/settings/networkwidget.cpp new file mode 100644 index 00000000..5495f0ce --- /dev/null +++ b/src/settings/networkwidget.cpp @@ -0,0 +1,100 @@ +/* ============================================================ +* +* 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> + +// 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/urlbar/lineedit.h b/src/settings/networkwidget.h index 67ded052..6b7abffd 100644 --- a/src/urlbar/lineedit.h +++ b/src/settings/networkwidget.h @@ -2,9 +2,7 @@ * * This file is a part of the rekonq project * -* Copyright (C) 2009 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) 2010 by Andrea Diamantini <adjam7 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -12,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 @@ -26,30 +24,40 @@ * ============================================================ */ -#ifndef LINEEDIT_H -#define LINEEDIT_H +#ifndef NETWORK_WIDGET_H +#define NETWORK_WIDGET_H // KDE Includes -#include <KLineEdit> +#include <KCModuleProxy> -// Forward Declarations -class QContextMenuEvent; -class QFocusEvent; -class QKeyEvent; +// Qt Includes +#include <QWidget> -class LineEdit : public KLineEdit +class NetworkWidget : public QWidget { Q_OBJECT public: - explicit LineEdit(QWidget *parent = 0); - virtual ~LineEdit(); + NetworkWidget(QWidget *parent = 0); + ~NetworkWidget(); + + void save(); + bool changed(); + +signals: + void changed(bool); + +private slots: + void hasChanged(); + +private: + KCModuleProxy *_cacheModule; + KCModuleProxy *_cookiesModule; + KCModuleProxy *_proxyModule; -protected: - virtual void keyPressEvent(QKeyEvent*); - virtual void mouseDoubleClickEvent(QMouseEvent *); + bool _changed; }; -#endif // LINEEDIT_H +#endif // NETWORK_WIDGET_H diff --git a/src/settings/settings_adblock.ui b/src/settings/settings_adblock.ui new file mode 100644 index 00000000..bb0b6156 --- /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 (days):</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_fonts.ui b/src/settings/settings_fonts.ui index 3f9aa9ef..52c7872e 100644 --- a/src/settings/settings_fonts.ui +++ b/src/settings/settings_fonts.ui @@ -19,30 +19,70 @@ <property name="title"> <string>Fonts</string> </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Standard font:</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Fixed font:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="KFontComboBox" name="kcfg_fixedFont"/> - </item> - <item row="0" column="1"> - <widget class="KFontComboBox" name="kcfg_standardFont"/> - </item> - </layout> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Standard font:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="KFontComboBox" name="kcfg_standardFont"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Fixed font:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="KFontComboBox" name="kcfg_fixedFont"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> </item> </layout> </widget> @@ -52,34 +92,70 @@ <property name="title"> <string>Dimension</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Font size:</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="kcfg_fontSize"/> - </item> - </layout> + <layout class="QFormLayout" name="formLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Font size:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="kcfg_fontSize"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Minimal font size:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout2"> - <item> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Minimal font size:</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="kcfg_minFontSize"/> - </item> - </layout> + <item row="1" column="1"> + <widget class="QSpinBox" name="kcfg_minFontSize"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> </item> </layout> </widget> diff --git a/src/settings/settings_general.ui b/src/settings/settings_general.ui index 17ac0d0f..ccc3fa20 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"> @@ -19,8 +19,8 @@ <property name="title"> <string>Startup</string> </property> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> <widget class="QLabel" name="label"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> @@ -30,13 +30,7 @@ </property> <property name="minimumSize"> <size> - <width>120</width> - <height>0</height> - </size> - </property> - <property name="baseSize"> - <size> - <width>0</width> + <width>150</width> <height>0</height> </size> </property> @@ -46,9 +40,12 @@ <property name="text"> <string>When starting rekonq:</string> </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> </widget> </item> - <item> + <item row="0" column="1"> <widget class="KComboBox" name="kcfg_startupBehaviour"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> @@ -81,7 +78,7 @@ <property name="title"> <string>Home Page</string> </property> - <layout class="QGridLayout" name="gridLayout"> + <layout class="QFormLayout" name="formLayout_2"> <item row="0" column="0"> <widget class="QLabel" name="label_2"> <property name="sizePolicy"> @@ -92,19 +89,16 @@ </property> <property name="minimumSize"> <size> - <width>120</width> - <height>0</height> - </size> - </property> - <property name="baseSize"> - <size> - <width>120</width> + <width>150</width> <height>0</height> </size> </property> <property name="text"> <string>Home page URL:</string> </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> </widget> </item> <item row="0" column="1"> @@ -150,11 +144,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"> + <layout class="QFormLayout" name="formLayout_3"> <item row="0" column="0"> - <widget class="QLabel" name="label_4"> + <widget class="QLabel" name="label_3"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -163,26 +157,23 @@ </property> <property name="minimumSize"> <size> - <width>120</width> + <width>150</width> <height>0</height> </size> </property> - <property name="baseSize"> - <size> - <width>120</width> - <height>0</height> - </size> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> </property> <property name="text"> - <string>New tab opens:</string> + <string>Default search engine:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> <item row="0" column="1"> - <widget class="KComboBox" name="kcfg_newTabsBehaviour"> - <property name="enabled"> - <bool>true</bool> - </property> + <widget class="KComboBox" name="kcfg_searchEngine"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -191,75 +182,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> + <string>lycos</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>wikipedia</string> </property> </item> <item> <property name="text"> - <string>closed tabs</string> - </property> - </item> - <item> - <property name="text"> - <string>history</string> - </property> - </item> - <item> - <property name="text"> - <string>bookmarks</string> + <string>wolfram</string> </property> </item> </widget> @@ -272,16 +215,19 @@ <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"> <property name="text"> - <string>Download with KGet</string> + <string>Use KGet for downloading files</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> <property name="text"> <string>List links with KGet</string> </property> @@ -298,7 +244,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..8bc3ae70 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,113 @@ </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>New Tabs Behaviour</string> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_4"> + <property name="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>New tab opens:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </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="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>New tab page starts with:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </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 +186,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..e87e3fec 100644 --- a/src/settings/settings_webkit.ui +++ b/src/settings/settings_webkit.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>437</width> - <height>346</height> + <width>643</width> + <height>560</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout"> @@ -17,99 +17,106 @@ <string>WebKit Settings</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0" colspan="2"> + <item row="0" column="0"> <widget class="QCheckBox" name="kcfg_autoLoadImages"> <property name="text"> <string>Autoload images</string> </property> </widget> </item> - <item row="0" column="3"> + <item row="0" column="1" rowspan="7"> + <widget class="Line" name="line"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item row="0" column="2"> <widget class="QCheckBox" name="kcfg_linksIncludedInFocusChain"> <property name="text"> <string>Links included in focus chain</string> </property> </widget> </item> - <item row="1" column="0" colspan="2"> - <widget class="QCheckBox" name="kcfg_javascriptEnabled"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> + <item row="1" column="0"> + <widget class="QCheckBox" name="kcfg_dnsPrefetch"> <property name="text"> - <string>JavaScript support</string> + <string>Prefetch DNS entries</string> </property> </widget> </item> - <item row="1" column="3"> + <item row="1" column="2"> <widget class="QCheckBox" name="kcfg_zoomTextOnly"> <property name="text"> <string>Zoom text only</string> </property> </widget> </item> - <item row="2" column="0" colspan="2"> - <widget class="QCheckBox" name="kcfg_javaEnabled"> + <item row="2" column="0"> + <widget class="QCheckBox" name="kcfg_javascriptEnabled"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="text"> - <string>Java support</string> + <string>JavaScript support</string> </property> </widget> </item> - <item row="2" column="3"> + <item row="2" column="2"> <widget class="QCheckBox" name="kcfg_printElementBackgrounds"> <property name="text"> <string>Print element backgrounds</string> </property> </widget> </item> - <item row="3" column="3"> + <item row="4" column="2"> <widget class="QCheckBox" name="kcfg_offlineStorageDatabaseEnabled"> <property name="text"> <string>Offline storage database</string> </property> </widget> </item> - <item row="4" column="3"> - <widget class="QCheckBox" name="kcfg_offlineWebApplicationCacheEnabled"> + <item row="3" column="0" rowspan="2"> + <widget class="QCheckBox" name="kcfg_javaEnabled"> <property name="text"> - <string>Offline web application cache</string> + <string>Java support</string> </property> </widget> </item> - <item row="5" column="3"> - <widget class="QCheckBox" name="kcfg_localStorageDatabaseEnabled"> + <item row="5" column="0"> + <widget class="QCheckBox" name="kcfg_javascriptCanOpenWindows"> <property name="text"> - <string>Local storage database</string> + <string>JavaScript can open windows</string> </property> </widget> </item> - <item row="3" column="0"> - <widget class="QCheckBox" name="kcfg_javascriptCanOpenWindows"> + <item row="5" column="2"> + <widget class="QCheckBox" name="kcfg_offlineWebApplicationCacheEnabled"> <property name="text"> - <string>JavaScript can open windows</string> + <string>Offline web application cache</string> </property> </widget> </item> - <item row="4" column="0"> + <item row="6" column="0"> <widget class="QCheckBox" name="kcfg_javascriptCanAccessClipboard"> <property name="text"> <string>JavaScript can access clipboard</string> </property> </widget> </item> - <item row="0" column="2" rowspan="6"> - <widget class="Line" name="line"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="orientation"> - <enum>Qt::Vertical</enum> + <item row="6" column="2"> + <widget class="QCheckBox" name="kcfg_localStorageEnabled"> + <property name="text"> + <string>Local Storage</string> </property> </widget> </item> @@ -130,8 +137,8 @@ <property name="title"> <string>Plugin Settings</string> </property> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> <widget class="QLabel" name="label_2"> <property name="enabled"> <bool>true</bool> @@ -142,15 +149,24 @@ <verstretch>0</verstretch> </sizepolicy> </property> + <property name="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> <property name="text"> <string>When loading web pages:</string> </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> </widget> </item> - <item> - <widget class="QComboBox" name="kcfg_pluginsEnabled"> + <item row="0" column="1"> + <widget class="KComboBox" name="kcfg_pluginsEnabled"> <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -180,15 +196,24 @@ <property name="title"> <string>User Style Sheet</string> </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> + <layout class="QFormLayout" name="formLayout_2"> + <item row="0" column="0"> <widget class="QLabel" name="label"> + <property name="minimumSize"> + <size> + <width>150</width> + <height>0</height> + </size> + </property> <property name="text"> <string>User CSS path:</string> </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> </widget> </item> - <item> + <item row="0" column="1"> <widget class="KUrlRequester" name="kcfg_userCSS"> <property name="filter"> <string>*.css</string> @@ -219,6 +244,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..d2d5c0d0 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 @@ -12,9 +11,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 @@ -37,6 +36,9 @@ #include "application.h" #include "mainwindow.h" #include "webtab.h" +#include "adblockwidget.h" +#include "networkwidget.h" +#include "searchengine.h" //Ui Includes #include "ui_settings_general.h" @@ -53,26 +55,25 @@ #include <KCModuleProxy> // Qt Includes -#include <QtCore/QPointer> #include <QtGui/QWidget> class Private { private: - + Ui::general generalUi; Ui::tabs tabsUi; Ui::fonts fontsUi; Ui::webkit webkitUi; - - KCModuleProxy *proxyModule; + + AdBlockWidget *adBlockWidg; + NetworkWidget *networkWidg; + KCModuleProxy *ebrowsingModule; - KCModuleProxy *cookiesModule; - KCModuleProxy *cacheModule; - KCModuleProxy *adblockModule; + KShortcutsEditor *shortcutsEditor; - + Private(SettingsDialog *parent); friend class SettingsDialog; @@ -102,21 +103,6 @@ Private::Private(SettingsDialog *parent) 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); widget->layout()->setMargin(0); @@ -125,23 +111,28 @@ 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")); pageItem->setIcon(KIcon("configure-shortcuts")); KCModuleInfo ebrowsingInfo("ebrowsing.desktop"); - ebrowsingModule = new KCModuleProxy(ebrowsingInfo,parent); + ebrowsingModule = new KCModuleProxy(ebrowsingInfo, 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!! - parent->setMinimumSize(700,525); + // WARNING remember wheh changing here that the smallest netbooks + // have a 1024x576 resolution. So DON'T bother that limits!! + parent->setMinimumSize(700, 525); } @@ -153,24 +144,24 @@ 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(); } @@ -184,6 +175,7 @@ SettingsDialog::~SettingsDialog() void SettingsDialog::setWebSettingsToolTips() { d->webkitUi.kcfg_autoLoadImages->setToolTip(i18n("Specifies whether images are automatically loaded in web pages.")); + d->webkitUi.kcfg_dnsPrefetch->setToolTip(i18n("Specifies whether WebKit will try to prefetch DNS entries to speed up browsing.")); d->webkitUi.kcfg_javascriptEnabled->setToolTip(i18n("Enables the execution of JavaScript programs.")); d->webkitUi.kcfg_javaEnabled->setToolTip(i18n("Enables support for Java applets.")); d->webkitUi.kcfg_pluginsEnabled->setToolTip(i18n("Enables support for plugins in web pages.")); @@ -194,7 +186,7 @@ void SettingsDialog::setWebSettingsToolTips() d->webkitUi.kcfg_printElementBackgrounds->setToolTip(i18n("If enabled, background colors and images are also drawn when the page is printed.")); d->webkitUi.kcfg_offlineStorageDatabaseEnabled->setToolTip(i18n("Enables support for the HTML 5 offline storage feature.")); d->webkitUi.kcfg_offlineWebApplicationCacheEnabled->setToolTip(i18n("Enables support for the HTML 5 web application cache feature.")); - d->webkitUi.kcfg_localStorageDatabaseEnabled->setToolTip(i18n("Enables support for the HTML 5 local storage feature.")); + d->webkitUi.kcfg_localStorageEnabled->setToolTip(i18n("Enables support for the HTML 5 local storage feature.")); } @@ -209,26 +201,32 @@ 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(); + SearchEngine::loadDefaultWS(); + SearchEngine::loadDelimiter(); + SearchEngine::loadFavorites(); + + + 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->shortcutsEditor->isModified(); - ; + return KConfigDialog::hasChanged() + || 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..25b2fe9b 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 @@ -12,9 +11,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 @@ -30,6 +29,9 @@ #define SETTINGS_DIALOG_H +// Rekonq Includes +#include "rekonq_defines.h" + // KDE Includes #include <KConfigDialog> @@ -38,14 +40,14 @@ class QWidget; class Private; -class SettingsDialog : public KConfigDialog +class REKONQ_TESTS_EXPORT SettingsDialog : public KConfigDialog { Q_OBJECT public: SettingsDialog(QWidget *parent = 0); ~SettingsDialog(); - + virtual bool hasChanged(); private: diff --git a/src/sslinfodialog_p.h b/src/sslinfodialog_p.h new file mode 100644 index 00000000..72f16791 --- /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 7326d7af..1274d813 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 @@ -13,9 +13,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 @@ -86,29 +86,29 @@ TabBar::~TabBar() QSize TabBar::tabSizeHint(int index) const { MainView *view = qobject_cast<MainView *>(parent()); - + int buttonSize = view->addTabButton()->size().width(); int tabBarWidth = view->size().width() - buttonSize; - int baseWidth = view->sizeHint().width()/BASE_WIDTH_DIVISOR; - int minWidth = view->sizeHint().width()/MIN_WIDTH_DIVISOR; + int baseWidth = view->sizeHint().width() / BASE_WIDTH_DIVISOR; + int minWidth = view->sizeHint().width() / MIN_WIDTH_DIVISOR; int w; - if (baseWidth*count()<tabBarWidth) + if (baseWidth*count() < tabBarWidth) { w = baseWidth; } - else + else { - if (count() > 0 && tabBarWidth/count()>minWidth) + if (count() > 0 && tabBarWidth / count() > minWidth) { - w = tabBarWidth/count(); + w = tabBarWidth / count(); } else { w = minWidth; } } - + int h = KTabBar::tabSizeHint(index).height(); QSize ts = QSize(w, h); @@ -149,68 +149,83 @@ void TabBar::detachTab() 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)); + + 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 int i = 0; - int tab = -1; - while (i<count() && tab==-1) + int tabIndex = -1; + while (i < count() + && tabIndex == -1 + ) { - if (tabRect(i).contains(event->pos())) + if (tabRect(i).contains(event->pos())) { - tab = i; + tabIndex = i; } i++; } - //if found and not the current tab then show tab preview - if (tab != -1 && tab != currentIndex() && m_currentTabPreview != tab) + // if found and not the current tab then show tab preview + if (tabIndex != -1 + && tabIndex != currentIndex() + && m_currentTabPreview != tabIndex + && event->buttons() == Qt::NoButton + ) { - showTabPreview(tab); - m_currentTabPreview = tab; + showTabPreview(tabIndex); + m_currentTabPreview = tabIndex; } - //if current tab or not found then hide previous tab preview - if (tab==currentIndex() || tab==-1) + // if current tab or not found then hide previous tab preview + if (tabIndex == currentIndex() || tabIndex == -1) { - if ( m_previewPopup) + if (!m_previewPopup.isNull()) { - m_previewPopup->hide(); + m_previewPopup.data()->hide(); } m_currentTabPreview = -1; } @@ -225,9 +240,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,10 +253,19 @@ 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; - + KTabBar::mousePressEvent(event); } @@ -253,15 +277,18 @@ void TabBar::contextMenu(int tab, const QPoint &pos) KMenu menu; MainWindow *mainWindow = Application::instance()->mainWindow(); - menu.addAction(mainWindow->actionByName(QLatin1String("new_tab"))); - menu.addAction( mainWindow->actionByName("clone_tab") ); - menu.addAction( mainWindow->actionByName("detach_tab") ); + menu.addAction(mainWindow->actionByName( QL1S("new_tab") )); + menu.addAction(mainWindow->actionByName( QL1S("clone_tab") )); + if (count() > 1) + menu.addAction(mainWindow->actionByName( QL1S("detach_tab") )); + menu.addAction(mainWindow->actionByName( QL1S("open_closed_tabs") )); + menu.addAction(mainWindow->actionByName( QL1S("closed_tab_menu") )); menu.addSeparator(); - menu.addAction( mainWindow->actionByName("close_tab") ); - menu.addAction( mainWindow->actionByName("close_other_tabs") ); + menu.addAction(mainWindow->actionByName( QL1S("close_tab") )); + menu.addAction(mainWindow->actionByName( QL1S("close_other_tabs") )); menu.addSeparator(); - menu.addAction( mainWindow->actionByName("reload_tab") ); - menu.addAction( mainWindow->actionByName("reload_all_tabs") ); + menu.addAction(mainWindow->actionByName( QL1S("reload_tab") )); + menu.addAction(mainWindow->actionByName( QL1S("reload_all_tabs") )); menu.exec(pos); } @@ -272,9 +299,34 @@ void TabBar::emptyAreaContextMenu(const QPoint &pos) KMenu menu; MainWindow *mainWindow = Application::instance()->mainWindow(); - menu.addAction(mainWindow->actionByName(QLatin1String("new_tab"))); + menu.addAction(mainWindow->actionByName( QL1S("new_tab") )); + menu.addAction(mainWindow->actionByName( QL1S("open_closed_tabs") )); + menu.addAction(mainWindow->actionByName( QL1S("closed_tab_menu") )); menu.addSeparator(); - menu.addAction( mainWindow->actionByName("reload_all_tabs") ); + menu.addAction(mainWindow->actionByName( QL1S("reload_all_tabs") )); 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..af3c537b 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 @@ -13,9 +13,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 @@ -31,11 +31,11 @@ #define TABBAR_H -// Local Includes -#include "rekonqprivate_export.h" +// Rekonq Includes +#include "rekonq_defines.h" // Qt Includes -#include <QPointer> +#include <QWeakPointer> // KDE Includes #include <KTabBar> @@ -61,8 +61,6 @@ public: TabBar(QWidget *parent); ~TabBar(); - void showTabPreview(int tab); - signals: void cloneTab(int index); void closeTab(int index); @@ -76,30 +74,34 @@ protected: * Added to fix tab dimension */ virtual QSize tabSizeHint(int index) const; - + 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(); void closeTab(); void closeOtherTabs(); void reloadTab(); void detachTab(); - + void contextMenu(int, const QPoint &); void emptyAreaContextMenu(const QPoint &); private: + void showTabPreview(int tab); + friend class MainView; - + /** * the index in which we are seeing a Context menu */ 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..c9555441 --- /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..d32eb58f 100644 --- a/src/tests/mainview_test.cpp +++ b/src/tests/mainview_test.cpp @@ -11,9 +11,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 @@ -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,71 +43,60 @@ class MainViewTest : public QObject public slots: void initTestCase(); void cleanupTestCase(); - void init(); - void cleanup(); private slots: void tabwidget_data(); void tabwidget(); - + void closeTab_data(); void closeTab(); - + void currentWebView_data(); void currentWebView(); - + void newTab_data(); void newTab(); - + void nextTab_data(); void nextTab(); - + void previousTab_data(); void previousTab(); - + void recentlyClosedTabs_data(); void recentlyClosedTabs(); - + void setCurrentTitle_data(); void setCurrentTitle(const QString &); - + void showStatusBarMessage_data(); void showStatusBarMessage(const QString &); - + 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..af3a2aa2 --- /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..28b05075 --- /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..dbf33684 --- /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..bb784219 --- /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..6df38657 100644 --- a/src/tests/tabbar_test.cpp +++ b/src/tests/tabbar_test.cpp @@ -24,116 +24,125 @@ #include <QtCore> #include <QtGui> -#include "../tabbar.h" +#include "mainwindow.h" +#include "mainview.h" +#include "tabbar.h" -class TabBarTest : public QObject +/** + * Subclass that exposes the protected functions. + */ +class SubTabBar : public TabBar { - Q_OBJECT +public: -public slots: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); + SubTabBar(QWidget *parent) : TabBar(parent) {}; -private slots: - void tabbar_data(); - void tabbar(); + QSize call_tabSizeHint(int index) const + { + return SubTabBar::tabSizeHint(index); + } - void tabSizeHint_data(); - void tabSizeHint(); -}; + void call_mouseMoveEvent(QMouseEvent* event) + { + return SubTabBar::mouseMoveEvent(event); + } + void call_leaveEvent(QEvent* event) + { + return SubTabBar::leaveEvent(event); + } -// Subclass that exposes the protected functions. -class SubTabBar : public TabBar -{ -public: - void call_cloneTab(int index) - { return SubTabBar::cloneTab(index); } + void call_mousePressEvent(QMouseEvent* event) + { + return SubTabBar::mousePressEvent(event); + } + + void call_mouseReleaseEvent(QMouseEvent* event) + { + return SubTabBar::mouseReleaseEvent(event); + } +}; - void call_closeOtherTabs(int index) - { return SubTabBar::closeOtherTabs(index); } - void call_closeTab(int index) - { return SubTabBar::closeTab(index); } +// ------------------------------------------------------------------ - void call_mouseMoveEvent(QMouseEvent* event) - { return SubTabBar::mouseMoveEvent(event); } - void call_mousePressEvent(QMouseEvent* event) - { return SubTabBar::mousePressEvent(event); } +class TabBarTest : public QObject +{ + Q_OBJECT - void call_reloadAllTabs() - { return SubTabBar::reloadAllTabs(); } +public slots: + void initTestCase(); + void cleanupTestCase(); - void call_reloadTab(int index) - { return SubTabBar::reloadTab(index); } +private slots: + void tabSizeHint_data(); + void tabSizeHint(); - QSize call_tabSizeHint(int index) const - { return SubTabBar::tabSizeHint(index); } + void mousePress_data(); + void mousePress(); - void call_showTabPreview(int tab) - { return SubTabBar::showTabPreview(tab); } +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..fc7c1718 --- /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..d4036981 --- /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..c06ce7a5 --- /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..1bfb440d --- /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..0e5833b4 --- /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..7eb968c7 --- /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..1bb01785 --- /dev/null +++ b/src/urlbar/completionwidget.cpp @@ -0,0 +1,280 @@ +/* ============================================================ +* +* 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" +#include "searchengine.h" + +// KDE Includes +#include <KGlobalSettings> +#include <KUrl> + +// Qt Includes +#include <QtCore/QPoint> +#include <QtCore/QSize> +#include <QtCore/QEvent> + +#include <QtGui/QVBoxLayout> +#include <QtGui/QKeyEvent> + + + +CompletionWidget::CompletionWidget(QWidget *parent) + : QFrame(parent, Qt::ToolTip) + , _parent(parent) + , _currentIndex(-1) + , _searchEngine(SearchEngine::defaultEngine()) +{ + 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(const 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(); + } +} diff --git a/src/urlbar/completionwidget.h b/src/urlbar/completionwidget.h new file mode 100644 index 00000000..4ce8248d --- /dev/null +++ b/src/urlbar/completionwidget.h @@ -0,0 +1,90 @@ +/* ============================================================ +* +* 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 + + +// Rekonq Includes +#include "rekonq_defines.h" + +// Local Includes +#include "listitem.h" + +// KDE Includes +#include <KService> + +// 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); + + KService::Ptr searchEngine() + { + return _searchEngine; + }; + + void setCurrentEngine(KService::Ptr engine) + { + _searchEngine = engine; + }; + + void suggestUrls(const QString &text); + +private slots: + void itemChosen(ListItem *item, Qt::MouseButton = Qt::LeftButton); + +signals: + void chosenUrl(const KUrl &, Rekonq::OpenType); + void nextItemSubChoice(); + +private: + void insertSearchList(const UrlSearchList &list, const QString& text); + void popup(); + void clear(); + + void sizeAndPosition(); + void up(); + void down(); + + QWidget *_parent; + + UrlSearchList _list; + int _currentIndex; + + KService::Ptr _searchEngine; +}; + +#endif // COMPLETION_WIDGET_H diff --git a/src/urlbar/listitem.cpp b/src/urlbar/listitem.cpp new file mode 100644 index 00000000..c6f75348 --- /dev/null +++ b/src/urlbar/listitem.cpp @@ -0,0 +1,427 @@ +/* ============================================================ +* +* 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" +#include "searchengine.h" + +// KDE Includes +#include <KIcon> +#include <KAction> + +// Qt Includes +#include <QActionGroup> +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QLabel> +#include <QSizePolicy> +#include <QPixmap> +#include <QStylePainter> +#include <QMouseEvent> +#include <QWebSettings> +#include <QFile> + + +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); + + 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; + 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) +{ + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->setSpacing(4); + + 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); + hLayout->addWidget(previewLabelIcon); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->setMargin(0); + vLayout->addWidget(new TextLabel(item.title, text, this)); + vLayout->addWidget(new TextLabel("<i>" + item.url.url() + "</i>", text, this)); + + hLayout->addLayout(vLayout); + + hLayout->addWidget(new TypeIconLabel(item.type, this)); + + setLayout(hLayout); +} + + +// --------------------------------------------------------------- + + +PreviewLabel::PreviewLabel(const QString &url, int width, int height, QWidget *parent) + : QLabel(parent) +{ + setFixedSize(width, height); + setFrameStyle(QFrame::StyledPanel | QFrame::Raised); + + KUrl u = KUrl(url); + if (WebSnap::existsImage(KUrl(u))) + { + QPixmap preview; + preview.load(WebSnap::imagePathFromUrl(u)); + 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) +{ + KService::Ptr currentEngine = SearchEngine::defaultEngine(); + + QString query = text; + KService::Ptr engine = SearchEngine::fromString(text); + if (engine) + { + query = query.remove(0, text.indexOf(SearchEngine::delimiter()) + 1); + } + else + { + engine = currentEngine; + } + + m_url = SearchEngine::buildQuery(engine, query); + + m_iconLabel = new IconLabel("edit-find", this); //TODO: get the default engine icon + m_titleLabel = new TextLabel(searchItemTitle(engine->name(), query), QString(), this); + m_engineBar = new EngineBar(currentEngine, parent); + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->setSpacing(4); + + hLayout->addWidget(m_iconLabel); + hLayout->addWidget(m_titleLabel); + hLayout->addWidget(new QLabel(i18n("Engines: "), this)); + hLayout->addWidget(m_engineBar); + hLayout->addWidget(new TypeIconLabel(item.type, this)); + + setLayout(hLayout); + + connect(m_engineBar, SIGNAL(searchEngineChanged(KService::Ptr)), this, SLOT(changeSearchEngine(KService::Ptr))); +} + + +QString SearchListItem::searchItemTitle(QString engine, QString text) +{ + return QString(i18nc("%1=search engine, e.g. Google, Wikipedia %2=text to search for", "Search %1 for <b>%2</b>", engine, text)); +} + +void SearchListItem::changeSearchEngine(KService::Ptr engine) +{ + m_titleLabel->setText(searchItemTitle(engine->name(), m_text)); + m_iconLabel->setPixmap(Application::icon(KUrl(engine->property("Query").toString())).pixmap(16)); + m_url = SearchEngine::buildQuery(engine, m_text); + + CompletionWidget *w = qobject_cast<CompletionWidget *>(parent()); + w->setCurrentEngine(engine); +} + + +void SearchListItem::nextItemSubChoice() +{ + m_engineBar->selectNextEngine(); +} + + +// ----------------------------------------------------------------------------------------------- + + +EngineBar::EngineBar(KService::Ptr selectedEngine, QWidget *parent) + : KToolBar(parent) +{ + setIconSize(QSize(16, 16)); + setToolButtonStyle(Qt::ToolButtonIconOnly); + + m_engineGroup = new QActionGroup(this); + m_engineGroup->setExclusive(true); + + m_engineGroup->addAction(newEngineAction(SearchEngine::defaultEngine(), selectedEngine)); + foreach(KService::Ptr engine, SearchEngine::favorites()) + { + if (engine->desktopEntryName() != SearchEngine::defaultEngine()->desktopEntryName()) + { + m_engineGroup->addAction(newEngineAction(engine, selectedEngine)); + } + } + + addActions(m_engineGroup->actions()); +} + + +KAction *EngineBar::newEngineAction(KService::Ptr engine, KService::Ptr selectedEngine) +{ + QString url = engine->property("Query").toString(); + KAction *a = new KAction(Application::icon(url), engine->name(), this); + a->setCheckable(true); + if (engine->desktopEntryName() == selectedEngine->desktopEntryName()) a->setChecked(true); + a->setData(engine->entryPath()); + connect(a, SIGNAL(triggered(bool)), this, SLOT(changeSearchEngine())); + return a; +} + + +void EngineBar::changeSearchEngine() +{ + KAction *a = qobject_cast<KAction*>(sender()); + emit searchEngineChanged(KService::serviceByDesktopPath(a->data().toString())); +} + + +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; + + kDebug() << text; + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->setSpacing(4); + + hLayout->addWidget(new IconLabel(item.url.url(), this)); + hLayout->addWidget(new TextLabel(item.url.url(), text, this)); + hLayout->addWidget(new TypeIconLabel(item.type, this)); + + setLayout(hLayout); +} + + +// --------------------------------------------------------------- + + +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..c26a1893 --- /dev/null +++ b/src/urlbar/listitem.h @@ -0,0 +1,220 @@ +/* ============================================================ +* +* 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 + + +// Rekonq Includes +#include "rekonq_defines.h" + +// Local Includes +#include "urlresolver.h" + +// KDE Includes +#include <KToolBar> +#include <KService> + +// Qt Includes +#include <QWidget> +#include <QStyleOptionViewItemV4> +#include <QLabel> + +// Forward Declarations +class UrlSearchItem; +class KAction; +class QActionGroup; + + +class ListItem : public QWidget +{ + Q_OBJECT + +public: + explicit 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: + explicit TypeIconLabel(int type, QWidget *parent = 0); + +private: + QLabel *getIcon(QString icon); +}; + + +// ------------------------------------------------------------------------- + + +class IconLabel : public QLabel +{ + Q_OBJECT + +public: + explicit IconLabel(const QString &icon, QWidget *parent = 0); +}; + + +// ------------------------------------------------------------------------- + + +class TextLabel : public QLabel +{ + Q_OBJECT + +public: + explicit TextLabel(const QString &text, const QString &textToPointOut = QString(), QWidget *parent = 0); +}; + + +// ------------------------------------------------------------------------- + + +class EngineBar : public KToolBar +{ + Q_OBJECT + +public: + explicit EngineBar(KService::Ptr selectedEngine, QWidget *parent = 0); + void selectNextEngine(); + +signals: + void searchEngineChanged(KService::Ptr engine); + +private slots: + void changeSearchEngine(); + +private: + KAction *newEngineAction(KService::Ptr engine, KService::Ptr selectedEngine); + QActionGroup *m_engineGroup; +}; + + +// ------------------------------------------------------------------------- + + +class SearchListItem : public ListItem +{ + Q_OBJECT + +public: + explicit SearchListItem(const UrlSearchItem &item, const QString &text, QWidget *parent = 0); + +public slots: + virtual void nextItemSubChoice(); + +private slots: + void changeSearchEngine(KService::Ptr engine); + +private: + QString searchItemTitle(QString engine, QString text); + + TextLabel* m_titleLabel; + IconLabel* m_iconLabel; + EngineBar* m_engineBar; + QString m_text; + KService::Ptr m_currentEngine; +}; + + +// ------------------------------------------------------------------------- + + +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/rsswidget.cpp b/src/urlbar/rsswidget.cpp new file mode 100644 index 00000000..395d7bab --- /dev/null +++ b/src/urlbar/rsswidget.cpp @@ -0,0 +1,168 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* 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/>. +* +* ============================================================ */ + + +// Auto Includes +#include "rsswidget.h" +#include "rsswidget.moc" + +// Local includes +#include "application.h" +#include "mainwindow.h" +#include "webtab.h" +#include "webview.h" + +// KDE Includes +#include <KLocalizedString> +#include <KIcon> +#include <KProcess> +#include <KMessageBox> + +// Qt Includes +#include <QtGui/QFormLayout> +#include <QtGui/QDialogButtonBox> +#include <QtGui/QLabel> +#include <QtGui/QPushButton> + +#include <QtDBus/QDBusInterface> +#include <QtDBus/QDBusConnectionInterface> + + + +RSSWidget::RSSWidget(const QMap< KUrl, QString > &map, QWidget *parent) + : QFrame(parent, Qt::Popup) + , m_map(map) +{ + setAttribute(Qt::WA_DeleteOnClose); + setFixedWidth(250); + setFrameStyle(Panel); + + QFormLayout *layout = new QFormLayout(this); + setLayout(layout); + + QLabel *agregator = new QLabel(this); + agregator->setText(i18n("Aggregator:")); + + m_agregators = new KComboBox(this); + m_agregators->addItem(KIcon("application-rss+xml"), QString("Akregator")); + m_agregators->addItem(Application::icon(KUrl("http://google.com/reader")), i18n("Google Reader")); + + layout->addRow(agregator, m_agregators); + + + QLabel *feed = new QLabel(this); + feed->setText(i18n("Feed:")); + + m_feeds = new KComboBox(this); + + foreach(const QString &title, m_map) + { + m_feeds->addItem(title); + } + + layout->addRow(feed, m_feeds); + + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); + buttonBox->button(QDialogButtonBox::Ok)->setText(i18n("Add Feed")); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + layout->addWidget(buttonBox); +} + + +RSSWidget::~RSSWidget() +{ + delete m_agregators; + delete m_feeds; +} + + +void RSSWidget::showAt(const QPoint &pos) +{ + QPoint p; + p.setX(pos.x() - 200); + p.setY(pos.y() + 10); + move(p); + show(); +} + + +void RSSWidget::accept() +{ + QString url = m_map.key(m_feeds->currentText()).toMimeDataString(); + + if (m_agregators->currentIndex() == 0) + addWithAkregator(url); + else + addWithGoogleReader(url); + + reject(); +} + + +void RSSWidget::reject() +{ + close(); + this->deleteLater(); +} + + +void RSSWidget::addWithGoogleReader(const QString &url) +{ + KUrl toLoad = KUrl("http://www.google.com/ig/add?feedurl=" + url); + Application::instance()->mainWindow()->currentTab()->view()->load(toLoad); +} + + +void RSSWidget::addWithAkregator(const QString &url) +{ + // Akregator is running + if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.akregator")) + { + QDBusInterface akregator("org.kde.akregator", "/Akregator", "org.kde.akregator.part"); + QDBusReply<void> reply = akregator.call("addFeedsToGroup", QStringList(url) , i18n("Imported Feeds")); + + if (!reply.isValid()) + { + KMessageBox::error(0, QString(i18n("Could not add stream to akregator, Please add it manually :") + + "<br /><br /> <a href=\"" + url + "\">" + url + "</a>")); + } + } + // Akregator is not running + else + { + KProcess proc; + proc << "akregator" << "-g" << i18n("Imported Feeds"); + proc << "-a" << url; + if (proc.startDetached() == 0) + { + KMessageBox::error(0, QString(i18n("There was an error. Please verify Akregator is installed on your system.") + + "<br /><br /> <a href=\"" + url + "\">" + url + "</a>")); + } + + } +} diff --git a/src/urlbar/rsswidget.h b/src/urlbar/rsswidget.h new file mode 100644 index 00000000..0272805e --- /dev/null +++ b/src/urlbar/rsswidget.h @@ -0,0 +1,68 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* 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/>. +* +* ============================================================ */ + + +#ifndef RSSWIDGET_H +#define RSSWIDGET_H + +// Rekonq Includes +#include "rekonq_defines.h" + +// KDE Includes +#include <KComboBox> +#include <KUrl> + +// Qt Includes +#include <QtCore/QMap> + +#include <QtGui/QFrame> + + +class RSSWidget : public QFrame +{ + Q_OBJECT + +public: + // QMap< feedUrl, feedTitle> + RSSWidget(const QMap<KUrl, QString> &map, QWidget *parent = 0); + ~RSSWidget(); + + void showAt(const QPoint &pos); + +private slots: + void accept(); + void reject(); + +private: + void addWithAkregator(const QString &url); + void addWithGoogleReader(const QString &url); + + QMap<KUrl, QString> m_map; + + KComboBox *m_agregators; + KComboBox *m_feeds; +}; + +#endif // RSSWIDGET_H diff --git a/src/urlbar/urlbar.cpp b/src/urlbar/urlbar.cpp index be19dae4..e1e542b7 100644 --- a/src/urlbar/urlbar.cpp +++ b/src/urlbar/urlbar.cpp @@ -13,9 +13,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 @@ -31,307 +31,383 @@ #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 "webpage.h" #include "webview.h" -#include "historymanager.h" +#include "completionwidget.h" // KDE Includes -#include <KDebug> #include <KCompletionBox> -#include <KUrl> // Qt Includes -#include <QPainter> -#include <QPaintEvent> -#include <QPalette> -#include <QTimer> +#include <QtGui/QPainter> +#include <QtGui/QPaintEvent> +#include <QtGui/QPalette> +#include <QtGui/QVBoxLayout> -QColor UrlBar::s_defaultBaseColor; +IconButton::IconButton(QWidget *parent) + : QToolButton(parent) +{ + setToolButtonStyle(Qt::ToolButtonIconOnly); + setStyleSheet("IconButton { background-color:transparent; border: none; padding: 0px}"); + setCursor(Qt::ArrowCursor); +} -UrlBar::UrlBar(QWidget *parent) - : KHistoryComboBox(true, parent) - , m_lineEdit(new LineEdit) - , m_progress(0) +void IconButton::mouseReleaseEvent(QMouseEvent* event) { - setUrlDropsEnabled(true); - setAutoDeleteCompletionObject(true); + emit clicked(event->globalPos()); +} - //cosmetic - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - setMinimumWidth(180); - - 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())); +UrlBar::UrlBar(QWidget *parent) + : KLineEdit(parent) + , _tab(0) + , _privateMode(false) + , _icon(new IconButton(this)) + , _suggestionTimer(new QTimer(this)) +{ + // initial style + setStyleSheet(QString("UrlBar { padding: 0 0 0 %1px;} ").arg(_icon->sizeHint().width())); - // setup completion box - setCompletionObject( Application::historyManager()->completionObject() ); - - // set dropdown list background - QPalette p = view()->palette(); - p.setColor(QPalette::Base, palette().color(QPalette::Base)); - view()->setPalette(p); + // cosmetic + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + setMinimumWidth(200); + setMinimumHeight(26); - // load urls on activated urlbar signal - connect(this, SIGNAL(activated(const KUrl&)), Application::instance(), SLOT(loadUrl(const KUrl&))); -} + // doesn't show the clear button + setClearButtonShown(false); + // trap Key_Enter & Key_Return events, while emitting the returnPressed signal + setTrapReturnKey(true); -UrlBar::~UrlBar() -{ -} + // insert decoded URLs + setUrlDropsEnabled(true); + // accept focus, via tabbing, clicking & wheeling + setFocusPolicy(Qt::WheelFocus); -void UrlBar::selectAll() const -{ - lineEdit()->selectAll(); -} + // disable completion object (we have our own :) ) + setCompletionObject(0); + _tab = qobject_cast<WebTab *>(parent); -KUrl UrlBar::url() const -{ - return m_currentUrl; -} + 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())); + // load typed urls + connect(this, SIGNAL(returnPressed(const QString &)), this, SLOT(loadTyped(const QString &))); -KLineEdit *UrlBar::lineEdit() const -{ - return m_lineEdit; + _suggestionTimer->setSingleShot(true); + connect(_suggestionTimer, SIGNAL(timeout()), this, SLOT(suggest())); + + activateSuggestions(true); } -void UrlBar::setupLineEdit() +UrlBar::~UrlBar() { - // 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(); + activateSuggestions(false); + delete _icon; + _box.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(); + _icon->setIcon(KIcon("arrow-right")); + clear(); setFocus(); } else { - m_currentUrl = KUrl(url); + clearFocus(); + KLineEdit::setUrl(url); + setCursorPosition(0); + _icon->setIcon(Application::icon(url)); } - updateUrl(); } -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()) + QColor backgroundColor; + if (_privateMode) { - icon = KIcon("arrow-right"); + backgroundColor = QColor(220, 220, 220); // light gray } - else + else { - icon = Application::icon(m_currentUrl); + backgroundColor = Application::palette().color(QPalette::Base); } - if (count()) + // set background color of UrlBar + QPalette p = palette(); + + int progr = _tab->progress(); + if (progr == 0) { - changeUrl(0, icon, m_currentUrl); + if (_tab->url().scheme() == QL1S("https")) + { + backgroundColor = QColor(255, 255, 171); // light yellow + } + p.setBrush(QPalette::Base, backgroundColor); } else { - insertUrl(0, icon, m_currentUrl); + 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); - setCurrentIndex(0); + // you need this before our code to draw inside the line edit.. + KLineEdit::paintEvent(event); - // important security consideration: always display the beginning - // of the url rather than its end to prevent spoofing attempts. - // Must be AFTER setCurrentIndex - if (!hasFocus()) + if (text().isEmpty()) { - lineEdit()->setCursorPosition(0); + 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("Start typing here to search your bookmarks, history and the web...") + ); } } -void UrlBar::activated(const QString& urlString) +void UrlBar::keyPressEvent(QKeyEvent *event) { - if (urlString.isEmpty()) - return; + // this handles the Modifiers + Return key combinations + QString currentText = text().trimmed(); + if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) + && !currentText.startsWith(QL1S("http://"), Qt::CaseInsensitive)) + { + QString append; + if (event->modifiers() == Qt::ControlModifier) + { + append = QL1S(".com"); + } + else if (event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) + { + append = QL1S(".org"); + } + else if (event->modifiers() == Qt::ShiftModifier) + { + append = QL1S(".net"); + } - setUrl(urlString); - emit activated(m_currentUrl); + QUrl url(QL1S("http://www.") + currentText); + QString host = url.host(); + if (!host.endsWith(append, Qt::CaseInsensitive)) + { + host += append; + url.setHost(host); + setText(url.toString()); + } + } + + if (event->key() == Qt::Key_Escape) + { + clearFocus(); + event->accept(); + } + + KLineEdit::keyPressEvent(event); } -void UrlBar::cleared() +void UrlBar::focusInEvent(QFocusEvent *event) { - // clear the history on user's request from context menu - clear(); + activateSuggestions(true); + + KLineEdit::focusInEvent(event); } -void UrlBar::loadFinished(bool) +void UrlBar::setPrivateMode(bool on) { - // reset progress bar after small delay - m_progress = 0; - QTimer::singleShot(200, this, SLOT(repaint())); + _privateMode = on; } -void UrlBar::updateProgress(int progress) +void UrlBar::dropEvent(QDropEvent *event) { - m_progress = progress; - repaint(); + KLineEdit::dropEvent(event); + activated(text()); } -void UrlBar::paintEvent(QPaintEvent *event) +void UrlBar::loadFinished() { - // set background color of UrlBar - QPalette p = palette(); - p.setColor(QPalette::Base, s_defaultBaseColor); - setPalette(p); + if (_tab->progress() != 0) + return; - KHistoryComboBox::paintEvent(event); + if (_tab->url().scheme() == QL1S("about")) + { + update(); + return; + } - if (!hasFocus()) + // show KGet downloads?? + if (ReKonfig::kgetList()) { - QPainter painter(this); + IconButton *bt = addRightIcon(UrlBar::KGet); + connect(bt, SIGNAL(clicked(QPoint)), _tab->page(), SLOT(downloadAllContentsWithKGet(QPoint))); + } - QColor loadingColor; - if (m_currentUrl.scheme() == QLatin1String("https")) - { - loadingColor = QColor(248, 248, 100); - } - else - { - loadingColor = QColor(116, 192, 250); - } - 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(); + // show RSS + if (_tab->hasRSSInfo()) + { + IconButton *bt = addRightIcon(UrlBar::RSS); + connect(bt, SIGNAL(clicked(QPoint)), _tab, SLOT(showRSSInfo(QPoint))); + } + + // show SSL + if (_tab->url().scheme() == QL1S("https")) + { + IconButton *bt = addRightIcon(UrlBar::SSL); + connect(bt, SIGNAL(clicked(QPoint)), _tab->page(), SLOT(showSSLInfo(QPoint))); } + + update(); } -QSize UrlBar::sizeHint() const +void UrlBar::loadTyped(const QString &text) { - return lineEdit()->sizeHint(); + activated(KUrl(text)); } -QLinearGradient UrlBar::generateGradient(const QColor &color, int height) +void UrlBar::activateSuggestions(bool b) { - 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; + if (b) + { + if (_box.isNull()) + { + _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 &)), this, SLOT(detectTypedString(const QString &))); + } + } + else + { + disconnect(this, SIGNAL(textChanged(const QString &)), this, SLOT(detectTypedString(const QString &))); + removeEventFilter(_box.data()); + _box.data()->deleteLater(); + } } -void UrlBar::setBackgroundColor(QColor c) +void UrlBar::mouseDoubleClickEvent(QMouseEvent *) { - s_defaultBaseColor = c; - repaint(); + selectAll(); } -bool UrlBar::isLoading() +IconButton *UrlBar::addRightIcon(UrlBar::icon ic) { - if(m_progress == 0) + IconButton *rightIcon = new IconButton(this); + + switch (ic) { - return false; + case UrlBar::KGet: + rightIcon->setIcon(KIcon("download")); + rightIcon->setToolTip(i18n("List all links with KGet")); + break; + case UrlBar::RSS: + rightIcon->setIcon(KIcon("application-rss+xml")); + rightIcon->setToolTip(i18n("List all available RSS feeds")); + break; + case UrlBar::SSL: + rightIcon->setIcon(KIcon("object-locked")); + rightIcon->setToolTip(i18n("Show SSL Info")); + break; + default: + kDebug() << "ERROR.. default non extant case!!"; + break; } - return true; + + _rightIconsList << rightIcon; + int iconsCount = _rightIconsList.count(); + rightIcon->move(width() - 23*iconsCount, 6); + rightIcon->show(); + + return rightIcon; } -void UrlBar::keyPressEvent(QKeyEvent *event) + +void UrlBar::clearRightIcons() { - QString currentText = m_lineEdit->text().trimmed(); - if ((event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) - && !currentText.startsWith(QLatin1String("http://"), Qt::CaseInsensitive)) - { - 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"); - } + qDeleteAll(_rightIconsList); + _rightIconsList.clear(); +} - 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()); - } + +void UrlBar::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); } - KHistoryComboBox::keyPressEvent(event); + KLineEdit::resizeEvent(event); + +} + + +void UrlBar::detectTypedString(const QString &typed) +{ + Q_UNUSED(typed); + + if(_suggestionTimer->isActive()) + _suggestionTimer->stop(); + _suggestionTimer->start(200); } + +void UrlBar::suggest() +{ + if(!_box.isNull()) + _box.data()->suggestUrls( text() ); +}
\ No newline at end of file diff --git a/src/urlbar/urlbar.h b/src/urlbar/urlbar.h index 8d267b2c..cda8a2e1 100644 --- a/src/urlbar/urlbar.h +++ b/src/urlbar/urlbar.h @@ -13,9 +13,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 @@ -30,69 +30,99 @@ #ifndef URLBAR_H #define URLBAR_H - -// Local Includes -#include "lineedit.h" +// Rekonq Includes +#include "rekonq_defines.h" // KDE Includes #include <KUrl> -#include <KHistoryComboBox> +#include <KLineEdit> // Qt Includes -#include <QUrl> +#include <QWeakPointer> +#include <QToolButton> // Forward Declarations class QLinearGradient; class QWidget; -class KCompletion; +class CompletionWidget; +class WebTab; +class QTimer; + + +class IconButton : public QToolButton +{ + Q_OBJECT + +public: + IconButton(QWidget *parent = 0); + +signals: + void clicked(QPoint); + +protected: + void mouseReleaseEvent(QMouseEvent *event); + +}; -class UrlBar : public KHistoryComboBox +// Definitions +typedef QList<IconButton *> IconButtonPointerList; + + +// ------------------------------------------------------------------------------------ + + +class REKONQ_TESTS_EXPORT UrlBar : public KLineEdit { Q_OBJECT public: - UrlBar(QWidget *parent = 0); + + enum icon + { + KGet = 0x00000001, + RSS = 0x00000010, + SSL = 0x00000100, + }; + + explicit UrlBar(QWidget *parent = 0); ~UrlBar(); - void selectAll() const; - KUrl url() const; - QSize sizeHint() const; - void setBackgroundColor(QColor); - bool isLoading(); - - void setProgress(int progress); + void setPrivateMode(bool on); -signals: - void activated(const KUrl&); +private slots: + void activated(const KUrl& url, Rekonq::OpenType = Rekonq::CurrentTab); + void setQUrl(const QUrl &url); -public slots: - void setUrl(const QUrl &url); - void updateProgress(int progress); - void updateUrl(); + void loadFinished(); + void loadTyped(const QString &); + + void clearRightIcons(); -private slots: - void activated(const QString& url); - void loadFinished(bool); - void cleared(); + void detectTypedString(const QString &); + void suggest(); protected: - virtual void paintEvent(QPaintEvent *event); - virtual void keyPressEvent(QKeyEvent *event); + void paintEvent(QPaintEvent *event); + void keyPressEvent(QKeyEvent *event); + void focusInEvent(QFocusEvent *event); + void dropEvent(QDropEvent *event); + void mouseDoubleClickEvent(QMouseEvent *); + void resizeEvent(QResizeEvent *); private: - void setupLineEdit(); + IconButton *addRightIcon(UrlBar::icon); + void activateSuggestions(bool); - KLineEdit *lineEdit() const; + QWeakPointer<CompletionWidget> _box; + WebTab *_tab; + bool _privateMode; - static QLinearGradient generateGradient(const QColor &color, int height); + IconButton *_icon; + IconButtonPointerList _rightIconsList; - static QColor s_defaultBaseColor; - - LineEdit *m_lineEdit; - - KUrl m_currentUrl; - int m_progress; + QTimer *_suggestionTimer; }; + #endif diff --git a/src/urlbar/urlresolver.cpp b/src/urlbar/urlresolver.cpp new file mode 100644 index 00000000..e86adc62 --- /dev/null +++ b/src/urlbar/urlresolver.cpp @@ -0,0 +1,245 @@ +/* ============================================================ +* +* 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 <KService> +#include <KConfig> +#include <KConfigGroup> + +// Qt Includes +#include <QByteArray> + +// 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==(const UrlSearchItem &i) const +{ + 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(); + } + else + { + list << webSearchesResolution(); + list << qurlFromUserInputResolution(); + } + + + if (_typedString.length() >= 2) + { + 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(const UrlSearchItem &i, common) + { + list << i; + } + + foreach(const UrlSearchItem &i, bookmarksList) + { + if (!common.contains(i)) + list << i; + } + } + + list = placeTypedDomaineNameOnTop(list); + + 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( QL1S("http://") ) + || _typedString.startsWith( QL1S("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()) + { + QString gTitle = i18nc("Browse a website", "Browse"); + UrlSearchItem gItem(UrlSearchItem::Browse, urlFromUserInput, gTitle); + list << gItem; + } + + return list; +} + + +// STEP 2 = Web Searches +UrlSearchList UrlResolver::webSearchesResolution() +{ + return UrlSearchList() << UrlSearchItem(UrlSearchItem::Search, KUrl(), QString()); +} + + +// 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; +} + + +UrlSearchList UrlResolver::placeTypedDomaineNameOnTop(UrlSearchList list) +{ + int i=0; + bool found = false; + + while(i<list.count() && !found) + { + UrlSearchItem item = list.at(i); + if (item.url.url().contains("."+_typedString+".") || item.url.url().contains("/"+_typedString+".")) + { + list.removeAt(i); + list.insert(0,item); + found = true; + } + i++; + } + + return list; +} + diff --git a/src/urlbar/urlresolver.h b/src/urlbar/urlresolver.h new file mode 100644 index 00000000..7a8262b3 --- /dev/null +++ b/src/urlbar/urlresolver.h @@ -0,0 +1,90 @@ +/* ============================================================ +* +* 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 + + +// Rekonq Includes +#include "rekonq_defines.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==(const UrlSearchItem &i) const; +}; + +typedef QList <UrlSearchItem> UrlSearchList; + + +// ---------------------------------------------------------------------- + + +class UrlResolver +{ +public: + UrlResolver(const QString &typedUrl); + + UrlSearchList orderedSearchItems(); + +private: + QString _typedString; + + UrlSearchList webSearchesResolution(); + UrlSearchList historyResolution(); + UrlSearchList qurlFromUserInputResolution(); + UrlSearchList bookmarksResolution(); + UrlSearchList placeTypedDomaineNameOnTop(UrlSearchList list); + + bool isHttp(); +}; + +#endif // URL_RESOLVER_H diff --git a/src/walletbar.cpp b/src/walletbar.cpp index c5d705e0..292e48bd 100644 --- a/src/walletbar.cpp +++ b/src/walletbar.cpp @@ -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 @@ -28,6 +28,9 @@ #include "walletbar.h" #include "walletbar.moc" +// Auto Includes +#include "rekonq.h" + // KDE Includes #include <klocalizedstring.h> #include <KIcon> @@ -40,8 +43,8 @@ WalletBar::WalletBar(QWidget *parent) - : QWidget(parent) - , m_label( new QLabel(this) ) + : QWidget(parent) + , m_label(new QLabel(this)) { m_label->setWordWrap(true); @@ -57,15 +60,15 @@ WalletBar::WalletBar(QWidget *parent) connect(rememberButton, SIGNAL(clicked()), this, SLOT(rememberData())); connect(neverHereButton, SIGNAL(clicked()), this, SLOT(neverRememberData())); connect(notNowButton, SIGNAL(clicked()), this, SLOT(notNowRememberData())); - + // layout QGridLayout *layout = new QGridLayout(this); - layout->addWidget(closeButton,0,0); - layout->addWidget(m_label,0,1); - layout->addWidget(rememberButton,0,2); - layout->addWidget(neverHereButton,0,3); - layout->addWidget(notNowButton,0,4); - layout->setColumnStretch(1,100); + layout->addWidget(closeButton, 0, 0); + layout->addWidget(m_label, 0, 1); + layout->addWidget(rememberButton, 0, 2); + layout->addWidget(neverHereButton, 0, 3); + layout->addWidget(notNowButton, 0, 4); + layout->setColumnStretch(1, 100); setLayout(layout); } @@ -85,14 +88,18 @@ 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(); } void WalletBar::notNowRememberData() { - emit saveFormDataRejected (m_key); + emit saveFormDataRejected(m_key); destroy(); } @@ -109,7 +116,7 @@ void WalletBar::destroy() void WalletBar::onSaveFormData(const QString &key, const QUrl &url) { - m_label->setText( i18n("Do you want rekonq to remember the password on %1?", url.host() ) ); + m_label->setText(i18n("Do you want rekonq to remember the password on %1?", url.host())); m_key = key; m_url = url; diff --git a/src/walletbar.h b/src/walletbar.h index d2e39373..5901c659 100644 --- a/src/walletbar.h +++ b/src/walletbar.h @@ -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 @@ -24,9 +24,12 @@ * ============================================================ */ -#ifndef WALLET_WIDGET_H -#define WALLET_WIDGET_H +#ifndef WALLET_BAR_H +#define WALLET_BAR_H + +// Rekonq Includes +#include "rekonq_defines.h" // Qt Includes #include <QWidget> @@ -35,7 +38,7 @@ #include <QLabel> -class WalletBar : public QWidget +class REKONQ_TESTS_EXPORT WalletBar : public QWidget { Q_OBJECT @@ -44,7 +47,7 @@ public: ~WalletBar(); private slots: - + void rememberData(); void neverRememberData(); void notNowRememberData(); @@ -52,7 +55,7 @@ private slots: public slots: void onSaveFormData(const QString &, const QUrl &); -signals: +signals: void saveFormDataAccepted(const QString &); void saveFormDataRejected(const QString &); @@ -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..31833ea9 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 @@ -35,29 +35,28 @@ // KDE Includes #include "KAction" -#include "KDebug" // Qt Includes #include <QWebInspector> -WebInspectorPanel::WebInspectorPanel(QString title, QWidget *parent) - : QDockWidget(title, parent) +WebInspectorPanel::WebInspectorPanel(QString title, QWidget *parent) + : QDockWidget(title, parent) { setObjectName("webInspectorDock"); - setWidget( new QWebInspector(this) ); + setWidget(new QWebInspector(this)); } - -void WebInspectorPanel::closeEvent(QCloseEvent *event) -{ + +void WebInspectorPanel::closeEvent(QCloseEvent *event) +{ Q_UNUSED(event); toggle(false); } MainWindow* WebInspectorPanel::mainWindow() -{ +{ return qobject_cast< MainWindow* >(parentWidget()); } @@ -79,8 +78,8 @@ void WebInspectorPanel::toggle(bool enable) } -void WebInspectorPanel::changeCurrentPage() -{ +void WebInspectorPanel::changeCurrentPage() +{ bool enable = mainWindow()->currentTab()->view()->settings()->testAttribute(QWebSettings::DeveloperExtrasEnabled); toggle(enable); } diff --git a/src/webinspectorpanel.h b/src/webinspectorpanel.h index 8f65b48a..8b1e3507 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 @@ -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 @@ -28,6 +28,9 @@ #define WEBINSPECTOR_PANEL_H +// Rekonq Includes +#include "rekonq_defines.h" + // Local Includes #include "mainwindow.h" @@ -38,21 +41,21 @@ Docked web inspector behaviour : hide/show by tab, not globally */ -class WebInspectorPanel : public QDockWidget +class REKONQ_TESTS_EXPORT WebInspectorPanel : public QDockWidget { Q_OBJECT public: WebInspectorPanel(QString title, QWidget *parent); - + public slots: void toggle(bool enable); - void changeCurrentPage(); - + void changeCurrentPage(); + protected: virtual void closeEvent(QCloseEvent *event); - + MainWindow *mainWindow(); - + }; #endif diff --git a/src/webpage.cpp b/src/webpage.cpp index b2bedffc..d266b257 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 @@ -14,9 +15,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 @@ -44,10 +45,11 @@ #include "networkaccessmanager.h" #include "adblockmanager.h" +#include "sslinfodialog_p.h" + // KDE Includes #include <KStandardDirs> #include <KUrl> -#include <KDebug> #include <KToolInvocation> #include <KProtocolManager> #include <kwebwallet.h> @@ -69,31 +71,69 @@ #include <QtGui/QClipboard> #include <QtGui/QKeyEvent> +#include <QtWebKit/QWebFrame> + + +// 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... -WebPage::WebPage(QObject *parent) + while (u1List.count() > 2) + u1List.removeFirst(); + + while (u2List.count() > 2) + u2List.removeFirst(); + + return (u1List == u2List); +} + + +// --------------------------------------------------------------------------------- + + +WebPage::WebPage(QWidget *parent) : KWebPage(parent, KWalletIntegration) + , _networkAnalyzer(false) { + // ----- 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); - - // disable QtWebKit cache to just use KIO one.. - manager->setCache(0); - + manager->setCache(0); // disable QtWebKit cache to just use KIO one.. + + // set cookieJar window ID.. + if (parent && parent->window()) + manager->setCookieJarWindowId(parent->window()->winId()); + setNetworkAccessManager(manager); - - // Web Plugin Factory + + // activate ssl warnings + setSessionMetaData("ssl_activate_warnings", "TRUE"); + + // 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()); + + // ----- Web Plugin Factory setPluginFactory(new WebPluginFactory(this)); - - connect(networkAccessManager(), SIGNAL(finished(QNetworkReply*)), this, SLOT(manageNetworkErrors(QNetworkReply*))); - - connect(this, SIGNAL(unsupportedContent(QNetworkReply *)), this, SLOT(handleUnsupportedContent(QNetworkReply *))); + // ----- 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 +145,68 @@ WebPage::~WebPage() bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type) { - // advise users on resubmitting data - if(type == QWebPage::NavigationTypeFormResubmitted) + _loadingUrl = request.url(); + + 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; - m_requestedUrl = request.url(); + 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"); + } + } return KWebPage::acceptNavigationRequest(frame, request, type); } @@ -135,9 +220,9 @@ WebPage *WebPage::createWindow(QWebPage::WebWindowType type) kDebug() << "Modal Dialog"; WebTab *w = 0; - if(ReKonfig::openTabNoWindow()) + if (ReKonfig::openTabNoWindow()) { - w = Application::instance()->mainWindow()->mainView()->newWebTab(!ReKonfig::openTabsBack()); + w = Application::instance()->mainWindow()->mainView()->newWebTab(!ReKonfig::openTabsBack(), ReKonfig::openTabsNearCurrent()); } else { @@ -149,96 +234,160 @@ WebPage *WebPage::createWindow(QWebPage::WebWindowType type) void WebPage::handleUnsupportedContent(QNetworkReply *reply) { + // NOTE + // This is probably needed just in ONE stupid case.. + if (_protHandler.postHandling(reply->request(), mainFrame())) + return; // FIXME RE-ENABLE ME reply->deleteLater(); + if (reply->error() == QNetworkReply::NoError) { - const KUrl url( reply->url() ); + const KUrl url(reply->url()); QString mimeType = reply->header(QNetworkRequest::ContentTypeHeader).toString(); - KService::Ptr offer = KMimeTypeTrader::self()->preferredService(mimeType); + KService::Ptr appService = KMimeTypeTrader::self()->preferredService(mimeType); bool isLocal = url.isLocalFile(); - - if( offer.isNull() ) // no service can handle this. We can just download it.. + + if (appService.isNull()) // no service can handle this. We can just download it.. { - isLocal ? KMessageBox::sorry(view(), i18n("No service can handle this :(") ) : downloadRequest(reply->request()); - return; + 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; // FIXME RE-ENABLE ME reply->deleteLater(); } - if(!isLocal) + if (!isLocal) { - + KParts::BrowserOpenOrSaveQuestion dlg(Application::instance()->mainWindow(), url, mimeType); - switch ( dlg.askEmbedOrSave() ) + switch (dlg.askEmbedOrSave()) { - case KParts::BrowserOpenOrSaveQuestion::Save: - downloadRequested(reply->request()); - return; - case KParts::BrowserOpenOrSaveQuestion::Cancel: - return; - default: // non extant case - break; + case KParts::BrowserOpenOrSaveQuestion::Save: + kDebug() << "service handling: download!"; + downloadRequest(reply->request()); + return; // FIXME RE-ENABLE ME reply->deleteLater(); + + case KParts::BrowserOpenOrSaveQuestion::Cancel: + return; // FIXME RE-ENABLE ME reply->deleteLater(); + + default: // non extant case + break; } } + // case KParts::BrowserRun::Embed - KUrl::List list; - list.append(url); - KRun::run(*offer,url,0); + + KService::List partServices = KMimeTypeTrader::self()->query(mimeType, QL1S("KParts/ReadOnlyPart")); + if (partServices.count() > 0) + { + // A part can handle this. Embed it! + 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); + } + else + { + // No parts, just app services. Load it! + KRun::run(*appService, url, 0); + } + + return ; // FIXME RE-ENABLE ME reply->deleteLater(); } } -void WebPage::loadFinished(bool) +void WebPage::loadFinished(bool ok) { + Q_UNUSED(ok); + 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; + Q_ASSERT(reply); - if(m_protHandler.postHandling( reply->request(), mainFrame() )) - return; + QWebFrame* frame = qobject_cast<QWebFrame *>(reply->request().originatingObject()); + const bool isMainFrameRequest = (frame == mainFrame()); - // don't bother on adblocked urls - if( reply->error() == QNetworkReply::ContentAccessDenied ) - return; - - if( reply->url() != m_requestedUrl ) // prevent favicon loading - return; - - 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::ContentAccessDenied: // access to remote content denied (similar to HTTP error 401) + kDebug() << "We (hopefully) are managing this through the adblock :)"; + break; + + case QNetworkReply::UnknownNetworkError: // unknown network-related error detected + if (_protHandler.postHandling(reply->request(), mainFrame())) + 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 + + if (reply->url() == _loadingUrl) + mainFrame()->setHtml(errorPage(reply), reply->url()); + break; + + default: + kDebug() << "Nothing to do here.."; + break; + } + // FIXME RE-ENABLE ME reply->deleteLater(); } @@ -254,11 +403,21 @@ QString WebPage::errorPage(QNetworkReply *reply) return QString("Couldn't open the rekonqinfo.html file"); } - QString title = i18n("Error loading: %1", reply->url().path()); - QString msg = "<h1>" + reply->errorString() + "</h1>"; - QString urlString = reply->url().toString( QUrl::RemoveUserInfo | QUrl::RemoveQuery ); - - msg += "<h2>" + i18nc("%1=an URL, e.g.'kde.org'", "When connecting to: %1", urlString ) + "</h2>"; + QString title = i18n("Error loading: %1", reply->url().path()); + QString urlString = reply->url().toString(QUrl::RemoveUserInfo | QUrl::RemoveQuery); + + QString iconPath = QString("file://") + KIconLoader::global()->iconPath("dialog-warning" , KIconLoader::Small); + iconPath.replace(QL1S("16"), QL1S("128")); + + QString msg; + msg += "<table>"; + msg += "<tr><td>"; + msg += "<img src=\"" + iconPath + "\" />"; + msg += "</td><td>"; + msg += "<h1>" + reply->errorString() + "</h1>"; + msg += "<h2>" + i18nc("%1=an URL, e.g.'kde.org'", "When connecting to: <b>%1</b>", urlString) + "</h2>"; + msg += "</td></tr></table>"; + msg += "<ul><li>" + i18n("Check the address for errors such as <b>ww</b>.kde.org instead of <b>www</b>.kde.org"); msg += "</li><li>" + i18n("If the address is correct, try to check the network connection.") + "</li><li>" ; msg += i18n("If your computer or network is protected by a firewall or proxy, make sure that rekonq is permitted to access the network."); @@ -266,83 +425,175 @@ QString WebPage::errorPage(QNetworkReply *reply) msg += "</li></ul><br/><br/>"; msg += "<input type=\"button\" id=\"reloadButton\" onClick=\"document.location.href='" + urlString + "';\" value=\""; msg += i18n("Try Again") + "\" />"; - - QString html = QString(QLatin1String(file.readAll())) - .arg(title) - .arg(msg) - ; + + QString html = QString(QL1S(file.readAll())) + .arg(title) + .arg(msg) + ; return html; } +// 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; - KUrl destUrl; - KUrl srcUrl (request.url()); - int result = KIO::R_OVERWRITE; + do + { + destUrl = KFileDialog::getSaveFileName(srcUrl.fileName(), QString(), view()); - do + if (destUrl.isLocalFile()) { - destUrl = KFileDialog::getSaveFileName(srcUrl.fileName(), QString(), view()); - - if (destUrl.isLocalFile()) + QFileInfo finfo(destUrl.toLocalFile()); + if (finfo.exists()) { - 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(); - } + 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()); + } + } + 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 (result == KIO::R_OVERWRITE && destUrl.isValid()) + if (ReKonfig::kgetDownload()) { - //*End of copy code - //KGet integration: - if(!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) + 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, 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); } - else KWebPage::downloadRequest(request); } -void WebPage::downloadAllContentsWithKGet() +void WebPage::downloadAllContentsWithKGet(QPoint) { - 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")) + + if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) { 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(QPoint) +{ + 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") + ); + } +} + + +void WebPage::updateImage(bool ok) +{ + if (ok) + { + NewTabPage p(mainFrame()); + p.snapFinished(); + } +} + + +bool WebPage::hasNetworkAnalyzerEnabled() const +{ + return _networkAnalyzer; +} + + +void WebPage::enableNetworkAnalyzer(bool b) +{ + _networkAnalyzer = b; } diff --git a/src/webpage.h b/src/webpage.h index 9169ad60..74695f35 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 @@ -14,9 +15,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 @@ -32,8 +33,13 @@ #define WEBPAGE_H +// Rekonq Includes +#include "rekonq_defines.h" + // Local Includes #include "protocolhandler.h" +#include "newtabpage.h" +#include "websslinfo.h" // KDE Includes #include <KWebPage> @@ -46,36 +52,43 @@ 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(); + bool hasNetworkAnalyzerEnabled() const; + void enableNetworkAnalyzer(bool); + public slots: - void manageNetworkErrors(QNetworkReply *reply); virtual void downloadRequest(const QNetworkRequest &request); - void downloadAllContentsWithKGet(); + void downloadAllContentsWithKGet(QPoint); + protected: WebPage *createWindow(WebWindowType type); - - virtual bool acceptNavigationRequest(QWebFrame *frame, - const QNetworkRequest &request, + + virtual bool acceptNavigationRequest(QWebFrame *frame, + const QNetworkRequest &request, NavigationType type); - -protected Q_SLOTS: - virtual void handleUnsupportedContent(QNetworkReply *reply); private slots: + void handleUnsupportedContent(QNetworkReply *reply); + void manageNetworkErrors(QNetworkReply *reply); void loadFinished(bool); + void showSSLInfo(QPoint); + void updateImage(bool ok); private: - QString errorPage(QNetworkReply *); + QString errorPage(QNetworkReply *reply); + QUrl _loadingUrl; - QUrl m_requestedUrl; - ProtocolHandler m_protHandler; + ProtocolHandler _protHandler; + WebSslInfo _sslInfo; + + bool _networkAnalyzer; }; #endif diff --git a/src/webpluginfactory.cpp b/src/webpluginfactory.cpp index aec4e18d..fe2f965b 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 @@ -10,9 +11,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 @@ -32,30 +33,20 @@ #include "rekonq.h" #include "application.h" #include "mainwindow.h" -#include "previewimage.h" #include "clicktoflash.h" -// KDE Includes -#include <KDebug> - WebPluginFactory::WebPluginFactory(QObject *parent) - : KWebPluginFactory(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; } @@ -65,62 +56,37 @@ QObject *WebPluginFactory::create(const QString &mimeType, const QStringList &argumentValues) const { kDebug() << "loading mimeType: " << mimeType; - - if(mimeType == QString("application/image-preview") ) - { - 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 + switch (ReKonfig::pluginsEnabled()) { - 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; - } - - 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); -} + default: + kDebug() << "oh oh.. this should NEVER happen.."; + break; + } -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; + return KWebPluginFactory::create(mimeType, url, argumentNames, argumentValues); } diff --git a/src/webpluginfactory.h b/src/webpluginfactory.h index c1e4c28f..c5eefa45 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 @@ -10,9 +11,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 @@ -28,6 +29,9 @@ #define WEB_PLUGIN_FACTORY_H +// Rekonq Includes +#include "rekonq_defines.h" + // KDE Includes #include <KWebPluginFactory> @@ -36,34 +40,30 @@ #include <QtGui/QWidget> -class WebPluginFactory : public KWebPluginFactory +class REKONQ_TESTS_EXPORT WebPluginFactory : public KWebPluginFactory { -Q_OBJECT + 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: void setLoadClickToFlash(bool load); - + 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..aaaed1d5 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 @@ -11,9 +12,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 @@ -29,76 +30,73 @@ #include "websnap.h" #include "websnap.moc" +// Local Includes +#include "newtabpage.h" + // KDE Includes -#include <KDebug> #include <KStandardDirs> // Qt Includes -#include <QSize> -#include <QWebFrame> -#include <QWebSettings> -#include <QPainter> -#include <QTimer> -#include <QFile> +#include <QtCore/QSize> +#include <QtCore/QTimer> +#include <QtCore/QFile> +#include <QtGui/QPainter> -#define WIDTH 200 -#define HEIGHT 150 +#include <QtWebKit/QWebFrame> +#include <QtWebKit/QWebSettings> -WebSnap::WebSnap(const QUrl &url) - : QObject() -{ - m_url = url; +WebSnap::WebSnap(const KUrl& url, QObject *parent) + : QObject(parent) + , m_url(url) +{ // this to not register websnap history m_page.settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, true); - + // this to not let this page open other windows m_page.settings()->setAttribute(QWebSettings::PluginsEnabled, false); 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() -{ + QTimer::singleShot(0, this, SLOT(load())); } - 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) { + // NOTE + // it seems no way to enable/disable scrollbars in new QtWebKit's + // and this is affecting tabbed browsing + // 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::Horizontal, Qt::ScrollBarAlwaysOff); - page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); + QSize oldSize = page.viewportSize(); +// page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); +// page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); // find the best size QSize size; - if (page.viewportSize().width() && page.viewportSize().height()) - { - size = page.viewportSize(); - } - else + int width = page.mainFrame()->contentsSize().width(); + if (width < 640) { - 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); @@ -106,43 +104,60 @@ QPixmap WebSnap::renderPreview(const QWebPage &page,int w, int h) pageImage = pageImage.scaled(w, h, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); // 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); - - return QPixmap::fromImage(pageImage); -} +// page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded); +// page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded); + page.setViewportSize(oldSize); + QPixmap pm = QPixmap::fromImage(pageImage); + KUrl url(page.mainFrame()->url()); + kDebug() << "saving preview"; -void WebSnap::saveResult(bool ok) -{ - // crude error-checking - if (!ok) - { - kDebug() << "Error loading site.."; - return; - } + QString path = imagePathFromUrl(url); + QFile::remove(path); + pm.save(path); - m_image = renderPreview(m_page, WIDTH, HEIGHT); - emit finished(); + return pm; } - -QString WebSnap::snapTitle() +QString WebSnap::imagePathFromUrl(const KUrl &url) { - return m_page.mainFrame()->title(); + QUrl temp = QUrl(url.url()); + QString name = temp.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 KStandardDirs::locateLocal("cache", QString("thumbs/") + name + ".png", true); } -QUrl WebSnap::snapUrl() +void WebSnap::saveResult(bool ok) { - return m_url; + if (ok) + { + QPixmap image = renderPreview(m_page, WIDTH, HEIGHT); + QString path = imagePathFromUrl(m_url); + QFile::remove(path); + image.save(path); + } + + emit snapDone(ok); + kDebug() << "SAVE RESULTS: " << ok << " URL: " << m_url; + + this->deleteLater(); } -QPixmap WebSnap::previewImage() +bool WebSnap::existsImage(const KUrl &u) { - return m_image; + return QFile::exists(imagePathFromUrl(u)); } diff --git a/src/websnap.h b/src/websnap.h index 6c5b4af9..c85dc0d2 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 @@ -11,9 +12,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 @@ -28,48 +29,92 @@ #ifndef WEB_SNAP_H #define WEB_SNAP_H + +// Rekonq Includes +#include "rekonq_defines.h" + // KDE Includes #include <KUrl> // Qt Includes #include <QtCore/QObject> -#include <QPixmap> -#include <QImage> -#include <QWebPage> + +#include <QtGui/QPixmap> + +#include <QtWebKit/QWebPage> + +// Defines +#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 AND save an image) + * - PreviewSelector class: to save new favorite selection (given a page, you show AND save an image) + * + * - NewTabPage class: to show the favorites page "preview" (given an url, 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); - - QString snapTitle(); - QUrl snapUrl(); + /** + * Creates a WebSnap object. It will load the url in one WebPage + * and snap an image from it. + * + * @param url the url to load + * @param parent the object parent + */ + explicit WebSnap(const KUrl &url, QObject *parent = 0); + + /** + * Snaps a pixmap of size w * h from a page and save it to cache + * + * @param page the page to snap + * @param w the image width + * @param h the image height + * + * @return the pixmap snapped from the page + */ + static QPixmap renderPreview(const QWebPage &page, int w = WIDTH, int h = HEIGHT); + + /** + * Guess the local path where the image for the url provided + * should be + * + * @param url the url to guess snap path + * + * @return the local path of the url snap + */ + static QString imagePathFromUrl(const KUrl &url); + + /** + * Determines if a snap exists for that url + * + */ + static bool existsImage(const KUrl &url); -signals: - void finished(); private slots: + void saveResult(bool ok = true); void load(); - void saveResult(bool ok); + +signals: + void snapDone(bool ok); private: QWebPage m_page; - QPixmap m_image; - - QUrl m_url; - QString m_snapTitle; + KUrl m_url; }; #endif // WEB_SNAP_H diff --git a/src/websslinfo.cpp b/src/websslinfo.cpp new file mode 100644 index 00000000..35112504 --- /dev/null +++ b/src/websslinfo.cpp @@ -0,0 +1,214 @@ +/* + * 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..4ac708cc --- /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..d8fff875 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 @@ -11,9 +11,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 @@ -39,6 +39,8 @@ #include "webpage.h" #include "bookmarksmanager.h" #include "walletbar.h" +#include "previewselectorbar.h" +#include "rsswidget.h" // KDE Includes #include <KService> @@ -48,73 +50,87 @@ #include <KActionMenu> #include <KWebView> #include <kwebwallet.h> +#include <KDE/KMessageBox> // Qt Includes -#include <QContextMenuEvent> -#include <QWheelEvent> -#include <QMouseEvent> -#include <QClipboard> -#include <QKeyEvent> -#include <QAction> -#include <QVBoxLayout> - - -WebTab::WebTab(QWidget* parent) - : QWidget(parent) - , m_view( new WebView(this) ) - , m_progress(0) +#include <QtGui/QContextMenuEvent> +#include <QtGui/QWheelEvent> +#include <QtGui/QMouseEvent> +#include <QtGui/QClipboard> +#include <QtGui/QKeyEvent> +#include <QtGui/QVBoxLayout> + + +WebTab::WebTab(QWidget *parent) + : QWidget(parent) + , _view(new WebView(this)) + , m_progress(0) { - QVBoxLayout* l = new QVBoxLayout(this); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QVBoxLayout *l = new QVBoxLayout(this); l->setMargin(0); l->setSpacing(0); - QWidget* messageBar = new QWidget(this); - l->addWidget(messageBar); - messageBar->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Minimum); + l->addWidget(_view); + _view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - QVBoxLayout* l2 = new QVBoxLayout(messageBar); - l2->setMargin(0); - l2->setSpacing(0); + // fix focus handling + setFocusProxy(_view); - l->addWidget(m_view); - m_view->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); - - KWebWallet *wallet = page()->wallet(); - - if(wallet) + KWebWallet *wallet = _view->page()->wallet(); + + if (wallet) { connect(wallet, SIGNAL(saveFormDataRequested(const QString &, const QUrl &)), 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; + return _view; } WebPage *WebTab::page() { - return m_view->page(); // FIXME + return view()->page(); } -KUrl WebTab::url() const -{ - return KUrl(m_view->url()); +// TODO: +// Import the "about" check and the one in protocolhandler +// in some (static?) methods in NewTabPage +KUrl WebTab::url() +{ + KUrl u = KUrl(view()->url()); + if (u.scheme() == QL1S("about")) + { + QWebElement rootElement = page()->mainFrame()->documentElement(); + if (rootElement.document().findAll("#rekonq-newtabpage").count() == 0) + return u; + if (rootElement.findAll(".favorites").count() > 0) + return KUrl("about:favorites"); + if (rootElement.findAll(".closedTabs").count() > 0) + return KUrl("about:closedTabs"); + if (rootElement.findAll(".history").count() > 0) + return KUrl("about:history"); + if (rootElement.findAll(".bookmarks").count() > 0) + return KUrl("about:bookmarks"); + if (rootElement.findAll(".downloads").count() > 0) + return KUrl("about:downloads"); + } + return u; } @@ -124,18 +140,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,16 +153,77 @@ void WebTab::loadFinished(bool) void WebTab::createWalletBar(const QString &key, const QUrl &url) -{ - KWebWallet *wallet = page()->wallet(); - QWidget *messageBar = layout()->itemAt(0)->widget(); +{ + // check if the url is in the wallet blacklist + QString urlString = url.toString(); + QStringList blackList = ReKonfig::walletBlackList(); + if (blackList.contains(urlString)) + return; - WalletBar *walletBar = new WalletBar(messageBar); - walletBar->onSaveFormData(key,url); - messageBar->layout()->addWidget(walletBar); + KWebWallet *wallet = page()->wallet(); + WalletBar *walletBar = new WalletBar(this); + walletBar->onSaveFormData(key, url); + qobject_cast<QVBoxLayout *>(layout())->insertWidget(0, walletBar); connect(walletBar, SIGNAL(saveFormDataAccepted(const QString &)), wallet, SLOT(acceptSaveFormDataRequest(const QString &))); connect(walletBar, SIGNAL(saveFormDataRejected(const QString &)), wallet, SLOT(rejectSaveFormDataRequest(const QString &))); } + + +void WebTab::createPreviewSelectorBar(int index) +{ + PreviewSelectorBar *bar = new PreviewSelectorBar(index, this); + qobject_cast<QVBoxLayout *>(layout())->insertWidget(0, 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() +{ + QWebElementCollection col = page()->mainFrame()->findAllElements("link[type=\"application/rss+xml\"]"); + col.append(page()->mainFrame()->findAllElements("link[type=\"application/atom+xml\"]")); + if (col.count() != 0) + return true; + + return false; +} + + +void WebTab::showRSSInfo(QPoint pos) +{ + QWebElementCollection col = page()->mainFrame()->findAllElements("link[type=\"application/rss+xml\"]"); + col.append(page()->mainFrame()->findAllElements("link[type=\"application/atom+xml\"]")); + + QMap<KUrl, QString> map; + + foreach(QWebElement el, col) + { + QString urlString; + if (el.attribute("href").startsWith(QL1S("http"))) + urlString = 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"))) + urlString = u.toMimeDataString(); + } + + QString title = el.attribute("title"); + if (title.isEmpty()) + title = el.attribute("href"); + + map.insert(KUrl(urlString), title); + } + + RSSWidget *widget = new RSSWidget(map, window()); + widget->showAt(pos); +} diff --git a/src/webtab.h b/src/webtab.h index ecf8e5b3..309ecd9a 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 @@ -11,9 +11,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 @@ -29,16 +29,21 @@ #define WEBTAB_H +// Rekonq Includes +#include "rekonq_defines.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(QPoint pos); + private: - WebView *const m_view; + WebView *_view; + int m_progress; - QString m_statusBarText; }; #endif diff --git a/src/webview.cpp b/src/webview.cpp index 3936ed3c..e7226740 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 @@ -11,9 +11,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 @@ -37,6 +37,7 @@ #include "mainview.h" #include "webpage.h" #include "bookmarksmanager.h" +#include "searchengine.h" // KDE Includes #include <KService> @@ -47,45 +48,64 @@ #include <ktoolinvocation.h> // Qt Includes -#include <QContextMenuEvent> -#include <QWheelEvent> -#include <QMouseEvent> -#include <QClipboard> -#include <QKeyEvent> -#include <QAction> -#include <QLayout> +#include <QtCore/QDir> + +#include <QtGui/QAction> +#include <QtGui/QContextMenuEvent> +#include <QtGui/QWheelEvent> +#include <QtGui/QMouseEvent> +#include <QtGui/QClipboard> +#include <QtGui/QKeyEvent> +#include <QtGui/QLayout> + #include <QtDBus/QDBusConnectionInterface> #include <QtDBus/QDBusInterface> #include <QtDBus/QDBusReply> -#include <QDir> WebView::WebView(QWidget* parent) - : KWebView(parent, false) - , m_page( new WebPage(this) ) - , m_mousePos(QPoint(0,0)) + : KWebView(parent, false) + , _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 &))); - + connect(this, SIGNAL(linkShiftClicked(const KUrl &)), + 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 &)), - this, SLOT(loadUrlInNewTab(const KUrl &)) ); + connect(this, SIGNAL(linkMiddleOrCtrlClicked(const KUrl &)), + this, SLOT(loadUrlInNewTab(const KUrl &))); // loadUrl signal - connect(this, SIGNAL(loadUrl(const KUrl &, const Rekonq::OpenType &)), + 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; } @@ -111,7 +131,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) connect(a, SIGNAL(triggered(bool)), this, SLOT(openLinkInNewWindow())); menu.addAction(a); - menu.addAction(pageAction(KWebPage::DownloadLinkToDisk)); + menu.addAction(pageAction(KWebPage::DownloadLinkToDisk)); menu.addAction(pageAction(KWebPage::CopyLinkToClipboard)); menu.addSeparator(); } @@ -124,10 +144,10 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) } // is content selected) Add COPY - if(result.isContentSelected()) + if (result.isContentSelected()) { a = pageAction(KWebPage::Copy); - if(!result.linkUrl().isEmpty()) + if (!result.linkUrl().isEmpty()) a->setText(i18n("Copy Text")); //for link else a->setText(i18n("Copy")); @@ -135,41 +155,23 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) } // is content editable? Add PASTE - if(result.isContentEditable()) + if (result.isContentEditable()) { menu.addAction(pageAction(KWebPage::Paste)); } // is content selected? Add SEARCH actions - if(result.isContentSelected()) + if (result.isContentSelected()) { KActionMenu *searchMenu = new KActionMenu(KIcon("edit-find"), i18n("Search with"), this); - KConfig config("kuriikwsfilterrc"); //Share with konqueror - KConfigGroup cg = config.group("General"); - QStringList favoriteEngines; - favoriteEngines << "wikipedia" << "google"; //defaults - favoriteEngines = cg.readEntry("FavoriteSearchEngines", favoriteEngines); - QString keywordDelimiter = cg.readEntry("KeywordDelimiter", ":"); - KService::Ptr service; - KUriFilterData data; - - Q_FOREACH(const QString &engine, favoriteEngines) + foreach(KService::Ptr engine, SearchEngine::favorites()) { - if(!engine.isEmpty()) - { - service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(engine)); - if(service) - { - 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->setData(searchProviderPrefix); - connect(a, SIGNAL(triggered(bool)), this, SLOT(search())); - searchMenu->addAction(a); - } - } + a = new KAction(engine->name(), this); + a->setIcon(Application::icon(SearchEngine::buildQuery(engine, ""))); + a->setData(engine->entryPath()); + connect(a, SIGNAL(triggered(bool)), this, SLOT(search())); + searchMenu->addAction(a); } if (!searchMenu->menu()->isEmpty()) @@ -178,7 +180,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) } menu.addSeparator(); - // TODO Add translate, show translation + // TODO Add translate, show translation } // is an image? @@ -186,7 +188,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) { menu.addSeparator(); - // TODO remove copy_this_image action + // TODO remove copy_this_image action a = new KAction(KIcon("view-media-visualization"), i18n("&View Image"), this); a->setData(result.imageUrl()); connect(a, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)), this, SLOT(viewImage(Qt::MouseButtons, Qt::KeyboardModifiers))); @@ -198,13 +200,13 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) } // Open url text in new tab/window - if(result.linkUrl().isEmpty()) + if (result.linkUrl().isEmpty()) { - QString text = selectedText(); - if (text.startsWith( QLatin1String("http://") ) - || text.startsWith( QLatin1String("https://") ) - || text.startsWith( QLatin1String("www.") ) + QString text = selectedText(); + if (text.startsWith(QL1S("http://")) + || text.startsWith(QL1S("https://")) + || text.startsWith(QL1S("www.")) ) { QString truncatedURL = text; @@ -237,23 +239,23 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) // navigation QWebHistory *history = page()->history(); - if(history->canGoBack()) + if (history->canGoBack()) { menu.addAction(pageAction(KWebPage::Back)); } - if(history->canGoForward()) + if (history->canGoForward()) { menu.addAction(pageAction(KWebPage::Forward)); } menu.addAction(mainwindow->actionByName("view_redisplay")); - if( result.pixmap().isNull() ) + if (result.pixmap().isNull()) { menu.addSeparator(); - menu.addAction(mainwindow->actionByName("new_tab")); + menu.addAction(mainwindow->actionByName("new_tab")); menu.addAction(mainwindow->actionByName("new_window")); menu.addSeparator(); @@ -263,14 +265,14 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) frameMenu->addAction(pageAction(KWebPage::OpenFrameInNewWindow)); - a = new KAction( KIcon("document-print-frame"), i18n("Print Frame"), this); + a = new KAction(KIcon("document-print-frame"), i18n("Print Frame"), this); connect(a, SIGNAL(triggered()), this, SLOT(printFrame())); frameMenu->addAction(a); menu.addAction(frameMenu); - + menu.addSeparator(); - + // Page Actions menu.addAction(pageAction(KWebPage::SelectAll)); @@ -278,22 +280,22 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) if (ReKonfig::kgetList()) { - a = new KAction(KIcon("kget"), i18n("List all links"), this); + a = new KAction(KIcon("kget"), i18n("List All Links"), this); connect(a, SIGNAL(triggered(bool)), page(), SLOT(downloadAllContentsWithKGet())); menu.addAction(a); } menu.addAction(mainwindow->actionByName("page_source")); - - a = new KAction( KIcon("layer-visible-on"), i18n("Inspect Element"), this); + + a = new KAction(KIcon("layer-visible-on"), i18n("Inspect Element"), this); connect(a, SIGNAL(triggered(bool)), this, SLOT(inspect())); menu.addAction(a); - + a = Application::bookmarkProvider()->actionByName("rekonq_add_bookmark"); menu.addAction(a); } - if(mainwindow->isFullScreen()) + if (mainwindow->isFullScreen()) { menu.addSeparator(); menu.addAction(mainwindow->actionByName("fullscreen")); @@ -306,33 +308,69 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) void WebView::mousePressEvent(QMouseEvent *event) { - switch(event->button()) + 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: + case Qt::XButton1: triggerPageAction(KWebPage::Back); break; - case Qt::XButton2: + + case Qt::XButton2: triggerPageAction(KWebPage::Forward); break; - default: - KWebView::mousePressEvent(event); + + case Qt::MidButton: + if (_canEnableAutoScroll && !_isAutoScrollEnabled) + { + setCursor(KIcon("transform-move").pixmap(32)); + _clickPos = event->pos(); + _isAutoScrollEnabled = true; + } + break; + + default: 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) + { + if (event->pos().y() >= 0 && event->pos().y() <= 4) { - Application::instance()->mainWindow()->setWidgetsVisible(true); + Application::instance()->mainWindow()->setWidgetsVisible(true); } else { - Application::instance()->mainWindow()->setWidgetsVisible(false); + Application::instance()->mainWindow()->setWidgetsVisible(false); } } KWebView::mouseMoveEvent(event); @@ -341,16 +379,16 @@ void WebView::mouseMoveEvent(QMouseEvent *event) QPoint WebView::mousePos() { - return m_mousePos; + return _mousePos; } void WebView::search() { KAction *a = qobject_cast<KAction*>(sender()); - QString search = a->data().toString() + selectedText(); - KUrl urlSearch = KUrl::fromEncoded(search.toUtf8()); - + KService::Ptr engine = KService::serviceByDesktopPath(a->data().toString()); + KUrl urlSearch = KUrl(SearchEngine::buildQuery(engine, selectedText())); + emit loadUrl(urlSearch, Rekonq::NewCurrentTab); } @@ -381,7 +419,7 @@ void WebView::openLinkInNewWindow() { KAction *a = qobject_cast<KAction*>(sender()); KUrl url(a->data().toUrl()); - + emit loadUrl(url, Rekonq::NewWindow); } @@ -390,25 +428,80 @@ void WebView::openLinkInNewTab() { KAction *a = qobject_cast<KAction*>(sender()); KUrl url(a->data().toUrl()); - + emit loadUrl(url, Rekonq::SettingOpenTab); } 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->key() == Qt::Key_A) + { + triggerPageAction(KWebPage::SelectAll); + return; + } } - if ((event->modifiers() == Qt::ControlModifier) && (event->key() == Qt::Key_A)) + 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); } @@ -416,8 +509,9 @@ void WebView::keyPressEvent(QKeyEvent *event) void WebView::inspect() { QAction *a = Application::instance()->mainWindow()->actionByName("web_inspector"); - if(a && !a->isChecked()) + if (a && !a->isChecked()) a->trigger(); + pageAction(QWebPage::InspectElement)->trigger(); } @@ -425,3 +519,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..71e3047f 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 @@ -11,9 +11,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 @@ -28,8 +28,9 @@ #ifndef WEBVIEW_H #define WEBVIEW_H -// Local Includes -#include "application.h" + +// Rekonq Includes +#include "rekonq_defines.h" // KDE Includes #include <KWebView> @@ -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); @@ -63,16 +64,24 @@ private slots: void loadUrlInNewTab(const KUrl &); void openLinkInNewWindow(); void openLinkInNewTab(); - + 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 |