diff options
author | Andrea Diamantini <adjam7@gmail.com> | 2012-08-01 17:46:50 +0200 |
---|---|---|
committer | Andrea Diamantini <adjam7@gmail.com> | 2012-12-10 02:48:04 +0100 |
commit | d2fdce46263a6cee66c4adee9ea7366d085a1729 (patch) | |
tree | c50747e1d05bc43dddd1fef2b651a6f1a37cd81a | |
parent | Remove a lot of application calls by refactoring code (diff) | |
download | rekonq-d2fdce46263a6cee66c4adee9ea7366d085a1729.tar.xz |
Urlbar, first code ported to the new API
-rw-r--r-- | src/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/urlbar/bookmarkwidget.cpp | 363 | ||||
-rw-r--r-- | src/urlbar/bookmarkwidget.h | 101 | ||||
-rw-r--r-- | src/urlbar/completionwidget.cpp | 402 | ||||
-rw-r--r-- | src/urlbar/completionwidget.h | 93 | ||||
-rw-r--r-- | src/urlbar/favoritewidget.cpp | 115 | ||||
-rw-r--r-- | src/urlbar/favoritewidget.h | 58 | ||||
-rw-r--r-- | src/urlbar/listitem.cpp | 664 | ||||
-rw-r--r-- | src/urlbar/listitem.h | 291 | ||||
-rw-r--r-- | src/urlbar/rsswidget.cpp | 165 | ||||
-rw-r--r-- | src/urlbar/rsswidget.h | 61 | ||||
-rw-r--r-- | src/urlbar/sslwidget.cpp | 251 | ||||
-rw-r--r-- | src/urlbar/sslwidget.h | 58 | ||||
-rw-r--r-- | src/urlbar/urlbar.cpp | 776 | ||||
-rw-r--r-- | src/urlbar/urlbar.h | 156 | ||||
-rw-r--r-- | src/urlbar/urlsuggester.cpp | 397 | ||||
-rw-r--r-- | src/urlbar/urlsuggester.h | 155 | ||||
-rw-r--r-- | src/urlbar/webshortcutwidget.cpp | 163 | ||||
-rw-r--r-- | src/urlbar/webshortcutwidget.h | 76 | ||||
-rw-r--r-- | src/webtab/webtab.cpp | 18 | ||||
-rw-r--r-- | src/webtab/webtab.h | 3 |
21 files changed, 4376 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 35bbe67e..0a2fa6ef 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,6 +67,16 @@ set(rekonq_KDEINIT_SRCS tabwindow/tabpreviewpopup.cpp tabwindow/tabwindow.cpp #---------------------------------------- + urlbar/urlbar.cpp + urlbar/completionwidget.cpp + urlbar/listitem.cpp + urlbar/rsswidget.cpp + urlbar/sslwidget.cpp + urlbar/bookmarkwidget.cpp + urlbar/webshortcutwidget.cpp + urlbar/favoritewidget.cpp + urlbar/urlsuggester.cpp + #---------------------------------------- useragent/useragentinfo.cpp useragent/useragentmanager.cpp useragent/useragentwidget.cpp diff --git a/src/urlbar/bookmarkwidget.cpp b/src/urlbar/bookmarkwidget.cpp new file mode 100644 index 00000000..1a69c052 --- /dev/null +++ b/src/urlbar/bookmarkwidget.cpp @@ -0,0 +1,363 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 by Yoann Laissus <yoann dot laissus at gmail dot com> +* Copyright (C) 2012 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (c) 2011-2012 by Phaneendra Hegde <pnh.pes@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/>. +* +* ============================================================ */ + + +// Auto Includes +#include "bookmarkwidget.h" +#include "bookmarkwidget.moc" + +// Local includes +#include "bookmarkmanager.h" +#include "bookmarkowner.h" + +// KDE Includes +#include <KComboBox> +#include <KLocalizedString> +#include <KIcon> +#include <KLineEdit> +#include <KRatingWidget> + +// Qt Includes +#include <QDialogButtonBox> +#include <QFormLayout> +#include <QLabel> +#include <QPushButton> +#include <QCompleter> +#include <QTextCursor> +#include <QDBusConnection> +#include <QDBusConnectionInterface> + +// Nepomuk config include +#include "config-nepomuk.h" + +#ifdef HAVE_NEPOMUK +// Local Nepomuk Includes +#include "resourcelinkdialog.h" + +//Nepomuk Includes +#include <Soprano/Vocabulary/NAO> +#endif + + + +BookmarkWidget::BookmarkWidget(const KBookmark &bookmark, QWidget *parent) + : QMenu(parent) + , m_bookmark(new KBookmark(bookmark)) +{ + setAttribute(Qt::WA_DeleteOnClose); + setFixedWidth(320); + +#ifdef HAVE_NEPOMUK + m_nfoResource = (QUrl)m_bookmark->url(); + m_isNepomukEnabled = QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.NepomukServer"); + kDebug() << "IS NEPOMUK ACTUALLY RUNNING? " << m_isNepomukEnabled; +#endif + + QFormLayout *layout = new QFormLayout(this); + layout->setHorizontalSpacing(20); + + // Title + QHBoxLayout *hLayout = new QHBoxLayout; + QLabel *bookmarkInfo = new QLabel(this); + bookmarkInfo->setText(i18n(" Bookmark")); + QFont f = bookmarkInfo->font(); + f.setBold(true); + bookmarkInfo->setFont(f); + + // Remove button + QLabel *removeLabel = new QLabel(this); + removeLabel->setText(i18n("<a href='Remove'>Remove</a>")); + removeLabel->setAlignment(Qt::AlignRight); + hLayout->addWidget(bookmarkInfo); + hLayout->addWidget(removeLabel); + layout->addRow(hLayout); + + connect(removeLabel, SIGNAL(linkActivated(QString)), this, SLOT(removeBookmark())); + + //Bookmark Folder + QLabel *folderLabel = new QLabel(this); + folderLabel->setText(i18n("Folder:")); + + m_folder = new KComboBox(this); + layout->addRow(folderLabel, m_folder); + setupFolderComboBox(); + + // Bookmark name + QLabel *nameLabel = new QLabel(this); + nameLabel->setText(i18n("Name:")); + m_name = new KLineEdit(this); + if (m_bookmark->isNull()) + { + m_name->setEnabled(false); + } + else + { + m_name->setText(m_bookmark->text()); + m_name->setFocus(); + } + layout->addRow(nameLabel, m_name); + +#ifdef HAVE_NEPOMUK + + if (m_isNepomukEnabled) + { + QLabel* rateLabel = new QLabel(this); + rateLabel->setText(i18n("Rate:")); + KRatingWidget *ratingWidget = new KRatingWidget(this); + if (m_nfoResource.rating() != 0) + { + ratingWidget->setRating(m_nfoResource.rating()); + } + connect(ratingWidget, SIGNAL(ratingChanged(int)), this, SLOT(setRatingSlot(int))); + ratingWidget->setToolTip(i18n("Rate this page")); + layout->addRow(rateLabel, ratingWidget); + + //Add comments + QLabel *commentLabel = new QLabel(this); + commentLabel->setText(i18n("Describe:")); + commentLabel->setAlignment(Qt::AlignCenter); + m_commentEdit = new QPlainTextEdit(this); + if (!m_nfoResource.description().isEmpty()) + { + m_commentEdit->setPlainText(m_nfoResource.description()); + } + connect(m_commentEdit, SIGNAL(textChanged()), this, SLOT(addCommentSlot())); + layout->addRow(commentLabel, m_commentEdit); + + // Create tags + QLabel *tagLabel = new QLabel(this); + tagLabel->setText(i18n("Tags:")); + tagLabel->setAlignment(Qt::AlignLeft); + m_tagLine = new KLineEdit(this); + m_tagLine->setPlaceholderText(i18n("add tags(comma separated)")); + + + QList<Nepomuk::Tag> tagList = Nepomuk::Tag::allTags(); + Q_FOREACH(Nepomuk::Tag t, tagList) + { + m_tList.append(t.label()); + } + QCompleter *completeTag = new QCompleter(m_tList); + completeTag->setCompletionMode(QCompleter::PopupCompletion); + m_tagLine->setCompleter(completeTag); + loadTags(); + + layout->addRow(tagLabel, m_tagLine); + + QPushButton *linkToResource = new QPushButton(this); + linkToResource->setText(i18n("Link Resources")); + connect(linkToResource, SIGNAL(clicked()), this, SLOT(linkToResourceSlot())); + layout->addWidget(linkToResource); + } + else + { + QLabel *nepomukLabel = new QLabel(this); + QPalette p = nepomukLabel->palette(); + p.setColor(QPalette::WindowText, Qt::red); + nepomukLabel->setPalette(p); + nepomukLabel->setText(i18n("Nepomuk is actually disabled.")); + layout->addWidget(nepomukLabel); + } +#endif + + // Ok & Cancel buttons + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); + layout->addWidget(buttonBox); +} + + +BookmarkWidget::~BookmarkWidget() +{ + delete m_bookmark; +} + + +void BookmarkWidget::showAt(const QPoint &pos) +{ + adjustSize(); + + QPoint p(pos.x() - width(), pos.y() + 10); + move(p); + show(); +} + + +void BookmarkWidget::accept() +{ + if (!m_bookmark->isNull() && m_name->text() != m_bookmark->fullText()) + { + m_bookmark->setFullText(m_name->text()); + BookmarkManager::self()->emitChanged(); + } + QString folderAddress = m_folder->itemData(m_folder->currentIndex()).toString(); + KBookmarkGroup a = BookmarkManager::self()->manager()->findByAddress(folderAddress).toGroup(); + + KBookmarkGroup parent = m_bookmark->parentGroup(); + parent.deleteBookmark(*m_bookmark); + a.addBookmark(*m_bookmark); + BookmarkManager::self()->manager()->emitChanged(a); + +#ifdef HAVE_NEPOMUK + if (m_isNepomukEnabled) + { + parseTags(); + } +#endif + + close(); +} + + +void BookmarkWidget::setupFolderComboBox() +{ + KBookmarkGroup root = BookmarkManager::self()->manager()->toolbar(); + + if (BookmarkManager::self()->manager()->toolbar().address() == BookmarkManager::self()->manager()->root().address()) + { + m_folder->addItem(i18n("Bookmark Toolbar"), + BookmarkManager::self()->manager()->toolbar().address()); + } + else + { + m_folder->addItem(BookmarkManager::self()->manager()->toolbar().text(), + BookmarkManager::self()->manager()->toolbar().address()); + } + m_folder->insertSeparator(1); + + if (m_bookmark->parentGroup().address() != BookmarkManager::self()->manager()->toolbar().address()) + { + m_folder->addItem(m_bookmark->parentGroup().text(), + m_bookmark->parentGroup().address()); + m_folder->insertSeparator(3); + } + + for (KBookmark bookmark = root.first(); !bookmark.isNull(); bookmark = root.next(bookmark)) + { + if (bookmark.isGroup()) + { + m_folder->addItem(bookmark.text(), bookmark.address()); + } + } + + if (m_bookmark->parentGroup().address() == root.address()) + { + m_folder->setCurrentIndex(0); + } + else + { + int index = m_folder->findText(m_bookmark->parentGroup().text()); + m_folder->setCurrentIndex(index); + } +} + + +void BookmarkWidget::removeBookmark() +{ + BookmarkManager::self()->owner()->deleteBookmark(*m_bookmark); + close(); + + emit updateIcon(); +} + + +#ifdef HAVE_NEPOMUK +void BookmarkWidget::addTags(QList<Nepomuk::Tag> tagList) +{ + Q_FOREACH(const Nepomuk::Tag & tag, tagList) + { + if (!m_nfoResource.tags().contains(tag)) + { + m_nfoResource.addTag(tag); + } + } + Q_FOREACH(Nepomuk::Tag tag, m_nfoResource.tags()) + { + if (!tagList.contains(tag)) + { + tag.remove(); + } + } +} + +void BookmarkWidget::parseTags() +{ + QList<Nepomuk::Tag> tagList; + if (m_tagLine->text().contains(',')) + { + QString text = m_tagLine->text(); + QStringList tagStringList = text.split(QChar::fromAscii(',')); + + Q_FOREACH(const QString & tag, tagStringList) + { + QString trimmedTag = tag.trimmed(); + if (!trimmedTag.isEmpty()) + tagList << trimmedTag; + } + } + else + { + tagList << m_tagLine->text().trimmed(); + } + addTags(tagList); +} + + +void BookmarkWidget::loadTags() +{ + QString list; + if (!m_nfoResource.tags().isEmpty()) + { + Q_FOREACH(const Nepomuk::Tag & tag, m_nfoResource.tags()) + { + list.append(tag.genericLabel()); + list.append(","); + } + m_tagLine->setText(list); + } +} + + +void BookmarkWidget::setRatingSlot(int rate) +{ + m_nfoResource.setRating(rate); +} + + +void BookmarkWidget::addCommentSlot() +{ + m_nfoResource.setDescription(m_commentEdit->toPlainText()); +} + + +void BookmarkWidget::linkToResourceSlot() +{ + Nepomuk::ResourceLinkDialog r(m_nfoResource); + r.exec(); +} +#endif diff --git a/src/urlbar/bookmarkwidget.h b/src/urlbar/bookmarkwidget.h new file mode 100644 index 00000000..e5f25d37 --- /dev/null +++ b/src/urlbar/bookmarkwidget.h @@ -0,0 +1,101 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 by Yoann Laissus <yoann dot laissus at gmail dot com> +* Copyright (C) 2012 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (c) 2011-2012 by Phaneendra Hegde <pnh.pes@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 BOOKMARKWIDGET_H +#define BOOKMARKWIDGET_H + +// Qt Includes +#include <QMenu> +#include <QGridLayout> +#include <QPlainTextEdit> + +// Nepomuk config include +#include "config-nepomuk.h" + +#ifdef HAVE_NEPOMUK + +// Nepomuk Includes +#include <Nepomuk/Resource> +#include <Nepomuk/Tag> +#include <Nepomuk/Vocabulary/NFO> + +#endif + +// Forward Declarations +class KBookmark; +class KLineEdit; +class KComboBox; + + +class BookmarkWidget : public QMenu +{ + Q_OBJECT + +public: + explicit BookmarkWidget(const KBookmark &bookmark, QWidget *parent = 0); + virtual ~BookmarkWidget(); + + void showAt(const QPoint &pos); + +#ifdef HAVE_NEPOMUK + void addTags(QList<Nepomuk::Tag>); + void parseTags(); + void loadTags(); +#endif + +Q_SIGNALS: + void updateIcon(); + +private: + void setupFolderComboBox(); + +private Q_SLOTS: + void accept(); + void removeBookmark(); + +#ifdef HAVE_NEPOMUK + void setRatingSlot(int rate); + void addCommentSlot(); + void linkToResourceSlot(); +#endif + +private: + KBookmark *m_bookmark; + KLineEdit *m_name; + KComboBox *m_folder; + KLineEdit *m_tagLine; + QPlainTextEdit *m_commentEdit; + QStringList m_tList; + +#ifdef HAVE_NEPOMUK + Nepomuk::Resource m_nfoResource; + bool m_isNepomukEnabled; +#endif +}; + +#endif diff --git a/src/urlbar/completionwidget.cpp b/src/urlbar/completionwidget.cpp new file mode 100644 index 00000000..5ef65fd9 --- /dev/null +++ b/src/urlbar/completionwidget.cpp @@ -0,0 +1,402 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009-2012 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 "searchengine.h" + +#include "listitem.h" +#include "urlbar.h" + +// KDE Includes +#include <KGlobalSettings> +#include <KUrl> + +// Qt Includes +#include <QApplication> +#include <QPoint> +#include <QSize> +#include <QEvent> + +#include <QVBoxLayout> +#include <QKeyEvent> + + + +CompletionWidget::CompletionWidget(QWidget *parent) + : QFrame(parent, Qt::ToolTip) + , _parent(parent) + , _currentIndex(0) + , _hasSuggestions(false) +{ + setFrameStyle(QFrame::Panel); + setLayoutDirection(Qt::LeftToRight); + QVBoxLayout *layout = new QVBoxLayout; + layout->setMargin(0); + layout->setSpacing(0); + setLayout(layout); +} + + +void CompletionWidget::insertItems(const UrlSuggestionList &list, const QString& text, int offset) +{ + Q_FOREACH(const UrlSuggestionItem & item, list) + { + ListItem *suggestion = ListItemFactory::create(item, text, this); + suggestion->setBackgroundRole(offset % 2 ? QPalette::AlternateBase : QPalette::Base); + connect(suggestion, + SIGNAL(itemClicked(ListItem*, Qt::MouseButton, Qt::KeyboardModifiers)), + this, + SLOT(itemChosen(ListItem*, Qt::MouseButton, Qt::KeyboardModifiers))); + connect(suggestion, SIGNAL(updateList()), this, SLOT(updateList())); + connect(this, SIGNAL(nextItemSubChoice()), suggestion, SLOT(nextItemSubChoice())); + + suggestion->setObjectName(QString::number(offset++)); + layout()->addWidget(suggestion); + } +} + + +void CompletionWidget::updateSuggestionList(const UrlSuggestionList &list, const QString& text) +{ + if (_hasSuggestions || _typedString != text) + return; + _hasSuggestions = true; + + if (_resList.count() > 0) + { + clear(); + + insertItems(_resList, text); + _list = _resList; + + UrlSuggestionList sugList = list.mid(0, 4); + insertItems(sugList, text, _list.count()); + _list.append(sugList); + popup(); + } +} + + +void CompletionWidget::sizeAndPosition() +{ + setFixedWidth(_parent->width()); + + int h = 0; + for (int i = 0; i < layout()->count(); i++) + { + QWidget *widget = layout()->itemAt(i)->widget(); + h += widget->sizeHint().height(); + } + setFixedSize(_parent->width(), h + 5); + + // position + QPoint p = _parent->mapToGlobal(QPoint(0, 0)); + move(p.x(), p.y() + _parent->height()); +} + + +void CompletionWidget::popup() +{ + findChild<ListItem *>(QString::number(0))->activate(); //activate first listitem + sizeAndPosition(); + if (!isVisible()) + show(); +} + + +void CompletionWidget::up() +{ + if (_currentIndex >= 0) + findChild<ListItem *>(QString::number(_currentIndex))->deactivate(); // deactivate previous + + --_currentIndex; + if (_currentIndex < -1) + { + _currentIndex = _list.count() - 1; + } + + activateCurrentListItem(); +} + + +void CompletionWidget::down() +{ + if (_currentIndex >= 0) + findChild<ListItem *>(QString::number(_currentIndex))->deactivate(); // deactivate previous + + ++_currentIndex; + if (_currentIndex == _list.count()) + _currentIndex = -1; + + activateCurrentListItem(); +} + + +void CompletionWidget::activateCurrentListItem() +{ + UrlBar *bar = qobject_cast<UrlBar *>(_parent); + + // activate "new" current + ListItem *widget = findChild<ListItem *>(QString::number(_currentIndex)); + + // update text of the url bar + bar->blockSignals(true); // without compute suggestions + if (widget) + { + widget->activate(); + bar->setQUrl(widget->text()); + } + else + { + bar->setText(_typedString); + } + bar->blockSignals(false); + bar->setFocus(); + bar->setCursorPosition(bar->text().length()); +} + + +void CompletionWidget::clear() +{ + QLayoutItem *child; + while ((child = layout()->takeAt(0)) != 0) + { + delete child->widget(); + delete child; + } + _currentIndex = 0; + _hasSuggestions = false; +} + + +bool CompletionWidget::eventFilter(QObject *obj, QEvent *ev) +{ + int type = ev->type(); + QWidget *wid = qobject_cast<QWidget*>(obj); + + if (obj == 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; + UrlBar *w; + + if (type == QEvent::KeyPress) + { + QKeyEvent *kev = static_cast<QKeyEvent *>(ev); + switch (kev->key()) + { + case Qt::Key_Up: + case Qt::Key_Backtab: + if (kev->modifiers() == Qt::NoButton || (kev->modifiers() & Qt::ShiftModifier)) + { + up(); + kev->accept(); + return true; + } + break; + + case Qt::Key_Down: + case Qt::Key_Tab: + if (kev->modifiers() == Qt::NoButton) + { + down(); + kev->accept(); + return true; + } + if (kev->modifiers() & Qt::ControlModifier) + { + emit nextItemSubChoice(); + kev->accept(); + return true; + } + break; + + case Qt::Key_Enter: + case Qt::Key_Return: + w = qobject_cast<UrlBar *>(parent()); + if (kev->modifiers() == Qt::AltModifier) + { + if (kev->key() == Qt::Key_Return || kev->key() == Qt::Key_Enter) + { + emit chosenUrl(w->text(), Rekonq::NewFocusedTab); + } + } + + if (!w->text().startsWith(QL1S("http://"), Qt::CaseInsensitive)) + { + QString append; + if (kev->modifiers() == Qt::ControlModifier) + { + append = QL1S(".com"); + } + else if (kev->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) + { + append = QL1S(".org"); + } + else if (kev->modifiers() == Qt::ShiftModifier) + { + append = QL1S(".net"); + } + + if (!append.isEmpty()) + { + QUrl url(QL1S("http://") + w->text()); + QString host = url.host(); + if (!host.endsWith(append, Qt::CaseInsensitive)) + { + host += append; + url.setHost(host); + } + + emit chosenUrl(url, Rekonq::CurrentTab); + } + } + + kDebug() << "Suggestion INDEX chosen: " << _currentIndex; + if (_currentIndex == -1) + _currentIndex = 0; + child = findChild<ListItem *>(QString::number(_currentIndex)); + + if (child) //the completionwidget is visible and the user had press down + { + //we can use the url of the listitem + emit chosenUrl(child->url(), Rekonq::CurrentTab); + } + else //the user type too fast (completionwidget not visible or suggestion not downloaded) + { + UrlSuggester res(w->text()); + UrlSuggestionList list = res.orderedSearchItems(); + if (list.isEmpty()) + { + emit chosenUrl(KUrl(_typedString), Rekonq::CurrentTab); + } + else + { + emit chosenUrl(list.first().url, Rekonq::CurrentTab); + } + } + kev->accept(); + hide(); + return true; + + case Qt::Key_Escape: + hide(); + return true; + } + } + } + + return QFrame::eventFilter(obj, ev); +} + + +void CompletionWidget::setVisible(bool visible) +{ + if (visible) + { + qApp->installEventFilter(this); + } + else + { + qApp->removeEventFilter(this); + } + + QFrame::setVisible(visible); +} + + +void CompletionWidget::itemChosen(ListItem *item, Qt::MouseButton button, Qt::KeyboardModifiers modifier) +{ + if (button == Qt::MidButton + || modifier == Qt::ControlModifier) + { + emit chosenUrl(item->url(), Rekonq::NewFocusedTab); + } + else + { + emit chosenUrl(item->url(), Rekonq::CurrentTab); + } + hide(); +} + + +void CompletionWidget::updateList() +{ + suggestUrls(_typedString); +} + + +void CompletionWidget::suggestUrls(const QString &text) +{ + _typedString = text; + + QWidget *w = qobject_cast<QWidget *>(parent()); + if (!w->hasFocus()) + return; + + if (text.isEmpty()) + { + hide(); + return; + } + + if (!isVisible()) + { +// FIXME UrlResolver::setSearchEngine(SearchEngine::defaultEngine()); + } + + UrlSuggester *res = new UrlSuggester(text); + connect(res, SIGNAL(suggestionsReady(UrlSuggestionList, QString)), + this, SLOT(updateSuggestionList(UrlSuggestionList, QString))); + _resList = res->orderedSearchItems(); + + // NOTE: It's important to call this AFTER orderedSearchItems() to let everything work + res->computeSuggestions(); +} diff --git a/src/urlbar/completionwidget.h b/src/urlbar/completionwidget.h new file mode 100644 index 00000000..098aa9f9 --- /dev/null +++ b/src/urlbar/completionwidget.h @@ -0,0 +1,93 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009-2012 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 "urlsuggester.h" + +// KDE Includes +#include <KService> + +// Qt Includes +#include <QFrame> + +// Forward Declarations +class ListItem; + + +class CompletionWidget : public QFrame +{ + Q_OBJECT + +public: + CompletionWidget(QWidget *parent); + + virtual bool eventFilter(QObject *obj, QEvent *ev); + void setVisible(bool visible); + + void suggestUrls(const QString &text); + +private Q_SLOTS: + void itemChosen(ListItem *item, Qt::MouseButton = Qt::LeftButton, Qt::KeyboardModifiers = Qt::NoModifier); + void updateSuggestionList(const UrlSuggestionList &list, const QString& text); + void updateList(); + +Q_SIGNALS: + void chosenUrl(const KUrl &, Rekonq::OpenType); + void nextItemSubChoice(); + +private: + void insertItems(const UrlSuggestionList &list, const QString& text, int offset = 0); + + void popup(); + void clear(); + + void sizeAndPosition(); + void up(); + void down(); + void activateCurrentListItem(); + + QWidget *_parent; + + UrlSuggestionList _list; + + int _currentIndex; + + KService::Ptr _searchEngine; + + QString _typedString; + bool _hasSuggestions; + + UrlSuggestionList _resList; +}; + +#endif // COMPLETION_WIDGET_H diff --git a/src/urlbar/favoritewidget.cpp b/src/urlbar/favoritewidget.cpp new file mode 100644 index 00000000..6a4ffaba --- /dev/null +++ b/src/urlbar/favoritewidget.cpp @@ -0,0 +1,115 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011 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 "favoritewidget.h" +#include "favoritewidget.moc" + +// Auto Includes +#include "rekonq.h" + +// Local includes +#include "application.h" +#include "bookmarkmanager.h" +#include "bookmarkowner.h" +#include "webtab.h" + +// KDE Includes +#include <KLocalizedString> +#include <KIcon> +#include <KLineEdit> + +// Qt Includes +#include <QDialogButtonBox> +#include <QFormLayout> +#include <QLabel> +#include <QPushButton> + + +FavoriteWidget::FavoriteWidget(WebTab *tab, QWidget *parent) + : QMenu(parent) + , m_tab(tab) +{ + setAttribute(Qt::WA_DeleteOnClose); + setFixedWidth(350); + + QFormLayout *layout = new QFormLayout(this); + QVBoxLayout *vLay = new QVBoxLayout; + + // Favorite icon + QLabel *bookmarkIcon = new QLabel(this); + bookmarkIcon->setPixmap(KIcon("emblem-favorite").pixmap(32, 32)); + + // Title + QLabel *favoriteInfo = new QLabel(this); + favoriteInfo->setText(i18n("<h4>Remove this favorite?</h4>")); + vLay->addWidget(favoriteInfo); + + // Favorite name + QLabel *nameLabel = new QLabel(this); + nameLabel->setText(i18n("Name: %1", m_tab->view()->title())); + vLay->addWidget(nameLabel); + + // Favorite url + QLabel *urlLabel = new QLabel(this); + urlLabel->setText(i18n("URL: %1", m_tab->url().url())); + vLay->addWidget(urlLabel); + + layout->addRow(bookmarkIcon, vLay); + + // Ok & Cancel buttons + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); + layout->addWidget(buttonBox); +} + + +void FavoriteWidget::showAt(const QPoint &pos) +{ + adjustSize(); + + QPoint p(pos.x() - width(), pos.y() + 10); + move(p); + show(); +} + + +void FavoriteWidget::accept() +{ + QStringList urls = ReKonfig::previewUrls(); + if (urls.removeOne(m_tab->url().url())) + { + ReKonfig::setPreviewUrls(urls); + QStringList titles = ReKonfig::previewNames(); + titles.removeOne(m_tab->view()->title()); + ReKonfig::setPreviewNames(titles); + + emit updateIcon(); + } + + close(); +} diff --git a/src/urlbar/favoritewidget.h b/src/urlbar/favoritewidget.h new file mode 100644 index 00000000..d0b05f14 --- /dev/null +++ b/src/urlbar/favoritewidget.h @@ -0,0 +1,58 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011 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 FAVORITE_WIDGET_H +#define FAVORITE_WIDGET_H + + +// Qt Includes +#include <QMenu> +#include <QCheckBox> + +// Forward Declarations +class WebTab; + + +class FavoriteWidget : public QMenu +{ + Q_OBJECT + +public: + explicit FavoriteWidget(WebTab *tab, QWidget *parent = 0); + + void showAt(const QPoint &pos); + +Q_SIGNALS: + void updateIcon(); + +private Q_SLOTS: + void accept(); + +private: + WebTab *m_tab; +}; + +#endif // FAVORITE_WIDGET_H diff --git a/src/urlbar/listitem.cpp b/src/urlbar/listitem.cpp new file mode 100644 index 00000000..b47d23bf --- /dev/null +++ b/src/urlbar/listitem.cpp @@ -0,0 +1,664 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009-2012 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 "iconmanager.h" + +#include "urlsuggester.h" +#include "completionwidget.h" + +#include "websnap.h" +#include "searchengine.h" + +// KDE Includes +#include <KIcon> +#include <KAction> +#include <kio/jobclasses.h> +#include <kio/scheduler.h> + +// Qt Includes +#include <QApplication> +#include <QActionGroup> +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QSizePolicy> +#include <QPixmap> +#include <QStylePainter> +#include <QMouseEvent> +#include <QWebSettings> +#include <QFile> +#include <QTextDocument> +#include <QBitArray> + + +ListItem::ListItem(const UrlSuggestionItem &item, QWidget *parent) + : QWidget(parent) + , m_option() + , m_url(item.url) +{ + m_option.initFrom(this); + m_option.direction = Qt::LeftToRight; + + // use the same application palette (hence, the same colors) + // Qt docs says that using this cctor is possible & fast (qt:qpalette) + QPalette p(QApplication::palette()); + 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); + + QWidget::paintEvent(event); + QPainter painter(this); + m_option.rect = QRect(QPoint(), size()); + painter.fillRect(m_option.rect, palette().brush(backgroundRole())); + + if (m_option.state.testFlag(QStyle::State_Selected) || m_option.state.testFlag(QStyle::State_MouseOver)) + { + style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &m_option, &painter, this); + } + +} + + +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(), e->modifiers()); + QWidget::mousePressEvent(e); +} + + +KUrl ListItem::url() +{ + return m_url; +} + + +QString ListItem::text() +{ + return m_url.url(); +} + + +void ListItem::nextItemSubChoice() +{ + // will be override +} + + +// --------------------------------------------------------------- + + +TypeIconLabel::TypeIconLabel(int type, QWidget *parent) + : QLabel(parent) +{ + setMinimumWidth(16); + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->setMargin(0); + hLayout->setAlignment(Qt::AlignRight); + setLayout(hLayout); + + if (type & UrlSuggestionItem::Search) + hLayout->addWidget(getIcon("edit-find")); + if (type & UrlSuggestionItem::Browse) + hLayout->addWidget(getIcon("applications-internet")); + if (type & UrlSuggestionItem::Bookmark) + hLayout->addWidget(getIcon("rating")); + if (type & UrlSuggestionItem::History) + hLayout->addWidget(getIcon("view-history")); + if (type & UrlSuggestionItem::Suggestion) + hLayout->addWidget(getIcon("help-hint")); +} + + +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 = IconManager::self()->iconForUrl(KUrl(icon)).pixmap(16); + setFixedSize(16, 16); + setPixmap(pixmapIcon); +} + + +IconLabel::IconLabel(const KIcon &icon, QWidget *parent) + : QLabel(parent) +{ + QPixmap pixmapIcon = icon.pixmap(16); + setFixedSize(16, 16); + setPixmap(pixmapIcon); +} + + +// --------------------------------------------------------------- + + +static QString highlightWordsInText(const QString &text, const QStringList &words) +{ + QString ret = text; + QBitArray boldSections(ret.size()); + Q_FOREACH(const QString & wordToPointOut, words) + { + int index = ret.indexOf(wordToPointOut, 0, Qt::CaseInsensitive); + while (index > -1) + { + boldSections.fill(true, index, index + wordToPointOut.size()); + index = ret.indexOf(wordToPointOut, index + wordToPointOut.size(), Qt::CaseInsensitive); + } + } + + + if (boldSections.isEmpty()) + return ret; + + int numSections = 0; + for (int i = 0; i < boldSections.size() - 1; ++i) + { + if (boldSections.testBit(i) && !boldSections.testBit(i + 1)) + ++numSections; + } + if (boldSections.testBit(boldSections.size() - 1)) //last char was still part of a bold section + ++numSections; + const int tagLength = 7; // length of "<b>" and "</b>" we're going to add for each bold section. + ret.reserve(ret.size() + numSections * tagLength); + bool bold = false; + for (int i = boldSections.size() - 1; i >= 0; --i) + { + if (!bold && boldSections.testBit(i)) + { + ret.insert(i + 1, QL1S("</b>")); + bold = true; + } + else if (bold && !boldSections.testBit(i)) + { + ret.insert(i + 1, QL1S("<b>")); + bold = false; + } + } + if (bold) + ret.insert(0, QL1S("<b>")); + return ret; +} + + +TextLabel::TextLabel(const QString &text, const QString &textToPointOut, QWidget *parent) + : QLabel(parent) +{ + setTextFormat(Qt::RichText); + setMouseTracking(false); + QString t = text; + const bool wasItalic = t.startsWith(QL1S("<i>")); + if (wasItalic) + t.remove(QRegExp(QL1S("<[/ib]*>"))); + t = Qt::escape(t); + QStringList words = Qt::escape(textToPointOut.simplified()).split(QL1C(' ')); + t = highlightWordsInText(t, words); + if (wasItalic) + t = QL1S("<i>") + t + QL1S("</i>"); + setText(t); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); +} + + +TextLabel::TextLabel(QWidget *parent) + : QLabel(parent) +{ + setTextFormat(Qt::RichText); + setMouseTracking(false); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); +} + + +void TextLabel::setEngineText(const QString &engine, const QString &text) +{ + setText(i18nc("%1=search engine, e.g. Google, Wikipedia %2=text to search for", "Search %1 for <b>%2</b>", engine, Qt::escape(text))); +} + + +// --------------------------------------------------------------- + + +DescriptionLabel::DescriptionLabel(const QString &text, QWidget *parent) + : QLabel(parent) +{ + QString t = text; + const bool wasItalic = t.startsWith(QL1S("<i>")); + if (wasItalic) + t.remove(QRegExp("<[/ib]*>")); + + if (wasItalic) + t = QL1S("<i>") + t + QL1S("</i>"); + + setWordWrap(false); //NOTE: why setWordWrap(true) make items have a strange behavior ? + setText(t); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); +} + + +//-------------------------------------------------------------------------------------------- + + +PreviewListItem::PreviewListItem(const UrlSuggestionItem &item, const QString &text, QWidget *parent) + : ListItem(item, parent) +{ + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->setSpacing(4); + + // icon + hLayout->addWidget(new TypeIconLabel(item.type, this)); + + // url + text + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->setMargin(0); + + QString title = item.title; + if (title.isEmpty()) + { + title = item.url; + title = title.remove("http://"); + title.truncate(title.indexOf("/")); + } + + vLayout->addWidget(new TextLabel(title, text, this)); + vLayout->addWidget(new TextLabel("<i>" + item.url + "</i>", text, this)); + hLayout->addLayout(vLayout); + + // preview label icon + QLabel *previewLabelIcon = new QLabel(this); + previewLabelIcon->setFixedSize(45, 33); + new PreviewLabel(item.url, 38, 29, previewLabelIcon); + IconLabel* icon = new IconLabel(item.url, previewLabelIcon); + icon->move(27, 16); + hLayout->addWidget(previewLabelIcon); + + 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)); + } +} + + +// --------------------------------------------------------------- + + +ImageLabel::ImageLabel(const QString &url, int width, int height, QWidget *parent) + : QLabel(parent), + m_url(url) +{ + setFixedSize(width, height); + if (WebSnap::existsImage(KUrl(url))) + { + QPixmap pix; + pix.load(WebSnap::imagePathFromUrl(url)); + setPixmap(pix); + } + else + { + KIO::TransferJob *job = KIO::get(KUrl(url), KIO::NoReload, KIO::HideProgressInfo); + connect(job, SIGNAL(data(KIO::Job*, QByteArray)), + this, SLOT(slotData(KJob*, QByteArray))); + connect(job, SIGNAL(result(KJob*)), + this, SLOT(slotResult(KJob*))); + } +} + + +void ImageLabel::slotData(KJob *job, const QByteArray &data) +{ + Q_UNUSED(job); + m_data.append(data); +} + + +void ImageLabel::slotResult(KJob *) +{ + QPixmap pix; + if (!pix.loadFromData(m_data)) + kDebug() << "error while loading image: "; + setPixmap(pix); + pix.save(WebSnap::imagePathFromUrl(m_url), "PNG"); +} + + +// --------------------------------------------------------------- + + +SearchListItem::SearchListItem(const UrlSuggestionItem &item, const QString &text, QWidget *parent) + : ListItem(item, parent) + , m_text(text) +{ + // FIXME +// m_iconLabel = new IconLabel(SearchEngine::buildQuery(UrlResolver::searchEngine(), ""), this); +// m_titleLabel = new TextLabel(this); +// m_titleLabel->setEngineText(UrlResolver::searchEngine()->name(), item.title); +// m_engineBar = new EngineBar(UrlResolver::searchEngine(), 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::text() +{ + return m_text; +} + + +void SearchListItem::changeSearchEngine(KService::Ptr engine) +{ + // NOTE: This to let rekonq loading text typed in the requested engine on click. + // There probably is a better way to do it. I just cannot see it now... + UrlSuggestionItem item = UrlSuggestionItem(UrlSuggestionItem::Search, SearchEngine::buildQuery(engine, m_text), m_text); + SearchListItem sItem(item, m_text, this); + emit itemClicked(&sItem, Qt::LeftButton, Qt::NoModifier); +} + + +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); + + if (SearchEngine::defaultEngine().isNull()) + return; + m_engineGroup->addAction(newEngineAction(SearchEngine::defaultEngine(), selectedEngine)); + Q_FOREACH(const 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) +{ + QUrl u = engine->property("Query").toUrl(); + KUrl url = KUrl(u.toString(QUrl::RemovePath | QUrl::RemoveQuery)); + + KAction *a = new KAction(IconManager::self()->iconForUrl(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(); + } +} + + +// --------------------------------------------------------------- + + +SuggestionListItem::SuggestionListItem(const UrlSuggestionItem &item, const QString &text, QWidget *parent) + : ListItem(item, parent) + , m_text(item.title) +{ + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->setSpacing(4); + + hLayout->addWidget(new IconLabel(item.url, this)); + hLayout->addWidget(new TextLabel(item.title, text, this)); + hLayout->addWidget(new TypeIconLabel(item.type, this)); + + setLayout(hLayout); +} + + +QString SuggestionListItem::text() +{ + return m_text; +} + + +// --------------------------------------------------------------- + + +VisualSuggestionListItem::VisualSuggestionListItem(const UrlSuggestionItem &item, const QString &text, QWidget *parent) + : ListItem(item, parent) + , m_text(item.title) +{ + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->setSpacing(4); + QLabel *previewLabelIcon = new QLabel(this); + + if (!item.image.isEmpty()) + { + previewLabelIcon->setFixedSize(item.image_width + 10, item.image_height + 10); + new ImageLabel(item.image, item.image_width, item.image_height, previewLabelIcon); + IconLabel* icon = new IconLabel(item.url, previewLabelIcon); + icon->move(item.image_width - 10, item.image_height - 10); + } + else + { + previewLabelIcon->setFixedSize(18, 18); + new IconLabel(item.url, previewLabelIcon); + } + + hLayout->addWidget(previewLabelIcon); + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->setMargin(0); + vLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::MinimumExpanding)); + vLayout->addWidget(new TextLabel(item.title, text, this)); + DescriptionLabel *d = new DescriptionLabel("", this); + vLayout->addWidget(d); + vLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::MinimumExpanding)); + hLayout->addLayout(vLayout); + hLayout->addWidget(new TypeIconLabel(item.type, this)); + setLayout(hLayout); + d->setText("<i>" + item.description + "</i>"); +} + + +QString VisualSuggestionListItem::text() +{ + return m_text; +} + + +// --------------------------------------------------------------- + + +BrowseListItem::BrowseListItem(const UrlSuggestionItem &item, const QString &text, QWidget *parent) + : ListItem(item, parent) +{ + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->setSpacing(4); + + hLayout->addWidget(new IconLabel(item.url, this)); + hLayout->addWidget(new TextLabel(item.url, text, this)); + hLayout->addWidget(new TypeIconLabel(item.type, this)); + + setLayout(hLayout); +} + + +// --------------------------------------------------------------- + + +ListItem *ListItemFactory::create(const UrlSuggestionItem &item, const QString &text, QWidget *parent) +{ + if (item.type & UrlSuggestionItem::Search) + { + return new SearchListItem(item, text, parent); + } + + if (item.type & UrlSuggestionItem::Browse) + { + return new BrowseListItem(item, text, parent); + } + + if (item.type & UrlSuggestionItem::History) + { + return new PreviewListItem(item, text, parent); + } + + if (item.type & UrlSuggestionItem::Bookmark) + { + return new PreviewListItem(item, text, parent); + } + + if (item.type & UrlSuggestionItem::Suggestion) + { + if (item.description.isEmpty()) + { + return new SuggestionListItem(item, text, parent); + } + + return new VisualSuggestionListItem(item, text, parent); + } + + return new PreviewListItem(item, text, parent); +} diff --git a/src/urlbar/listitem.h b/src/urlbar/listitem.h new file mode 100644 index 00000000..21867685 --- /dev/null +++ b/src/urlbar/listitem.h @@ -0,0 +1,291 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009-2012 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" + +// KDE Includes +#include <KToolBar> +#include <KService> +#include <KUrl> + +// Qt Includes +#include <QWidget> +#include <QLabel> +#include <QStyleOptionViewItemV4> +#include <QString> +#include <QByteArray> + +// Forward Declarations +class UrlSuggestionItem; + +class KAction; +class KIcon; +class KJob; + +class QActionGroup; + + +class ListItem : public QWidget +{ + Q_OBJECT + +public: + explicit ListItem(const UrlSuggestionItem &item, QWidget *parent = 0); + virtual ~ListItem(); + + void activate(); + void deactivate(); + + KUrl url(); + virtual QString text(); + +public Q_SLOTS: + virtual void nextItemSubChoice(); + +Q_SIGNALS: + void itemClicked(ListItem *item, Qt::MouseButton, Qt::KeyboardModifiers); + void updateList(); + +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); + explicit IconLabel(const KIcon &icon, QWidget *parent = 0); +}; + + +// ------------------------------------------------------------------------- + + +class REKONQ_TESTS_EXPORT TextLabel : public QLabel +{ + Q_OBJECT + +public: + explicit TextLabel(const QString &text, const QString &textToPointOut = QString(), QWidget *parent = 0); + explicit TextLabel(QWidget *parent = 0); + + void setEngineText(const QString &engine, const QString &text); +}; + +// ------------------------------------------------------------------------- + + +class DescriptionLabel : public QLabel +{ + Q_OBJECT + +public: + explicit DescriptionLabel(const QString &text, QWidget *parent = 0); +}; + + +// ------------------------------------------------------------------------- + + +class EngineBar : public KToolBar +{ + Q_OBJECT + +public: + explicit EngineBar(KService::Ptr selectedEngine, QWidget *parent = 0); + void selectNextEngine(); + +Q_SIGNALS: + void searchEngineChanged(KService::Ptr engine); + +private Q_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 UrlSuggestionItem &item, const QString &text, QWidget *parent = 0); + QString text(); + +public Q_SLOTS: + virtual void nextItemSubChoice(); + +private Q_SLOTS: + void changeSearchEngine(KService::Ptr engine); + +private: + TextLabel* m_titleLabel; + IconLabel* m_iconLabel; + EngineBar* m_engineBar; + QString m_text; + KService::Ptr m_currentEngine; +}; + + +// ------------------------------------------------------------------------- + + +class SuggestionListItem : public ListItem +{ + Q_OBJECT + +public: + SuggestionListItem(const UrlSuggestionItem &item, const QString &text, QWidget *parent = 0); + QString text(); + +private: + QString m_text; +}; + + +// ------------------------------------------------------------------------- + + +class VisualSuggestionListItem : public ListItem +{ + Q_OBJECT + +public: + VisualSuggestionListItem(const UrlSuggestionItem &item, const QString &text, QWidget *parent = 0); + QString text(); + +private: + QString m_text; +}; + + +// ------------------------------------------------------------------------- + + +class PreviewListItem : public ListItem +{ + Q_OBJECT + +public: + PreviewListItem(const UrlSuggestionItem &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 ImageLabel : public QLabel +{ + Q_OBJECT + +public: + ImageLabel(const QString &url, int width, int height, QWidget *parent); + +private: + QString m_url; + QByteArray m_data; + +private Q_SLOTS: + void slotData(KJob* job, const QByteArray& data); + void slotResult(KJob* job); +}; + + +// ------------------------------------------------------------------------- + + +class BrowseListItem : public ListItem +{ + Q_OBJECT + +public: + BrowseListItem(const UrlSuggestionItem &item, const QString &text, QWidget *parent = 0); +}; + + +//------------------------------------------------------------------------------------------------- + + +class ListItemFactory +{ +public: + static ListItem *create(const UrlSuggestionItem &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..0d142d19 --- /dev/null +++ b/src/urlbar/rsswidget.cpp @@ -0,0 +1,165 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 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 "tabwindow.h" +#include "iconmanager.h" + +// KDE Includes +#include <KComboBox> +#include <KLocalizedString> +#include <KMessageBox> +#include <KProcess> +#include <KUrl> + +// Qt Includes +#include <QDBusConnectionInterface> +#include <QDBusInterface> + +#include <QDialogButtonBox> +#include <QFormLayout> +#include <QLabel> +#include <QPushButton> + + +RSSWidget::RSSWidget(const QMap< KUrl, QString > &map, QWidget *parent) + : QMenu(parent) + , m_map(map) +{ + setAttribute(Qt::WA_DeleteOnClose); + setFixedWidth(350); + + QFormLayout *layout = new QFormLayout(this); + + // Title + QLabel *title = new QLabel(this); + title->setText(i18n("Subscribe to RSS Feeds")); + QFont f = title->font(); + f.setBold(true); + title->setFont(f); + layout->addRow(title); + + // Agregators + QLabel *agregator = new QLabel(this); + agregator->setText(i18n("Aggregator:")); + + m_agregators = new KComboBox(this); + m_agregators->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + m_agregators->addItem(KIcon("akregator"), QString("Akregator")); + m_agregators->addItem(IconManager::self()->iconForUrl(KUrl("http://google.com/reader")), i18n("Google Reader")); + + layout->addRow(agregator, m_agregators); + + // Feeds List + QLabel *feed = new QLabel(this); + feed->setText(i18n("Feed:")); + + m_feeds = new KComboBox(this); + m_feeds->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + Q_FOREACH(const QString & title, m_map) + { + m_feeds->addItem(title); + } + + layout->addRow(feed, m_feeds); + + // Buttons + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel, Qt::Horizontal, this); + + QPushButton *addFeed = new QPushButton(KIcon("list-add"), i18n("Add Feed"), buttonBox); + buttonBox->addButton(addFeed, QDialogButtonBox::AcceptRole); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); + + layout->addRow(buttonBox); +} + + +void RSSWidget::showAt(const QPoint &pos) +{ + adjustSize(); + + QPoint p(pos.x() - width(), 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); + + close(); +} + + +void RSSWidget::addWithGoogleReader(const QString &url) +{ + KUrl toLoad = KUrl("http://www.google.com/ig/add?feedurl=" + url); + rApp->tabWindow()->loadUrl(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 feed 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..eaa3de7d --- /dev/null +++ b/src/urlbar/rsswidget.h @@ -0,0 +1,61 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2010-2011 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 + +// Qt Includes +#include <QMenu> + +// Forward Declarations +class KComboBox; +class KUrl; + + +class RSSWidget : public QMenu +{ + Q_OBJECT + +public: + // QMap< feedUrl, feedTitle> + RSSWidget(const QMap<KUrl, QString> &map, QWidget *parent = 0); + + void showAt(const QPoint &pos); + +private Q_SLOTS: + void accept(); + +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/sslwidget.cpp b/src/urlbar/sslwidget.cpp new file mode 100644 index 00000000..a9d3e9b6 --- /dev/null +++ b/src/urlbar/sslwidget.cpp @@ -0,0 +1,251 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011-2012 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 "sslwidget.h" +#include "sslwidget.moc" + +// Local includes +#include "historymanager.h" +#include "sslinfodialog.h" + +// Qt Includes +#include <QPointer> + +#include <QDialogButtonBox> +#include <QGridLayout> +#include <QLabel> +#include <QPushButton> +#include <QTextDocument> + + +SSLWidget::SSLWidget(const QUrl &url, const WebSslInfo &info, QWidget *parent) + : QMenu(parent) + , m_url(url) + , m_info(info) +{ + setAttribute(Qt::WA_DeleteOnClose); + setMinimumWidth(400); + + QList<QSslCertificate> certList = m_info.certificateChain(); + QSslCertificate cert; + if (!certList.isEmpty()) + cert = certList.first(); + + QList<QStringList> certErrorList = SslInfoDialog::errorsFromString(m_info.certificateErrors()); + QStringList firstCertErrorList; + if (!certErrorList.isEmpty()) + firstCertErrorList = certErrorList.first(); + + QGridLayout *layout = new QGridLayout(this); + + QLabel *label; + QLabel *imageLabel; + + int rows = 0; + // ------------------------------------------------------------------------------------------------------ + imageLabel = new QLabel(this); + layout->addWidget(imageLabel, rows , 0, Qt::AlignCenter); + + label = new QLabel(this); + label->setWordWrap(true); + label->setText(i18n("Identity")); + QFont f1 = label->font(); + f1.setBold(true); + label->setFont(f1); + layout->addWidget(label, rows++, 1); + + label = new QLabel(this); + label->setWordWrap(true); + if (cert.isNull()) + { + label->setText(i18n("Warning: this site is NOT carrying a certificate.")); + imageLabel->setPixmap(KIcon("security-low").pixmap(32)); + layout->addWidget(label, rows++, 1); + } + else + { + if (cert.isValid() && firstCertErrorList.isEmpty()) + { + label->setText(i18n("The certificate for this site is valid and has been verified by:\n%1.", + Qt::escape(cert.issuerInfo(QSslCertificate::CommonName)))); + + imageLabel->setPixmap(KIcon("security-high").pixmap(32)); + } + else + { + QString c = QL1S("<ul>"); + Q_FOREACH(const QString & s, firstCertErrorList) + { + c += QL1S("<li>") + s + QL1S("</li>"); + } + c += QL1S("</ul>"); + + label->setText(i18n("The certificate for this site is NOT valid, for the following reasons:\n%1.", c)); + label->setTextFormat(Qt::RichText); + imageLabel->setPixmap(KIcon("security-low").pixmap(32)); + } + + layout->addWidget(label, rows++, 1); + + label = new QLabel(this); + label->setWordWrap(true); + label->setText(QL1S("<a href=\"moresslinfos\">") + i18n("Certificate Information") + QL1S("</a>")); + connect(label, SIGNAL(linkActivated(QString)), this, SLOT(showMoreSslInfos(QString))); + layout->addWidget(label, rows++, 1); + } + + // ------------------------------------------------------------------------------------------------------------- + label = new QLabel(this); + label->setWordWrap(true); + label->setText(i18n("Encryption")); + QFont f2 = label->font(); + f2.setBold(true); + label->setFont(f2); + layout->addWidget(label, rows, 1); + + imageLabel = new QLabel(this); + layout->addWidget(imageLabel, rows++ , 0, Qt::AlignCenter); + + QString ciph = m_info.ciphers(); + if (ciph.isEmpty()) // NOTE: Can I verify encryption in another (better?) way? + { + label = new QLabel(this); + label->setWordWrap(true); + label->setText(i18n("Your connection to %1 is NOT encrypted.\n", m_url.host())); + layout->addWidget(label, rows++ , 1); + + imageLabel->setPixmap(KIcon("security-low").pixmap(32)); + } + else + { + label = new QLabel(this); + label->setWordWrap(true); + label->setText(i18n("Your connection to \"%1\" is encrypted.\n", m_url.host())); + layout->addWidget(label, rows++, 1); + + QString vers = m_info.protocol(); + QString sslVersion; + if (vers == QL1S("SSLv3")) + { + sslVersion = QL1S("SSL 3.0"); + imageLabel->setPixmap(KIcon("security-high").pixmap(32)); + } + else if (vers == QL1S("SSLv2")) + { + sslVersion = QL1S("SSL 2.0"); + imageLabel->setPixmap(KIcon("security-low").pixmap(32)); + } + else if (vers == QL1S("TLSv1")) + { + sslVersion = QL1S("TLS 1.0"); + imageLabel->setPixmap(KIcon("security-high").pixmap(32)); + } + else + { + sslVersion = i18n("Unknown"); + imageLabel->setPixmap(KIcon("security-low").pixmap(32)); + } + + label = new QLabel(this); + label->setWordWrap(true); + label->setText(i18n("It uses protocol: %1.\n", sslVersion)); + layout->addWidget(label, rows++, 1); + + const QStringList cipherInfo = m_info.ciphers().split('\n', QString::SkipEmptyParts); + label = new QLabel(this); + label->setWordWrap(true); + label->setText( + i18n("It is encrypted using %1 at %2 bits, with %3 for message authentication and %4 with Auth %5 as key exchange mechanism.\n\n", + cipherInfo[0], + m_info.usedChiperBits(), + cipherInfo[3], + cipherInfo[2], + cipherInfo[1]) + ); + layout->addWidget(label, rows++, 1); + + } + + // ------------------------------------------------------------------------------------------------------------------ + imageLabel = new QLabel(this); + layout->addWidget(imageLabel, rows , 0, Qt::AlignCenter); + + label = new QLabel(this); + label->setWordWrap(true); + label->setText(i18n("Site Information")); + QFont f3 = label->font(); + f3.setBold(true); + label->setFont(f3); + layout->addWidget(label, rows++, 1); + + label = new QLabel(this); + label->setWordWrap(true); + + QList<HistoryItem> hList = HistoryManager::self()->find(url.toString()); + HistoryItem firstVisit = hList.isEmpty() ? + HistoryItem() : + hList.first() ; + + if (firstVisit.visitCount == 1) + { + label->setText(i18n("It is your first time visiting this site.")); + imageLabel->setPixmap(KIcon("security-medium").pixmap(32)); + } + else + { + label->setText(i18n("You just visited this site.\nYour first visit was on %1.\n", firstVisit.firstDateTimeVisit.toString())); + imageLabel->setPixmap(KIcon("security-high").pixmap(32)); + } + layout->addWidget(label, rows++, 1); + +} + + +void SSLWidget::showAt(const QPoint &pos) +{ + adjustSize(); + + QPoint p(pos.x() - width(), pos.y() + 10); + move(p); + show(); +} + + +void SSLWidget::accept() +{ + close(); +} + + +void SSLWidget::showMoreSslInfos(const QString &) +{ + QPointer<SslInfoDialog> dlg = new SslInfoDialog(m_url.host(), m_info, this); + dlg->exec(); + delete dlg; + + return; +} diff --git a/src/urlbar/sslwidget.h b/src/urlbar/sslwidget.h new file mode 100644 index 00000000..dd6f020d --- /dev/null +++ b/src/urlbar/sslwidget.h @@ -0,0 +1,58 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2011-2012 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 SSL_WIDGET_H +#define SSL_WIDGET_H + + +// Local Includes +#include "websslinfo.h" + +// Qt Includes +#include <QMenu> + +#include <QUrl> + + +class SSLWidget : public QMenu +{ + Q_OBJECT + +public: + SSLWidget(const QUrl &url, const WebSslInfo &info, QWidget *parent = 0); + + void showAt(const QPoint &pos); + +private Q_SLOTS: + void showMoreSslInfos(const QString &); + void accept(); + +private: + QUrl m_url; + WebSslInfo m_info; +}; + +#endif // SSL_WIDGET_H diff --git a/src/urlbar/urlbar.cpp b/src/urlbar/urlbar.cpp new file mode 100644 index 00000000..c6159594 --- /dev/null +++ b/src/urlbar/urlbar.cpp @@ -0,0 +1,776 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@gmail.com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> +* Copyright (C) 2009-2011 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/>. +* +* ============================================================ */ + + +// Self Includes +#include "urlbar.h" +#include "urlbar.moc" + +// Auto Includes +#include "rekonq.h" + +// App Includes +#include "application.h" + +// Local Includes +#include "bookmarkmanager.h" +#include "bookmarkowner.h" // FIXME: Why is this needed? Why everything interesting in BookmarkManager is in its owner? +#include "iconmanager.h" + +#include "completionwidget.h" +#include "bookmarkwidget.h" +#include "favoritewidget.h" +#include "urlsuggester.h" + +#include "webtab.h" +#include "webpage.h" +#include "webview.h" +#include "searchengine.h" +#include "websnap.h" + +// KDE Includes +#include <KCompletionBox> +#include <KStandardDirs> +#include <KColorScheme> +#include <KMenu> +#include <KIcon> +#include <KIconLoader> +#include <KStandardAction> +#include <KAction> + +// Qt Includes +#include <QPainter> +#include <QPaintEvent> +#include <QPalette> +#include <QVBoxLayout> +#include <QClipboard> +#include <QTimer> + +// const values +const int c_iconMargin = 4; + + +IconButton::IconButton(QWidget *parent) + : QToolButton(parent) +{ + setToolButtonStyle(Qt::ToolButtonIconOnly); + setStyleSheet("IconButton { background-color:transparent; border: none; padding: 0px}"); + setCursor(Qt::ArrowCursor); + + setContextMenuPolicy(Qt::PreventContextMenu); +} + + +void IconButton::mouseReleaseEvent(QMouseEvent* event) +{ + emit clicked(event->globalPos()); +} + + +// ----------------------------------------------------------------------------------------------------------- + + +QString guessUrlWithCustomFirstLevel(const QString &str1, const QString &str2) +{ + QUrl url(QL1S("http://www.") + str1); + QString host = url.host().toLower(); + if (!host.endsWith(str2, Qt::CaseInsensitive)) + { + host += str2; + url.setHost(host); + } + return url.toString(); +} + +// ----------------------------------------------------------------------------------------------------------- + + +UrlBar::UrlBar(QWidget *parent) + : KLineEdit(parent) + , _tab(0) + , _icon(new IconButton(this)) + , _suggestionTimer(new QTimer(this)) +{ + setLayoutDirection(Qt::LeftToRight); + + // set initial icon + _icon->setIcon(KIcon("arrow-right")); + + // initial style + setStyleSheet(QString("UrlBar { padding: 2px 0 2px %1px; height: %1px } ").arg(_icon->sizeHint().width())); + + // doesn't show the clear button + setClearButtonShown(false); + + // enable dragging + setDragEnabled(true); + + // insert decoded URLs + setUrlDropsEnabled(true); + + // tooltip + setToolTip(i18n("Type here to search your bookmarks, history and the web...")); + + // accept focus, via tabbing, clicking & wheeling + setFocusPolicy(Qt::WheelFocus); + + // disable completion object (we have our own :) ) + setCompletionObject(0); + + _tab = qobject_cast<WebTab *>(parent); + + connect(_tab, SIGNAL(loadProgressing()), this, SLOT(update())); + + connect(_tab->view(), SIGNAL(urlChanged(QUrl)), this, SLOT(setQUrl(QUrl))); + connect(_tab->view(), SIGNAL(loadFinished(bool)), this, SLOT(loadFinished())); + connect(_tab->view(), SIGNAL(loadStarted()), this, SLOT(clearRightIcons())); + connect(_tab->view(), SIGNAL(iconChanged()), this, SLOT(refreshFavicon())); + + // bookmark icon + connect(BookmarkManager::self(), SIGNAL(bookmarksUpdated()), this, SLOT(updateRightIcons())); + + _suggestionTimer->setSingleShot(true); + connect(_suggestionTimer, SIGNAL(timeout()), this, SLOT(suggest())); + + activateSuggestions(true); +} + + +UrlBar::~UrlBar() +{ + _suggestionTimer->stop(); + activateSuggestions(false); + _box.clear(); + + disconnect(); +} + + +void UrlBar::setQUrl(const QUrl& url) +{ + if (url.scheme() == QL1S("about")) + { + clear(); + setFocus(); + } + else + { + clearFocus(); + KLineEdit::setUrl(url); + setCursorPosition(0); + refreshFavicon(); + } +} + + +void UrlBar::loadRequestedUrl(const KUrl& url, Rekonq::OpenType type) +{ + activateSuggestions(false); + clearFocus(); + setUrl(url); + rApp->loadUrl(url, type); +} + + +void UrlBar::loadDigitedUrl() +{ + UrlSuggester res(text()); + UrlSuggestionList list = res.orderedSearchItems(); + if (list.isEmpty()) + { + loadRequestedUrl(KUrl(text())); + } + else + { + loadRequestedUrl(list.first().url); + } +} + + +void UrlBar::paintEvent(QPaintEvent *event) +{ + KColorScheme colorScheme(palette().currentColorGroup()); + QColor backgroundColor; + QColor foregroundColor; + + if (QWebSettings::globalSettings()->testAttribute(QWebSettings::PrivateBrowsingEnabled)) + { + backgroundColor = QColor(220, 220, 220); // light gray + foregroundColor = Qt::black; + } + else + { + backgroundColor = rApp->palette().color(QPalette::Base); + foregroundColor = rApp->palette().color(QPalette::Text); + } + + // set background color of UrlBar + QPalette p = palette(); + + int progr = _tab->progress(); + if (progr == 0 || progr == 100) + { + if (_tab->url().scheme() == QL1S("https")) + { + backgroundColor = _tab->page()->hasSslValid() + ? colorScheme.background(KColorScheme::PositiveBackground).color() + : colorScheme.background(KColorScheme::NegativeBackground).color(); + + foregroundColor = colorScheme.foreground(KColorScheme::NormalText).color(); + } + p.setBrush(QPalette::Base, backgroundColor); + p.setBrush(QPalette::Text, foregroundColor); + } + else + { + QColor highlight = rApp->palette().color(QPalette::Highlight); + + int r = (highlight.red() + 2 * backgroundColor.red()) / 3; + int g = (highlight.green() + 2 * backgroundColor.green()) / 3; + int b = (highlight.blue() + 2 * backgroundColor.blue()) / 3; + + QColor loadingColor(r, g, b); + + if (abs(loadingColor.lightness() - backgroundColor.lightness()) < 20) //eg. Gaia color scheme + { + r = (2 * highlight.red() + backgroundColor.red()) / 3; + g = (2 * highlight.green() + backgroundColor.green()) / 3; + b = (2 * highlight.blue() + backgroundColor.blue()) / 3; + loadingColor = QColor(r, g, b); + } + + QLinearGradient gradient(QPoint(0, 0), QPoint(width(), 0)); + gradient.setColorAt(0, loadingColor); + gradient.setColorAt(((double)progr) / 100 - .000001, loadingColor); + gradient.setColorAt(((double)progr) / 100, backgroundColor); + p.setBrush(QPalette::Base, gradient); + } + setPalette(p); + + // you need this before our code to draw inside the line edit.. + KLineEdit::paintEvent(event); + + if (text().isEmpty() && (progr == 0 || progr == 100)) + { + QStyleOptionFrame option; + initStyleOption(&option); + QRect textRect = style()->subElementRect(QStyle::SE_LineEditContents, &option, this); + QPainter painter(this); + painter.setPen(Qt::gray); + painter.drawText(textRect, + Qt::AlignVCenter | Qt::AlignCenter, + i18n("Type here to search your bookmarks, history and the web...") + ); + } +} + + +void UrlBar::keyPressEvent(QKeyEvent *event) +{ + QString currentText = text().trimmed(); + + if (currentText.isEmpty()) + return KLineEdit::keyPressEvent(event); + + // this handles the Modifiers + Return key combinations + if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) + { + switch (event->modifiers()) + { + case Qt::AltModifier: + loadRequestedUrl(currentText, Rekonq::NewFocusedTab); + break; + + case Qt::ControlModifier: + loadRequestedUrl(guessUrlWithCustomFirstLevel(currentText, QL1S(".com"))); + break; + + case 0x06000000: // Qt::ControlModifier | Qt::ShiftModifier: + loadRequestedUrl(guessUrlWithCustomFirstLevel(currentText, QL1S(".org"))); + break; + + case Qt::ShiftModifier: + loadRequestedUrl(guessUrlWithCustomFirstLevel(currentText, QL1S(".net"))); + break; + + default: + loadRequestedUrl(currentText); + break; + } + } + + if (event->key() == Qt::Key_Escape) + { + clearFocus(); + if (!(_tab->url().protocol() == QL1S("about"))) + setText(_tab->url().url()); + event->accept(); + } + + KLineEdit::keyPressEvent(event); +} + + +void UrlBar::focusInEvent(QFocusEvent *event) +{ + activateSuggestions(true); + KLineEdit::focusInEvent(event); +} + + +void UrlBar::dropEvent(QDropEvent *event) +{ + // handles only plain-text with url format + if (event->mimeData()->hasFormat("text/plain") && event->source() != this) + { + QUrl url = QUrl::fromUserInput(event->mimeData()->data("text/plain")); + + if (url.isValid()) + { + setQUrl(url); + loadRequestedUrl(text()); + return; + } + } + + // handles everything else + KLineEdit::dropEvent(event); + loadRequestedUrl(text()); +} + + +void UrlBar::loadFinished() +{ + if (_tab->url().scheme() == QL1S("about")) + { + update(); + return; + } + + // show bookmark info + IconButton *bt = addRightIcon(UrlBar::BK); + connect(bt, SIGNAL(clicked(QPoint)), this, SLOT(manageBookmarks())); + + // show favorite icon + IconButton *fbt = addRightIcon(UrlBar::Favorite); + connect(fbt, SIGNAL(clicked(QPoint)), this, SLOT(manageFavorites(QPoint))); + + // show KGet downloads?? + if (!KStandardDirs::findExe("kget").isNull() && ReKonfig::kgetList()) + { + IconButton *bt = addRightIcon(UrlBar::KGet); + connect(bt, SIGNAL(clicked(QPoint)), _tab->page(), SLOT(downloadAllContentsWithKGet())); + } + + // show RSS + if (_tab->hasRSSInfo()) + { + IconButton *bt = addRightIcon(UrlBar::RSS); + connect(bt, SIGNAL(clicked(QPoint)), this, SLOT(showRSSInfo(QPoint))); + } + + // show SSL + if (_tab->url().scheme() == QL1S("https")) + { + // NOTE: the choice for the right SSL icon is done in the addRightIcon method + IconButton *bt = addRightIcon(UrlBar::SSL); + connect(bt, SIGNAL(clicked(QPoint)), _tab->page(), SLOT(showSSLInfo(QPoint))); + } + + // show add search engine + if (_tab->hasNewSearchEngine()) + { + IconButton *bt = addRightIcon(UrlBar::SearchEngine); + connect(bt, SIGNAL(clicked(QPoint)), this, SLOT(showSearchEngine(QPoint))); + } + +// FIXME Reimplement if (_tab->hasAdBlockedElements()) +// { +// IconButton *bt = addRightIcon(UrlBar::AdBlock); +// connect(bt, SIGNAL(clicked(QPoint)), (QObject *) AdBlockManager::self(), SLOT(showBlockedItemDialog())); +// } + + // we need to update urlbar after the right icon settings + // removing this code (where setStyleSheet automatically calls update) needs adding again + // an update call + int oneIconWidth = _icon->sizeHint().width(); + int rightIconWidth = (oneIconWidth + c_iconMargin) * (_rightIconsList.count()); + setStyleSheet(QString("UrlBar { padding: 2px %2px 2px %1px; height: %1px } ").arg(oneIconWidth).arg(rightIconWidth)); +} + + +void UrlBar::updateRightIcons() +{ + if (!_tab->isPageLoading()) + { + clearRightIcons(); + loadFinished(); + } +} + + +void UrlBar::activateSuggestions(bool b) +{ + if (b) + { + if (_box.isNull()) + { + _box = new CompletionWidget(this); + installEventFilter(_box.data()); + connect(_box.data(), SIGNAL(chosenUrl(KUrl, Rekonq::OpenType)), this, SLOT(loadRequestedUrl(KUrl, Rekonq::OpenType))); + + // activate suggestions on edit text + connect(this, SIGNAL(textChanged(QString)), this, SLOT(detectTypedString(QString))); + } + } + else + { + disconnect(this, SIGNAL(textChanged(QString)), this, SLOT(detectTypedString(QString))); + removeEventFilter(_box.data()); + if (!_box.isNull()) + _box.data()->deleteLater(); + } +} + + +void UrlBar::mouseDoubleClickEvent(QMouseEvent *event) +{ + Q_UNUSED(event); + + selectAll(); +} + + +void UrlBar::contextMenuEvent(QContextMenuEvent* event) +{ + KMenu menu; + const bool clipboardFilled = !rApp->clipboard()->text().isEmpty(); + + // Cut + KAction *a = KStandardAction::cut(this, SLOT(cut()), this); + a->setEnabled(hasSelectedText()); + menu.addAction(a); + + // Copy + a = KStandardAction::copy(this, SLOT(copy()), this); + a->setEnabled(hasSelectedText()); + menu.addAction(a); + + // Paste + a = KStandardAction::paste(this, SLOT(paste()), this); + a->setEnabled(clipboardFilled); + menu.addAction(a); + + // Paste & Go + const QString clipboardText = rApp->clipboard()->text(); + if (isValidURL(clipboardText) || clipboardText.isEmpty()) + { + a = new KAction(i18n("Paste && Go"), this); + connect(a, SIGNAL(triggered(bool)), this, SLOT(pasteAndGo())); + } + else + { + a = new KAction(i18n("Paste && Search"), this); + connect(a, SIGNAL(triggered(bool)), this, SLOT(pasteAndSearch())); + } + a->setEnabled(clipboardFilled); + menu.addAction(a); + + // Delete + a = new KAction(KIcon("edit-delete"), i18n("Delete"), this); + connect(a, SIGNAL(triggered(bool)), this, SLOT(delSlot())); + a->setEnabled(hasSelectedText()); + menu.addAction(a); + + menu.addSeparator(); + + // Select All + a = KStandardAction::selectAll(this, SLOT(selectAll()), this); + a->setEnabled(!text().isEmpty()); + menu.addAction(a); + + menu.exec(event->globalPos()); +} + + +bool UrlBar::isValidURL(QString url) +{ + bool isValid = false; + if (url.startsWith(QL1S("http://")) + || url.startsWith(QL1S("https://")) + || url.startsWith(QL1S("ftp://")) + ) + url = url.remove(QRegExp("(http|https|ftp)://")); + + if (url.contains(QL1C('.')) + && url.indexOf(QL1C('.')) > 0 + && url.indexOf(QL1C('.')) < url.length() + && !url.trimmed().contains(QL1C(' ')) + && QUrl::fromUserInput(url).isValid() + ) + isValid = true; + + return isValid; +} + + +IconButton *UrlBar::addRightIcon(UrlBar::icon ic) +{ + IconButton *rightIcon = new IconButton(this); + + switch (ic) + { + 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: + _tab->page()->hasSslValid() + ? rightIcon->setIcon(KIcon("object-locked")) + : rightIcon->setIcon(KIcon("object-unlocked")); + rightIcon->setToolTip(i18n("Show SSL Info")); + break; + case UrlBar::BK: + if (BookmarkManager::self()->bookmarkForUrl(_tab->url()).isNull()) + { + rightIcon->setIcon(KIcon("bookmarks").pixmap(32, 32, QIcon::Disabled)); + rightIcon->setToolTip(i18n("Bookmark this page")); + } + else + { + rightIcon->setIcon(KIcon("bookmarks")); + rightIcon->setToolTip(i18n("Edit this bookmark")); + } + break; + case UrlBar::SearchEngine: + { + KIcon wsIcon("edit-web-search"); + if (wsIcon.isNull()) + { + wsIcon = KIcon("preferences-web-browser-shortcuts"); + } + rightIcon->setIcon(wsIcon); + rightIcon->setToolTip(i18n("Add search engine")); + break; + } + case UrlBar::Favorite: + if (ReKonfig::previewUrls().contains(_tab->url().url())) + { + rightIcon->setIcon(KIcon("emblem-favorite")); + rightIcon->setToolTip(i18n("Remove from favorite")); + } + else + { + rightIcon->setIcon(KIcon("emblem-favorite").pixmap(32, 32, QIcon::Disabled)); + rightIcon->setToolTip(i18n("Add to favorites")); + } + break; + case UrlBar::AdBlock: + rightIcon->setIcon(KIcon("preferences-web-browser-adblock")); + rightIcon->setToolTip(i18n("There are elements blocked by AdBlock")); + break; + default: + ASSERT_NOT_REACHED("ERROR.. default non extant case!!"); + break; + } + + _rightIconsList << rightIcon; + + int iconsCount = _rightIconsList.count(); + updateRightIconPosition(rightIcon, iconsCount); + + rightIcon->show(); + + return rightIcon; +} + + +void UrlBar::clearRightIcons() +{ + qDeleteAll(_rightIconsList); + _rightIconsList.clear(); +} + + +void UrlBar::resizeEvent(QResizeEvent *event) +{ + int ih = _icon->sizeHint().height(); + int iconsCount = _rightIconsList.count(); + int iconHeight = (height() - ih) / 2; + + _icon->move(c_iconMargin, iconHeight); + + for (int i = 0; i < iconsCount; ++i) + { + IconButton *bt = _rightIconsList.at(i); + updateRightIconPosition(bt, i + 1); + } + + KLineEdit::resizeEvent(event); +} + + +void UrlBar::detectTypedString(const QString &typed) +{ + if (typed.count() == 1) + { + QTimer::singleShot(0, this, SLOT(suggest())); + return; + } + + if (_suggestionTimer->isActive()) + _suggestionTimer->stop(); + _suggestionTimer->start(50); +} + + +void UrlBar::suggest() +{ + if (!_box.isNull()) + _box.data()->suggestUrls(text()); +} + + +void UrlBar::refreshFavicon() +{ + if (QWebSettings::globalSettings()->testAttribute(QWebSettings::PrivateBrowsingEnabled)) + { + _icon->setIcon(KIcon("view-media-artist")); + return; + } + + KUrl u = _tab->url(); + if (u.scheme() == QL1S("about")) + { + _icon->setIcon(KIcon("arrow-right")); + return; + } + + _icon->setIcon(IconManager::self()->iconForUrl(u)); +} + + +void UrlBar::pasteAndGo() +{ + loadRequestedUrl(rApp->clipboard()->text()); +} + + +void UrlBar::pasteAndSearch() +{ + KService::Ptr defaultEngine = SearchEngine::defaultEngine(); + if (defaultEngine) + loadRequestedUrl(KUrl(SearchEngine::buildQuery(defaultEngine, QApplication::clipboard()->text()))); +} + + +void UrlBar::delSlot() +{ + del(); +} + + +void UrlBar::manageBookmarks() +{ + if (_tab->url().scheme() == QL1S("about")) + return; + + KBookmark bookmark = BookmarkManager::self()->bookmarkForUrl(_tab->url()); + + if (bookmark.isNull()) + { + bookmark = BookmarkManager::self()->owner()->bookmarkCurrentPage(); + } + + // calculate position + int iconSize = IconSize(KIconLoader::Small) + c_iconMargin; + + // Add a generic 10 to move it a bit below and right. + // No need to be precise... + int iconWidth = 10 + width() - ((iconSize + c_iconMargin)); + int iconHeight = 10 + (height() - iconSize) / 2; + + QPoint p = mapToGlobal(QPoint(iconWidth, iconHeight)); + + // show bookmark widget + BookmarkWidget *widget = new BookmarkWidget(bookmark, window()); + widget->showAt(p); +} + + +void UrlBar::manageFavorites(QPoint pos) +{ + IconButton *bt = qobject_cast<IconButton *>(this->sender()); + if (!bt) + return; + + if (_tab->url().scheme() == QL1S("about")) + return; + + if (ReKonfig::previewUrls().contains(_tab->url().url())) + { + // remove site from favorites + FavoriteWidget *widget = new FavoriteWidget(_tab, window()); + connect(widget, SIGNAL(updateIcon()), this, SLOT(updateRightIcons())); + widget->showAt(pos); + return; + } + + // else, add as favorite + QStringList urls = ReKonfig::previewUrls(); + urls << _tab->url().url(); + ReKonfig::setPreviewUrls(urls); + + QStringList titles = ReKonfig::previewNames(); + titles << _tab->view()->title(); + ReKonfig::setPreviewNames(titles); + + // also, save a site snapshot + WebSnap *snap = new WebSnap(_tab->url(), this); + Q_UNUSED(snap); + + updateRightIcons(); +} + + +void UrlBar::updateRightIconPosition(IconButton *icon, int iconsCount) +{ + // NOTE: cannot show a (let's say) 16x16 icon in a 16x16 square. + // It needs some margin. It usually is 3, but using 4 (default rekonq icon margin) + // seems NOT a big problem and let's us using just one const ;) + int iconSize = IconSize(KIconLoader::Small) + c_iconMargin; + + int iconWidth = width() - ((iconSize + c_iconMargin) * iconsCount); + int iconHeight = (height() - iconSize) / 2; + + icon->move(iconWidth, iconHeight); +} diff --git a/src/urlbar/urlbar.h b/src/urlbar/urlbar.h new file mode 100644 index 00000000..b2cf44ac --- /dev/null +++ b/src/urlbar/urlbar.h @@ -0,0 +1,156 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2012 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@gmail.com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> +* Copyright (C) 2009-2011 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 URLBAR_H +#define URLBAR_H + +// Rekonq Includes +#include "rekonq_defines.h" + +// KDE Includes +#include <KUrl> +#include <KLineEdit> + +// Qt Includes +#include <QWeakPointer> +#include <QToolButton> + +// Forward Declarations +class QWidget; +class CompletionWidget; +class WebTab; +class QTimer; + + +class IconButton : public QToolButton +{ + Q_OBJECT + +public: + IconButton(QWidget *parent = 0); + +Q_SIGNALS: + void clicked(QPoint); + +protected: + void mouseReleaseEvent(QMouseEvent *event); +}; + + +// Definitions +typedef QList<IconButton *> IconButtonPointerList; + + +// ------------------------------------------------------------------------------------ + + +class REKONQ_TESTS_EXPORT UrlBar : public KLineEdit +{ + Q_OBJECT + +public: + + enum icon + { + KGet = 0x00000001, + RSS = 0x00000010, + SSL = 0x00000100, + BK = 0x00001000, + SearchEngine = 0x00010000, + Favorite = 0x00100000, + AdBlock = 0x01000000 + }; + + explicit UrlBar(QWidget *parent = 0); + ~UrlBar(); + + void activateSuggestions(bool); + +public Q_SLOTS: + void setQUrl(const QUrl &url); + + /** + * Let us add bookmarks as the major browsers do + * + */ + void manageBookmarks(); + +private Q_SLOTS: + void loadRequestedUrl(const KUrl& url, Rekonq::OpenType = Rekonq::CurrentTab); + + void loadFinished(); + + void clearRightIcons(); + void updateRightIcons(); + + void detectTypedString(const QString &); + void suggest(); + + void manageFavorites(QPoint); + + void refreshFavicon(); + + void pasteAndGo(); + void pasteAndSearch(); + void delSlot(); + bool isValidURL(QString url); + + /** + * Load digited url + */ + void loadDigitedUrl(); + +protected: + void paintEvent(QPaintEvent *event); + void keyPressEvent(QKeyEvent *event); + void focusInEvent(QFocusEvent *event); + void dropEvent(QDropEvent *event); + void mouseDoubleClickEvent(QMouseEvent *); + void contextMenuEvent(QContextMenuEvent *event); + void resizeEvent(QResizeEvent *); + +private: + /** + * Updates right icon position, given its number in the right icons list + * and considering rekonq window position/dimension + */ + void updateRightIconPosition(IconButton *, int); + IconButton *addRightIcon(UrlBar::icon); + + QWeakPointer<CompletionWidget> _box; + WebTab *_tab; + + IconButton *_icon; + IconButtonPointerList _rightIconsList; + + QTimer *_suggestionTimer; +}; + + +#endif diff --git a/src/urlbar/urlsuggester.cpp b/src/urlbar/urlsuggester.cpp new file mode 100644 index 00000000..52ba7640 --- /dev/null +++ b/src/urlbar/urlsuggester.cpp @@ -0,0 +1,397 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009-2012 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 "urlsuggester.h" +#include "urlsuggester.moc" + +// Local Includes +#include "historymanager.h" +#include "bookmarkmanager.h" + +#include "searchengine.h" + +// KDE Includes +#include <KBookmark> +#include <KService> +#include <KProtocolInfo> + +// Qt Includes +#include <QByteArray> + + +// NOTE +// default kurifilter plugin list (at least in my box): +// 1. "kshorturifilter" +// 2. "kurisearchfilter" +// 3. "localdomainurifilter" +// 4 ."kuriikwsfilter" +// 5. "fixhosturifilter" + + +// ------------------------------------------------------------------------ + + +// NOTE +// Induce an order in the history items +bool isHistoryItemRelevant(const HistoryItem &a, const HistoryItem &b) +{ + return a.relevance() > b.relevance(); +} + + +// ------------------------------------------------------------------------ + + +QRegExp UrlSuggester::_browseRegexp; +QRegExp UrlSuggester::_searchEnginesRegexp; + + +UrlSuggester::UrlSuggester(const QString &typedUrl) + : QObject() + , _typedString(typedUrl.trimmed()) +{ + if (_browseRegexp.isEmpty()) + { + QString protocol = QString("^(%1)").arg(KProtocolInfo::protocols().join("|")); + + QString localhost = QL1S("^localhost"); + + QString local = QL1S("^/"); + + QString ipv4 = QL1S("^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 = QL1S("^([0-9a-fA-F]{4}|0)(\\:([0-9a-fA-F]{4}|0)){7}"); + + QString address = QL1S("[\\d\\w-.]+\\.(a[cdefgilmnoqrstuwz]|b[abdefghijmnorstvwyz]|"\ + "c[acdfghiklmnoruvxyz]|d[ejkmnoz]|e[ceghrstu]|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|local|mil|museum|name|net|org|"\ + "pro)"); + + QString joiner = QL1S(")|("); + _browseRegexp = QRegExp(QL1C('(') + + protocol + joiner + + localhost + joiner + + local + joiner + + address + joiner + + ipv6 + joiner + + ipv4 + QL1C(')') + ); + } + + if (_searchEnginesRegexp.isEmpty()) + { + QString reg; + QString engineUrl; + Q_FOREACH(KService::Ptr s, SearchEngine::favorites()) + { + engineUrl = QRegExp::escape(s->property("Query").toString()).replace(QL1S("\\\\\\{@\\}"), QL1S("[\\d\\w-.]+")); + if (reg.isEmpty()) + reg = QL1C('(') + engineUrl + QL1C(')'); + else + reg = reg + QL1S("|(") + engineUrl + QL1C(')'); + } + _searchEnginesRegexp = QRegExp(reg); + } +} + + +UrlSuggestionList UrlSuggester::orderedSearchItems() +{ + if (_typedString.startsWith(QL1S("about:"))) + { + QStringList aboutUrlList; + aboutUrlList + << QL1S("about:home") + << QL1S("about:favorites") + << QL1S("about:closedTabs") + << QL1S("about:bookmarks") + << QL1S("about:history") + << QL1S("about:downloads") + << QL1S("about:tabs") + << QL1S("about:info"); + + QStringList aboutUrlResults = aboutUrlList.filter(_typedString, Qt::CaseInsensitive); + + UrlSuggestionList list; + + if (aboutUrlResults.isEmpty()) + { + UrlSuggestionItem info(UrlSuggestionItem::Browse, QL1S("about:info"), QL1S("info")); + list << info; + + return list; + } + + Q_FOREACH(const QString & urlResult, aboutUrlResults) + { + QString name = urlResult; + name.remove(0, 6); + UrlSuggestionItem item(UrlSuggestionItem::Browse, urlResult, name); + list << item; + } + + return list; + } + + //compute lists + computeHistory(); + computeQurlFromUserInput(); + computeWebSearches(); + computeBookmarks(); + + return orderLists(); +} + + +UrlSuggestionList UrlSuggester::orderLists() +{ + // NOTE + // The const int here decides the number of proper suggestions, taken from history & bookmarks + // You have to add here the "browse & search" options, always available. + const int availableEntries = 8; + + bool webSearchFirst = false; + // Browse & Search results + UrlSuggestionList browseSearch; + QString lowerTypedString = _typedString.toLower(); + if (_browseRegexp.indexIn(lowerTypedString) != -1) + { + webSearchFirst = true; + browseSearch << _webSearches; + } + else + { + browseSearch << _webSearches; + browseSearch << _qurlFromUserInput; + } + + + // find relevant items (the one you are more probably searching...) + UrlSuggestionList relevant; + + // history + Q_FOREACH(const UrlSuggestionItem & item, _history) + { + QString hst = KUrl(item.url).host(); + if (item.url.startsWith(_typedString) + || hst.startsWith(_typedString) + || hst.remove("www.").startsWith(_typedString)) + { + relevant << item; + _history.removeOne(item); + break; + } + } + + // bookmarks + Q_FOREACH(const UrlSuggestionItem & item, _bookmarks) + { + QString hst = KUrl(item.url).host(); + if (item.url.startsWith(_typedString) + || hst.startsWith(_typedString) + || hst.remove("www.").startsWith(_typedString)) + { + relevant << item; + _bookmarks.removeOne(item); + break; + } + } + + // decide history & bookmarks number + int historyCount = _history.count(); + int bookmarksCount = _bookmarks.count(); + int relevantCount = relevant.count(); + + const int historyEntries = (availableEntries - relevantCount) / 2; + const int bookmarksEntries = availableEntries - relevantCount - historyEntries; + + if (historyCount >= historyEntries && bookmarksCount >= bookmarksEntries) + { + _history = _history.mid(0, historyEntries); + _bookmarks = _bookmarks.mid(0, bookmarksEntries); + } + else if (historyCount < historyEntries && bookmarksCount >= bookmarksEntries) + { + if (historyCount + bookmarksCount > availableEntries) + { + _bookmarks = _bookmarks.mid(0, availableEntries - historyCount); + } + } + else if (historyCount >= historyEntries && bookmarksCount < bookmarksEntries) + { + if (historyCount + bookmarksCount > availableEntries) + { + _history = _history.mid(0, availableEntries - bookmarksCount); + } + } + + // and finally, results + UrlSuggestionList list; + + if (webSearchFirst) + list << _qurlFromUserInput; + list += relevant + browseSearch + _history + _bookmarks; + return list; +} + + +////////////////////////////////////////////////////////////////////////// +// PRIVATE ENGINES + + +// QUrl from User Input (easily the best solution... ) +void UrlSuggester::computeQurlFromUserInput() +{ + QString url = _typedString; + QUrl urlFromUserInput = QUrl::fromUserInput(url); + if (urlFromUserInput.isValid()) + { + // ensure http(s) hosts are lower cases + if (urlFromUserInput.scheme().startsWith(QL1S("http"))) + { + QString hst = urlFromUserInput.host(); + urlFromUserInput.setHost(hst.toLower()); + } + + QString urlString = urlFromUserInput.toString(); + QString gTitle = i18nc("Browse a website", "Browse"); + UrlSuggestionItem gItem(UrlSuggestionItem::Browse, urlString, gTitle); + _qurlFromUserInput << gItem; + } +} + + +// webSearches +void UrlSuggester::computeWebSearches() +{ + QString query = _typedString; + KService::Ptr engine = SearchEngine::fromString(_typedString); + if (engine) + { + query = query.remove(0, _typedString.indexOf(SearchEngine::delimiter()) + 1); + + UrlSuggestionItem item = UrlSuggestionItem(UrlSuggestionItem::Search, SearchEngine::buildQuery(engine, query), query); + UrlSuggestionList list; + list << item; + _webSearches = list; + } +} + + +// history +void UrlSuggester::computeHistory() +{ + QList<HistoryItem> found = HistoryManager::self()->find(_typedString); + qSort(found.begin(), found.end(), isHistoryItemRelevant); + + Q_FOREACH(const HistoryItem & i, found) + { + if (_searchEnginesRegexp.isEmpty() || _searchEnginesRegexp.indexIn(i.url) == -1) //filter all urls that are search engine results + { + UrlSuggestionItem gItem(UrlSuggestionItem::History, i.url, i.title); + _history << gItem; + } + } +} + + +// bookmarks +void UrlSuggester::computeBookmarks() +{ + QList<KBookmark> found = BookmarkManager::self()->find(_typedString); + Q_FOREACH(const KBookmark & b, found) + { + UrlSuggestionItem gItem(UrlSuggestionItem::Bookmark, b.url().url(), b.fullText()); + _bookmarks << gItem; + } +} + + +// opensearch suggestion +void UrlSuggester::computeSuggestions() +{ + // NOTE + // This attempt basically cuts out open search suggestions. + UrlSuggestionList list; + emit suggestionsReady(list, _typedString); + return; + +// // if a string startsWith /, it is probably a local path +// // so, no need for suggestions... +// if (_typedString.startsWith('/') || !rApp->opensearchManager()->isSuggestionAvailable()) +// { +// UrlSuggestionList list; +// emit suggestionsReady(list, _typedString); +// return; +// } +// +// QString query = _typedString; +// KService::Ptr engine = SearchEngine::fromString(_typedString); +// if (engine) +// { +// query = query.remove(0, _typedString.indexOf(SearchEngine::delimiter()) + 1); +// setSearchEngine(engine); +// } +// +// connect(rApp->opensearchManager(), +// SIGNAL(suggestionsReceived(QString,ResponseList)), +// this, +// SLOT(suggestionsReceived(QString,ResponseList))); +// +// _typedQuery = query; +// rApp->opensearchManager()->requestSuggestion(query); +} + + +// void UrlSuggester::suggestionsReceived(const QString &text, const ResponseList &suggestions) +// { +// if (text != _typedString) +// return; +// +// UrlSuggestionList sugList; +// QString urlString; +// Q_FOREACH(const Response & i, suggestions) +// { +// if (text == i.title) +// continue; +// +// urlString = i.url; +// if (urlString.isEmpty()) +// { +// urlString = SearchEngine::buildQuery(UrlSuggester::searchEngine(), i.title); +// } +// +// UrlSuggestionItem gItem(UrlSuggestionItem::Suggestion, urlString, i.title, i.description, i.image, i.image_width, i.image_height); +// sugList << gItem; +// } +// emit suggestionsReady(sugList, _typedString); +// this->deleteLater(); +// } diff --git a/src/urlbar/urlsuggester.h b/src/urlbar/urlsuggester.h new file mode 100644 index 00000000..4f20e701 --- /dev/null +++ b/src/urlbar/urlsuggester.h @@ -0,0 +1,155 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009-2012 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_SUGGESTER_H +#define URL_SUGGESTER_H + + +// Rekonq Includes +#include "rekonq_defines.h" + +// KDE Includes +#include <KUrl> +#include <KService> + +// Qt Includes +#include <QString> +#include <QList> + + +class UrlSuggestionItem +{ +public: + + enum types + { + Undefined = 0x00000000, + Search = 0x00000001, + Browse = 0x00000010, + History = 0x00000100, + Bookmark = 0x00001000, + Suggestion = 0x00010000 + }; + + int type; + QString url; + QString title; + QString description; + QString image; + int image_width; + int image_height; + QString bookmarkPath; + + UrlSuggestionItem(const UrlSuggestionItem &item) + : type(item.type) + , url(item.url) + , title(item.title) + , description(item.description) + , image(item.image) + , image_width(item.image_width) + , image_height(item.image_height) + {}; + + UrlSuggestionItem() + : type(UrlSuggestionItem::Undefined) + , url(QString()) + , title(QString()) + , description(QString()) + , image(QString()) + , image_width(0) + , image_height(0) + {}; + + UrlSuggestionItem(const int &_type, + const QString &_url, + const QString &_title = QString(), + const QString &_description = QString(), + const QString &_image = QString(), + const int &_image_width = 0, + const int &_image_height = 0 + ) + : type(_type) + , url(_url) + , title(_title) + , description(_description) + , image(_image) + , image_width(_image_width) + , image_height(_image_height) + {}; + + inline bool operator==(const UrlSuggestionItem &i) const + { + return i.url == url;//TODO && i.title == title; + } +}; + + +typedef QList <UrlSuggestionItem> UrlSuggestionList; + + +// ---------------------------------------------------------------------- + + +class HistoryItem; + + +class UrlSuggester : public QObject +{ + Q_OBJECT + +public: + UrlSuggester(const QString &typedUrl); + + UrlSuggestionList orderedSearchItems(); + + void computeSuggestions(); + +Q_SIGNALS: + void suggestionsReady(const UrlSuggestionList &, const QString &); + +private: + void computeWebSearches(); + void computeHistory(); + void computeQurlFromUserInput(); + void computeBookmarks(); + + UrlSuggestionList orderLists(); + + QString _typedString; + + UrlSuggestionList _webSearches; + UrlSuggestionList _qurlFromUserInput; + UrlSuggestionList _history; + UrlSuggestionList _bookmarks; + UrlSuggestionList _suggestions; + + static QRegExp _browseRegexp; + static QRegExp _searchEnginesRegexp; +}; + +// ------------------------------------------------------------------------------ + +#endif // URL_SUGGESTER_H diff --git a/src/urlbar/webshortcutwidget.cpp b/src/urlbar/webshortcutwidget.cpp new file mode 100644 index 00000000..c6dc3b79 --- /dev/null +++ b/src/urlbar/webshortcutwidget.cpp @@ -0,0 +1,163 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Fredy Yanardi <fyanardi@gmail.com> +* Copyright (C) 2010-2011 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2012 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 "webshortcutwidget.h" +#include "webshortcutwidget.moc" + +// KDE Includes +#include <KGlobalSettings> +#include <KIcon> +#include <KLocale> +#include <KServiceTypeTrader> + +// Qt Includes +#include <QSet> +#include <QLabel> +#include <QLineEdit> +#include <QDialogButtonBox> +#include <QFormLayout> + + +WebShortcutWidget::WebShortcutWidget(QWidget *parent) + : QMenu(parent) + , m_wsLineEdit(new QLineEdit(this)) + , m_nameLineEdit(new QLineEdit(this)) + , m_noteLabel(new QLabel(this)) +{ + setAttribute(Qt::WA_DeleteOnClose); + setFixedWidth(350); + + QFormLayout *layout = new QFormLayout(this); + QVBoxLayout *vLay = new QVBoxLayout; + + // Web Search Icon + QLabel *webSearchIcon = new QLabel(this); + webSearchIcon->setPixmap(KIcon("edit-web-search").pixmap(32, 32)); + + // Title + QLabel *titleLabel = new QLabel(this); + titleLabel->setText("<h4>" + i18n("Add Search Engine") + "</h4>"); + vLay->addWidget(titleLabel); + + // Name + vLay->addWidget(m_nameLineEdit); + + layout->addRow(webSearchIcon, vLay); + + // Shortcuts + QLabel *shortcutsLabel = new QLabel(i18n("Shortcuts:"), this); + layout->addRow(shortcutsLabel, m_wsLineEdit); + connect(m_wsLineEdit, SIGNAL(textChanged(QString)), SLOT(shortcutsChanged(QString))); + + // Note + m_noteLabel->setWordWrap(true); + layout->addRow(m_noteLabel); + m_noteLabel->hide(); + + // Ok & Cancel buttons + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); + layout->addWidget(buttonBox); + + m_providers = KServiceTypeTrader::self()->query("SearchProvider"); + + m_wsLineEdit->setFocus(); +} + + +void WebShortcutWidget::showAt(const QPoint &pos) +{ + adjustSize(); + + QPoint p(pos.x() - width(), pos.y() + 10); + move(p); + exec(); +} + + +void WebShortcutWidget::show(const KUrl &url, const QString &openSearchName, const QPoint &pos) +{ + m_wsLineEdit->clear(); + m_nameLineEdit->setText(openSearchName); + m_url = url; + showAt(pos); +} + + +void WebShortcutWidget::accept() +{ + emit webShortcutSet(m_url, m_nameLineEdit->text(), m_wsLineEdit->text()); + + // close widget (and destroy it) + close(); +} + + +void WebShortcutWidget::shortcutsChanged(const QString& newShorthands) +{ + int savedCursorPosition = m_wsLineEdit->cursorPosition(); + QString normalizedShorthands = QString(newShorthands).replace(QL1C(' '), QL1C(',')); + m_wsLineEdit->setText(normalizedShorthands); + m_wsLineEdit->setCursorPosition(savedCursorPosition); + + QSet<QString> shorthands = normalizedShorthands.split(QL1C(',')).toSet(); + QString contenderName = ""; + QString contenderWS = ""; + + Q_FOREACH(const QString & shorthand, shorthands) + { + Q_FOREACH(KService::Ptr provider, m_providers) + { + if (provider->property("Keys").toStringList().contains(shorthand)) + { + contenderName = provider->property("Name").toString(); + contenderWS = shorthand; + break; + } + } + } + + if (!contenderName.isEmpty()) + { + m_noteLabel->setText(i18n("The shortcut \"%1\" is already assigned to \"%2\".", contenderWS, contenderName)); + m_noteLabel->setVisible(true); + resize(minimumSize().width(), minimumSizeHint().height() + 15); + } + else + { + m_noteLabel->clear(); + bool noteIsVisible = m_noteLabel->isVisible(); + m_noteLabel->setVisible(false); + if (noteIsVisible) + { + resize(minimumSize()); + } + } +} diff --git a/src/urlbar/webshortcutwidget.h b/src/urlbar/webshortcutwidget.h new file mode 100644 index 00000000..d1291714 --- /dev/null +++ b/src/urlbar/webshortcutwidget.h @@ -0,0 +1,76 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Fredy Yanardi <fyanardi@gmail.com> +* Copyright (C) 2010-2011 by Lionel Chauvin <megabigbug@yahoo.fr> +* Copyright (C) 2012 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 WEBSHORTCUTWIDGET_H +#define WEBSHORTCUTWIDGET_H + + +// Rekonq Includes +#include "rekonq_defines.h" + +// KDE Includes +#include <KUrl> +#include <KService> + +// Qt Includes +#include <QMenu> + +// Forward Declarations +class QLabel; +class QLineEdit; +class QPushButton; + + +class REKONQ_TESTS_EXPORT WebShortcutWidget : public QMenu +{ + Q_OBJECT +public: + WebShortcutWidget(QWidget *parent = 0); + + void show(const KUrl &url, const QString &openSearchName, const QPoint &pos); + +private Q_SLOTS: + void accept(); + void shortcutsChanged(const QString& newShorthands); + +Q_SIGNALS: + void webShortcutSet(const KUrl &url, const QString &openSearchName, const QString &webShortcut); + +private: + QLineEdit *m_wsLineEdit; + QLineEdit *m_nameLineEdit; + QLabel *m_noteLabel; + + KService::List m_providers; + KUrl m_url; + + void showAt(const QPoint &pos); +}; + +#endif // WEBSHORTCUTWIDGET_H + diff --git a/src/webtab/webtab.cpp b/src/webtab/webtab.cpp index 2dce52d4..27e711fd 100644 --- a/src/webtab/webtab.cpp +++ b/src/webtab/webtab.cpp @@ -168,6 +168,24 @@ bool WebTab::isPageLoading() } +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; +} + + +bool WebTab::hasNewSearchEngine() +{ + QWebElement e = page()->mainFrame()->findFirstElement(QL1S("head >link[rel=\"search\"][ type=\"application/opensearchdescription+xml\"]")); + return !e.isNull(); // FIXME && !rApp->opensearchManager()->engineExists(extractOpensearchUrl(e)); +} + + void WebTab::createWalletBar(const QString &key, const QUrl &url) { // check if the url is in the wallet blacklist diff --git a/src/webtab/webtab.h b/src/webtab/webtab.h index f875071d..5984ea53 100644 --- a/src/webtab/webtab.h +++ b/src/webtab/webtab.h @@ -70,6 +70,9 @@ public: KUrl url(); + bool hasRSSInfo(); + bool hasNewSearchEngine(); + void createPreviewSelectorBar(int index); void hideSelectorBar(); |