diff options
| author | adjam <adjam@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-05-03 23:51:22 +0000 | 
|---|---|---|
| committer | adjam <adjam@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-05-03 23:51:22 +0000 | 
| commit | c0190e41f7f2e5fe30fa8556fa35f43950afbfdb (patch) | |
| tree | 086794c886f413b3e4dbcfad9d3697a55f8dd64b /src | |
| parent | Initial rekcommit.. (diff) | |
| download | rekonq-c0190e41f7f2e5fe30fa8556fa35f43950afbfdb.tar.xz | |
Importing recode (rekonq code).
I'm sorry I coudn't perform this with gitsvn or tailor..
but I cannot lose all the evening just for this.
And I need to sleep now..
git-svn-id: svn+ssh://svn.kde.org/home/kde/trunk/playground/network/rekonq@963146 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src')
59 files changed, 11069 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..a64cc747 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,63 @@ +SET( rekonq_SRCS +    autosaver.cpp  +    application.cpp  +    mainwindow.cpp  +    mainview.cpp +    tabbar.cpp +    cookiejar.cpp  +    edittableview.cpp  +    edittreeview.cpp  +    history.cpp +    download.cpp +    bookmarks.cpp +    modelmenu.cpp  +    networkaccessmanager.cpp +    urlbar.cpp +    findbar.cpp +    searchbar.cpp +    settings.cpp +    webview.cpp  +    main.cpp +    sidepanel.cpp +    panelhistory.cpp +    lineedit.cpp +    stackedurlbar.cpp +) + +KDE4_ADD_UI_FILES( rekonq_SRCS +    cookies.ui +    cookiesexceptions.ui +    history.ui +    password.ui +    proxy.ui +    settings_general.ui +    settings_fonts.ui +    settings_privacy.ui +    settings_proxy.ui +    settings_webkit.ui + ) + +KDE4_ADD_KCFG_FILES( rekonq_SRCS rekonq.kcfgc ) + +### ------------------------------------------ + +ADD_DEFINITIONS( ${KDE4_DEFINITIONS} ) + +KDE4_ADD_EXECUTABLE( rekonq ${rekonq_SRCS} ) + +TARGET_LINK_LIBRARIES( rekonq +    ${QT_LIBRARIES}  +    ${QT_QTNETWORK_LIBRARY} +    ${QT_QTWEBKIT_LIBRARY}  +    ${QT_QTUITOOLS_LIBRARY} +	${KDE4_KUTILS_LIBS} +	${KDE4_KDEUI_LIBS} +    ${KDE4_KIO_LIBS} +) + +INSTALL( TARGETS rekonq ${INSTALL_TARGETS_DEFAULT_ARGS} ) + +########### install files ############### + +INSTALL( FILES rekonq.kcfg  DESTINATION  ${KCFG_INSTALL_DIR} ) +INSTALL( FILES rekonqui.rc  DESTINATION  ${DATA_INSTALL_DIR}/rekonq ) diff --git a/src/application.cpp b/src/application.cpp new file mode 100644 index 00000000..ec24691e --- /dev/null +++ b/src/application.cpp @@ -0,0 +1,206 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +// Self Includes +#include "application.h" +#include "application.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "mainwindow.h" +#include "cookiejar.h" +#include "history.h" +#include "networkaccessmanager.h" +#include "mainview.h" +#include "webview.h" +#include "download.h" + +// KDE Includes +#include <KCmdLineArgs> +#include <KAboutData> +#include <KStandardDirs> +#include <KConfig> +#include <kio/job.h> +#include <kio/jobclasses.h> + +// Qt Includes +#include <QtCore> +#include <QtWebKit> + + +QPointer<HistoryManager> Application::s_historyManager; +QPointer<NetworkAccessManager> Application::s_networkAccessManager; +QPointer<DownloadManager> Application::s_downloadManager; +QPointer<BookmarkProvider> Application::s_bookmarkProvider; + + + +Application::Application() +        : KUniqueApplication() +{ +} + + +Application::~Application() +{ +    delete m_mainWindow; +    delete s_bookmarkProvider; +    delete s_networkAccessManager; +    delete s_historyManager; +} + + +int Application::newInstance() +{ +    KCmdLineArgs::setCwd(QDir::currentPath().toUtf8()); +    KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + +    if (!m_mainWindow) +    { +        m_mainWindow = new MainWindow(); + +        m_mainWindow->setObjectName("MainWindow"); +        setWindowIcon(KIcon("rekonq")); + +        m_mainWindow->show(); + +        QTimer::singleShot(0, this, SLOT(postLaunch())); +    } + +    if (args->count() > 0) +    { +        for (int i = 0; i < args->count(); ++i) +        { +            KUrl url = MainWindow::guessUrlFromString(args->arg(i)); +            newWebView(); +            mainWindow()->loadUrl(url); +        } +        args->clear(); +    } +    else +    { +        newWebView(); +        mainWindow()->slotHome(); +    } + +    return 0; +} + + +Application *Application::instance() +{ +    return (static_cast<Application *>(QCoreApplication::instance())); +} + + +void Application::postLaunch() +{ +    // set Icon Database Path to store "favicons" associated with web sites +    QString directory = KStandardDirs::locateLocal("cache" , "" , true); +    if (directory.isEmpty()) +    { +        directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName(); +    } +    QWebSettings::setIconDatabasePath(directory); + +    Application::historyManager(); +} + + + +void Application::slotSaveConfiguration() const +{ +    ReKonfig::self()->writeConfig(); +} + + +MainWindow *Application::mainWindow() +{ +    return m_mainWindow; +} + + +WebView *Application::newWebView(Rekonq::OpenType type) +{ +    return m_mainWindow->mainView()->newWebView(type); +} + + +CookieJar *Application::cookieJar() +{ +    return (CookieJar*)networkAccessManager()->cookieJar(); +} + + +NetworkAccessManager *Application::networkAccessManager() +{ +    if (!s_networkAccessManager) +    { +        s_networkAccessManager = new NetworkAccessManager(); +        s_networkAccessManager->setCookieJar(new CookieJar); +    } +    return s_networkAccessManager; +} + + +HistoryManager *Application::historyManager() +{ +    if (!s_historyManager) +    { +        s_historyManager = new HistoryManager(); +        QWebHistoryInterface::setDefaultInterface(s_historyManager); +    } +    return s_historyManager; +} + + +DownloadManager *Application::downloadManager() +{ +    if (!s_downloadManager) +    { +        s_downloadManager = new DownloadManager(); +    } +    return s_downloadManager; +} + + +BookmarkProvider *Application::bookmarkProvider() +{ +    if (!s_bookmarkProvider) +    { +        s_bookmarkProvider = new BookmarkProvider(); +    } +    return s_bookmarkProvider; +} + + +KIcon Application::icon(const KUrl &url) const +{ +    KIcon icon = KIcon(QWebSettings::iconForUrl(url)); +    if (icon.isNull()) +    { +        icon = KIcon("kde"); +    } +    return icon; +} diff --git a/src/application.h b/src/application.h new file mode 100644 index 00000000..61f4af81 --- /dev/null +++ b/src/application.h @@ -0,0 +1,115 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#ifndef APPLICATION_H +#define APPLICATION_H + +// Qt Includes +#include <QPointer> + +// KDE Includes +#include <KUniqueApplication> +#include <KCmdLineArgs> +#include <KIcon> +#include <KUrl> +#include <KJob> +#include <kio/job.h> +#include <kio/jobclasses.h> + + +// Forward Declarations +class KIcon; +class KUrl; +class BookmarkProvider; +class CookieJar; +class DownloadManager; +class HistoryManager; +class MainWindow; +class NetworkAccessManager; +class WebView; + + +namespace Rekonq +{ +    /** +     * @short Open link options +     * Different modes of opening new tab +     */ +    enum OpenType +    { +        Default,    ///< open url according to users settings +        New,        ///< open url in new tab and make it current +        Background  ///< open url in new tab in background +    }; +} + + +/** +  * +  */ +class Application : public KUniqueApplication +{ +    Q_OBJECT + +public: +    Application(); +    ~Application(); +    int newInstance(); +    static Application *instance(); + +    MainWindow *mainWindow(); +    WebView* newWebView(Rekonq::OpenType type = Rekonq::Default); + +    KIcon icon(const KUrl &url) const; + +    static HistoryManager *historyManager(); +    static CookieJar *cookieJar(); +    static NetworkAccessManager *networkAccessManager(); +    static DownloadManager *downloadManager(); +    static BookmarkProvider *bookmarkProvider(); + +public slots: +    /** +     * Save application's configuration +     * @see ReKonfig::self()->writeConfig(); +     */ +    void slotSaveConfiguration() const; + + +private slots: + +    /** +     * Any actions that can be delayed until the window is visible +     */ +    void postLaunch(); + + +private: +    static QPointer<HistoryManager> s_historyManager; +    static QPointer<NetworkAccessManager> s_networkAccessManager; +    static QPointer<DownloadManager> s_downloadManager; +    static QPointer<BookmarkProvider> s_bookmarkProvider; + +    QPointer<MainWindow> m_mainWindow; +}; + +#endif // APPLICATION_H diff --git a/src/autosaver.cpp b/src/autosaver.cpp new file mode 100644 index 00000000..25bf9016 --- /dev/null +++ b/src/autosaver.cpp @@ -0,0 +1,90 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +// Local Includes +#include "autosaver.h" + +// KDE Includes +#include <KDebug> + +// Qt Includes +#include <QtCore> + + +#define AUTOSAVE_IN  1000 * 3  // seconds +#define MAXWAIT      1000 * 15 // seconds + + +AutoSaver::AutoSaver(QObject *parent) : QObject(parent) +{ +    Q_ASSERT(parent); +} + + +AutoSaver::~AutoSaver() +{ +    if (m_timer.isActive()) +        kWarning() << "AutoSaver: still active when destroyed, changes not saved."; +} + + +void AutoSaver::changeOccurred() +{ +    if (m_firstChange.isNull()) +        m_firstChange.start(); + +    if (m_firstChange.elapsed() > MAXWAIT) +    { +        saveIfNeccessary(); +    } +    else +    { +        m_timer.start(AUTOSAVE_IN, this); +    } +} + + +void AutoSaver::timerEvent(QTimerEvent *event) +{ +    if (event->timerId() == m_timer.timerId()) +    { +        saveIfNeccessary(); +    } +    else +    { +        QObject::timerEvent(event); +    } +} + + +void AutoSaver::saveIfNeccessary() +{ +    if (!m_timer.isActive()) +        return; +    m_timer.stop(); +    m_firstChange = QTime(); +    if (!QMetaObject::invokeMethod(parent(), "save", Qt::DirectConnection)) +    { +        kWarning() << "AutoSaver: error invoking slot save() on parent"; +    } +} + diff --git a/src/autosaver.h b/src/autosaver.h new file mode 100644 index 00000000..8931da13 --- /dev/null +++ b/src/autosaver.h @@ -0,0 +1,55 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#ifndef AUTOSAVER_H +#define AUTOSAVER_H + +#include <QtCore> + +/* +    This class will call the save() slot on the parent object when the parent changes. +    It will wait several seconds after changed() to combining multiple changes and +    prevent continuous writing to disk. +  */ +class AutoSaver : public QObject +{ +    Q_OBJECT + +public: +    AutoSaver(QObject *parent); +    ~AutoSaver(); +    void saveIfNeccessary(); + +public slots: +    void changeOccurred(); + +protected: +    void timerEvent(QTimerEvent *event); + +private: +    QBasicTimer m_timer; +    QTime m_firstChange; + +}; + +#endif // AUTOSAVER_H + diff --git a/src/bookmarks.cpp b/src/bookmarks.cpp new file mode 100644 index 00000000..c7f4da98 --- /dev/null +++ b/src/bookmarks.cpp @@ -0,0 +1,278 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +// Self Includes +#include "bookmarks.h" +#include "bookmarks.moc" + +// Local Includes +#include "mainwindow.h" +#include "webview.h" +#include "application.h" + +// KDE Includes +#include <KActionCollection> +#include <KBookmark> +#include <KBookmarkAction> +#include <KBookmarkActionMenu> +#include <KBookmarkGroup> +#include <KBookmarkMenu> +#include <KToolBar> +#include <KDebug> +#include <KMenu> +#include <KMimeType> +#include <KStandardDirs> +#include <KUrl> + +// Qt Includes +#include <QActionGroup> +#include <QFile> + + +BookmarkOwner::BookmarkOwner(QObject *parent) +        : QObject(parent) +        , KBookmarkOwner() +{ +} + + +void BookmarkOwner::openBookmark(const KBookmark & bookmark, +                                 Qt::MouseButtons mouseButtons, +                                 Qt::KeyboardModifiers keyboardModifiers) +{ +    Q_UNUSED(mouseButtons) +    Q_UNUSED(keyboardModifiers) + +    emit openUrl(bookmark.url()); +} + + +QString BookmarkOwner::currentUrl() const +{ +    return Application::instance()->mainWindow()->currentTab()->url().url(); +} + + +QString BookmarkOwner::currentTitle() const +{ +    return Application::instance()->mainWindow()->currentTab()->title(); +} + + +void BookmarkOwner::openFolderinTabs(const KBookmarkGroup &bm) +{ +    QList<KUrl> urlList = bm.groupUrlList(); +    QList<KUrl>::iterator url; +    Application* app = Application::instance(); +    for (url = urlList.begin(); url != urlList.end(); ++url) +    { +        app->newWebView(); +        app->mainWindow()->loadUrl(*url); +    } +} + + +// ------------------------------------------------------------------------------------------------------ + + +BookmarkMenu::BookmarkMenu(KBookmarkManager *manager, +                           KBookmarkOwner *owner, +                           KMenu *menu, +                           KActionCollection* actionCollection) +        : KBookmarkMenu(manager, owner, menu, actionCollection) + +{ +    actionCollection->addAction(KStandardAction::AddBookmark, +                                QLatin1String("add_bookmark_payload"), +                                this, SLOT(slotAddBookmark())); + +} + +BookmarkMenu::~BookmarkMenu() +{ +} + + +KMenu *BookmarkMenu::viewContextMenu(QAction *action) +{ +    return contextMenu(action); +} + + +void BookmarkMenu::slotAddBookmark() +{ +    KAction *action = qobject_cast<KAction *>(sender()); +    if (action && !action->data().isNull()) +    { +        KBookmarkGroup parentBookmark = manager()->findByAddress(parentAddress()).toGroup(); +        /// TODO Add bookmark Icon +        parentBookmark.addBookmark(owner()->currentTitle(), action->data().toUrl()); +        manager()->emitChanged(); +        return; +    } + +    KBookmarkMenu::slotAddBookmark(); +} + + +// ------------------------------------------------------------------------------------------------------ + + +BookmarkProvider::BookmarkProvider(QWidget *parent) +        : QWidget(parent) +        , m_manager(0) +        , m_owner(0) +        , m_menu(new KMenu(this)) +        , m_actionCollection(new KActionCollection(this)) +        , m_bookmarkMenu(0) +        , m_bookmarkToolBar(0) +{ +    KUrl bookfile = KUrl("~/.kde/share/apps/konqueror/bookmarks.xml");  // share konqueror bookmarks + +    if (!QFile::exists(bookfile.path())) +    { +        bookfile = KUrl("~/.kde4/share/apps/konqueror/bookmarks.xml"); +        if (!QFile::exists(bookfile.path())) +        { +            QString bookmarksDefaultPath = KStandardDirs::locate("appdata" , "defaultbookmarks.xbel"); +            kWarning() << bookmarksDefaultPath; +            QFile bkms(bookmarksDefaultPath); +            QString bookmarksPath = KStandardDirs::locateLocal("appdata", "bookmarks.xml", true); +            bookmarksPath.replace("rekonq", "konqueror"); +            bkms.copy(bookmarksPath); + +            bookfile = KUrl(bookmarksPath); +        } +    } +    m_manager = KBookmarkManager::managerForExternalFile(bookfile.path()); +    connect(m_manager, SIGNAL(changed(const QString &, const QString &)), +            this, SLOT(slotBookmarksChanged(const QString &, const QString &))); + +    // setup menu +    m_owner = new BookmarkOwner(this); +    connect(m_owner, SIGNAL(openUrl(const KUrl&)), this, SIGNAL(openUrl(const KUrl&))); +    m_bookmarkMenu = new BookmarkMenu(m_manager, m_owner, m_menu, m_actionCollection); + +    // setup toolbar +    setupToolBar(); +} + + +BookmarkProvider::~BookmarkProvider() +{ +    delete m_bookmarkToolBar; +    delete m_bookmarkMenu; +    delete m_actionCollection; +    delete m_menu; +    delete m_owner; +    delete m_manager; +} + + +void BookmarkProvider::setupToolBar() +{ +    m_bookmarkToolBar = new KToolBar(this); +    m_bookmarkToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); +    m_bookmarkToolBar->setIconDimensions(16); +    m_bookmarkToolBar->setAcceptDrops(true); +    m_bookmarkToolBar->setContentsMargins(0, 0, 0, 0); +    m_bookmarkToolBar->setMinimumHeight(16); +    m_bookmarkToolBar->setContextMenuPolicy(Qt::CustomContextMenu); +    connect(m_bookmarkToolBar, SIGNAL(customContextMenuRequested(const QPoint &)), +            this, SLOT(contextMenu(const QPoint &))); + +    slotBookmarksChanged("", ""); +} + + +void BookmarkProvider::slotBookmarksChanged(const QString &group, const QString &caller) +{ +    Q_UNUSED(group) +    Q_UNUSED(caller) + +    if (!m_bookmarkToolBar) +    { +        kWarning() << "There is no bookmark toolbar"; +        return; +    } + +    KActionCollection bookmarkCollection(this); + +    KBookmarkGroup toolBarGroup = m_manager->toolbar(); +    if (toolBarGroup.isNull()) +        return; + +    KBookmark bookmark = toolBarGroup.first(); +    while (!bookmark.isNull()) +    { +        if (!bookmark.isGroup()) +        { +            KAction *action = new KBookmarkAction(bookmark, m_owner, this); +            QString text = bookmark.address(); +            bookmarkCollection.addAction(text, action); +        } +        bookmark = toolBarGroup.next(bookmark); +    } +    m_bookmarkToolBar->clear(); +    m_bookmarkToolBar->addActions(bookmarkCollection.actions()); +} + + +QAction *BookmarkProvider::actionByName(const QString &name) +{ +    QAction *action = m_actionCollection->action(name); +    if (action) +        return action; +    /* else */ +    kWarning() << "Action named: " << name << " not found, returning empty action."; +    return new QAction(this);  // return empty object instead of NULL pointer +} + + +void BookmarkProvider::contextMenu(const QPoint &point) +{ +    KAction* action = dynamic_cast<KAction*>(m_bookmarkToolBar->actionAt(point)); +    if (!action) +        return; +    KMenu *menu = m_bookmarkMenu->viewContextMenu(action); +    menu->popup(m_bookmarkToolBar->mapToGlobal(point)); +} + + +KActionMenu* BookmarkProvider::bookmarkActionMenu() +{ +    KActionMenu *bookmarkActionMenu = new KActionMenu(this); +    bookmarkActionMenu->setMenu(m_menu); +    bookmarkActionMenu->setText(i18n("&Bookmarks")); +    return bookmarkActionMenu; +} + + +KAction* BookmarkProvider::bookmarkToolBarAction() +{ +    KAction *bookmarkToolBarAction = new KAction(this); +    bookmarkToolBarAction->setDefaultWidget(m_bookmarkToolBar);  // The ownership is transferred to action +    bookmarkToolBarAction->setText(i18n("Bookmarks Bar")); +    bookmarkToolBarAction->setShortcutConfigurable(false); +    return bookmarkToolBarAction; +} + diff --git a/src/bookmarks.h b/src/bookmarks.h new file mode 100644 index 00000000..d7213cb7 --- /dev/null +++ b/src/bookmarks.h @@ -0,0 +1,238 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#ifndef BOOKMARKS_H +#define BOOKMARKS_H + +// Qt Includes +#include <QWidget> + +// KDE Includes +#include <KBookmarkOwner> + +// Forward Declarations +class BookmarkProvider; + +class KAction; +class KActionCollection; +class KActionMenu; +class KUrl; +class KToolBar; +class KBookmarkManager; + + +/** + * Reimplementation of KBookmarkOwner, this class allows to manage + * bookmarks as actions + * + */ +class BookmarkOwner : public QObject , public KBookmarkOwner +{ +    Q_OBJECT + +public: + +    /** +     * @short The class constructor. +     * +     * @param parent the pointer parent Bookmark provider. We need it +     *               to get pointer to MainWindow +     */ +    BookmarkOwner(QObject *parent = 0); +    virtual ~BookmarkOwner() {} + +    /** +     * This function is called when a bookmark is selected and belongs to +     * the ancestor class. +     * This method actually emits signal to load bookmark's url. +     * +     * @param bookmark          the bookmark to open +     * @param mouseButtons      the mouse buttons clicked to select the bookmark +     * @param keyboardModifiers the keyboard modifiers pushed when the bookmark was selected +     */ +    virtual void openBookmark(const KBookmark &bookmark, +                              Qt::MouseButtons mouseButtons, +                              Qt::KeyboardModifiers keyboardModifiers); + + +    /** +     * this method, from KBookmarkOwner interface, allows to add the current page +     * to the bookmark list, returning the URL page as QString. +     * +     * @return the current page's URL +     */ +    virtual QString currentUrl() const; + +    /** +     * this method, from KBookmarkOwner interface, allows to add the current page +     * to the bookmark list, returning the title's page as QString. +     * +     * @return the current page's title +     */ +    virtual QString currentTitle() const; + +    /** +    * This function returns whether the owner supports tabs. +    */ +    virtual bool supportsTabs() const +    { +        return true; +    } + +    /** +    * Called if the user wants to open every bookmark in this folder in a new tab. +    * The default implementation does nothing. +    * This is only called if supportsTabs() returns true +    */ +    virtual void openFolderinTabs(const KBookmarkGroup &bm); + +signals: +    /** +     * This signal is emitted when an url has to be loaded +     * +     * @param url the URL to load +     * +     */ +    void openUrl(const KUrl &); + +private: + +}; + +// ------------------------------------------------------------------------------ + + +#include <KBookmarkMenu> + + +/** + * This class represent the rekonq bookmarks menu. + * It's just a simple class inherited from KBookmarkMenu + * + */ +class BookmarkMenu : public KBookmarkMenu +{ +    Q_OBJECT + +public: +    BookmarkMenu(KBookmarkManager* manager, +                 KBookmarkOwner* owner, +                 KMenu* menu, +                 KActionCollection* actionCollection); +    ~BookmarkMenu(); + +    virtual KMenu *viewContextMenu(QAction* action); + +protected slots: +    void slotAddBookmark(); + +}; + + +// ------------------------------------------------------------------------------ + + +/** + * This class represent the interface to rekonq bookmarks system. + * All rekonq needs (Bookmarks Menu, Bookmarks Toolbar) is provided + * from this class. + * So it implements code to have each one + * + * + */ +class BookmarkProvider : public QWidget +{ +    Q_OBJECT + +public: +    /** +    * @short Class constructor. +    * Connect BookmarksProvider with bookmarks source +    * (actually konqueror's bookmarks) +    * @param parent The MainWindow to provide bookmarks objects +    * +    */ +    BookmarkProvider(QWidget* parent = 0); +    ~BookmarkProvider(); + +    /** +     * @short Get the Bookmarks Menu Action +     * @return the Bookmarks Menu +     */ +    KActionMenu *bookmarkActionMenu(); + + +    /** +    * @short Get the Bookmarks Toolbar Action +    * @return the Bookmarks Toolbar Action +    */ +    KAction *bookmarkToolBarAction(); + + +    /** +     * @short Get action by name +     * This method returns poiner bookmark action of given name. +     * @pre m_actionCollection != NULL +     * @param name Name of action you want to get +     * @return It returns actions if one exists or empty object +     */ +    QAction *actionByName(const QString &name); + +signals: +    /** +    * @short This signal is emitted when an url has to be loaded +    * +    * @param url the URL to load +    */ +    void openUrl(const KUrl &url); + + +public slots: +    /** +     * @short Opens the context menu on given position +     * @param point Point on whitch you want to open this menu +     */ +    void contextMenu(const QPoint &point); + +    /** +     * @short Waits for signal that the group with the address has been modified by the caller. +     * Waits for signal that the group (or any of its children) with the address +     * @p groupAddress (e.g. "/4/5") has been modified by the caller @p caller. +     * +     * @param group bookmark group adress +     * @param caller caller that modified the bookmarks +     * @see  KBookmarkManager::changed +     */ +    void slotBookmarksChanged(const QString &group, const QString &caller); + +private: +    void setupToolBar(); + +    KBookmarkManager *m_manager; +    BookmarkOwner *m_owner; +    KMenu *m_menu; +    KActionCollection *m_actionCollection; +    BookmarkMenu *m_bookmarkMenu; +    KToolBar *m_bookmarkToolBar; +}; + +#endif diff --git a/src/cookiejar.cpp b/src/cookiejar.cpp new file mode 100644 index 00000000..de7d7d7e --- /dev/null +++ b/src/cookiejar.cpp @@ -0,0 +1,841 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +// Self Includes +#include "cookiejar.h" +#include "cookiejar.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "autosaver.h" + +// KDE Includes +#include <KConfig> +#include <KStandardDirs> +#include <KDebug> + +// Qt Includes +#include <QtCore> +#include <QtGui> +#include <QtWebKit> + + +static const unsigned int JAR_VERSION = 23; + + +QDataStream &operator<<(QDataStream &stream, const QList<QNetworkCookie> &list) +{ +    stream << JAR_VERSION; +    stream << quint32(list.size()); +    for (int i = 0; i < list.size(); ++i) +        stream << list.at(i).toRawForm(); +    return stream; +} + + +QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list) +{ +    list.clear(); + +    quint32 version; +    stream >> version; + +    if (version != JAR_VERSION) +        return stream; + +    quint32 count; +    stream >> count; +    for (quint32 i = 0; i < count; ++i) +    { +        QByteArray value; +        stream >> value; +        QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(value); +        if (newCookies.count() == 0 && value.length() != 0) +        { +            kWarning() << "CookieJar: Unable to parse saved cookie:" << value; +        } +        for (int j = 0; j < newCookies.count(); ++j) +            list.append(newCookies.at(j)); +        if (stream.atEnd()) +            break; +    } +    return stream; +} + + +CookieJar::CookieJar(QObject *parent) +        : QNetworkCookieJar(parent) +        , m_loaded(false) +        , m_saveTimer(new AutoSaver(this)) +        , m_acceptCookies(AcceptOnlyFromSitesNavigatedTo) +{ +    load(); +} + + +CookieJar::~CookieJar() +{ +    if (m_keepCookies == KeepUntilExit) +        clear(); +    m_saveTimer->saveIfNeccessary(); +} + + +void CookieJar::clear() +{ +    setAllCookies(QList<QNetworkCookie>()); +    m_saveTimer->changeOccurred(); +    emit cookiesChanged(); +} + + +void CookieJar::load() +{ +    if (m_loaded) +        return; + +    // load cookies and exceptions +    QString filepath = KStandardDirs::locateLocal("appdata", "cookies.ini"); +    qRegisterMetaTypeStreamOperators<QList<QNetworkCookie> >("QList<QNetworkCookie>"); +    QSettings cookieSettings(filepath, QSettings::IniFormat); +    setAllCookies(qvariant_cast<QList<QNetworkCookie> >(cookieSettings.value(QLatin1String("cookies")))); +    cookieSettings.beginGroup(QLatin1String("Exceptions")); +    m_exceptions_block = cookieSettings.value(QLatin1String("block")).toStringList(); +    m_exceptions_allow = cookieSettings.value(QLatin1String("allow")).toStringList(); +    m_exceptions_allowForSession = cookieSettings.value(QLatin1String("allowForSession")).toStringList(); +    qSort(m_exceptions_block.begin(), m_exceptions_block.end()); +    qSort(m_exceptions_allow.begin(), m_exceptions_allow.end()); +    qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end()); + +    loadSettings(); + +    save(); +} + + +void CookieJar::loadSettings() +{ +    int canAcceptCookies = ReKonfig::acceptCookies(); + +    switch (canAcceptCookies) +    { +    case 0: +        m_acceptCookies = AcceptAlways; +        break; +    case 1: +        m_acceptCookies = AcceptNever; +        break; +    case 2: +    default: +        m_acceptCookies = AcceptOnlyFromSitesNavigatedTo; +        break; +    } + +    int canKeepCookiesUntil = ReKonfig::keepCookiesUntil(); + +    switch (canKeepCookiesUntil) +    { +    default: +    case 0: +        m_keepCookies = KeepUntilExpire; +        break; +    case 1: +        m_keepCookies = KeepUntilExit; +        setAllCookies(QList<QNetworkCookie>()); +        break; +    case 2: +        m_keepCookies = KeepUntilTimeLimit; +        break; +    } + +    m_loaded = true; +    emit cookiesChanged(); +} + + +void CookieJar::save() +{ +    if (!m_loaded) +        return; +    purgeOldCookies(); + +    QString filepath = KStandardDirs::locateLocal("appdata", "cookies.ini"); +    QSettings cookieSettings(filepath, QSettings::IniFormat); +    QList<QNetworkCookie> cookies = allCookies(); +    for (int i = cookies.count() - 1; i >= 0; --i) +    { +        if (cookies.at(i).isSessionCookie()) +            cookies.removeAt(i); +    } + +    cookieSettings.setValue(QLatin1String("cookies"), qVariantFromValue<QList<QNetworkCookie> >(cookies)); +    cookieSettings.beginGroup(QLatin1String("Exceptions")); +    cookieSettings.setValue(QLatin1String("block"), m_exceptions_block); +    cookieSettings.setValue(QLatin1String("allow"), m_exceptions_allow); +    cookieSettings.setValue(QLatin1String("allowForSession"), m_exceptions_allowForSession); + +    // save cookie settings +    int n; +    switch (m_acceptCookies) +    { +    case AcceptAlways: +        n = 0; +        break; +    case AcceptNever: +        n = 1; +        break; +    case AcceptOnlyFromSitesNavigatedTo: +    default: +        n = 2; +        break; +    } +    ReKonfig::setAcceptCookies(n); + + +    switch (m_keepCookies) +    { +    default: +    case KeepUntilExpire: +        n = 0; +        break; +    case KeepUntilExit: +        n = 1; +        break; +    case KeepUntilTimeLimit: +        n = 2; +        break; +    } +    ReKonfig::setKeepCookiesUntil(n); +} + + +void CookieJar::purgeOldCookies() +{ +    QList<QNetworkCookie> cookies = allCookies(); +    if (cookies.isEmpty()) +        return; +    int oldCount = cookies.count(); +    QDateTime now = QDateTime::currentDateTime(); +    for (int i = cookies.count() - 1; i >= 0; --i) +    { +        if (!cookies.at(i).isSessionCookie() && cookies.at(i).expirationDate() < now) +            cookies.removeAt(i); +    } +    if (oldCount == cookies.count()) +        return; +    setAllCookies(cookies); +    emit cookiesChanged(); +} + + +QList<QNetworkCookie> CookieJar::cookiesForUrl(const QUrl &url) const +{ +    CookieJar *that = const_cast<CookieJar*>(this); +    if (!m_loaded) +        that->load(); + +    QWebSettings *globalSettings = QWebSettings::globalSettings(); +    if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) +    { +        QList<QNetworkCookie> noCookies; +        return noCookies; +    } + +    return QNetworkCookieJar::cookiesForUrl(url); +} + + +bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) +{ +    if (!m_loaded) +        load(); + +    QWebSettings *globalSettings = QWebSettings::globalSettings(); +    if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) +        return false; + +    QString host = url.host(); +    bool eBlock = qBinaryFind(m_exceptions_block.begin(), m_exceptions_block.end(), host) != m_exceptions_block.end(); +    bool eAllow = qBinaryFind(m_exceptions_allow.begin(), m_exceptions_allow.end(), host) != m_exceptions_allow.end(); +    bool eAllowSession = qBinaryFind(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end(), host) != m_exceptions_allowForSession.end(); + +    bool addedCookies = false; +    // pass exceptions +    bool acceptInitially = (m_acceptCookies != AcceptNever); +    if ((acceptInitially && !eBlock) || (!acceptInitially && (eAllow || eAllowSession))) +    { +        // pass url domain == cookie domain +        QDateTime soon = QDateTime::currentDateTime(); +        soon = soon.addDays(90); +        foreach(QNetworkCookie cookie, cookieList) +        { +            QList<QNetworkCookie> lst; +            if (m_keepCookies == KeepUntilTimeLimit +                    && !cookie.isSessionCookie() +                    && cookie.expirationDate() > soon) +            { +                cookie.setExpirationDate(soon); +            } +            lst += cookie; +            if (QNetworkCookieJar::setCookiesFromUrl(lst, url)) +            { +                addedCookies = true; +            } +            else +            { +                // finally force it in if wanted +                if (m_acceptCookies == AcceptAlways) +                { +                    QList<QNetworkCookie> cookies = allCookies(); +                    cookies += cookie; +                    setAllCookies(cookies); +                    addedCookies = true; +                } +#if 0 +                else +                    kWarning() << "setCookiesFromUrl failed" << url << cookieList.value(0).toRawForm(); +#endif +            } +        } +    } + +    if (addedCookies) +    { +        m_saveTimer->changeOccurred(); +        emit cookiesChanged(); +    } +    return addedCookies; +} + + +CookieJar::AcceptPolicy CookieJar::acceptPolicy() const +{ +    if (!m_loaded) +        (const_cast<CookieJar*>(this))->load(); +    return m_acceptCookies; +} + + +void CookieJar::setAcceptPolicy(AcceptPolicy policy) +{ +    if (!m_loaded) +        load(); +    if (policy == m_acceptCookies) +        return; +    m_acceptCookies = policy; +    m_saveTimer->changeOccurred(); +} + + +CookieJar::KeepPolicy CookieJar::keepPolicy() const +{ +    if (!m_loaded) +        (const_cast<CookieJar*>(this))->load(); +    return m_keepCookies; +} + + +void CookieJar::setKeepPolicy(KeepPolicy policy) +{ +    if (!m_loaded) +        load(); +    if (policy == m_keepCookies) +        return; +    m_keepCookies = policy; +    m_saveTimer->changeOccurred(); +} + + +QStringList CookieJar::blockedCookies() const +{ +    if (!m_loaded) +        (const_cast<CookieJar*>(this))->load(); +    return m_exceptions_block; +} + + +QStringList CookieJar::allowedCookies() const +{ +    if (!m_loaded) +        (const_cast<CookieJar*>(this))->load(); +    return m_exceptions_allow; +} + + +QStringList CookieJar::allowForSessionCookies() const +{ +    if (!m_loaded) +        (const_cast<CookieJar*>(this))->load(); +    return m_exceptions_allowForSession; +} + + +void CookieJar::setBlockedCookies(const QStringList &list) +{ +    if (!m_loaded) +        load(); +    m_exceptions_block = list; +    qSort(m_exceptions_block.begin(), m_exceptions_block.end()); +    m_saveTimer->changeOccurred(); +} + + +void CookieJar::setAllowedCookies(const QStringList &list) +{ +    if (!m_loaded) +        load(); +    m_exceptions_allow = list; +    qSort(m_exceptions_allow.begin(), m_exceptions_allow.end()); +    m_saveTimer->changeOccurred(); +} + + +void CookieJar::setAllowForSessionCookies(const QStringList &list) +{ +    if (!m_loaded) +        load(); +    m_exceptions_allowForSession = list; +    qSort(m_exceptions_allowForSession.begin(), m_exceptions_allowForSession.end()); +    m_saveTimer->changeOccurred(); +} + + +// ------------------------------------------------------------------------------------------- + + +CookieModel::CookieModel(CookieJar *cookieJar, QObject *parent) +        : QAbstractTableModel(parent) +        , m_cookieJar(cookieJar) +{ +    connect(m_cookieJar, SIGNAL(cookiesChanged()), this, SLOT(cookiesChanged())); +    m_cookieJar->load(); +} + + +QVariant CookieModel::headerData(int section, Qt::Orientation orientation, int role) const +{ +    if (role == Qt::SizeHintRole) +    { +        QFont font; +        font.setPointSize(10); +        QFontMetrics fm(font); +        int height = fm.height() + fm.height() / 3; +        int width = fm.width(headerData(section, orientation, Qt::DisplayRole).toString()); +        return QSize(width, height); +    } + +    if (orientation == Qt::Horizontal) +    { +        if (role != Qt::DisplayRole) +            return QVariant(); + +        switch (section) +        { +        case 0: +            return i18n("Website"); +        case 1: +            return i18n("Name"); +        case 2: +            return i18n("Path"); +        case 3: +            return i18n("Secure"); +        case 4: +            return i18n("Expires"); +        case 5: +            return i18n("Contents"); +        default: +            return QVariant(); +        } +    } +    return QAbstractTableModel::headerData(section, orientation, role); +} + + +QVariant CookieModel::data(const QModelIndex &index, int role) const +{ +    QList<QNetworkCookie> lst; +    if (m_cookieJar) +        lst = m_cookieJar->allCookies(); +    if (index.row() < 0 || index.row() >= lst.size()) +        return QVariant(); + +    switch (role) +    { +    case Qt::DisplayRole: +    case Qt::EditRole: +    { +        QNetworkCookie cookie = lst.at(index.row()); +        switch (index.column()) +        { +        case 0: +            return cookie.domain(); +        case 1: +            return cookie.name(); +        case 2: +            return cookie.path(); +        case 3: +            return cookie.isSecure(); +        case 4: +            return cookie.expirationDate(); +        case 5: +            return cookie.value(); +        } +    } +    case Qt::FontRole: +    { +        QFont font; +        font.setPointSize(10); +        return font; +    } +    } + +    return QVariant(); +} + + +int CookieModel::columnCount(const QModelIndex &parent) const +{ +    return (parent.isValid()) ? 0 : 6; +} + + +int CookieModel::rowCount(const QModelIndex &parent) const +{ +    return (parent.isValid() || !m_cookieJar) ? 0 : m_cookieJar->allCookies().count(); +} + + +bool CookieModel::removeRows(int row, int count, const QModelIndex &parent) +{ +    if (parent.isValid() || !m_cookieJar) +        return false; +    int lastRow = row + count - 1; +    beginRemoveRows(parent, row, lastRow); +    QList<QNetworkCookie> lst = m_cookieJar->allCookies(); +    for (int i = lastRow; i >= row; --i) +    { +        lst.removeAt(i); +    } +    m_cookieJar->setAllCookies(lst); +    endRemoveRows(); +    return true; +} + + +void CookieModel::cookiesChanged() +{ +    reset(); +} + + + +// ------------------------------------------------------------------------------------------------ + + +CookiesDialog::CookiesDialog(CookieJar *cookieJar, QWidget *parent) +        : QDialog(parent) +{ +    setupUi(this); +    setWindowFlags(Qt::Sheet); +    CookieModel *model = new CookieModel(cookieJar, this); +    m_proxyModel = new QSortFilterProxyModel(this); +    connect(search, SIGNAL(textChanged(QString)), +            m_proxyModel, SLOT(setFilterFixedString(QString))); +    connect(removeButton, SIGNAL(clicked()), cookiesTable, SLOT(removeOne())); +    connect(removeAllButton, SIGNAL(clicked()), cookiesTable, SLOT(removeAll())); +    m_proxyModel->setSourceModel(model); +    cookiesTable->verticalHeader()->hide(); +    cookiesTable->setSelectionBehavior(QAbstractItemView::SelectRows); +    cookiesTable->setModel(m_proxyModel); +    cookiesTable->setAlternatingRowColors(true); +    cookiesTable->setTextElideMode(Qt::ElideMiddle); +    cookiesTable->setShowGrid(false); +    cookiesTable->setSortingEnabled(true); +    QFont f = font(); +    f.setPointSize(10); +    QFontMetrics fm(f); +    int height = fm.height() + fm.height() / 3; +    cookiesTable->verticalHeader()->setDefaultSectionSize(height); +    cookiesTable->verticalHeader()->setMinimumSectionSize(-1); +    for (int i = 0; i < model->columnCount(); ++i) +    { +        int header = cookiesTable->horizontalHeader()->sectionSizeHint(i); +        switch (i) +        { +        case 0: +            header = fm.width(QLatin1String("averagehost.domain.com")); +            break; +        case 1: +            header = fm.width(QLatin1String("_session_id")); +            break; +        case 4: +            header = fm.width(QDateTime::currentDateTime().toString(Qt::LocalDate)); +            break; +        } +        int buffer = fm.width(QLatin1String("xx")); +        header += buffer; +        cookiesTable->horizontalHeader()->resizeSection(i, header); +    } +    cookiesTable->horizontalHeader()->setStretchLastSection(true); +} + + +// --------------------------------------------------------------------------------------------------- + + +CookieExceptionsModel::CookieExceptionsModel(CookieJar *cookiejar, QObject *parent) +        : QAbstractTableModel(parent) +        , m_cookieJar(cookiejar) +{ +    m_allowedCookies = m_cookieJar->allowedCookies(); +    m_blockedCookies = m_cookieJar->blockedCookies(); +    m_sessionCookies = m_cookieJar->allowForSessionCookies(); +} + + +QVariant CookieExceptionsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ +    if (role == Qt::SizeHintRole) +    { +        QFont font; +        font.setPointSize(10); +        QFontMetrics fm(font); +        int height = fm.height() + fm.height() / 3; +        int width = fm.width(headerData(section, orientation, Qt::DisplayRole).toString()); +        return QSize(width, height); +    } + +    if (orientation == Qt::Horizontal +            && role == Qt::DisplayRole) +    { +        switch (section) +        { +        case 0: +            return i18n("Website"); +        case 1: +            return i18n("Status"); +        } +    } +    return QAbstractTableModel::headerData(section, orientation, role); +} + + +QVariant CookieExceptionsModel::data(const QModelIndex &index, int role) const +{ +    if (index.row() < 0 || index.row() >= rowCount()) +        return QVariant(); + +    switch (role) +    { +    case Qt::DisplayRole: +    case Qt::EditRole: +    { +        int row = index.row(); +        if (row < m_allowedCookies.count()) +        { +            switch (index.column()) +            { +            case 0: +                return m_allowedCookies.at(row); +            case 1: +                return i18n("Allow"); +            } +        } +        row = row - m_allowedCookies.count(); +        if (row < m_blockedCookies.count()) +        { +            switch (index.column()) +            { +            case 0: +                return m_blockedCookies.at(row); +            case 1: +                return i18n("Block"); +            } +        } +        row = row - m_blockedCookies.count(); +        if (row < m_sessionCookies.count()) +        { +            switch (index.column()) +            { +            case 0: +                return m_sessionCookies.at(row); +            case 1: +                return i18n("Allow For Session"); +            } +        } +    } +    case Qt::FontRole: +    { +        QFont font; +        font.setPointSize(10); +        return font; +    } +    } +    return QVariant(); +} + + +int CookieExceptionsModel::columnCount(const QModelIndex &parent) const +{ +    return (parent.isValid()) ? 0 : 2; +} + + +int CookieExceptionsModel::rowCount(const QModelIndex &parent) const +{ +    return (parent.isValid() || !m_cookieJar) ? 0 : m_allowedCookies.count() + m_blockedCookies.count() + m_sessionCookies.count(); +} + + +bool CookieExceptionsModel::removeRows(int row, int count, const QModelIndex &parent) +{ +    if (parent.isValid() || !m_cookieJar) +        return false; + +    int lastRow = row + count - 1; +    beginRemoveRows(parent, row, lastRow); +    for (int i = lastRow; i >= row; --i) +    { +        if (i < m_allowedCookies.count()) +        { +            m_allowedCookies.removeAt(row); +            continue; +        } +        i = i - m_allowedCookies.count(); +        if (i < m_blockedCookies.count()) +        { +            m_blockedCookies.removeAt(row); +            continue; +        } +        i = i - m_blockedCookies.count(); +        if (i < m_sessionCookies.count()) +        { +            m_sessionCookies.removeAt(row); +            continue; +        } +    } +    m_cookieJar->setAllowedCookies(m_allowedCookies); +    m_cookieJar->setBlockedCookies(m_blockedCookies); +    m_cookieJar->setAllowForSessionCookies(m_sessionCookies); +    endRemoveRows(); +    return true; +} + + +// ---------------------------------------------------------------------------------------------------------------- + + +CookiesExceptionsDialog::CookiesExceptionsDialog(CookieJar *cookieJar, QWidget *parent) +        : QDialog(parent) +        , m_cookieJar(cookieJar) +{ +    setupUi(this); +    setWindowFlags(Qt::Sheet); +    connect(removeButton, SIGNAL(clicked()), exceptionTable, SLOT(removeOne())); +    connect(removeAllButton, SIGNAL(clicked()), exceptionTable, SLOT(removeAll())); +    exceptionTable->verticalHeader()->hide(); +    exceptionTable->setSelectionBehavior(QAbstractItemView::SelectRows); +    exceptionTable->setAlternatingRowColors(true); +    exceptionTable->setTextElideMode(Qt::ElideMiddle); +    exceptionTable->setShowGrid(false); +    exceptionTable->setSortingEnabled(true); +    m_exceptionsModel = new CookieExceptionsModel(cookieJar, this); +    m_proxyModel = new QSortFilterProxyModel(this); +    m_proxyModel->setSourceModel(m_exceptionsModel); +    connect(search, SIGNAL(textChanged(QString)), +            m_proxyModel, SLOT(setFilterFixedString(QString))); +    exceptionTable->setModel(m_proxyModel); + +    CookieModel *cookieModel = new CookieModel(cookieJar, this); +    domainLineEdit->setCompleter(new QCompleter(cookieModel, domainLineEdit)); + +    connect(domainLineEdit, SIGNAL(textChanged(const QString &)), +            this, SLOT(textChanged(const QString &))); +    connect(blockButton, SIGNAL(clicked()), this, SLOT(block())); +    connect(allowButton, SIGNAL(clicked()), this, SLOT(allow())); +    connect(allowForSessionButton, SIGNAL(clicked()), this, SLOT(allowForSession())); + +    QFont f = font(); +    f.setPointSize(10); +    QFontMetrics fm(f); +    int height = fm.height() + fm.height() / 3; +    exceptionTable->verticalHeader()->setDefaultSectionSize(height); +    exceptionTable->verticalHeader()->setMinimumSectionSize(-1); +    for (int i = 0; i < m_exceptionsModel->columnCount(); ++i) +    { +        int header = exceptionTable->horizontalHeader()->sectionSizeHint(i); +        switch (i) +        { +        case 0: +            header = fm.width(QLatin1String("averagebiglonghost.domain.com")); +            break; +        case 1: +            header = fm.width(QLatin1String("Allow For Session")); +            break; +        } +        int buffer = fm.width(QLatin1String("xx")); +        header += buffer; +        exceptionTable->horizontalHeader()->resizeSection(i, header); +    } +} + + +void CookiesExceptionsDialog::textChanged(const QString &text) +{ +    bool enabled = !text.isEmpty(); +    blockButton->setEnabled(enabled); +    allowButton->setEnabled(enabled); +    allowForSessionButton->setEnabled(enabled); +} + + +void CookiesExceptionsDialog::block() +{ +    if (domainLineEdit->text().isEmpty()) +        return; +    m_exceptionsModel->m_blockedCookies.append(domainLineEdit->text()); +    m_cookieJar->setBlockedCookies(m_exceptionsModel->m_blockedCookies); +    m_exceptionsModel->reset(); +} + + +void CookiesExceptionsDialog::allow() +{ +    if (domainLineEdit->text().isEmpty()) +        return; +    m_exceptionsModel->m_allowedCookies.append(domainLineEdit->text()); +    m_cookieJar->setAllowedCookies(m_exceptionsModel->m_allowedCookies); +    m_exceptionsModel->reset(); +} + + +void CookiesExceptionsDialog::allowForSession() +{ +    if (domainLineEdit->text().isEmpty()) +        return; +    m_exceptionsModel->m_sessionCookies.append(domainLineEdit->text()); +    m_cookieJar->setAllowForSessionCookies(m_exceptionsModel->m_sessionCookies); +    m_exceptionsModel->reset(); +} diff --git a/src/cookiejar.h b/src/cookiejar.h new file mode 100644 index 00000000..27071b6d --- /dev/null +++ b/src/cookiejar.h @@ -0,0 +1,200 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef COOKIEJAR_H +#define COOKIEJAR_H + + +// KDE Includes +#include <QDialog> + +// Qt Includes +#include <QNetworkCookieJar> +#include <QAbstractItemModel> +#include <QStringList> +#include <QTableView> + +// Forward Declarations +class QSortFilterProxyModel; +class QKeyEvent; +class AutoSaver; + + +class CookieJar : public QNetworkCookieJar +{ +    friend class CookieModel; +    Q_OBJECT +    Q_PROPERTY(AcceptPolicy acceptPolicy READ acceptPolicy WRITE setAcceptPolicy) +    Q_PROPERTY(KeepPolicy keepPolicy READ keepPolicy WRITE setKeepPolicy) +    Q_PROPERTY(QStringList blockedCookies READ blockedCookies WRITE setBlockedCookies) +    Q_PROPERTY(QStringList allowedCookies READ allowedCookies WRITE setAllowedCookies) +    Q_PROPERTY(QStringList allowForSessionCookies READ allowForSessionCookies WRITE setAllowForSessionCookies) +    Q_ENUMS(KeepPolicy) +    Q_ENUMS(AcceptPolicy) + +signals: +    void cookiesChanged(); + +public: +    enum AcceptPolicy +    { +        AcceptAlways, +        AcceptNever, +        AcceptOnlyFromSitesNavigatedTo +    }; + +    enum KeepPolicy +    { +        KeepUntilExpire, +        KeepUntilExit, +        KeepUntilTimeLimit +    }; + +    CookieJar(QObject *parent = 0); +    ~CookieJar(); + +    QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const; +    bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url); + +    AcceptPolicy acceptPolicy() const; +    void setAcceptPolicy(AcceptPolicy policy); + +    KeepPolicy keepPolicy() const; +    void setKeepPolicy(KeepPolicy policy); + +    QStringList blockedCookies() const; +    QStringList allowedCookies() const; +    QStringList allowForSessionCookies() const; + +    void setBlockedCookies(const QStringList &list); +    void setAllowedCookies(const QStringList &list); +    void setAllowForSessionCookies(const QStringList &list); + +public slots: +    void clear(); +    void loadSettings(); + +private slots: +    void save(); + +private: +    void purgeOldCookies(); +    void load(); +    bool m_loaded; +    AutoSaver *m_saveTimer; + +    AcceptPolicy m_acceptCookies; +    KeepPolicy m_keepCookies; + +    QStringList m_exceptions_block; +    QStringList m_exceptions_allow; +    QStringList m_exceptions_allowForSession; +}; + + +// ------------------------------------------------------------------------------------------------------------- + + +class CookieModel : public QAbstractTableModel +{ +    Q_OBJECT + +public: +    CookieModel(CookieJar *jar, QObject *parent = 0); +    QVariant headerData(int section, Qt::Orientation orientation, int role) const; +    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; +    int columnCount(const QModelIndex &parent = QModelIndex()) const; +    int rowCount(const QModelIndex &parent = QModelIndex()) const; +    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + +private slots: +    void cookiesChanged(); + +private: +    CookieJar *m_cookieJar; +}; + + +// ---------------------------------------------------------------------------------------------------------------------- + + +#include "ui_cookies.h" + +class CookiesDialog : public QDialog, public Ui_CookiesDialog +{ +    Q_OBJECT + +public: +    CookiesDialog(CookieJar *cookieJar, QWidget *parent = 0); + +private: +    QSortFilterProxyModel *m_proxyModel; +}; + +class CookieExceptionsModel : public QAbstractTableModel +{ +    Q_OBJECT +    friend class CookiesExceptionsDialog; + +public: +    CookieExceptionsModel(CookieJar *cookieJar, QObject *parent = 0); +    QVariant headerData(int section, Qt::Orientation orientation, int role) const; +    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; +    int columnCount(const QModelIndex &parent = QModelIndex()) const; +    int rowCount(const QModelIndex &parent = QModelIndex()) const; +    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + +private: +    CookieJar *m_cookieJar; + +    // Domains we allow, Domains we block, Domains we allow for this session +    QStringList m_allowedCookies; +    QStringList m_blockedCookies; +    QStringList m_sessionCookies; +}; + + +// ----------------------------------------------------------------------------------------------------------------- + + +#include "ui_cookiesexceptions.h" + +class CookiesExceptionsDialog : public QDialog, public Ui_CookiesExceptionsDialog +{ +    Q_OBJECT + +public: +    CookiesExceptionsDialog(CookieJar *cookieJar, QWidget *parent = 0); + +private slots: +    void block(); +    void allow(); +    void allowForSession(); +    void textChanged(const QString &text); + +private: +    CookieExceptionsModel *m_exceptionsModel; +    QSortFilterProxyModel *m_proxyModel; +    CookieJar *m_cookieJar; +}; + +#endif // COOKIEJAR_H diff --git a/src/cookies.ui b/src/cookies.ui new file mode 100644 index 00000000..49ad3a96 --- /dev/null +++ b/src/cookies.ui @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CookiesDialog</class> + <widget class="QDialog" name="CookiesDialog"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>550</width> +    <height>370</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>Cookies</string> +  </property> +  <layout class="QGridLayout"> +   <item row="0" column="0"> +    <spacer> +     <property name="orientation"> +      <enum>Qt::Horizontal</enum> +     </property> +     <property name="sizeHint" stdset="0"> +      <size> +       <width>252</width> +       <height>20</height> +      </size> +     </property> +    </spacer> +   </item> +   <item row="0" column="1"> +    <widget class="KLineEdit" name="search"/> +   </item> +   <item row="1" column="0" colspan="2"> +    <widget class="EditTableView" name="cookiesTable"/> +   </item> +   <item row="2" column="0" colspan="2"> +    <layout class="QHBoxLayout"> +     <item> +      <widget class="QPushButton" name="removeButton"> +       <property name="text"> +        <string>&Remove</string> +       </property> +      </widget> +     </item> +     <item> +      <widget class="QPushButton" name="removeAllButton"> +       <property name="text"> +        <string>Remove &All Cookies</string> +       </property> +      </widget> +     </item> +     <item> +      <spacer> +       <property name="orientation"> +        <enum>Qt::Horizontal</enum> +       </property> +       <property name="sizeHint" stdset="0"> +        <size> +         <width>40</width> +         <height>20</height> +        </size> +       </property> +      </spacer> +     </item> +     <item> +      <widget class="QDialogButtonBox" name="buttonBox"> +       <property name="standardButtons"> +        <set>QDialogButtonBox::Ok</set> +       </property> +      </widget> +     </item> +    </layout> +   </item> +  </layout> + </widget> + <customwidgets> +  <customwidget> +   <class>KLineEdit</class> +   <extends>QLineEdit</extends> +   <header>klineedit.h</header> +  </customwidget> +  <customwidget> +   <class>EditTableView</class> +   <extends>QTableView</extends> +   <header>edittableview.h</header> +  </customwidget> + </customwidgets> + <resources/> + <connections> +  <connection> +   <sender>buttonBox</sender> +   <signal>accepted()</signal> +   <receiver>CookiesDialog</receiver> +   <slot>accept()</slot> +   <hints> +    <hint type="sourcelabel"> +     <x>472</x> +     <y>329</y> +    </hint> +    <hint type="destinationlabel"> +     <x>461</x> +     <y>356</y> +    </hint> +   </hints> +  </connection> + </connections> +</ui> diff --git a/src/cookiesexceptions.ui b/src/cookiesexceptions.ui new file mode 100644 index 00000000..de59eee0 --- /dev/null +++ b/src/cookiesexceptions.ui @@ -0,0 +1,179 @@ +<ui version="4.0" > + <class>CookiesExceptionsDialog</class> + <widget class="QDialog" name="CookiesExceptionsDialog" > +  <property name="geometry" > +   <rect> +    <x>0</x> +    <y>0</y> +    <width>466</width> +    <height>446</height> +   </rect> +  </property> +  <property name="windowTitle" > +   <string>Cookie Exceptions</string> +  </property> +  <layout class="QVBoxLayout" > +   <item> +    <widget class="QGroupBox" name="newExceptionGroupBox" > +     <property name="title" > +      <string>New Exception</string> +     </property> +     <layout class="QGridLayout" > +      <item row="0" column="0" > +       <layout class="QHBoxLayout" > +        <item> +         <widget class="QLabel" name="label" > +          <property name="text" > +           <string>Domain:</string> +          </property> +         </widget> +        </item> +        <item> +         <widget class="KLineEdit" name="domainLineEdit" /> +        </item> +       </layout> +      </item> +      <item row="1" column="0" > +       <layout class="QHBoxLayout" > +        <item> +         <spacer> +          <property name="orientation" > +           <enum>Qt::Horizontal</enum> +          </property> +          <property name="sizeHint" stdset="0" > +           <size> +            <width>81</width> +            <height>25</height> +           </size> +          </property> +         </spacer> +        </item> +        <item> +         <widget class="QPushButton" name="blockButton" > +          <property name="enabled" > +           <bool>false</bool> +          </property> +          <property name="text" > +           <string>Block</string> +          </property> +         </widget> +        </item> +        <item> +         <widget class="QPushButton" name="allowForSessionButton" > +          <property name="enabled" > +           <bool>false</bool> +          </property> +          <property name="text" > +           <string>Allow For Session</string> +          </property> +         </widget> +        </item> +        <item> +         <widget class="QPushButton" name="allowButton" > +          <property name="enabled" > +           <bool>false</bool> +          </property> +          <property name="text" > +           <string>Allow</string> +          </property> +         </widget> +        </item> +       </layout> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <widget class="QGroupBox" name="ExceptionsGroupBox" > +     <property name="title" > +      <string>Exceptions</string> +     </property> +     <layout class="QGridLayout" > +      <item row="0" column="0" colspan="3" > +       <spacer> +        <property name="orientation" > +         <enum>Qt::Horizontal</enum> +        </property> +        <property name="sizeHint" stdset="0" > +         <size> +          <width>252</width> +          <height>20</height> +         </size> +        </property> +       </spacer> +      </item> +      <item row="0" column="3" > +       <widget class="KLineEdit" name="search" /> +      </item> +      <item row="1" column="0" colspan="4" > +       <widget class="EditTableView" name="exceptionTable" /> +      </item> +      <item row="2" column="0" > +       <widget class="QPushButton" name="removeButton" > +        <property name="text" > +         <string>&Remove</string> +        </property> +       </widget> +      </item> +      <item row="2" column="1" > +       <widget class="QPushButton" name="removeAllButton" > +        <property name="text" > +         <string>Remove &All</string> +        </property> +       </widget> +      </item> +      <item row="2" column="2" colspan="2" > +       <spacer> +        <property name="orientation" > +         <enum>Qt::Horizontal</enum> +        </property> +        <property name="sizeHint" stdset="0" > +         <size> +          <width>40</width> +          <height>20</height> +         </size> +        </property> +       </spacer> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <widget class="QDialogButtonBox" name="buttonBox" > +     <property name="orientation" > +      <enum>Qt::Horizontal</enum> +     </property> +     <property name="standardButtons" > +      <set>QDialogButtonBox::Ok</set> +     </property> +    </widget> +   </item> +  </layout> + </widget> + <customwidgets> +  <customwidget> +   <class>EditTableView</class> +   <extends>QTableView</extends> +   <header>edittableview.h</header> +  </customwidget> + </customwidgets> + <resources/> + <connections> +  <connection> +   <sender>buttonBox</sender> +   <signal>accepted()</signal> +   <receiver>CookiesExceptionsDialog</receiver> +   <slot>accept()</slot> +   <hints> +    <hint type="sourcelabel" > +     <x>381</x> +     <y>428</y> +    </hint> +    <hint type="destinationlabel" > +     <x>336</x> +     <y>443</y> +    </hint> +   </hints> +  </connection> + </connections> +</ui> diff --git a/src/download.cpp b/src/download.cpp new file mode 100644 index 00000000..9489b270 --- /dev/null +++ b/src/download.cpp @@ -0,0 +1,224 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007 Lukas Appelhans <l.appelhans@gmx.de> +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// local Includes +#include "download.h" +#include "download.moc" + +// KDE Includes +#include <KDebug> +#include <KFileDialog> +#include <KGlobalSettings> +#include <KMessageBox> +#include <KMimeType> +#include <KStandardDirs> + +// Qt Includes +#include <QFile> +#include <QFileInfo> + +// Local Includes +#include "application.h" +#include "mainwindow.h" + + +DownloadManager::DownloadManager() +        : QObject() +{ +} + + +DownloadManager::~DownloadManager() +{ +    foreach(Download *download, m_downloads) +    { +        // cancel all unfinished downloads +        download->cancel(); +        delete download; +    } +} + + +void DownloadManager::newDownload(const KUrl &srcUrl, const KUrl &destUrl) +{ +    KUrl destination = destUrl; +    Download::DownloadType type; + +    KSharedPtr<KMimeType> mimeType = KMimeType::findByPath(srcUrl.prettyUrl()); + +    QString typeText = KMimeType::extractKnownExtension(srcUrl.fileName()); +    typeText += " (" + mimeType->name() + ")"; + +    int answer = KMessageBox::questionYesNoCancel(NULL, +                 i18n("Download '%1'?\n""Type: %2", srcUrl.prettyUrl(), typeText), +                 i18n("Download '%1'...", srcUrl.fileName()), +                 KStandardGuiItem::save(), +                 KStandardGuiItem::open(), +                 KStandardGuiItem::cancel(), +                 "showOpenSaveDownloadDialog" +                                                 ); + +    switch (answer) +    { +    case KMessageBox::Cancel: +        return; +        break; + +    case KMessageBox::Yes:  // ----- SAVE +        // if destination is empty than ask for download path (if showOpenSaveDownloadDialog setting enabled) +        if (destination.isEmpty()) +        { +            destination = downloadDestination(srcUrl.fileName()); +        } +        type = Download::Save; +        break; + +    case KMessageBox::No:   // ----- OPEN +        // Download file to tmp dir +        destination.setDirectory(KStandardDirs::locateLocal("tmp", "", true)); +        destination.addPath(srcUrl.fileName()); +        type = Download::Open; +        break; + +    default: +        // impossible +        break; +    }; + +    // if user canceled download than abort +    if (destination.isEmpty()) +        return; + +    Download *download = new Download(srcUrl, destination, type); +    connect(download, SIGNAL(downloadFinished(int)), this, SLOT(slotDownloadFinished(int))); +    m_downloads.append(download); +} + + +const QList<Download *> &DownloadManager::downloads() const +{ +    return m_downloads; +}; + + +KUrl DownloadManager::downloadDestination(const QString &filename) +{ +    KUrl destination = ReKonfig::downloadDir(); +    if (destination.isEmpty()) +        destination = KGlobalSettings::downloadPath(); +    destination.addPath(filename); + +    if (!ReKonfig::downloadToDefaultDir()) +    { +        destination = KFileDialog::getSaveUrl(destination); +        // if user canceled the download return empty url +        if (destination.isEmpty()) +            return KUrl(); +    } +    return destination; +} + + +void DownloadManager::slotDownloadFinished(int errorCode) +{ +    Q_UNUSED(errorCode) + +    // if sender exists and list contains it - (open and) delete it +    Download *download = qobject_cast<Download *>(sender()); +    if (download && m_downloads.contains(download)) +    { +        if (download->type() == Download::Open) +        { +            KSharedPtr<KMimeType> mimeType = KMimeType::findByPath(download->destUrl().prettyUrl()); +            KRun::runUrl(download->destUrl(), mimeType->name(), NULL, true); +        } +        disconnect(download, SIGNAL(downloadFinished(int)), this, SLOT(slotDownloadFinished(int))); +        int index = m_downloads.indexOf(download); +        delete m_downloads.takeAt(index); +        return; +    } +    kWarning() << "Could not find download or invalid sender. Sender:" << sender(); +} + + +//---- + +#include <KJob> +#include <KIO/Job> +#include <KIO/CopyJob> + + +Download::Download(const KUrl &srcUrl, const KUrl &destUrl, DownloadType type) +        : QObject() +        , m_srcUrl(srcUrl) +        , m_destUrl(destUrl) +        , m_type(type) +{ +    Q_ASSERT(!m_srcUrl.isEmpty()); +    Q_ASSERT(!m_destUrl.isEmpty()); +    kDebug() << "DownloadFile: " << m_srcUrl.url() << " to dest: " << m_destUrl.url(); + +    m_copyJob = KIO::file_copy(m_srcUrl, m_destUrl); +    connect(m_copyJob, SIGNAL(result(KJob *)), SLOT(slotResult(KJob *))); +} + + +Download::~Download() +{ +} + + +void Download::cancel() +{ +    bool result = m_copyJob->kill(KJob::EmitResult); +    Q_ASSERT(result); +} + + +void Download::slotResult(KJob *job) +{ +    switch (job->error()) +    { +    case 0:  //The download has finished +    { +        kDebug() << "Downloading successfully finished: " << m_destUrl.url(); +        break; +    } +    case KIO::ERR_FILE_ALREADY_EXIST: +    { +        kWarning() << "ERROR - File already exists"; +        break; +    } +    case KIO::ERR_USER_CANCELED: +    { +        kWarning() << "ERROR - User canceled the downlaod"; +        break; +    } +    default: +        kWarning() << "We are sorry to say you, that there were errors while downloading :("; +        break; +    } + +    // inform the world +    emit downloadFinished(job->error()); +} diff --git a/src/download.h b/src/download.h new file mode 100644 index 00000000..0ad01e69 --- /dev/null +++ b/src/download.h @@ -0,0 +1,141 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007 Lukas Appelhans <l.appelhans@gmx.de> +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak at gmail dot com> +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef DOWNLOAD_H +#define DOWNLOAD_H + +// Auto Includes +#include "rekonq.h" + +// KDE Includes +#include <KIO/FileCopyJob> + +// Qt Includes +#include <QObject> + +// Forward Declarations +class KJob; + +namespace KIO +{ +class Job; +} + + +/** + * This class lets rekonq to download an object from the network. + * Creating a new object, you can continue downloading a file also + * when rekonq is closed. + * + */ +class Download : public QObject +{ +    Q_OBJECT + +public: +    enum DownloadType { Save, Open }; + +    /** +     * Class constructor. This is the unique method we need to +     * use this class. In fact Download class needs to know just +     * "where" catch the file to download and where it has to put it +     * +     * @param srcUrl the source url +     * @param destUrl the destination url +     * +     */ +    Download(const KUrl &srcUrl, const KUrl &destUrl, DownloadType type); + +    /** +     * class destructor +     */ +    ~Download(); + +    KUrl srcUrl() const +    { +        return m_srcUrl; +    } +    KUrl destUrl() const +    { +        return m_destUrl; +    } +    DownloadType type() const +    { +        return m_type; +    } +    void cancel(); + +signals: +    void downloadFinished(int errorCode); + +private slots: +    void slotResult(KJob *job); + +private: +    KIO::FileCopyJob *m_copyJob; +    KUrl m_srcUrl; +    KUrl m_destUrl; +    KUrl m_destFile; +    QByteArray m_data; +    DownloadType m_type; +}; + + +// ---------------------- + + +class DownloadManager : public QObject +{ +    Q_OBJECT + +public: +    DownloadManager(); +    ~DownloadManager(); + +    /** +    * @short Creates new download job. +    * This method lets you to download a file from a remote source url +    * to a local destination url. +    * +    * @param srcUrl the source url +    * @param destUrl the destination url (default value is your default download destination setting) +    * +    */ +    void newDownload(const KUrl &srcUrl, const KUrl &destUrl = KUrl()); + +    const QList<Download *> &downloads() const; + +public slots: +    void slotDownloadFinished(int errorCode); + +private: +    KUrl downloadDestination(const QString &filename); + +    QList<Download *> m_downloads; +}; + + +//-- + + +#endif diff --git a/src/edittableview.cpp b/src/edittableview.cpp new file mode 100644 index 00000000..bf1ef370 --- /dev/null +++ b/src/edittableview.cpp @@ -0,0 +1,61 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#include "edittableview.h" +#include <QtGui/QKeyEvent> + +EditTableView::EditTableView(QWidget *parent) +        : QTableView(parent) +{ +} + +void EditTableView::keyPressEvent(QKeyEvent *event) +{ +    if ((event->key() == Qt::Key_Delete +            || event->key() == Qt::Key_Backspace) +            && model()) +    { +        removeOne(); +    } +    else +    { +        QAbstractItemView::keyPressEvent(event); +    } +} + +void EditTableView::removeOne() +{ +    if (!model() || !selectionModel()) +        return; +    int row = currentIndex().row(); +    model()->removeRow(row, rootIndex()); +    QModelIndex idx = model()->index(row, 0, rootIndex()); +    if (!idx.isValid()) +        idx = model()->index(row - 1, 0, rootIndex()); +    selectionModel()->select(idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); +} + +void EditTableView::removeAll() +{ +    if (model()) +        model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex()); +} diff --git a/src/edittableview.h b/src/edittableview.h new file mode 100644 index 00000000..dbc9a145 --- /dev/null +++ b/src/edittableview.h @@ -0,0 +1,42 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#ifndef EDITTABLEVIEW_H +#define EDITTABLEVIEW_H + +#include <QtGui/QTableView> + +class EditTableView : public QTableView +{ +    Q_OBJECT + +public: +    EditTableView(QWidget *parent = 0); +    void keyPressEvent(QKeyEvent *event); + +public slots: +    void removeOne(); +    void removeAll(); +}; + +#endif // EDITTABLEVIEW_H + diff --git a/src/edittreeview.cpp b/src/edittreeview.cpp new file mode 100644 index 00000000..49730d67 --- /dev/null +++ b/src/edittreeview.cpp @@ -0,0 +1,61 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#include "edittreeview.h" + +#include <QtGui/QKeyEvent> + +EditTreeView::EditTreeView(QWidget *parent) +        : QTreeView(parent) +{ +} + +void EditTreeView::keyPressEvent(QKeyEvent *event) +{ +    if ((event->key() == Qt::Key_Delete +            || event->key() == Qt::Key_Backspace) +            && model()) +    { +        removeOne(); +    } +    else +    { +        QAbstractItemView::keyPressEvent(event); +    } +} + +void EditTreeView::removeOne() +{ +    if (!model()) +        return; +    QModelIndex ci = currentIndex(); +    int row = ci.row(); +    model()->removeRow(row, ci.parent()); +} + +void EditTreeView::removeAll() +{ +    if (!model()) +        return; +    model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex()); +} + diff --git a/src/edittreeview.h b/src/edittreeview.h new file mode 100644 index 00000000..5be0dc45 --- /dev/null +++ b/src/edittreeview.h @@ -0,0 +1,41 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef EDITTREEVIEW_H +#define EDITTREEVIEW_H + +#include <QtGui/QTreeView> + +class EditTreeView : public QTreeView +{ +    Q_OBJECT + +public: +    EditTreeView(QWidget *parent = 0); +    void keyPressEvent(QKeyEvent *event); + +public slots: +    void removeOne(); +    void removeAll(); +}; + +#endif // EDITTREEVIEW_H + diff --git a/src/findbar.cpp b/src/findbar.cpp new file mode 100644 index 00000000..11d890c1 --- /dev/null +++ b/src/findbar.cpp @@ -0,0 +1,137 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it +* and/or modify it under the terms of the GNU General +* Public License as published by the Free Software Foundation; +* either version 2, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// Self Includes +#include "findbar.h" +#include "findbar.moc" + +// KDE Includes +#include <KLineEdit> +#include <KAction> +#include <KIcon> +#include <KPushButton> +#include <klocalizedstring.h> + +// Qt Includes +#include <QtGui> + + +FindBar::FindBar(KXmlGuiWindow *mainwindow) +        : QWidget(mainwindow) +        , m_lineEdit(new KLineEdit(this)) +        , m_matchCase(new QCheckBox(i18n("&Match case"), this)) +{ +    QHBoxLayout *layout = new QHBoxLayout; + +    // cosmetic +    layout->setContentsMargins(2, 0, 2, 0); + +    // hide button +    QToolButton *hideButton = new QToolButton(this); +    hideButton->setAutoRaise(true); +    hideButton->setIcon(KIcon("dialog-close")); +    connect(hideButton, SIGNAL(clicked()), this, SLOT(hide())); +    layout->addWidget(hideButton); +    layout->setAlignment(hideButton, Qt::AlignLeft | Qt::AlignTop); + +    // label +    QLabel *label = new QLabel(i18n("Find: ")); +    layout->addWidget(label); + +    // lineEdit, focusProxy +    setFocusProxy(m_lineEdit); +    m_lineEdit->setMaximumWidth(250); +    connect(m_lineEdit, SIGNAL(textChanged(const QString &)), mainwindow, SLOT(slotFind(const QString &))); +    layout->addWidget(m_lineEdit); + +    // buttons +    KPushButton *findNext = new KPushButton(KIcon("go-down"), i18n("&Next"), this); +    KPushButton *findPrev = new KPushButton(KIcon("go-up"), i18n("&Previous"), this); +    connect(findNext, SIGNAL(clicked()), mainwindow, SLOT(slotFindNext())); +    connect(findPrev, SIGNAL(clicked()), mainwindow, SLOT(slotFindPrevious())); +    layout->addWidget(findNext); +    layout->addWidget(findPrev); + +    // Case sensitivity. Deliberately set so this is off by default. +    m_matchCase->setCheckState(Qt::Unchecked); +    m_matchCase->setTristate(false); +    layout->addWidget(m_matchCase); + +    // stretching widget on the left +    layout->addStretch(); + +    setLayout(layout); + +    // we start off hidden +    hide(); +} + + +FindBar::~FindBar() +{ +} + + +KLineEdit *FindBar::lineEdit() const +{ +    return m_lineEdit; +} + + +bool FindBar::matchCase() const +{ +    return m_matchCase->isChecked(); +} + + +void FindBar::clear() +{ +    m_lineEdit->setText(QString()); +} + + +void FindBar::showFindBar() +{ +    // show findbar if not visible +    if (!isVisible()) +    { +        show(); +    } +    // set focus to findbar if user select showFindBar shortcut +    m_lineEdit->setFocus(); +    m_lineEdit->selectAll(); +} + + +void FindBar::keyPressEvent(QKeyEvent* event) +{ +    if (event->key() == Qt::Key_Escape) +    { +        hide(); +        return; +    } +    if (event->key() == Qt::Key_Return && !m_lineEdit->text().isEmpty()) +    { +        emit searchString(m_lineEdit->text()); +        return; +    } +    QWidget::keyPressEvent(event); +} + diff --git a/src/findbar.h b/src/findbar.h new file mode 100644 index 00000000..15a82e1e --- /dev/null +++ b/src/findbar.h @@ -0,0 +1,61 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it +* and/or modify it under the terms of the GNU General +* Public License as published by the Free Software Foundation; +* either version 2, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#ifndef FINDBAR_H +#define FINDBAR_H + +// KDE Includes +#include <KLineEdit> +#include <KToolBar> +#include <KXmlGuiWindow> + +// Qt Includes +#include <QtCore> +#include <QtGui> + + +class FindBar : public QWidget +{ +    Q_OBJECT + +public: +    FindBar(KXmlGuiWindow *mainwindow); +    ~FindBar(); +    KLineEdit *lineEdit() const; +    bool matchCase() const; + +public slots: +    void clear(); +    void showFindBar(); + +protected Q_SLOTS: +    void keyPressEvent(QKeyEvent* event); + +signals: +    void searchString(const QString &); + +private: +    KLineEdit *m_lineEdit; +    QCheckBox *m_matchCase; +}; + + +#endif diff --git a/src/history.cpp b/src/history.cpp new file mode 100644 index 00000000..afcb477a --- /dev/null +++ b/src/history.cpp @@ -0,0 +1,1459 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// Self Includes +#include "history.h" +#include "history.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "autosaver.h" +#include "application.h" + +// KDE Includes +#include <KDebug> +#include <KStandardDirs> + +// Qt Includes +#include <QtCore> +#include <QtGui> +#include <QtWebKit> + +#include <QtAlgorithms> + + +static const unsigned int HISTORY_VERSION = 23; + + +HistoryManager::HistoryManager(QObject *parent) +        : QWebHistoryInterface(parent) +        , m_saveTimer(new AutoSaver(this)) +        , m_historyLimit(30) +        , m_historyModel(0) +        , m_historyFilterModel(0) +        , m_historyTreeModel(0) +{ +    m_expiredTimer.setSingleShot(true); +    connect(&m_expiredTimer, SIGNAL(timeout()), this, SLOT(checkForExpired())); +    connect(this, SIGNAL(entryAdded(const HistoryItem &)), m_saveTimer, SLOT(changeOccurred())); +    connect(this, SIGNAL(entryRemoved(const HistoryItem &)), m_saveTimer, SLOT(changeOccurred())); +    load(); + +    m_historyModel = new HistoryModel(this, this); +    m_historyFilterModel = new HistoryFilterModel(m_historyModel, this); +    m_historyTreeModel = new HistoryTreeModel(m_historyFilterModel, this); + +    // QWebHistoryInterface will delete the history manager +    QWebHistoryInterface::setDefaultInterface(this); +} + + +HistoryManager::~HistoryManager() +{ +    m_saveTimer->saveIfNeccessary(); +} + + +QList<HistoryItem> HistoryManager::history() const +{ +    return m_history; +} + + +bool HistoryManager::historyContains(const QString &url) const +{ +    return m_historyFilterModel->historyContains(url); +} + + +void HistoryManager::addHistoryEntry(const QString &url) +{ +    QUrl cleanUrl(url); +    cleanUrl.setPassword(QString()); +    cleanUrl.setHost(cleanUrl.host().toLower()); +    HistoryItem item(cleanUrl.toString(), QDateTime::currentDateTime()); +    addHistoryEntry(item); +} + + +void HistoryManager::setHistory(const QList<HistoryItem> &history, bool loadedAndSorted) +{ +    m_history = history; + +    // verify that it is sorted by date +    if (!loadedAndSorted) +        qSort(m_history.begin(), m_history.end()); + +    checkForExpired(); + +    if (loadedAndSorted) +    { +        m_lastSavedUrl = m_history.value(0).url; +    } +    else +    { +        m_lastSavedUrl = QString(); +        m_saveTimer->changeOccurred(); +    } +    emit historyReset(); +} + + +HistoryModel *HistoryManager::historyModel() const +{ +    return m_historyModel; +} + + +HistoryFilterModel *HistoryManager::historyFilterModel() const +{ +    return m_historyFilterModel; +} + + +HistoryTreeModel *HistoryManager::historyTreeModel() const +{ +    return m_historyTreeModel; +} + + +void HistoryManager::checkForExpired() +{ +    if (m_historyLimit < 0 || m_history.isEmpty()) +        return; + +    QDateTime now = QDateTime::currentDateTime(); +    int nextTimeout = 0; + +    while (!m_history.isEmpty()) +    { +        QDateTime checkForExpired = m_history.last().dateTime; +        checkForExpired.setDate(checkForExpired.date().addDays(m_historyLimit)); +        if (now.daysTo(checkForExpired) > 7) +        { +            // check at most in a week to prevent int overflows on the timer +            nextTimeout = 7 * 86400; +        } +        else +        { +            nextTimeout = now.secsTo(checkForExpired); +        } +        if (nextTimeout > 0) +            break; +        HistoryItem item = m_history.takeLast(); +        // remove from saved file also +        m_lastSavedUrl = QString(); +        emit entryRemoved(item); +    } + +    if (nextTimeout > 0) +        m_expiredTimer.start(nextTimeout * 1000); +} + + +void HistoryManager::addHistoryEntry(const HistoryItem &item) +{ +    QWebSettings *globalSettings = QWebSettings::globalSettings(); +    if (globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) +        return; + +    m_history.prepend(item); +    emit entryAdded(item); +    if (m_history.count() == 1) +        checkForExpired(); +} + + +void HistoryManager::updateHistoryEntry(const KUrl &url, const QString &title) +{ +    for (int i = 0; i < m_history.count(); ++i) +    { +        if (url == m_history.at(i).url) +        { +            m_history[i].title = title; +            m_saveTimer->changeOccurred(); +            if (m_lastSavedUrl.isEmpty()) +                m_lastSavedUrl = m_history.at(i).url; +            emit entryUpdated(i); +            break; +        } +    } +} + + +void HistoryManager::removeHistoryEntry(const HistoryItem &item) +{ +    m_lastSavedUrl.clear(); +    m_history.removeOne(item); +    emit entryRemoved(item); +} + + +void HistoryManager::removeHistoryEntry(const KUrl &url, const QString &title) +{ +    for (int i = 0; i < m_history.count(); ++i) +    { +        if (url == m_history.at(i).url +                && (title.isEmpty() || title == m_history.at(i).title)) +        { +            removeHistoryEntry(m_history.at(i)); +            break; +        } +    } +} + + +int HistoryManager::historyLimit() const +{ +    return m_historyLimit; +} + + +void HistoryManager::setHistoryLimit(int limit) +{ +    if (m_historyLimit == limit) +        return; +    m_historyLimit = limit; +    checkForExpired(); +    m_saveTimer->changeOccurred(); +} + + +void HistoryManager::clear() +{ +    m_history.clear(); +    m_lastSavedUrl = QString(); +    m_saveTimer->changeOccurred(); +    m_saveTimer->saveIfNeccessary(); +    historyReset(); +} + + +void HistoryManager::loadSettings() +{ +    int historyExpire = ReKonfig::expireHistory(); +    int days; +    switch (historyExpire) +    { +    case 0: days = 1; break; +    case 1: days = 7; break; +    case 2: days = 14; break; +    case 3: days = 30; break; +    case 4: days = 365; break; +    case 5: days = -1; break; +    default: days = -1; +    } +    m_historyLimit = days; +} + + +void HistoryManager::load() +{ +    loadSettings(); + +    QString historyFilePath = KStandardDirs::locateLocal("appdata" , "history"); +    QFile historyFile(historyFilePath); +    if (!historyFile.exists()) +        return; +    if (!historyFile.open(QFile::ReadOnly)) +    { +        kWarning() << "Unable to open history file" << historyFile.fileName(); +        return; +    } + +    QList<HistoryItem> list; +    QDataStream in(&historyFile); +    // Double check that the history file is sorted as it is read in +    bool needToSort = false; +    HistoryItem lastInsertedItem; +    QByteArray data; +    QDataStream stream; +    QBuffer buffer; +    stream.setDevice(&buffer); +    while (!historyFile.atEnd()) +    { +        in >> data; +        buffer.close(); +        buffer.setBuffer(&data); +        buffer.open(QIODevice::ReadOnly); +        quint32 ver; +        stream >> ver; +        if (ver != HISTORY_VERSION) +            continue; +        HistoryItem item; +        stream >> item.url; +        stream >> item.dateTime; +        stream >> item.title; + +        if (!item.dateTime.isValid()) +            continue; + +        if (item == lastInsertedItem) +        { +            if (lastInsertedItem.title.isEmpty() && !list.isEmpty()) +                list[0].title = item.title; +            continue; +        } + +        if (!needToSort && !list.isEmpty() && lastInsertedItem < item) +            needToSort = true; + +        list.prepend(item); +        lastInsertedItem = item; +    } +    if (needToSort) +        qSort(list.begin(), list.end()); + +    setHistory(list, true); + +    // If we had to sort re-write the whole history sorted +    if (needToSort) +    { +        m_lastSavedUrl = QString(); +        m_saveTimer->changeOccurred(); +    } +} + + +void HistoryManager::save() +{ +    bool saveAll = m_lastSavedUrl.isEmpty(); +    int first = m_history.count() - 1; +    if (!saveAll) +    { +        // find the first one to save +        for (int i = 0; i < m_history.count(); ++i) +        { +            if (m_history.at(i).url == m_lastSavedUrl) +            { +                first = i - 1; +                break; +            } +        } +    } +    if (first == m_history.count() - 1) +        saveAll = true; + +    QString historyFilePath = KStandardDirs::locateLocal("appdata" , "history"); +    QFile historyFile(historyFilePath); + +    // When saving everything use a temporary file to prevent possible data loss. +    QTemporaryFile tempFile; +    tempFile.setAutoRemove(false); +    bool open = false; +    if (saveAll) +    { +        open = tempFile.open(); +    } +    else +    { +        open = historyFile.open(QFile::Append); +    } + +    if (!open) +    { +        kWarning() << "Unable to open history file for saving" +        << (saveAll ? tempFile.fileName() : historyFile.fileName()); +        return; +    } + +    QDataStream out(saveAll ? &tempFile : &historyFile); +    for (int i = first; i >= 0; --i) +    { +        QByteArray data; +        QDataStream stream(&data, QIODevice::WriteOnly); +        HistoryItem item = m_history.at(i); +        stream << HISTORY_VERSION << item.url << item.dateTime << item.title; +        out << data; +    } +    tempFile.close(); + +    if (saveAll) +    { +        if (historyFile.exists() && !historyFile.remove()) +            kWarning() << "History: error removing old history." << historyFile.errorString(); +        if (!tempFile.rename(historyFile.fileName())) +            kWarning() << "History: error moving new history over old." << tempFile.errorString() << historyFile.fileName(); +    } +    m_lastSavedUrl = m_history.value(0).url; +} + + +// -------------------------------------------------------------------------------------------------------------------------- + + +HistoryModel::HistoryModel(HistoryManager *history, QObject *parent) +        : QAbstractTableModel(parent) +        , m_history(history) +{ +    Q_ASSERT(m_history); +    connect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset())); +    connect(m_history, SIGNAL(entryRemoved(const HistoryItem &)), this, SLOT(historyReset())); +    connect(m_history, SIGNAL(entryAdded(const HistoryItem &)), this, SLOT(entryAdded())); +    connect(m_history, SIGNAL(entryUpdated(int)), this, SLOT(entryUpdated(int))); +} + + +void HistoryModel::historyReset() +{ +    reset(); +} + + +void HistoryModel::entryAdded() +{ +    beginInsertRows(QModelIndex(), 0, 0); +    endInsertRows(); +} + + +void HistoryModel::entryUpdated(int offset) +{ +    QModelIndex idx = index(offset, 0); +    emit dataChanged(idx, idx); +} + + +QVariant HistoryModel::headerData(int section, Qt::Orientation orientation, int role) const +{ +    if (orientation == Qt::Horizontal +            && role == Qt::DisplayRole) +    { +        switch (section) +        { +        case 0: return i18n("Title"); +        case 1: return i18n("Address"); +        } +    } +    return QAbstractTableModel::headerData(section, orientation, role); +} + + +QVariant HistoryModel::data(const QModelIndex &index, int role) const +{ +    QList<HistoryItem> lst = m_history->history(); +    if (index.row() < 0 || index.row() >= lst.size()) +        return QVariant(); + +    const HistoryItem &item = lst.at(index.row()); +    switch (role) +    { +    case DateTimeRole: +        return item.dateTime; +    case DateRole: +        return item.dateTime.date(); +    case UrlRole: +        return QUrl(item.url); +    case UrlStringRole: +        return item.url; +    case Qt::DisplayRole: +    case Qt::EditRole: +    { +        switch (index.column()) +        { +        case 0: +            // when there is no title try to generate one from the url +            if (item.title.isEmpty()) +            { +                QString page = QFileInfo(QUrl(item.url).path()).fileName(); +                if (!page.isEmpty()) +                    return page; +                return item.url; +            } +            return item.title; +        case 1: +            return item.url; +        } +    } +    case Qt::DecorationRole: +        if (index.column() == 0) +        { +            return Application::instance()->icon(item.url); +        } +    } +    return QVariant(); +} + + +int HistoryModel::columnCount(const QModelIndex &parent) const +{ +    return (parent.isValid()) ? 0 : 2; +} + + +int HistoryModel::rowCount(const QModelIndex &parent) const +{ +    return (parent.isValid()) ? 0 : m_history->history().count(); +} + + +bool HistoryModel::removeRows(int row, int count, const QModelIndex &parent) +{ +    if (parent.isValid()) +        return false; +    int lastRow = row + count - 1; +    beginRemoveRows(parent, row, lastRow); +    QList<HistoryItem> lst = m_history->history(); +    for (int i = lastRow; i >= row; --i) +        lst.removeAt(i); +    disconnect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset())); +    m_history->setHistory(lst); +    connect(m_history, SIGNAL(historyReset()), this, SLOT(historyReset())); +    endRemoveRows(); +    return true; +} + + + +//  ----------------------------------------------------------------------------------------------- + + +#define MOVEDROWS 10 + + +/* +    Maps the first bunch of items of the source model to the root +*/ +HistoryMenuModel::HistoryMenuModel(HistoryTreeModel *sourceModel, QObject *parent) +        : QAbstractProxyModel(parent) +        , m_treeModel(sourceModel) +{ +    setSourceModel(sourceModel); +} + + +int HistoryMenuModel::bumpedRows() const +{ +    QModelIndex first = m_treeModel->index(0, 0); +    if (!first.isValid()) +        return 0; +    return qMin(m_treeModel->rowCount(first), MOVEDROWS); +} + + +int HistoryMenuModel::columnCount(const QModelIndex &parent) const +{ +    return m_treeModel->columnCount(mapToSource(parent)); +} + + +int HistoryMenuModel::rowCount(const QModelIndex &parent) const +{ +    if (parent.column() > 0) +        return 0; + +    if (!parent.isValid()) +    { +        int folders = sourceModel()->rowCount(); +        int bumpedItems = bumpedRows(); +        if (bumpedItems <= MOVEDROWS +                && bumpedItems == sourceModel()->rowCount(sourceModel()->index(0, 0))) +            --folders; +        return bumpedItems + folders; +    } + +    if (parent.internalId() == -1) +    { +        if (parent.row() < bumpedRows()) +            return 0; +    } + +    QModelIndex idx = mapToSource(parent); +    int defaultCount = sourceModel()->rowCount(idx); +    if (idx == sourceModel()->index(0, 0)) +        return defaultCount - bumpedRows(); +    return defaultCount; +} + + +QModelIndex HistoryMenuModel::mapFromSource(const QModelIndex &sourceIndex) const +{ +    // currently not used or autotested +    Q_ASSERT(false); +    int sr = m_treeModel->mapToSource(sourceIndex).row(); +    return createIndex(sourceIndex.row(), sourceIndex.column(), sr); +} + + +QModelIndex HistoryMenuModel::mapToSource(const QModelIndex &proxyIndex) const +{ +    if (!proxyIndex.isValid()) +        return QModelIndex(); + +    if (proxyIndex.internalId() == -1) +    { +        int bumpedItems = bumpedRows(); +        if (proxyIndex.row() < bumpedItems) +            return m_treeModel->index(proxyIndex.row(), proxyIndex.column(), m_treeModel->index(0, 0)); +        if (bumpedItems <= MOVEDROWS && bumpedItems == sourceModel()->rowCount(m_treeModel->index(0, 0))) +            --bumpedItems; +        return m_treeModel->index(proxyIndex.row() - bumpedItems, proxyIndex.column()); +    } + +    QModelIndex historyIndex = m_treeModel->sourceModel()->index(proxyIndex.internalId(), proxyIndex.column()); +    QModelIndex treeIndex = m_treeModel->mapFromSource(historyIndex); +    return treeIndex; +} + + +QModelIndex HistoryMenuModel::index(int row, int column, const QModelIndex &parent) const +{ +    if (row < 0 +            || column < 0 || column >= columnCount(parent) +            || parent.column() > 0) +        return QModelIndex(); +    if (!parent.isValid()) +        return createIndex(row, column, -1); + +    QModelIndex treeIndexParent = mapToSource(parent); + +    int bumpedItems = 0; +    if (treeIndexParent == m_treeModel->index(0, 0)) +        bumpedItems = bumpedRows(); +    QModelIndex treeIndex = m_treeModel->index(row + bumpedItems, column, treeIndexParent); +    QModelIndex historyIndex = m_treeModel->mapToSource(treeIndex); +    int historyRow = historyIndex.row(); +    if (historyRow == -1) +        historyRow = treeIndex.row(); +    return createIndex(row, column, historyRow); +} + + +QModelIndex HistoryMenuModel::parent(const QModelIndex &index) const +{ +    int offset = index.internalId(); +    if (offset == -1 || !index.isValid()) +        return QModelIndex(); + +    QModelIndex historyIndex = m_treeModel->sourceModel()->index(index.internalId(), 0); +    QModelIndex treeIndex = m_treeModel->mapFromSource(historyIndex); +    QModelIndex treeIndexParent = treeIndex.parent(); + +    int sr = m_treeModel->mapToSource(treeIndexParent).row(); +    int bumpedItems = bumpedRows(); +    if (bumpedItems <= MOVEDROWS && bumpedItems == sourceModel()->rowCount(sourceModel()->index(0, 0))) +        --bumpedItems; +    return createIndex(bumpedItems + treeIndexParent.row(), treeIndexParent.column(), sr); +} + + +// ------------------------------------------------------------------------------------------------------------- + + +HistoryMenu::HistoryMenu(QWidget *parent) +        : ModelMenu(parent) +        , m_history(0) +{ +    connect(this, SIGNAL(activated(const QModelIndex &)), this, SLOT(activated(const QModelIndex &))); +    setHoverRole(HistoryModel::UrlStringRole); +} + + +void HistoryMenu::activated(const QModelIndex &index) +{ +    emit openUrl(index.data(HistoryModel::UrlRole).toUrl()); +} + + +bool HistoryMenu::prePopulated() +{ +    if (!m_history) +    { +        m_history = Application::historyManager(); +        m_historyMenuModel = new HistoryMenuModel(m_history->historyTreeModel(), this); +        setModel(m_historyMenuModel); +    } +    // initial actions +    for (int i = 0; i < m_initialActions.count(); ++i) +        addAction(m_initialActions.at(i)); +    if (!m_initialActions.isEmpty()) +        addSeparator(); +    setFirstSeparator(m_historyMenuModel->bumpedRows()); + +    return false; +} + + +void HistoryMenu::postPopulated() +{ +    if (m_history->history().count() > 0) +        addSeparator(); + +    KAction *showAllAction = new KAction(i18n("Show All History"), this); +    connect(showAllAction, SIGNAL(triggered()), this, SLOT(showHistoryDialog())); +    addAction(showAllAction); + +    KAction *clearAction = new KAction(i18n("Clear History"), this); +    connect(clearAction, SIGNAL(triggered()), m_history, SLOT(clear())); +    addAction(clearAction); +} + + +void HistoryMenu::showHistoryDialog() +{ +    HistoryDialog *dialog = new HistoryDialog(this); +    connect(dialog, SIGNAL(openUrl(const KUrl&)), this, SIGNAL(openUrl(const KUrl&))); +    dialog->show(); +} + + +void HistoryMenu::setInitialActions(QList<QAction*> actions) +{ +    m_initialActions = actions; +    for (int i = 0; i < m_initialActions.count(); ++i) +        addAction(m_initialActions.at(i)); +} + + +// -------------------------------------------------------------------------------------------------------------- + + +TreeProxyModel::TreeProxyModel(QObject *parent) : QSortFilterProxyModel(parent) +{ +    setSortRole(HistoryModel::DateTimeRole); +    setFilterCaseSensitivity(Qt::CaseInsensitive); +} + + +bool TreeProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ +    if (!source_parent.isValid()) +        return true; +    return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); +} + + +// ----------------------------------------------------------------------------------------------------- + + +HistoryDialog::HistoryDialog(QWidget *parent, HistoryManager *setHistory) : QDialog(parent) +{ +    HistoryManager *history = setHistory; +    if (!history) +        history = Application::historyManager(); +    setupUi(this); +    tree->setUniformRowHeights(true); +    tree->setSelectionBehavior(QAbstractItemView::SelectRows); +    tree->setTextElideMode(Qt::ElideMiddle); +    QAbstractItemModel *model = history->historyTreeModel(); +    TreeProxyModel *proxyModel = new TreeProxyModel(this); +    connect(search, SIGNAL(textChanged(QString)), +            proxyModel, SLOT(setFilterFixedString(QString))); +    connect(removeButton, SIGNAL(clicked()), tree, SLOT(removeOne())); +    connect(removeAllButton, SIGNAL(clicked()), history, SLOT(clear())); +    proxyModel->setSourceModel(model); +    tree->setModel(proxyModel); +    tree->setExpanded(proxyModel->index(0, 0), true); +    tree->setAlternatingRowColors(true); +    QFontMetrics fm(font()); +    int header = fm.width(QLatin1Char('m')) * 40; +    tree->header()->resizeSection(0, header); +    tree->header()->setStretchLastSection(true); +    connect(tree, SIGNAL(activated(const QModelIndex&)), +            this, SLOT(open())); +    tree->setContextMenuPolicy(Qt::CustomContextMenu); +    connect(tree, SIGNAL(customContextMenuRequested(const QPoint &)), +            this, SLOT(customContextMenuRequested(const QPoint &))); +} + + +void HistoryDialog::customContextMenuRequested(const QPoint &pos) +{ +    QMenu menu; +    QModelIndex index = tree->indexAt(pos); +    index = index.sibling(index.row(), 0); +    if (index.isValid() && !tree->model()->hasChildren(index)) +    { +        menu.addAction(i18n("Open"), this, SLOT(open())); +        menu.addSeparator(); +        menu.addAction(i18n("Copy"), this, SLOT(copy())); +    } +    menu.addAction(i18n("Delete"), tree, SLOT(removeOne())); +    menu.exec(QCursor::pos()); +} + + +void HistoryDialog::open() +{ +    QModelIndex index = tree->currentIndex(); +    if (!index.parent().isValid()) +        return; +    emit openUrl(index.data(HistoryModel::UrlRole).toUrl()); +} + + +void HistoryDialog::copy() +{ +    QModelIndex index = tree->currentIndex(); +    if (!index.parent().isValid()) +        return; +    QString url = index.data(HistoryModel::UrlStringRole).toString(); + +    QClipboard *clipboard = QApplication::clipboard(); +    clipboard->setText(url); +} + + +// --------------------------------------------------------------------------------------------------------------- + +HistoryFilterModel::HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent) +        : QAbstractProxyModel(parent), +        m_loaded(false) +{ +    setSourceModel(sourceModel); +} + + +int HistoryFilterModel::historyLocation(const QString &url) const +{ +    load(); +    if (!m_historyHash.contains(url)) +        return 0; +    return sourceModel()->rowCount() - m_historyHash.value(url); +} + + +QVariant HistoryFilterModel::data(const QModelIndex &index, int role) const +{ +    return QAbstractProxyModel::data(index, role); +} + + +void HistoryFilterModel::setSourceModel(QAbstractItemModel *newSourceModel) +{ +    if (sourceModel()) +    { +        disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); +        disconnect(sourceModel(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), +                   this, SLOT(dataChanged(const QModelIndex &, const QModelIndex &))); +        disconnect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), +                   this, SLOT(sourceRowsInserted(const QModelIndex &, int, int))); +        disconnect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), +                   this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); +    } + +    QAbstractProxyModel::setSourceModel(newSourceModel); + +    if (sourceModel()) +    { +        m_loaded = false; +        connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); +        connect(sourceModel(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), +                this, SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); +        connect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), +                this, SLOT(sourceRowsInserted(const QModelIndex &, int, int))); +        connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), +                this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); +    } +} + + +void HistoryFilterModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ +    emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight)); +} + + +QVariant HistoryFilterModel::headerData(int section, Qt::Orientation orientation, int role) const +{ +    return sourceModel()->headerData(section, orientation, role); +} + + +void HistoryFilterModel::sourceReset() +{ +    m_loaded = false; +    reset(); +} + + +int HistoryFilterModel::rowCount(const QModelIndex &parent) const +{ +    load(); +    if (parent.isValid()) +        return 0; +    return m_historyHash.count(); +} + + +int HistoryFilterModel::columnCount(const QModelIndex &parent) const +{ +    return (parent.isValid()) ? 0 : 2; +} + + +QModelIndex HistoryFilterModel::mapToSource(const QModelIndex &proxyIndex) const +{ +    load(); +    int sourceRow = sourceModel()->rowCount() - proxyIndex.internalId(); +    return sourceModel()->index(sourceRow, proxyIndex.column()); +} + + +QModelIndex HistoryFilterModel::mapFromSource(const QModelIndex &sourceIndex) const +{ +    load(); +    QString url = sourceIndex.data(HistoryModel::UrlStringRole).toString(); +    if (!m_historyHash.contains(url)) +        return QModelIndex(); + +    // This can be done in a binary search, but we can't use qBinary find +    // because it can't take: qBinaryFind(m_sourceRow.end(), m_sourceRow.begin(), v); +    // so if this is a performance bottlneck then convert to binary search, until then +    // the cleaner/easier to read code wins the day. +    int realRow = -1; +    int sourceModelRow = sourceModel()->rowCount() - sourceIndex.row(); + +    for (int i = 0; i < m_sourceRow.count(); ++i) +    { +        if (m_sourceRow.at(i) == sourceModelRow) +        { +            realRow = i; +            break; +        } +    } +    if (realRow == -1) +        return QModelIndex(); + +    return createIndex(realRow, sourceIndex.column(), sourceModel()->rowCount() - sourceIndex.row()); +} + + +QModelIndex HistoryFilterModel::index(int row, int column, const QModelIndex &parent) const +{ +    load(); +    if (row < 0 || row >= rowCount(parent) +            || column < 0 || column >= columnCount(parent)) +        return QModelIndex(); + +    return createIndex(row, column, m_sourceRow[row]); +} + + +QModelIndex HistoryFilterModel::parent(const QModelIndex &) const +{ +    return QModelIndex(); +} + + +void HistoryFilterModel::load() const +{ +    if (m_loaded) +        return; +    m_sourceRow.clear(); +    m_historyHash.clear(); +    m_historyHash.reserve(sourceModel()->rowCount()); +    for (int i = 0; i < sourceModel()->rowCount(); ++i) +    { +        QModelIndex idx = sourceModel()->index(i, 0); +        QString url = idx.data(HistoryModel::UrlStringRole).toString(); +        if (!m_historyHash.contains(url)) +        { +            m_sourceRow.append(sourceModel()->rowCount() - i); +            m_historyHash[url] = sourceModel()->rowCount() - i; +        } +    } +    m_loaded = true; +} + + +void HistoryFilterModel::sourceRowsInserted(const QModelIndex &parent, int start, int end) +{ +    Q_ASSERT(start == end && start == 0); +    Q_UNUSED(end); +    if (!m_loaded) +        return; +    QModelIndex idx = sourceModel()->index(start, 0, parent); +    QString url = idx.data(HistoryModel::UrlStringRole).toString(); +    if (m_historyHash.contains(url)) +    { +        int sourceRow = sourceModel()->rowCount() - m_historyHash[url]; +        int realRow = mapFromSource(sourceModel()->index(sourceRow, 0)).row(); +        beginRemoveRows(QModelIndex(), realRow, realRow); +        m_sourceRow.removeAt(realRow); +        m_historyHash.remove(url); +        endRemoveRows(); +    } +    beginInsertRows(QModelIndex(), 0, 0); +    m_historyHash.insert(url, sourceModel()->rowCount() - start); +    m_sourceRow.insert(0, sourceModel()->rowCount()); +    endInsertRows(); +} + + +void HistoryFilterModel::sourceRowsRemoved(const QModelIndex &, int start, int end) +{ +    Q_UNUSED(start); +    Q_UNUSED(end); +    sourceReset(); +} + + +/* +    Removing a continuous block of rows will remove filtered rows too as this is +    the users intention. +*/ +bool HistoryFilterModel::removeRows(int row, int count, const QModelIndex &parent) +{ +    if (row < 0 || count <= 0 || row + count > rowCount(parent) || parent.isValid()) +        return false; +    int lastRow = row + count - 1; +    disconnect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), +               this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); +    beginRemoveRows(parent, row, lastRow); +    int oldCount = rowCount(); +    int start = sourceModel()->rowCount() - m_sourceRow.value(row); +    int end = sourceModel()->rowCount() - m_sourceRow.value(lastRow); +    sourceModel()->removeRows(start, end - start + 1); +    endRemoveRows(); +    connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), +            this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); +    m_loaded = false; +    if (oldCount - count != rowCount()) +        reset(); +    return true; +} + + +// ------------------------------------------------------------------------------------------------------ + + +HistoryCompletionModel::HistoryCompletionModel(QObject *parent) +        : QAbstractProxyModel(parent) +{ +} + + +QVariant HistoryCompletionModel::data(const QModelIndex &index, int role) const +{ +    if (sourceModel() +            && (role == Qt::EditRole || role == Qt::DisplayRole) +            && index.isValid()) +    { +        QModelIndex idx = mapToSource(index); +        idx = idx.sibling(idx.row(), 1); +        QString urlString = idx.data(HistoryModel::UrlStringRole).toString(); +        if (index.row() % 2) +        { +            QUrl url = urlString; +            QString s = url.toString(QUrl::RemoveScheme +                                     | QUrl::RemoveUserInfo +                                     | QUrl::StripTrailingSlash); +            return s.mid(2);  // strip // from the front +        } +        return urlString; +    } +    return QAbstractProxyModel::data(index, role); +} + + +int HistoryCompletionModel::rowCount(const QModelIndex &parent) const +{ +    return (parent.isValid() || !sourceModel()) ? 0 : sourceModel()->rowCount(parent) * 2; +} + + +int HistoryCompletionModel::columnCount(const QModelIndex &parent) const +{ +    return (parent.isValid()) ? 0 : 1; +} + + +QModelIndex HistoryCompletionModel::mapFromSource(const QModelIndex &sourceIndex) const +{ +    int row = sourceIndex.row() * 2; +    return index(row, sourceIndex.column()); +} + + +QModelIndex HistoryCompletionModel::mapToSource(const QModelIndex &proxyIndex) const +{ +    if (!sourceModel()) +        return QModelIndex(); +    int row = proxyIndex.row() / 2; +    return sourceModel()->index(row, proxyIndex.column()); +} + + +QModelIndex HistoryCompletionModel::index(int row, int column, const QModelIndex &parent) const +{ +    if (row < 0 || row >= rowCount(parent) +            || column < 0 || column >= columnCount(parent)) +        return QModelIndex(); +    return createIndex(row, column, 0); +} + + +QModelIndex HistoryCompletionModel::parent(const QModelIndex &) const +{ +    return QModelIndex(); +} + + +void HistoryCompletionModel::setSourceModel(QAbstractItemModel *newSourceModel) +{ +    if (sourceModel()) +    { +        disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); +        disconnect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), +                   this, SLOT(sourceReset())); +        disconnect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), +                   this, SLOT(sourceReset())); +    } + +    QAbstractProxyModel::setSourceModel(newSourceModel); + +    if (newSourceModel) +    { +        connect(newSourceModel, SIGNAL(modelReset()), this, SLOT(sourceReset())); +        connect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), +                this, SLOT(sourceReset())); +        connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), +                this, SLOT(sourceReset())); +    } + +    reset(); +} + + +void HistoryCompletionModel::sourceReset() +{ +    reset(); +} + + +// ------------------------------------------------------------------------------------------------------ + + +HistoryTreeModel::HistoryTreeModel(QAbstractItemModel *sourceModel, QObject *parent) +        : QAbstractProxyModel(parent) +{ +    setSourceModel(sourceModel); +} + + +QVariant HistoryTreeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ +    return sourceModel()->headerData(section, orientation, role); +} + + +QVariant HistoryTreeModel::data(const QModelIndex &index, int role) const +{ +    if ((role == Qt::EditRole || role == Qt::DisplayRole)) +    { +        int start = index.internalId(); +        if (start == 0) +        { +            int offset = sourceDateRow(index.row()); +            if (index.column() == 0) +            { +                QModelIndex idx = sourceModel()->index(offset, 0); +                QDate date = idx.data(HistoryModel::DateRole).toDate(); +                if (date == QDate::currentDate()) +                    return i18n("Earlier Today"); +                return date.toString(QLatin1String("dddd, MMMM d, yyyy")); +            } +            if (index.column() == 1) +            { +                return i18np("1 item", "%1 items", rowCount(index.sibling(index.row(), 0))); +            } +        } +    } +    if (role == Qt::DecorationRole && index.column() == 0 && !index.parent().isValid()) +        return KIcon("view-history"); +    if (role == HistoryModel::DateRole && index.column() == 0 && index.internalId() == 0) +    { +        int offset = sourceDateRow(index.row()); +        QModelIndex idx = sourceModel()->index(offset, 0); +        return idx.data(HistoryModel::DateRole); +    } + +    return QAbstractProxyModel::data(index, role); +} + + +int HistoryTreeModel::columnCount(const QModelIndex &parent) const +{ +    return sourceModel()->columnCount(mapToSource(parent)); +} + + +int HistoryTreeModel::rowCount(const QModelIndex &parent) const +{ +    if (parent.internalId() != 0 +            || parent.column() > 0 +            || !sourceModel()) +        return 0; + +    // row count OF dates +    if (!parent.isValid()) +    { +        if (!m_sourceRowCache.isEmpty()) +            return m_sourceRowCache.count(); +        QDate currentDate; +        int rows = 0; +        int totalRows = sourceModel()->rowCount(); + +        for (int i = 0; i < totalRows; ++i) +        { +            QDate rowDate = sourceModel()->index(i, 0).data(HistoryModel::DateRole).toDate(); +            if (rowDate != currentDate) +            { +                m_sourceRowCache.append(i); +                currentDate = rowDate; +                ++rows; +            } +        } +        Q_ASSERT(m_sourceRowCache.count() == rows); +        return rows; +    } + +    // row count FOR a date +    int start = sourceDateRow(parent.row()); +    int end = sourceDateRow(parent.row() + 1); +    return (end - start); +} + + +// Translate the top level date row into the offset where that date starts +int HistoryTreeModel::sourceDateRow(int row) const +{ +    if (row <= 0) +        return 0; + +    if (m_sourceRowCache.isEmpty()) +        rowCount(QModelIndex()); + +    if (row >= m_sourceRowCache.count()) +    { +        if (!sourceModel()) +            return 0; +        return sourceModel()->rowCount(); +    } +    return m_sourceRowCache.at(row); +} + + +QModelIndex HistoryTreeModel::mapToSource(const QModelIndex &proxyIndex) const +{ +    int offset = proxyIndex.internalId(); +    if (offset == 0) +        return QModelIndex(); +    int startDateRow = sourceDateRow(offset - 1); +    return sourceModel()->index(startDateRow + proxyIndex.row(), proxyIndex.column()); +} + + +QModelIndex HistoryTreeModel::index(int row, int column, const QModelIndex &parent) const +{ +    if (row < 0 +            || column < 0 || column >= columnCount(parent) +            || parent.column() > 0) +        return QModelIndex(); + +    if (!parent.isValid()) +        return createIndex(row, column, 0); +    return createIndex(row, column, parent.row() + 1); +} + + +QModelIndex HistoryTreeModel::parent(const QModelIndex &index) const +{ +    int offset = index.internalId(); +    if (offset == 0 || !index.isValid()) +        return QModelIndex(); +    return createIndex(offset - 1, 0, 0); +} + + +bool HistoryTreeModel::hasChildren(const QModelIndex &parent) const +{ +    QModelIndex grandparent = parent.parent(); +    if (!grandparent.isValid()) +        return true; +    return false; +} + + +Qt::ItemFlags HistoryTreeModel::flags(const QModelIndex &index) const +{ +    if (!index.isValid()) +        return Qt::NoItemFlags; +    return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled; +} + + +bool HistoryTreeModel::removeRows(int row, int count, const QModelIndex &parent) +{ +    if (row < 0 || count <= 0 || row + count > rowCount(parent)) +        return false; + +    if (parent.isValid()) +    { +        // removing pages +        int offset = sourceDateRow(parent.row()); +        return sourceModel()->removeRows(offset + row, count); +    } +    else +    { +        // removing whole dates +        for (int i = row + count - 1; i >= row; --i) +        { +            QModelIndex dateParent = index(i, 0); +            int offset = sourceDateRow(dateParent.row()); +            if (!sourceModel()->removeRows(offset, rowCount(dateParent))) +                return false; +        } +    } +    return true; +} + + +void HistoryTreeModel::setSourceModel(QAbstractItemModel *newSourceModel) +{ +    if (sourceModel()) +    { +        disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); +        disconnect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(sourceReset())); +        disconnect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), +                   this, SLOT(sourceRowsInserted(const QModelIndex &, int, int))); +        disconnect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), +                   this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); +    } + +    QAbstractProxyModel::setSourceModel(newSourceModel); + +    if (newSourceModel) +    { +        connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); +        connect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(sourceReset())); +        connect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), +                this, SLOT(sourceRowsInserted(const QModelIndex &, int, int))); +        connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), +                this, SLOT(sourceRowsRemoved(const QModelIndex &, int, int))); +    } + +    reset(); +} + + +void HistoryTreeModel::sourceReset() +{ +    m_sourceRowCache.clear(); +    reset(); +} + + +void HistoryTreeModel::sourceRowsInserted(const QModelIndex &parent, int start, int end) +{ +    Q_UNUSED(parent); // Avoid warnings when compiling release +    Q_ASSERT(!parent.isValid()); +    if (start != 0 || start != end) +    { +        m_sourceRowCache.clear(); +        reset(); +        return; +    } + +    m_sourceRowCache.clear(); +    QModelIndex treeIndex = mapFromSource(sourceModel()->index(start, 0)); +    QModelIndex treeParent = treeIndex.parent(); +    if (rowCount(treeParent) == 1) +    { +        beginInsertRows(QModelIndex(), 0, 0); +        endInsertRows(); +    } +    else +    { +        beginInsertRows(treeParent, treeIndex.row(), treeIndex.row()); +        endInsertRows(); +    } +} + + +QModelIndex HistoryTreeModel::mapFromSource(const QModelIndex &sourceIndex) const +{ +    if (!sourceIndex.isValid()) +        return QModelIndex(); + +    if (m_sourceRowCache.isEmpty()) +        rowCount(QModelIndex()); + +    QList<int>::iterator it; +    it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), sourceIndex.row()); +    if (*it != sourceIndex.row()) +        --it; + +    int dateRow = qMax(0, it - m_sourceRowCache.begin()); +    // FIXME fix crach on history submenu open. BUG:'ASSERT failure in QList<T>::at: "index out of range"' +    //       it crashes when dateRow == 1 +    // kDebug() << m_sourceRowCache << dateRow; +    int row = sourceIndex.row() - m_sourceRowCache.at(dateRow); +    return createIndex(row, sourceIndex.column(), dateRow + 1); +} + + +void HistoryTreeModel::sourceRowsRemoved(const QModelIndex &parent, int start, int end) +{ +    Q_UNUSED(parent); // Avoid warnings when compiling release +    Q_ASSERT(!parent.isValid()); +    if (m_sourceRowCache.isEmpty()) +        return; +    for (int i = end; i >= start;) +    { +        QList<int>::iterator it; +        it = qLowerBound(m_sourceRowCache.begin(), m_sourceRowCache.end(), i); +        // playing it safe +        if (it == m_sourceRowCache.end()) +        { +            m_sourceRowCache.clear(); +            reset(); +            return; +        } + +        if (*it != i) +            --it; +        int row = qMax(0, it - m_sourceRowCache.begin()); +        int offset = m_sourceRowCache[row]; +        QModelIndex dateParent = index(row, 0); +        // If we can remove all the rows in the date do that and skip over them +        int rc = rowCount(dateParent); +        if (i - rc + 1 == offset && start <= i - rc + 1) +        { +            beginRemoveRows(QModelIndex(), row, row); +            m_sourceRowCache.removeAt(row); +            i -= rc + 1; +        } +        else +        { +            beginRemoveRows(dateParent, i - offset, i - offset); +            ++row; +            --i; +        } +        for (int j = row; j < m_sourceRowCache.count(); ++j) +            --m_sourceRowCache[j]; +        endRemoveRows(); +    } +} diff --git a/src/history.h b/src/history.h new file mode 100644 index 00000000..ecae00c3 --- /dev/null +++ b/src/history.h @@ -0,0 +1,402 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef HISTORY_H +#define HISTORY_H + +// Local Includes +#include "modelmenu.h" + +// KDE Includes +#include <KAction> +#include <KUrl> + +// Qt Includes +#include <QDateTime> +#include <QHash> +#include <QObject> +#include <QTimer> +#include <QSortFilterProxyModel> +#include <QWebHistoryInterface> + + +/** + * Elements in this class represent an history item + * + */ + +class HistoryItem +{ +public: +    HistoryItem() {} +    HistoryItem(const QString &u, +                const QDateTime &d = QDateTime(), const QString &t = QString()) +            : title(t), url(u), dateTime(d) {} + +    inline bool operator==(const HistoryItem &other) const +    { +        return other.title == title +               && other.url == url && other.dateTime == dateTime; +    } + +    // history is sorted in reverse +    inline bool operator <(const HistoryItem &other) const +    { +        return dateTime > other.dateTime; +    } + +    QString title; +    QString url; +    QDateTime dateTime; +}; + + + +// --------------------------------------------------------------------------------------------------------------- + + +class AutoSaver; +class HistoryModel; +class HistoryFilterModel; +class HistoryTreeModel; + + +class HistoryManager : public QWebHistoryInterface +{ +    Q_OBJECT +    Q_PROPERTY(int historyLimit READ historyLimit WRITE setHistoryLimit) + +signals: +    void historyReset(); +    void entryAdded(const HistoryItem &item); +    void entryRemoved(const HistoryItem &item); +    void entryUpdated(int offset); + +public: +    HistoryManager(QObject *parent = 0); +    ~HistoryManager(); + +    bool historyContains(const QString &url) const; +    void addHistoryEntry(const QString &url); +    void updateHistoryEntry(const KUrl &url, const QString &title); +    void removeHistoryEntry(const KUrl &url, const QString &title = QString()); + +    int historyLimit() const; +    void setHistoryLimit(int limit); + +    QList<HistoryItem> history() const; +    void setHistory(const QList<HistoryItem> &history, bool loadedAndSorted = false); + +    // History manager keeps around these models for use by the completer and other classes +    HistoryModel *historyModel() const; +    HistoryFilterModel *historyFilterModel() const; +    HistoryTreeModel *historyTreeModel() const; + +public slots: +    void clear(); +    void loadSettings(); + +private slots: +    void save(); +    void checkForExpired(); + +protected: +    void addHistoryEntry(const HistoryItem &item); +    void removeHistoryEntry(const HistoryItem &item); + +private: +    void load(); + +    AutoSaver *m_saveTimer; +    int m_historyLimit; +    QTimer m_expiredTimer; +    QList<HistoryItem> m_history; +    QString m_lastSavedUrl; + +    HistoryModel *m_historyModel; +    HistoryFilterModel *m_historyFilterModel; +    HistoryTreeModel *m_historyTreeModel; +}; + + +// -------------------------------------------------------------------------------------------------------- + + +class HistoryModel : public QAbstractTableModel +{ +    Q_OBJECT + +public slots: +    void historyReset(); +    void entryAdded(); +    void entryUpdated(int offset); + +public: +    enum Roles +    { +        DateRole = Qt::UserRole + 1, +        DateTimeRole = Qt::UserRole + 2, +        UrlRole = Qt::UserRole + 3, +        UrlStringRole = Qt::UserRole + 4 +    }; + +    HistoryModel(HistoryManager *history, QObject *parent = 0); +    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; +    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; +    int columnCount(const QModelIndex &parent = QModelIndex()) const; +    int rowCount(const QModelIndex &parent = QModelIndex()) const; +    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + +private: +    HistoryManager *m_history; +}; + + +// ---------------------------------------------------------------------------------------------------- + +/** + * Proxy model that will remove any duplicate entries. + * Both m_sourceRow and m_historyHash store their offsets not from + * the front of the list, but as offsets from the back. + * + */ + +class HistoryFilterModel : public QAbstractProxyModel +{ +    Q_OBJECT + +public: +    HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent = 0); + +    inline bool historyContains(const QString &url) const +    { +        load(); return m_historyHash.contains(url); +    } +    int historyLocation(const QString &url) const; + +    QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; +    QModelIndex mapToSource(const QModelIndex &proxyIndex) const; +    void setSourceModel(QAbstractItemModel *sourceModel); +    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; +    int rowCount(const QModelIndex &parent = QModelIndex()) const; +    int columnCount(const QModelIndex &parent = QModelIndex()) const; +    QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const; +    QModelIndex parent(const QModelIndex& index = QModelIndex()) const; +    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); +    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + +private slots: +    void sourceReset(); +    void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); +    void sourceRowsInserted(const QModelIndex &parent, int start, int end); +    void sourceRowsRemoved(const QModelIndex &, int, int); + +private: +    void load() const; + +    mutable QList<int> m_sourceRow; +    mutable QHash<QString, int> m_historyHash; +    mutable bool m_loaded; +}; + + +// ---------------------------------------------------------------------------------------------------------------------- + +/** + * The history menu + * - Removes the first twenty entries and puts them as children of the top level. + * - If there are less then twenty entries then the first folder is also removed. + * + * The mapping is done by knowing that HistoryTreeModel is over a table + * We store that row offset in our index's private data. + * + */ + +class HistoryMenuModel : public QAbstractProxyModel +{ +    Q_OBJECT + +public: +    HistoryMenuModel(HistoryTreeModel *sourceModel, QObject *parent = 0); +    int columnCount(const QModelIndex &parent) const; +    int rowCount(const QModelIndex &parent = QModelIndex()) const; +    QModelIndex mapFromSource(const QModelIndex & sourceIndex) const; +    QModelIndex mapToSource(const QModelIndex & proxyIndex) const; +    QModelIndex index(int, int, const QModelIndex &parent = QModelIndex()) const; +    QModelIndex parent(const QModelIndex &index = QModelIndex()) const; + +    int bumpedRows() const; + +private: +    HistoryTreeModel *m_treeModel; +}; + + +// --------------------------------------------------------------------------------------------- + +/** + * Menu that is dynamically populated from the history + * + */ + +class HistoryMenu : public ModelMenu +{ +    Q_OBJECT + +signals: +    void openUrl(const KUrl &url); + +public: +    HistoryMenu(QWidget *parent = 0); +    void setInitialActions(QList<QAction*> actions); + +protected: +    bool prePopulated(); +    void postPopulated(); + +private slots: +    void activated(const QModelIndex &index); +    void showHistoryDialog(); + +private: +    HistoryManager *m_history; +    HistoryMenuModel *m_historyMenuModel; +    QList<QAction*> m_initialActions; +}; + + +// ---------------------------------------------------------------------------------------- + +/** + * Proxy model for the history model that + * exposes each url http://www.foo.com and + * it url starting at the host www.foo.com + * + */ + +class HistoryCompletionModel : public QAbstractProxyModel +{ +    Q_OBJECT + +public: +    HistoryCompletionModel(QObject *parent = 0); +    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; +    int rowCount(const QModelIndex &parent = QModelIndex()) const; +    int columnCount(const QModelIndex &parent = QModelIndex()) const; +    QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; +    QModelIndex mapToSource(const QModelIndex &proxyIndex) const; +    QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const; +    QModelIndex parent(const QModelIndex& index = QModelIndex()) const; +    void setSourceModel(QAbstractItemModel *sourceModel); + +private slots: +    void sourceReset(); + +}; + + +// --------------------------------------------------------------------------------------- + +/** + * Proxy model for the history model that converts the list + * into a tree, one top level node per day. + * Used in the HistoryDialog. + * + */ + +class HistoryTreeModel : public QAbstractProxyModel +{ +    Q_OBJECT + +public: +    HistoryTreeModel(QAbstractItemModel *sourceModel, QObject *parent = 0); +    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; +    int columnCount(const QModelIndex &parent) const; +    int rowCount(const QModelIndex &parent = QModelIndex()) const; +    QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; +    QModelIndex mapToSource(const QModelIndex &proxyIndex) const; +    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; +    QModelIndex parent(const QModelIndex &index = QModelIndex()) const; +    bool hasChildren(const QModelIndex &parent = QModelIndex()) const; +    Qt::ItemFlags flags(const QModelIndex &index) const; +    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); +    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + +    void setSourceModel(QAbstractItemModel *sourceModel); + +private slots: +    void sourceReset(); +    void sourceRowsInserted(const QModelIndex &parent, int start, int end); +    void sourceRowsRemoved(const QModelIndex &parent, int start, int end); + +private: +    int sourceDateRow(int row) const; +    mutable QList<int> m_sourceRowCache; + +}; + + +// ----------------------------------------------------------------------------------------------------------------- + +/** + * A modified QSortFilterProxyModel that always accepts + * the root nodes in the tree + * so filtering is only done on the children. + * Used in the HistoryDialog. + * + */ + +class TreeProxyModel : public QSortFilterProxyModel +{ +    Q_OBJECT + +public: +    TreeProxyModel(QObject *parent = 0); + +protected: +    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; +}; + + +// ------------------------------------------------------------------------------------------ + +#include "ui_history.h" + +class HistoryDialog : public QDialog, public Ui_HistoryDialog +{ +    Q_OBJECT + +signals: +    void openUrl(const KUrl &url); + +public: +    HistoryDialog(QWidget *parent = 0, HistoryManager *history = 0); + +private slots: +    void customContextMenuRequested(const QPoint &pos); +    void open(); +    void copy(); + +}; + +#endif // HISTORY_H + diff --git a/src/history.ui b/src/history.ui new file mode 100644 index 00000000..806bc9ad --- /dev/null +++ b/src/history.ui @@ -0,0 +1,101 @@ +<ui version="4.0" > + <class>HistoryDialog</class> + <widget class="QDialog" name="HistoryDialog" > +  <property name="geometry" > +   <rect> +    <x>0</x> +    <y>0</y> +    <width>758</width> +    <height>450</height> +   </rect> +  </property> +  <property name="windowTitle" > +   <string>History</string> +  </property> +  <layout class="QGridLayout" name="gridLayout" > +   <item row="0" column="0" > +    <spacer> +     <property name="orientation" > +      <enum>Qt::Horizontal</enum> +     </property> +     <property name="sizeHint" stdset="0" > +      <size> +       <width>252</width> +       <height>20</height> +      </size> +     </property> +    </spacer> +   </item> +   <item row="0" column="1" > +    <widget class="KLineEdit" name="search" /> +   </item> +   <item row="1" column="0" colspan="2" > +    <widget class="EditTreeView" name="tree" /> +   </item> +   <item row="2" column="0" colspan="2" > +    <layout class="QHBoxLayout" > +     <item> +      <widget class="QPushButton" name="removeButton" > +       <property name="text" > +        <string>&Remove</string> +       </property> +      </widget> +     </item> +     <item> +      <widget class="QPushButton" name="removeAllButton" > +       <property name="text" > +        <string>Remove &All</string> +       </property> +      </widget> +     </item> +     <item> +      <spacer> +       <property name="orientation" > +        <enum>Qt::Horizontal</enum> +       </property> +       <property name="sizeHint" stdset="0" > +        <size> +         <width>40</width> +         <height>20</height> +        </size> +       </property> +      </spacer> +     </item> +     <item> +      <widget class="QDialogButtonBox" name="buttonBox" > +       <property name="standardButtons" > +        <set>QDialogButtonBox::Ok</set> +       </property> +      </widget> +     </item> +    </layout> +   </item> +  </layout> + </widget> + <customwidgets> +  <customwidget> +   <class>EditTreeView</class> +   <extends>QTreeView</extends> +   <header>edittreeview.h</header> +  </customwidget> + </customwidgets> + <resources/> + <connections> +  <connection> +   <sender>buttonBox</sender> +   <signal>accepted()</signal> +   <receiver>HistoryDialog</receiver> +   <slot>accept()</slot> +   <hints> +    <hint type="sourcelabel" > +     <x>472</x> +     <y>329</y> +    </hint> +    <hint type="destinationlabel" > +     <x>461</x> +     <y>356</y> +    </hint> +   </hints> +  </connection> + </connections> +</ui> diff --git a/src/lineedit.cpp b/src/lineedit.cpp new file mode 100644 index 00000000..c9df7bfa --- /dev/null +++ b/src/lineedit.cpp @@ -0,0 +1,85 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + +// Self Includes +#include "lineedit.h" +#include "lineedit.moc" + +// Qt Includes +#include <QContextMenuEvent> +#include <QFocusEvent> +#include <QKeyEvent> + +// KDE Includes +#include <KDebug> + +// Local Includes + +LineEdit::LineEdit(QWidget* parent) +        : KLineEdit(parent) +{ +    setMinimumWidth(180); +    setFocusPolicy(Qt::WheelFocus); + +    setHandleSignals(true); +} + + +LineEdit::~LineEdit() +{ +} + + +void LineEdit::keyPressEvent(QKeyEvent *event) +{ +    if (event->key() == Qt::Key_Escape) +    { +        clearFocus(); +        event->accept(); +    } + +    KLineEdit::keyPressEvent(event); +} + + +void LineEdit::contextMenuEvent(QContextMenuEvent *event) +{ +    KLineEdit::contextMenuEvent(event); +} + + +void LineEdit::focusInEvent(QFocusEvent *event) +{ +    selectAll(); + +    KLineEdit::focusInEvent(event); +} + + +void LineEdit::focusOutEvent(QFocusEvent *event) +{ +    KLineEdit::focusOutEvent(event); + +    // reset cursor state and deselect +    setCursorPosition(0); +    deselect(); +} + + + diff --git a/src/lineedit.h b/src/lineedit.h new file mode 100644 index 00000000..f1bd8f88 --- /dev/null +++ b/src/lineedit.h @@ -0,0 +1,50 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef LINEEDIT_H +#define LINEEDIT_H + +// Qt Includes + +// KDE Includes +#include <KLineEdit> + +// Local Includes + +class QContextMenuEvent; +class QFocusEvent; +class QKeyEvent; + +class LineEdit : public KLineEdit +{ +    Q_OBJECT + +public: +    explicit LineEdit(QWidget *parent = 0); +    virtual ~LineEdit(); + +protected: +    virtual void keyPressEvent(QKeyEvent*); +    virtual void contextMenuEvent(QContextMenuEvent*); +    virtual void focusInEvent(QFocusEvent*); +    virtual void focusOutEvent(QFocusEvent*); +}; + +#endif // LINEEDIT_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 00000000..5ada94b4 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,98 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it +* and/or modify it under the terms of the GNU General +* Public License as published by the Free Software Foundation; +* either version 2, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#include "application.h" + +#include <KAboutData> +#include <KCmdLineArgs> +#include <KDebug> + + +static const char description[] = +    I18N_NOOP("KDE Browser Webkit Based"); + + +static const char version[] = "0.1alpha"; + + +int main(int argc, char **argv) +{ +    KAboutData about("rekonq", +                     0, +                     ki18n("rekonq"), +                     version, +                     ki18n(description), +                     KAboutData::License_GPL_V3, +                     ki18n("(C) 2008-2009 Andrea Diamantini"), +                     KLocalizedString(), +                     "http://rekonq.sourceforge.net", +                     "rekonq@kde.org" +                    ); + +    // about authors +    about.addAuthor(ki18n("Andrea Diamantini"), +                    ki18n("Project Lead, Developer, Italian translation"), +                    "adjam7@gmail.com", +                    "http://www.adjam.org"); + +    about.addAuthor(ki18n("Domrachev Alexandr"), +                    ki18n("Developer, Russian translation"), +                    "alexandr.domrachev@gmail.com", +                    ""); + +    about.addAuthor(ki18n("Pawel Prazak"), +                    ki18n("Developer"), +                    "kojots350@gmail.com", +                    ""); + +    about.addAuthor(ki18n("Panagiotis Papadopoulos"), +                    ki18n("German translation"), +                    "pano_90@gmx.net", +                    ""); + +//     about.addAuthor(ki18n("your name"), +//                     ki18n("your role"), +//                     "your mail", +//                     "your site"); + +    // Initialize command line args +    KCmdLineArgs::init(argc, argv, &about); + +    // Define the command line options using KCmdLineOptions +    KCmdLineOptions options; + +    // adding URL option +    options.add("+[URL]" , ki18n("Location to open")); + +    // Register the supported options +    KCmdLineArgs::addCmdLineOptions(options); + +    // Add options from Application class +    Application::addCmdLineOptions(); + +    if (!Application::start()) +    { +        kWarning() << "rekonq is already running!"; +        return 0; +    } + +    Application app; +    return app.exec(); +} diff --git a/src/mainview.cpp b/src/mainview.cpp new file mode 100644 index 00000000..d4edeb19 --- /dev/null +++ b/src/mainview.cpp @@ -0,0 +1,716 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +// Self Includes +#include "mainview.h" +#include "mainview.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "tabbar.h" +#include "application.h" +#include "mainwindow.h" +#include "history.h" +#include "stackedurlbar.h" +#include "urlbar.h" +#include "webview.h" + +// KDE Includes +#include <KUrl> +#include <KMenu> +#include <KAction> +#include <KShortcut> +#include <KStandardShortcut> +#include <KMessageBox> +#include <KActionCollection> +#include <KDebug> +#include <KStandardDirs> + +// Qt Includes +#include <QtCore> +#include <QtGui> +#include <QtWebKit> + + + +MainView::MainView(QWidget *parent) +        : KTabWidget(parent) +        , m_recentlyClosedTabsAction(0) +        , m_recentlyClosedTabsMenu(new KMenu(this)) +        , m_urlBars(new StackedUrlBar(this)) +        , m_tabBar(new TabBar(this)) +{ +    // setting tabbar +    setTabBar(m_tabBar); + +    // loading pixmap path +    m_loadingGitPath = KStandardDirs::locate("appdata" , "pics/loading.gif"); + +    // connecting tabbar signals +    connect(m_tabBar, SIGNAL(closeTab(int)), this, SLOT(slotCloseTab(int))); +    connect(m_tabBar, SIGNAL(cloneTab(int)), this, SLOT(slotCloneTab(int))); +    connect(m_tabBar, SIGNAL(closeOtherTabs(int)), this, SLOT(slotCloseOtherTabs(int))); +    connect(m_tabBar, SIGNAL(reloadTab(int)), this, SLOT(slotReloadTab(int))); +    connect(m_tabBar, SIGNAL(reloadAllTabs()), this, SLOT(slotReloadAllTabs())); +    connect(m_tabBar, SIGNAL(tabMoved(int, int)), this, SLOT(moveTab(int, int))); + +    // current page index changing +    connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int))); + +    setTabsClosable(true); +    connect(m_tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(slotCloseTab(int))); + +    QTimer::singleShot(0, this, SLOT(postLaunch())); +} + + +MainView::~MainView() +{ +} + + +void MainView::postLaunch() +{ +    // Recently Closed Tab Action +    connect(m_recentlyClosedTabsMenu, SIGNAL(aboutToShow()), this, SLOT(aboutToShowRecentTabsMenu())); +    connect(m_recentlyClosedTabsMenu, SIGNAL(triggered(QAction *)), this, SLOT(aboutToShowRecentTriggeredAction(QAction *))); +    m_recentlyClosedTabsAction = new KAction(i18n("Recently Closed Tabs"), this); +    m_recentlyClosedTabsAction->setMenu(m_recentlyClosedTabsMenu); +    m_recentlyClosedTabsAction->setEnabled(false); +} + +void MainView::showTabBar() +{ +    if (ReKonfig::alwaysShowTabBar()) +    { +        if (m_tabBar->isHidden()) +        { +            m_tabBar->show(); +        } +        return; +    } + +    if (m_tabBar->count() == 1) +    { +        m_tabBar->hide(); +    } +    else +    { +        if (m_tabBar->isHidden()) +        { +            m_tabBar->show(); +        } +    } +} + + +void MainView::slotWebReload() +{ +    WebView *webView = currentWebView(); +    QWebPage *currentParent = webView->webPage(); +    QAction *action = currentParent->action(QWebPage::Reload); +    action->trigger(); +} + + +void MainView::slotWebStop() +{ +    WebView *webView = currentWebView(); +    QWebPage *currentParent = webView->webPage(); +    QAction *action = currentParent->action(QWebPage::Stop); +    action->trigger(); +} + + +void MainView::slotWebBack() +{ +    WebView *webView = currentWebView(); +    QWebPage *currentParent = webView->webPage(); +    QAction *action = currentParent->action(QWebPage::Back); +    action->trigger(); +} + + +void MainView::slotWebForward() +{ +    WebView *webView = currentWebView(); +    QWebPage *currentParent = webView->webPage(); +    QAction *action = currentParent->action(QWebPage::Forward); +    action->trigger(); +} + + +void MainView::slotWebUndo() +{ +    WebView *webView = currentWebView(); +    QWebPage *currentParent = webView->webPage(); +    QAction *action = currentParent->action(QWebPage::Undo); +    action->trigger(); +} + + +void MainView::slotWebRedo() +{ +    WebView *webView = currentWebView(); +    QWebPage *currentParent = webView->webPage(); +    QAction *action = currentParent->action(QWebPage::Redo); +    action->trigger(); +} + + +void MainView::slotWebCut() +{ +    WebView *webView = currentWebView(); +    QWebPage *currentParent = webView->webPage(); +    QAction *action = currentParent->action(QWebPage::Cut); +    action->trigger(); +} + + +void MainView::slotWebCopy() +{ +    WebView *webView = currentWebView(); +    QWebPage *currentParent = webView->webPage(); +    QAction *action = currentParent->action(QWebPage::Copy); +    action->trigger(); +} + + +void MainView::slotWebPaste() +{ +    WebView *webView = currentWebView(); +    QWebPage *currentParent = webView->webPage(); +    QAction *action = currentParent->action(QWebPage::Paste); +    action->trigger(); +} + + +void MainView::clear() +{ +    // clear the recently closed tabs +    m_recentlyClosedTabs.clear(); +    // clear the line edit history +    for (int i = 0; i < m_urlBars->count(); ++i) +    { +        /// TODO What exacly do we need to clear here? +        urlBar(i)->clearHistory(); +        urlBar(i)->clear(); +    } +} + + +// When index is -1 index chooses the current tab +void MainView::slotReloadTab(int index) +{ +    if (index < 0) +        index = currentIndex(); +    if (index < 0 || index >= count()) +        return; + +    QWidget *widget = this->widget(index); +    if (WebView *tab = qobject_cast<WebView*>(widget)) +        tab->reload(); +} + + +void MainView::slotCurrentChanged(int index) +{ +    WebView *webView = this->webView(index); +    if (!webView) +        return; + +    Q_ASSERT(m_urlBars->count() == count()); + +    WebView *oldWebView = this->webView(m_urlBars->currentIndex()); +    if (oldWebView) +    { +        disconnect(oldWebView, SIGNAL(statusBarMessage(const QString&)), +                   this, SIGNAL(showStatusBarMessage(const QString&))); +        disconnect(oldWebView->page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)), +                   this, SIGNAL(linkHovered(const QString&))); +        disconnect(oldWebView, SIGNAL(loadProgress(int)), +                   this, SIGNAL(loadProgress(int))); +    } + +    connect(webView, SIGNAL(statusBarMessage(const QString&)), this, SIGNAL(showStatusBarMessage(const QString&))); +    connect(webView->page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)), this, SIGNAL(linkHovered(const QString&))); +    connect(webView, SIGNAL(loadProgress(int)), this, SIGNAL(loadProgress(int))); + +    emit setCurrentTitle(webView->title()); +    m_urlBars->setCurrentIndex(index); +    emit loadProgress(webView->progress()); +    emit showStatusBarMessage(webView->lastStatusBarText()); + +    // set focus to the current webview +    webView->setFocus(); +} + + +UrlBar *MainView::urlBar(int index) const +{ +    if (index == -1) +    { +        index = m_urlBars->currentIndex(); +    } +    UrlBar *urlBar = m_urlBars->urlBar(index); +    if (urlBar) +    { +        return urlBar; +    } +    kWarning() << "URL bar with index" << index << "not found. Returning NULL. (line:" << __LINE__ << ")"; +    return NULL; +} + + +WebView *MainView::webView(int index) const +{ +    QWidget *widget = this->widget(index); +    if (WebView *webView = qobject_cast<WebView*>(widget)) +    { +        return webView; +    } + +    kWarning() << "WebView with index " << index << "not found. Returning NULL." ; +    return 0; +} + + +WebView *MainView::newWebView(Rekonq::OpenType type) +{ +    // line edit +    UrlBar *urlBar = new UrlBar;  // Ownership of widget is passed on to the QStackedWidget (addWidget method). +    connect(urlBar, SIGNAL(activated(const KUrl&)), this, SLOT(loadUrl(const KUrl&))); +    m_urlBars->addUrlBar(urlBar); + +    WebView *webView = new WebView;  // should be deleted on tab close + +    // connecting webview with urlbar +    connect(webView, SIGNAL(loadProgress(int)), urlBar, SLOT(slotUpdateProgress(int))); +    connect(webView, SIGNAL(loadFinished(bool)), urlBar, SLOT(slotLoadFinished(bool))); +    connect(webView, SIGNAL(urlChanged(const QUrl &)), urlBar, SLOT(setUrl(const QUrl &))); +    connect(webView, SIGNAL(iconChanged()), urlBar, SLOT(slotUpdateUrl())); + +    // connecting webview with mainview +    connect(webView, SIGNAL(loadStarted()), this, SLOT(webViewLoadStarted())); +    connect(webView, SIGNAL(loadProgress(int)), this, SLOT(webViewLoadProgress(int))); +    connect(webView, SIGNAL(loadFinished(bool)), this, SLOT(webViewLoadFinished(bool))); +    connect(webView, SIGNAL(iconChanged()), this, SLOT(webViewIconChanged())); +    connect(webView, SIGNAL(titleChanged(const QString &)), this, SLOT(webViewTitleChanged(const QString &))); +    connect(webView, SIGNAL(urlChanged(const QUrl &)), this, SLOT(webViewUrlChanged(const QUrl &))); + +    connect(webView, SIGNAL(ctrlTabPressed()), this, SLOT(nextTab())); +    connect(webView, SIGNAL(shiftCtrlTabPressed()), this, SLOT(previousTab())); + +    // connecting webPage signals with mainview +    connect(webView->page(), SIGNAL(windowCloseRequested()), +            this, SLOT(windowCloseRequested())); +    connect(webView->page(), SIGNAL(geometryChangeRequested(const QRect &)), +            this, SIGNAL(geometryChangeRequested(const QRect &))); +    connect(webView->page(), SIGNAL(printRequested(QWebFrame *)), +            this, SIGNAL(printRequested(QWebFrame *))); +    connect(webView->page(), SIGNAL(menuBarVisibilityChangeRequested(bool)), +            this, SIGNAL(menuBarVisibilityChangeRequested(bool))); +    connect(webView->page(), SIGNAL(statusBarVisibilityChangeRequested(bool)), +            this, SIGNAL(statusBarVisibilityChangeRequested(bool))); +    connect(webView->page(), SIGNAL(toolBarVisibilityChangeRequested(bool)), +            this, SIGNAL(toolBarVisibilityChangeRequested(bool))); + +    addTab(webView, i18n("(Untitled)")); + +    switch(type) +    { +    case Rekonq::Default: +        if (!m_makeBackTab) +        { +            setCurrentWidget(webView);  // this method does NOT take ownership of webView +            urlBar->setFocus(); +        } +        break; +    case Rekonq::New: +        setCurrentWidget(webView);  // this method does NOT take ownership of webView +        urlBar->setFocus(); +        break; +    case Rekonq::Background: +        break; +    }; + +    emit tabsChanged(); + +    showTabBar(); + +    return webView; +} + + +void MainView::slotReloadAllTabs() +{ +    for (int i = 0; i < count(); ++i) +    { +        QWidget *tabWidget = widget(i); +        if (WebView *tab = qobject_cast<WebView*>(tabWidget)) +        { +            tab->reload(); +        } +    } +} + + +void MainView::windowCloseRequested() +{ + +    WebPage *webPage = qobject_cast<WebPage*>(sender()); +    WebView *webView = qobject_cast<WebView*>(webPage->view()); +    int index = webViewIndex(webView); + +    if (index >= 0) +    { +        if (count() == 1) +        { +            Application::instance()->mainWindow()->close(); +        } +        else +        { +            slotCloseTab(index); +        } +    } +    else +    { +        kWarning() << "Invalid tab index" << "line:" << __LINE__; +    } +} + + +void MainView::slotCloseOtherTabs(int index) +{ +    if (-1 == index) +        return; + +    for (int i = count() - 1; i > index; --i) +    { +        slotCloseTab(i); +    } + +    for (int i = index - 1; i >= 0; --i) +    { +        slotCloseTab(i); +    } + +    showTabBar(); +} + + +// When index is -1 index chooses the current tab +void MainView::slotCloneTab(int index) +{ +    if (index < 0) +        index = currentIndex(); +    if (index < 0 || index >= count()) +        return; +    WebView *tab = newWebView(); +    tab->setUrl(webView(index)->url()); + +    showTabBar(); +} + + +// When index is -1 index chooses the current tab +void MainView::slotCloseTab(int index) +{ +    // do nothing if just one tab is opened +    if (count() == 1) +        return; + +    if (index < 0) +        index = currentIndex(); +    if (index < 0 || index >= count()) +        return; + +    bool hasFocus = false; +    if (WebView *tab = webView(index)) +    { +        if (tab->isModified()) +        { +            int risp = KMessageBox::questionYesNo(this , +                                                  i18n("You have modified this page and when closing it you would lose the modification.\n" +                                                       "Do you really want to close this page?\n"), +                                                  i18n("Do you really want to close this page?") +                                                 ); +            if (risp == KMessageBox::No) +                return; +        } +        hasFocus = tab->hasFocus(); + +        m_recentlyClosedTabsAction->setEnabled(true); +        m_recentlyClosedTabs.prepend(tab->url()); + +        // don't add empty urls +        if (tab->url().isValid()) +        { +            m_recentlyClosedTabs.prepend(tab->url()); +        } + +        if (m_recentlyClosedTabs.size() >= MainView::m_recentlyClosedTabsSize) +        { +            m_recentlyClosedTabs.removeLast(); +        } +    } + +    QWidget *urlBar = m_urlBars->urlBar(index); +    m_urlBars->removeWidget(urlBar); +    urlBar->deleteLater();   // urlBar is scheduled for deletion. + +    QWidget *webView = widget(index); +    removeTab(index); +    webView->deleteLater();  // webView is scheduled for deletion. + +    emit tabsChanged(); + +    if (hasFocus && count() > 0) +    { +        currentWebView()->setFocus(); +    } + +    showTabBar(); +} + + +void MainView::webViewLoadStarted() +{ +    WebView *webView = qobject_cast<WebView*>(sender()); +    int index = webViewIndex(webView); +    if (-1 != index) +    { +        QLabel *label = animatedLoading(index, true); +        if (label->movie()) +        { +            label->movie()->start(); +        } +    } + +    if (index != currentIndex()) +        return; + +    emit showStatusBarMessage(i18n("Loading...")); +} + + +void MainView::webViewLoadProgress(int progress) +{ +    WebView *webView = qobject_cast<WebView*>(sender()); +    int index = webViewIndex(webView); +    if (index != currentIndex() || index < 0) +    { +        return; +    } + +    double totalBytes = static_cast<double>(webView->webPage()->totalBytes() / 1024); + +    QString message = i18n("Loading %1% (%2 %3)...", progress, totalBytes, QLatin1String("kB")); +    emit showStatusBarMessage(message); +} + + +void MainView::webViewLoadFinished(bool ok) +{ +    WebView *webView = qobject_cast<WebView*>(sender()); +    int index = webViewIndex(webView); + +    if (-1 != index) +    { +        QLabel *label = animatedLoading(index, true); +        QMovie *movie = label->movie(); +        if (movie) +            movie->stop(); +    } + +    webViewIconChanged(); + +    // don't display messages for background tabs +    if (index != currentIndex()) +    { +        return; +    } + +    if (ok) +        emit showStatusBarMessage(i18n("Done")); +    else +        emit showStatusBarMessage(i18n("Failed to load")); +} + + +void MainView::webViewIconChanged() +{ +    WebView *webView = qobject_cast<WebView*>(sender()); +    int index = webViewIndex(webView); +    if (-1 != index) +    { +        QIcon icon = Application::instance()->icon(webView->url()); +        QLabel *label = animatedLoading(index, false); +        QMovie *movie = label->movie(); +        delete movie; +        label->setMovie(0); +        label->setPixmap(icon.pixmap(16, 16)); +    } +} + + +void MainView::webViewTitleChanged(const QString &title) +{ +    QString tabTitle = title; +    if (title.isEmpty()) +    { +        tabTitle = i18n("(Untitled)"); +    } +    WebView *webView = qobject_cast<WebView*>(sender()); +    int index = webViewIndex(webView); +    if (-1 != index) +    { +        setTabText(index, tabTitle); +    } +    if (currentIndex() == index) +    { +        emit setCurrentTitle(tabTitle); +    } +    Application::historyManager()->updateHistoryEntry(webView->url(), tabTitle); +} + + +void MainView::webViewUrlChanged(const QUrl &url) +{ +    WebView *webView = qobject_cast<WebView*>(sender()); +    int index = webViewIndex(webView); +    if (-1 != index) +    { +        m_tabBar->setTabData(index, url); +    } +    emit tabsChanged(); +} + + +void MainView::aboutToShowRecentTabsMenu() +{ +    m_recentlyClosedTabsMenu->clear(); +    for (int i = 0; i < m_recentlyClosedTabs.count(); ++i) +    { +        KAction *action = new KAction(m_recentlyClosedTabsMenu); +        action->setData(m_recentlyClosedTabs.at(i)); +        QIcon icon = Application::instance()->icon(m_recentlyClosedTabs.at(i)); +        action->setIcon(icon); +        action->setText(m_recentlyClosedTabs.at(i).prettyUrl()); +        m_recentlyClosedTabsMenu->addAction(action); +    } +} + + +void MainView::aboutToShowRecentTriggeredAction(QAction *action) +{ +    KUrl url = action->data().toUrl(); +    loadUrl(url); +} + + +void MainView::loadUrl(const KUrl &url) +{ +    if (url.isEmpty()) +        return; + +    currentUrlBar()->setUrl(url.prettyUrl()); + +    WebView *webView = currentWebView(); + +    KUrl loadingUrl(url); + +    if (loadingUrl.isRelative()) +    { +        QString fn = loadingUrl.url(KUrl::RemoveTrailingSlash); +        loadingUrl.setUrl("//" + fn); +        loadingUrl.setScheme("http"); +    } + +    if (webView) +    { +        webView->load(loadingUrl); +        webView->setFocus(); +    } +} + + +void MainView::nextTab() +{ +    int next = currentIndex() + 1; +    if (next == count()) +        next = 0; +    setCurrentIndex(next); +} + + +void MainView::previousTab() +{ +    int next = currentIndex() - 1; +    if (next < 0) +        next = count() - 1; +    setCurrentIndex(next); +} + + +void MainView::moveTab(int fromIndex, int toIndex) +{ +    QWidget *lineEdit = m_urlBars->widget(fromIndex); +    m_urlBars->removeWidget(lineEdit); +    m_urlBars->insertWidget(toIndex, lineEdit); +} + + +QLabel *MainView::animatedLoading(int index, bool addMovie) +{ +    if (index == -1) +        return 0; + +    QLabel *label = qobject_cast<QLabel*>(m_tabBar->tabButton(index, QTabBar::LeftSide)); +    if (!label) +    { +        label = new QLabel(this); +    } +    if (addMovie && !label->movie()) +    { +        QMovie *movie = new QMovie(m_loadingGitPath, QByteArray(), label); +        movie->setSpeed(50); +        label->setMovie(movie); +        movie->start(); +    } +    m_tabBar->setTabButton(index, QTabBar::LeftSide, 0); +    m_tabBar->setTabButton(index, QTabBar::LeftSide, label); +    return label; +} + + +void MainView::mouseDoubleClickEvent(QMouseEvent *event) +{ +    if (!childAt(event->pos())) +    { +        newWebView(Rekonq::New); +        return; +    } +    KTabWidget::mouseDoubleClickEvent(event); +}
\ No newline at end of file diff --git a/src/mainview.h b/src/mainview.h new file mode 100644 index 00000000..372902dd --- /dev/null +++ b/src/mainview.h @@ -0,0 +1,198 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + + +#ifndef TABWIDGET_H +#define TABWIDGET_H + +// Local Includes +#include "webview.h" +#include "application.h" + +// KDE Includes +#include <KTabWidget> + +// Forward Declarations +class QLineEdit; +class QUrl; +class QWebFrame; +class QLabel; + +class KAction; +class KCompletion; +class KMenu; +class KUrl; + +class HistoryCompletionModel; +class StackedUrlBar; +class TabBar; +class UrlBar; + + +/** + *  This class represent rekonq Main View. It contains all WebViews and a stack widget + *  of associated line edits. + * + */ + +class MainView : public KTabWidget +{ +    Q_OBJECT + +public: +    MainView(QWidget *parent = 0); +    ~MainView(); + +public: + +    UrlBar *urlBar(int index) const; +    UrlBar *currentUrlBar() const { return urlBar(-1); } +    WebView *webView(int index) const; +    QList<WebView *> tabs();    // ? + +    // inlines +    TabBar *tabBar() const { return m_tabBar; } +    StackedUrlBar *urlBarStack() const { return m_urlBars; } +    WebView *currentWebView() const { return webView(currentIndex()); } +    int webViewIndex(WebView *webView) const { return indexOf(webView); } +    KAction *recentlyClosedTabsAction() const { return m_recentlyClosedTabsAction; } +    void setMakeBackTab(bool b) { m_makeBackTab = b; } + +    /** +     * show and hide TabBar if user doesn't choose +     * "Always Show TabBar" option +     * +     */ +    void showTabBar(); +    void clear(); + + +signals: +    // tab widget signals +    void tabsChanged(); +    void lastTabClosed(); + +    // current tab signals +    void setCurrentTitle(const QString &url); +    void showStatusBarMessage(const QString &message); +    void linkHovered(const QString &link); +    void loadProgress(int progress); + +    void geometryChangeRequested(const QRect &geometry); +    void menuBarVisibilityChangeRequested(bool visible); +    void statusBarVisibilityChangeRequested(bool visible); +    void toolBarVisibilityChangeRequested(bool visible); +    void printRequested(QWebFrame *frame); + +public slots: +    /** +     * Core browser slot. This create a new tab with a WebView inside +     * for browsing. +     * +     * @return a pointer to the new WebView +     */ +    WebView *newWebView(Rekonq::OpenType type = Rekonq::Default); + +    /** +     * Core browser slot. Load an url in a webview +     * +     * @param url The url to load +     */ +    void loadUrl(const KUrl &url); +    void slotCloneTab(int index = -1); +    void slotCloseTab(int index = -1); +    void slotCloseOtherTabs(int index); +    void slotReloadTab(int index = -1); +    void slotReloadAllTabs(); +    void nextTab(); +    void previousTab(); + +    // WEB slot actions +    void slotWebReload(); +    void slotWebStop(); +    void slotWebBack(); +    void slotWebForward(); +    void slotWebUndo(); +    void slotWebRedo(); +    void slotWebCut(); +    void slotWebCopy(); +    void slotWebPaste(); + +private slots: +    void slotCurrentChanged(int index); +    void aboutToShowRecentTabsMenu(); +    void aboutToShowRecentTriggeredAction(QAction *action); // need QAction! + +    void webViewLoadStarted(); +    void webViewLoadProgress(int progress); +    void webViewLoadFinished(bool ok); +    void webViewIconChanged(); +    void webViewTitleChanged(const QString &title); +    void webViewUrlChanged(const QUrl &url); + +    void windowCloseRequested(); + +    /** +     * This functions move tab informations "from index to index" +     * +     * @param fromIndex the index from which we move +     * +     * @param toIndex the index to which we move +     */ +    void moveTab(int fromIndex, int toIndex); + +    void postLaunch(); + +protected: + +    virtual void mouseDoubleClickEvent(QMouseEvent *event); + + +private: + +    /** +     * This function creates (if not exists) and returns a QLabel +     * with a loading QMovie. +     * Imported from Arora's code. +     * +     * @param index the tab index where inserting the animated label +     * @param addMovie creates or not a loading movie +     * +     * @return animated label's pointer +     */ +    QLabel *animatedLoading(int index, bool addMovie); + +    static const int m_recentlyClosedTabsSize = 10; +    KAction *m_recentlyClosedTabsAction; + +    KMenu *m_recentlyClosedTabsMenu; +    QList<KUrl> m_recentlyClosedTabs; + +    StackedUrlBar *m_urlBars; +    TabBar *m_tabBar; + +    QString m_loadingGitPath; + +    bool m_makeBackTab; +}; + +#endif diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 00000000..d1ab721f --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,930 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// Self Includes +#include "mainwindow.h" +#include "mainwindow.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "application.h" +#include "settings.h" +#include "history.h" +#include "cookiejar.h" +#include "networkaccessmanager.h" +#include "bookmarks.h" +#include "webview.h" +#include "mainview.h" +#include "bookmarks.h" +#include "download.h" +#include "findbar.h" +#include "sidepanel.h" +#include "urlbar.h" +#include "stackedurlbar.h" + +// KDE Includes +#include <KUrl> +#include <KStatusBar> +#include <KMenuBar> +#include <KShortcut> +#include <KStandardAction> +#include <KAction> +#include <KToggleFullScreenAction> +#include <KActionCollection> +#include <KMessageBox> +#include <KFileDialog> +#include <KMenu> +#include <KGlobalSettings> +#include <KPushButton> +#include <KTemporaryFile> + +#include <kdeprintdialog.h> +#include <kprintpreview.h> + + +// Qt Includes +#include <QtGui> +#include <QtCore> +#include <QtWebKit> + + +MainWindow::MainWindow() +        : KXmlGuiWindow() +        , m_view(new MainView(this)) +        , m_findBar(new FindBar(this)) +        , m_searchBar(new SearchBar(this)) +        , m_sidePanel(0) +{ +    // updating rekonq configuration +    slotUpdateConfiguration(); + +    // creating a centralWidget containing panel, m_view and the hidden findbar +    QWidget *centralWidget = new QWidget; +    centralWidget->setContentsMargins(0, 0, 0, 0); + +    // setting layout +    QVBoxLayout *layout = new QVBoxLayout; +    layout->setContentsMargins(0, 0, 0, 0); +    layout->addWidget(m_view); +    layout->addWidget(m_findBar); +    centralWidget->setLayout(layout); + +    // central widget +    setCentralWidget(centralWidget); + +    // setting size policies +    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + +    // then, setup our actions +    setupActions(); + +    // setting up toolbars: this has to be done BEFORE setupGUI!! +    setupToolBars(); + +    // Bookmark Menu +    KActionMenu *bmMenu = Application::bookmarkProvider()->bookmarkActionMenu(); +    actionCollection()->addAction(QLatin1String("bookmarks"), bmMenu); + +    // Side Panel: this has to be done BEFORE setupGUI!! +    setupSidePanel(); + +    // a call to KXmlGuiWindow::setupGUI() populates the GUI +    // with actions, using KXMLGUI. +    // It also applies the saved mainwindow settings, if any, and ask the +    // mainwindow to automatically save settings if changed: window size, +    // toolbar position, icon size, etc. +    setupGUI(); + +    QTimer::singleShot(0, this, SLOT(postLaunch())); +} + + +MainWindow::~MainWindow() +{ +    delete m_view; +} + + +void MainWindow::postLaunch() +{ +    // setup history menu: this has to be done AFTER setupGUI!! +    setupHistoryMenu(); + +    // --------- connect signals and slots +    connect(m_view, SIGNAL(setCurrentTitle(const QString &)), this, SLOT(slotUpdateWindowTitle(const QString &))); +    connect(m_view, SIGNAL(loadProgress(int)), this, SLOT(slotLoadProgress(int))); +    connect(m_view, SIGNAL(geometryChangeRequested(const QRect &)), this, SLOT(geometryChangeRequested(const QRect &))); +    connect(m_view, SIGNAL(printRequested(QWebFrame *)), this, SLOT(printRequested(QWebFrame *))); +    connect(m_view, SIGNAL(menuBarVisibilityChangeRequested(bool)), menuBar(), SLOT(setVisible(bool))); +    connect(m_view, SIGNAL(statusBarVisibilityChangeRequested(bool)), statusBar(), SLOT(setVisible(bool))); + +    // status bar messages +    connect(m_view, SIGNAL(showStatusBarMessage(const QString&)), statusBar(), SLOT(showMessage(const QString&))); +    connect(m_view, SIGNAL(linkHovered(const QString&)), statusBar(), SLOT(showMessage(const QString&))); + +    // update toolbar actions signals +    connect(m_view, SIGNAL(tabsChanged()), this, SLOT(slotUpdateActions())); +    connect(m_view, SIGNAL(currentChanged(int)), this, SLOT(slotUpdateActions())); + +    // Find Bar signal +    connect(m_findBar, SIGNAL(searchString(const QString &)), this, SLOT(slotFind(const QString &))); + +    // bookmarks loading +    connect(Application::bookmarkProvider(), SIGNAL(openUrl(const KUrl&)), this, SLOT(loadUrl(const KUrl&))); + +    // setting up toolbars to NOT have context menu enabled +    setContextMenuPolicy(Qt::DefaultContextMenu); + +    // accept d'n'd +    setAcceptDrops(true); +} + + +QSize MainWindow::sizeHint() const +{ +    QRect desktopRect = QApplication::desktop()->screenGeometry(); +    QSize size = desktopRect.size() * 0.8; +    return size; +} + + +void MainWindow::setupToolBars() +{ +    KAction *a; + +    // location bar +    a = new KAction(i18n("Location Bar"), this); +    a->setShortcut(KShortcut(Qt::Key_F6)); +    a->setDefaultWidget(m_view->urlBarStack()); +    actionCollection()->addAction(QLatin1String("url_bar"), a); + +    // search bar +    a = new KAction(i18n("Search Bar"), this); +    a->setShortcut(KShortcut(Qt::CTRL + Qt::Key_K)); +    a->setDefaultWidget(m_searchBar); +    connect(m_searchBar, SIGNAL(search(const KUrl&)), this, SLOT(loadUrl(const KUrl&))); +    actionCollection()->addAction(QLatin1String("search_bar"), a); + +    // bookmarks bar +    KAction *bookmarkBarAction = Application::bookmarkProvider()->bookmarkToolBarAction(); +    a = actionCollection()->addAction(QLatin1String("bookmarks_bar"), bookmarkBarAction); +} + + +void MainWindow::setupActions() +{ +    KAction *a; + +    // Standard Actions +    KStandardAction::open(this, SLOT(slotFileOpen()), actionCollection()); +    KStandardAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection()); +    KStandardAction::printPreview(this, SLOT(slotFilePrintPreview()), actionCollection()); +    KStandardAction::print(this, SLOT(slotFilePrint()), actionCollection()); +    KStandardAction::quit(this , SLOT(close()), actionCollection()); +    KStandardAction::find(this, SLOT(slotViewFindBar()) , actionCollection()); +    KStandardAction::findNext(this, SLOT(slotFindNext()) , actionCollection()); +    KStandardAction::findPrev(this, SLOT(slotFindPrevious()) , actionCollection()); +    KStandardAction::fullScreen(this, SLOT(slotViewFullScreen(bool)), this, actionCollection()); +    KStandardAction::home(this, SLOT(slotHome()), actionCollection()); +    KStandardAction::preferences(this, SLOT(slotPreferences()), actionCollection()); +    KStandardAction::showMenubar(this, SLOT(slotShowMenubar(bool)), actionCollection()); + +    // WEB Actions (NO KStandardActions..) +    a = KStandardAction::redisplay(m_view, SLOT(slotWebReload()), actionCollection()); +    a->setText(i18n("Reload")); +    KStandardAction::back(m_view, SLOT(slotWebBack()), actionCollection()); +    KStandardAction::forward(m_view, SLOT(slotWebForward()), actionCollection()); +    KStandardAction::undo(m_view, SLOT(slotWebUndo()), actionCollection()); +    KStandardAction::redo(m_view, SLOT(slotWebRedo()), actionCollection()); +    KStandardAction::cut(m_view, SLOT(slotWebCut()), actionCollection()); +    KStandardAction::copy(m_view, SLOT(slotWebCopy()), actionCollection()); +    KStandardAction::paste(m_view, SLOT(slotWebPaste()), actionCollection()); + +    a = new KAction(KIcon("process-stop"), i18n("&Stop"), this); +    a->setShortcut(KShortcut(Qt::CTRL | Qt::Key_Period)); +    actionCollection()->addAction(QLatin1String("stop"), a); +    connect(a, SIGNAL(triggered(bool)), m_view, SLOT(slotWebStop())); + +    // stop reload Action +    m_stopReloadAction = new KAction(KIcon("view-refresh"), i18n("Reload"), this); +    actionCollection()->addAction(QLatin1String("stop_reload") , m_stopReloadAction); +    m_stopReloadAction->setShortcutConfigurable(false); + +    // ============== Custom Actions +    a = new KAction(KIcon("document-open-remote"), i18n("Open Location"), this); +    a->setShortcut(Qt::CTRL + Qt::Key_L); +    actionCollection()->addAction(QLatin1String("open_location"), a); +    connect(a, SIGNAL(triggered(bool)) , this, SLOT(slotOpenLocation())); + +    a = new KAction(KIcon("zoom-in"), i18n("&Enlarge Font"), this); +    a->setShortcut(KShortcut(Qt::CTRL | Qt::Key_Plus)); +    actionCollection()->addAction(QLatin1String("bigger_font"), a); +    connect(a, SIGNAL(triggered(bool)), this, SLOT(slotViewTextBigger())); + +    a = new KAction(KIcon("zoom-original"),  i18n("&Normal Font"), this); +    a->setShortcut(KShortcut(Qt::CTRL | Qt::Key_0)); +    actionCollection()->addAction(QLatin1String("normal_font"), a); +    connect(a, SIGNAL(triggered(bool)), this, SLOT(slotViewTextNormal())); + +    a = new KAction(KIcon("zoom-out"),  i18n("&Shrink Font"), this); +    a->setShortcut(KShortcut(Qt::CTRL | Qt::Key_Minus)); +    actionCollection()->addAction(QLatin1String("smaller_font"), a); +    connect(a, SIGNAL(triggered(bool)), this, SLOT(slotViewTextSmaller())); + +    a = new KAction(i18n("Page S&ource"), this); +    actionCollection()->addAction(QLatin1String("page_source"), a); +    connect(a, SIGNAL(triggered(bool)), this, SLOT(slotViewPageSource())); + +    // ================ Tools (WebKit) Actions +    a = new KAction(KIcon("tools-report-bug"), i18n("Web &Inspector"), this); +    a->setCheckable(true); +    actionCollection()->addAction(QLatin1String("web_inspector"), a); +    connect(a, SIGNAL(triggered(bool)), this, SLOT(slotToggleInspector(bool))); + +    a = new KAction(KIcon("view-media-artist"), i18n("Private &Browsing"), this); +    a->setCheckable(true); +    actionCollection()->addAction(QLatin1String("private_browsing"), a); +    connect(a, SIGNAL(triggered(bool)) , this, SLOT(slotPrivateBrowsing(bool))); + +    // ================ history related actions +    m_historyBackAction = new KAction(KIcon("go-previous"), i18n("Back"), this); +    m_historyBackMenu = new KMenu(this); +    m_historyBackAction->setMenu(m_historyBackMenu); +    connect(m_historyBackAction, SIGNAL(triggered(bool)), this, SLOT(slotOpenPrevious())); +    connect(m_historyBackMenu, SIGNAL(aboutToShow()), this, SLOT(slotAboutToShowBackMenu())); +    connect(m_historyBackMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotOpenActionUrl(QAction *))); +    actionCollection()->addAction(QLatin1String("history_back"), m_historyBackAction); + +    m_historyForwardAction = new KAction(KIcon("go-next"), i18n("Forward"), this); +    connect(m_historyForwardAction, SIGNAL(triggered(bool)), this, SLOT(slotOpenNext())); +    actionCollection()->addAction(QLatin1String("history_forward"), m_historyForwardAction); + +    // =================== Tab Actions +    a = new KAction(KIcon("tab-new"), i18n("New &Tab"), this); +    QList<QKeySequence> newTabShortcutList; +    newTabShortcutList << QKeySequence(QKeySequence::New); +    newTabShortcutList << QKeySequence(QKeySequence::AddTab); +    a->setShortcut(KShortcut(newTabShortcutList)); +    actionCollection()->addAction(QLatin1String("new_tab"), a); +    connect(a, SIGNAL(triggered(bool)), m_view, SLOT(newWebView())); + +    a = new KAction(KIcon("tab-close"), i18n("&Close Tab"), this); +    a->setShortcut(KShortcut(Qt::CTRL + Qt::Key_W)); +    actionCollection()->addAction(QLatin1String("close_tab"), a); +    connect(a, SIGNAL(triggered(bool)), m_view, SLOT(slotCloseTab())); + +    a = new KAction(i18n("Show Next Tab"), this); +    a->setShortcuts(QApplication::isRightToLeft() ? KStandardShortcut::tabPrev() : KStandardShortcut::tabNext()); +    actionCollection()->addAction(QLatin1String("show_next_tab"), a); +    connect(a, SIGNAL(triggered(bool)), m_view, SLOT(nextTab())); + +    a = new KAction(i18n("Show Previous Tab"), this); +    a->setShortcuts(QApplication::isRightToLeft() ? KStandardShortcut::tabNext() : KStandardShortcut::tabPrev()); +    actionCollection()->addAction(QLatin1String("show_prev_tab"), a); +    connect(a, SIGNAL(triggered(bool)), m_view, SLOT(previousTab())); +} + + +void MainWindow::setupSidePanel() +{ +    // Setup history side panel +    m_sidePanel = new SidePanel(i18n("History"), this); +    connect(m_sidePanel, SIGNAL(openUrl(const KUrl&)), this, SLOT(loadUrl(const KUrl&))); +    connect(m_sidePanel, SIGNAL(destroyed()), Application::instance(), SLOT(slotSaveConfiguration())); + +    addDockWidget(Qt::LeftDockWidgetArea, m_sidePanel); + +    // setup side panel actions +    KAction* a = new KAction(this); +    a->setText(i18n("History")); +    a->setCheckable(true); +    a->setChecked(ReKonfig::showSideBar()); +    a->setShortcut(KShortcut(Qt::CTRL + Qt::Key_H)); +    actionCollection()->addAction(QLatin1String("show_history_panel"), a); + +    // connect to toogle action +    connect(a, SIGNAL(triggered(bool)), m_sidePanel->toggleViewAction(), SLOT(trigger())); +} + + +void MainWindow::setupHistoryMenu() +{ +    HistoryMenu *historyMenu = new HistoryMenu(this); +    connect(historyMenu, SIGNAL(openUrl(const KUrl&)), this, SLOT(loadUrl(const KUrl&))); +    connect(historyMenu, SIGNAL(hovered(const QString&)), this, SLOT(slotUpdateStatusbar(const QString&))); +    historyMenu->setTitle(i18n("&History")); + +    // setting history menu position +    menuBar()->insertMenu(actionCollection()->action("bookmarks"), historyMenu); + +    // setting initial actions +    QList<QAction*> historyActions; +    historyActions.append(actionCollection()->action("history_back")); +    historyActions.append(actionCollection()->action("history_forward")); +    historyActions.append(m_view->recentlyClosedTabsAction()); +    historyMenu->setInitialActions(historyActions); +} + + +void MainWindow::slotUpdateConfiguration() +{ +    // ============== General ================== +    m_homePage = ReKonfig::homePage(); +    mainView()->showTabBar(); +    mainView()->setMakeBackTab( ReKonfig::openTabsBack() ); + +    // =========== Fonts ============== +    QWebSettings *defaultSettings = QWebSettings::globalSettings(); + +    int fnSize = ReKonfig::fontSize(); + +    QFont standardFont = ReKonfig::standardFont(); +    defaultSettings->setFontFamily(QWebSettings::StandardFont, standardFont.family()); +    defaultSettings->setFontSize(QWebSettings::DefaultFontSize, fnSize); + +    QFont fixedFont = ReKonfig::fixedFont(); +    defaultSettings->setFontFamily(QWebSettings::FixedFont, fixedFont.family()); +    defaultSettings->setFontSize(QWebSettings::DefaultFixedFontSize, fnSize); + +    // ================ WebKit ============================ +    defaultSettings->setAttribute(QWebSettings::AutoLoadImages, ReKonfig::autoLoadImages()); +    defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, ReKonfig::javascriptEnabled()); +    defaultSettings->setAttribute(QWebSettings::JavaEnabled, ReKonfig::javaEnabled()); +    defaultSettings->setAttribute(QWebSettings::PluginsEnabled, ReKonfig::pluginsEnabled()); +    defaultSettings->setAttribute(QWebSettings::JavascriptCanOpenWindows, ReKonfig::javascriptCanOpenWindows()); +    defaultSettings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, ReKonfig::javascriptCanAccessClipboard()); +    defaultSettings->setAttribute(QWebSettings::LinksIncludedInFocusChain, ReKonfig::linksIncludedInFocusChain()); +    defaultSettings->setAttribute(QWebSettings::ZoomTextOnly, ReKonfig::zoomTextOnly()); +    defaultSettings->setAttribute(QWebSettings::PrintElementBackgrounds, ReKonfig::printElementBackgrounds()); +    defaultSettings->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, ReKonfig::offlineStorageDatabaseEnabled()); +    defaultSettings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, ReKonfig::offlineWebApplicationCacheEnabled()); +    defaultSettings->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, ReKonfig::localStorageDatabaseEnabled()); + +    // ====== load Settings on main classes +    Application::networkAccessManager()->loadSettings(); +    Application::cookieJar()->loadSettings(); +    Application::historyManager()->loadSettings(); +} + + +void MainWindow::slotUpdateBrowser() +{ +    slotUpdateConfiguration(); +    mainView()->slotReloadAllTabs(); +} + + +KUrl MainWindow::guessUrlFromString(const QString &string) +{ +    QString urlStr = string.trimmed(); +    QRegExp test(QLatin1String("^[a-zA-Z]+\\:.*")); + +    // Check if it looks like a qualified URL. Try parsing it and see. +    bool hasSchema = test.exactMatch(urlStr); + +    if (hasSchema) +    { +        QUrl qurl(urlStr, QUrl::TolerantMode); +        KUrl url(qurl); + +        if (url.isValid()) +        { +            return url; +        } +    } + +    // Might be a file. +    if (QFile::exists(urlStr)) +    { +        QFileInfo info(urlStr); +        return KUrl::fromPath(info.absoluteFilePath()); +    } + +    // Might be a shorturl - try to detect the schema. +    if (!hasSchema) +    { +        int dotIndex = urlStr.indexOf(QLatin1Char('.')); + +        if (dotIndex != -1) +        { +            QString prefix = urlStr.left(dotIndex).toLower(); +            QString schema = (prefix == QLatin1String("ftp")) ? prefix : QLatin1String("http"); +            QUrl qurl(schema + QLatin1String("://") + urlStr, QUrl::TolerantMode); +            KUrl url(qurl); + +            if (url.isValid()) +            { +                return url; +            } +        } +    } + +    // Fall back to QUrl's own tolerant parser. +    QUrl qurl = QUrl(string, QUrl::TolerantMode); +    KUrl url(qurl); + +    // finally for cases where the user just types in a hostname add http +    if (qurl.scheme().isEmpty()) +    { +        qurl = QUrl(QLatin1String("http://") + string, QUrl::TolerantMode); +        url = KUrl(qurl); +    } +    return url; +} + + +void MainWindow::loadUrl(const KUrl &url) +{ +    m_view->loadUrl(url); +} + + +void MainWindow::slotOpenLocation() +{ +    m_view->currentUrlBar()->selectAll(); +    m_view->currentUrlBar()->setFocus(); +} + + +void MainWindow::slotFileSaveAs() +{ +    KUrl srcUrl = currentTab()->url(); +    Application::downloadManager()->newDownload(srcUrl); +} + + +void MainWindow::slotPreferences() +{ +    // an instance the dialog could be already created and could be cached, +    // in which case you want to display the cached dialog +    if (SettingsDialog::showDialog("rekonfig")) +        return; + +    // we didn't find an instance of this dialog, so lets create it +    SettingsDialog *s = new SettingsDialog(this); + +    // keep us informed when the user changes settings +    connect(s, SIGNAL(settingsChanged(const QString&)), this, SLOT(slotUpdateBrowser())); + +    s->exec(); +} + + +void MainWindow::slotUpdateStatusbar(const QString &string) +{ +    statusBar()->showMessage(string, 2000); +} + + +void MainWindow::slotUpdateActions() +{ +    m_historyBackAction->setEnabled(currentTab()->history()->canGoBack()); +    m_historyForwardAction->setEnabled(currentTab()->history()->canGoForward()); +} + + +void MainWindow::slotUpdateWindowTitle(const QString &title) +{ +    if (title.isEmpty()) +    { +        setWindowTitle("rekonq"); +    } +    else +    { +        setWindowTitle(title + " - rekonq"); +    } +} + + +void MainWindow::slotFileOpen() +{ +    QString filePath = KFileDialog::getOpenFileName(KUrl(), +                       i18n("Web Resources (*.html *.htm *.svg *.png *.gif *.svgz); All files (*.*)"), +                       this, +                       i18n("Open Web Resource") +                                                   ); + +    if (filePath.isEmpty()) +        return; + +    loadUrl(guessUrlFromString(filePath)); +} + + +void MainWindow::slotFilePrintPreview() +{ +    if (!currentTab()) +        return; + +    QPrinter printer; +    KPrintPreview previewdlg(&printer, this); +    currentTab()->print(&printer); +    previewdlg.exec(); +} + + +void MainWindow::slotFilePrint() +{ +    if (!currentTab()) +        return; +    printRequested(currentTab()->page()->mainFrame()); +} + + +void MainWindow::printRequested(QWebFrame *frame) +{ +    QPrinter printer; + +    QPrintDialog *dialog = KdePrint::createPrintDialog(&printer, this); +    if (dialog->exec() != QDialog::Accepted) +        return; +    frame->print(&printer); +} + + +void MainWindow::slotPrivateBrowsing(bool enable) +{ +    QWebSettings *settings = QWebSettings::globalSettings(); +    if (enable) +    { +        QString title = i18n("Are you sure you want to turn on private browsing?"); +        QString text = "<b>" + title + i18n("</b><br><br>When private browsing in turned on," +                                            " webpages are not added to the history," +                                            " new cookies are not stored, current cookies cannot be accessed," \ +                                            " site icons will not be stored, session will not be saved, " \ +                                            " and searches are not addded to the pop-up menu in the Google search box." \ +                                            "  Until you close the window, you can still click the Back and Forward buttons" \ +                                            " to return to the webpages you have opened."); + +        int  button = KMessageBox::questionYesNo(this, text, title); +        if (button == KMessageBox::Ok) +        { +            settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, true); +        } +        else +        { +            actionCollection()->action("private_browsing")->setChecked(false); +        } +    } +    else +    { +        settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false); + +        MainWindow* win = Application::instance()->mainWindow(); +        win->m_lastSearch = QString::null; +        win->mainView()->clear(); +    } +} + +void MainWindow::slotFind(const QString & search) +{ +    if (!currentTab()) +        return; +    m_lastSearch = search; +    slotFindNext(); +} + + +void MainWindow::slotViewFindBar() +{ +    m_findBar->showFindBar(); +} + + +void MainWindow::slotFindNext() +{ +    if (!currentTab() && m_lastSearch.isEmpty()) +        return; + +    QWebPage::FindFlags options; +    if (m_findBar->matchCase()) +    { +        options = QWebPage::FindCaseSensitively | QWebPage::FindWrapsAroundDocument; +    } +    else +    { +        options = QWebPage::FindWrapsAroundDocument; +    } + +    if (!currentTab()->findText(m_lastSearch, options)) +    { +        slotUpdateStatusbar(QString(m_lastSearch) + i18n(" not found.")); +    } +} + + +void MainWindow::slotFindPrevious() +{ +    if (!currentTab() && m_lastSearch.isEmpty()) +        return; + +    QWebPage::FindFlags options; +    if (m_findBar->matchCase()) +    { +        options = QWebPage::FindCaseSensitively | QWebPage::FindBackward | QWebPage::FindWrapsAroundDocument; +    } +    else +    { +        options = QWebPage::FindBackward | QWebPage::FindWrapsAroundDocument; +    } + +    if (!currentTab()->findText(m_lastSearch, options)) +    { +        slotUpdateStatusbar(QString(m_lastSearch) + i18n(" not found.")); +    } +} + + +void MainWindow::slotViewTextBigger() +{ +    if (!currentTab()) +        return; +    currentTab()->setTextSizeMultiplier(currentTab()->textSizeMultiplier() + 0.1); +} + + +void MainWindow::slotViewTextNormal() +{ +    if (!currentTab()) +        return; +    currentTab()->setTextSizeMultiplier(1.0); +} + + +void MainWindow::slotViewTextSmaller() +{ +    if (!currentTab()) +        return; +    currentTab()->setTextSizeMultiplier(currentTab()->textSizeMultiplier() - 0.1); +} + + +void MainWindow::slotViewFullScreen(bool makeFullScreen) +{ +    // state flags +    static bool menubarFlag; +    static bool mainToolBarFlag; +    static bool bookmarksToolBarFlag; +    static bool statusBarFlag; +    static bool sidePanelFlag; + +    if (makeFullScreen == true) +    { +        // save current state +        menubarFlag = menuBar()->isHidden(); +        mainToolBarFlag = toolBar("mainToolBar")->isHidden(); +        bookmarksToolBarFlag = toolBar("bookmarksToolBar")->isHidden(); +        statusBarFlag = statusBar()->isHidden(); +        sidePanelFlag = sidePanel()->isHidden(); + +        menuBar()->hide(); +        toolBar("mainToolBar")->hide(); +        toolBar("bookmarksToolBar")->hide(); +        statusBar()->hide(); +        sidePanel()->hide(); +    } +    else +    { +        if (!menubarFlag) +            menuBar()->show(); +        if (!mainToolBarFlag) +            toolBar("mainToolBar")->show(); +        if (!bookmarksToolBarFlag) +            toolBar("bookmarksToolBar")->show(); +        if (!statusBarFlag) +            statusBar()->show(); +        if (!sidePanelFlag) +            sidePanel()->show(); +    } + +    KToggleFullScreenAction::setFullScreen(this, makeFullScreen); +} + + +void MainWindow::slotViewPageSource() +{ +    if (!currentTab()) +        return; + +    KUrl url(currentTab()->url()); +    bool isTempFile = false; +    if (!url.isLocalFile()) +    { +        KTemporaryFile sourceFile; + +        /// TODO: autochoose tempfile suffix +        sourceFile.setSuffix(QString(".html")); +        sourceFile.setAutoRemove(false); + +        if (sourceFile.open()) +        { +            QDataStream stream(&sourceFile); +            stream << currentTab()->page()->mainFrame()->toHtml().toUtf8(); + +            url = KUrl(); +            url.setPath(sourceFile.fileName()); +            isTempFile = true; +        } +    } +    KRun::runUrl(url, QLatin1String("text/plain"), this, isTempFile); +} + + +void MainWindow::slotHome() +{ +    loadUrl(KUrl(m_homePage)); +} + + +void MainWindow::slotToggleInspector(bool enable) +{ +    QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, enable); +    if (enable) +    { +        int result = KMessageBox::questionYesNo(this, +                                                i18n("The web inspector will only work correctly for pages that were loaded after enabling.\n" +                                                     "Do you want to reload all pages?"), +                                                i18n("Web Inspector") +                                               ); + +        if (result == KMessageBox::Yes) +        { +            m_view->slotReloadAllTabs(); +        } +    } +} + + +MainView *MainWindow::mainView() const +{ +    return m_view; +} + + + +WebView *MainWindow::currentTab() const +{ +    return m_view->currentWebView(); +} + + +void MainWindow::slotLoadProgress(int progress) +{ +    QAction *stop = actionCollection()->action("stop"); +    QAction *reload = actionCollection()->action("view_redisplay"); +    if (progress < 100 && progress > 0) +    { +        disconnect(m_stopReloadAction, SIGNAL(triggered(bool)), reload , SIGNAL(triggered(bool))); +        m_stopReloadAction->setIcon(KIcon("process-stop")); +        m_stopReloadAction->setToolTip(i18n("Stop loading the current page")); +        m_stopReloadAction->setText(i18n("Stop")); +        connect(m_stopReloadAction, SIGNAL(triggered(bool)), stop, SIGNAL(triggered(bool))); +    } +    else +    { +        disconnect(m_stopReloadAction, SIGNAL(triggered(bool)), stop , SIGNAL(triggered(bool))); +        m_stopReloadAction->setIcon(KIcon("view-refresh")); +        m_stopReloadAction->setToolTip(i18n("Reload the current page")); +        m_stopReloadAction->setText(i18n("Reload")); +        connect(m_stopReloadAction, SIGNAL(triggered(bool)), reload, SIGNAL(triggered(bool))); + +    } +} + + +void MainWindow::slotAboutToShowBackMenu() +{ +    m_historyBackMenu->clear(); +    if (!currentTab()) +        return; +    QWebHistory *history = currentTab()->history(); +    int historyCount = history->count(); +    for (int i = history->backItems(historyCount).count() - 1; i >= 0; --i) +    { +        QWebHistoryItem item = history->backItems(history->count()).at(i); +        KAction *action = new KAction(this); +        action->setData(-1*(historyCount - i - 1)); +        QIcon icon = Application::instance()->icon(item.url()); +        action->setIcon(icon); +        action->setText(item.title()); +        m_historyBackMenu->addAction(action); +    } +} + + +void MainWindow::slotOpenActionUrl(QAction *action) +{ +    int offset = action->data().toInt(); +    QWebHistory *history = currentTab()->history(); +    if (offset < 0) +    { +        history->goToItem(history->backItems(-1*offset).first()); // back +    } +    else +    { +        if (offset > 0) +        { +            history->goToItem(history->forwardItems(history->count() - offset + 1).back()); // forward +        } +    } +} + + +void MainWindow::slotOpenPrevious() +{ +    QWebHistory *history = currentTab()->history(); +    if (history->canGoBack()) +        history->goToItem(history->backItem()); +} + + +void MainWindow::slotOpenNext() +{ +    QWebHistory *history = currentTab()->history(); +    if (history->canGoForward()) +        history->goToItem(history->forwardItem()); +} + + +void MainWindow::geometryChangeRequested(const QRect &geometry) +{ +    setGeometry(geometry); +} + + +void MainWindow::slotShowMenubar(bool enable) +{ +    if (enable) +        menuBar()->show(); +    else +        menuBar()->hide(); +} + + +bool MainWindow::queryClose() +{ +    if (m_view->count() > 1) +    { + +        int answer = KMessageBox::questionYesNoCancel( +                         this, +                         i18np("Are you sure you want to close the window?\n" "You have 1 tab open","Are you sure you want to close the window?\n" "You have %1 tabs open" , m_view->count()), +                         i18n("Are you sure you want to close the window?"), +                         KStandardGuiItem::quit(), +                         KGuiItem(i18n("C&lose Current Tab"), KIcon("tab-close")), +                         KStandardGuiItem::cancel(), +                         "confirmClosingMultipleTabs" +                     ); + +        switch (answer) +        { +        case KMessageBox::Yes: +            // Quit +            return true; +            break; +        case KMessageBox::No: +            // Close only the current tab +            m_view->slotCloseTab(); +        default: +            return false; +        } +    } + +    return true; +} + + +QAction *MainWindow::actionByName(const QString name) +{ +    QAction *ret = actionCollection()->action(name); + +    if (ret) +        return ret; + +    /* else */ +    kWarning() << "Action named: " << name << " not found, returning empty action."; + +    return new QAction(this);  // return empty object instead of NULL pointer +} + diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 00000000..cdb7151d --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,153 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +// Local Includes +#include "searchbar.h" +#include "bookmarks.h" +#include "mainview.h" +#include "webview.h" + +// KDE Includes +#include <KXmlGuiWindow> +#include <KToolBar> + +// Forward Declarations +class QWebFrame; + +class KUrl; +class KAction; +class KActionMenu; +class KIcon; +class KMenu; + +class FindBar; +class HistoryMenu; +class SidePanel; +class WebView; + + +/** + * This class serves as the main window for rekonq. + * It handles the menus, toolbars, and status bars. + * + */ +class MainWindow : public KXmlGuiWindow +{ +    Q_OBJECT + +public: +    MainWindow(); +    ~MainWindow(); + +    static KUrl guessUrlFromString(const QString &url); +    MainView *mainView() const; +    WebView *currentTab() const; +    QAction *actionByName(const QString name); +    virtual QSize sizeHint() const; + +private: +    void setupActions(); +    void setupHistoryMenu(); +    void setupToolBars(); +    void setupSidePanel(); +    SidePanel *sidePanel() +    { +        return m_sidePanel; +    } + +public slots: +    void slotHome(); +    void loadUrl(const KUrl &url); +    void slotUpdateBrowser(); + +protected: +    bool queryClose(); + +private slots: +    void postLaunch(); +    void slotUpdateConfiguration(); +    void slotLoadProgress(int); +    void slotUpdateStatusbar(const QString &string); +    void slotUpdateActions(); +    void slotUpdateWindowTitle(const QString &title = QString()); +    void slotOpenLocation(); +    void slotAboutToShowBackMenu(); +    void geometryChangeRequested(const QRect &geometry); + +    // history related +    void slotOpenActionUrl(QAction *action); +    void slotOpenPrevious(); +    void slotOpenNext(); + +    // File Menu slots +    void slotFileOpen(); +    void slotFilePrintPreview(); +    void slotFilePrint(); +    void slotPrivateBrowsing(bool); +    void slotFileSaveAs(); +    void printRequested(QWebFrame *frame); + +    // Edit Menu slots +    void slotFind(const QString &); +    void slotFindNext(); +    void slotFindPrevious(); + +    // View Menu slots +    void slotViewTextBigger(); +    void slotViewTextNormal(); +    void slotViewTextSmaller(); +    void slotViewPageSource(); +    void slotViewFullScreen(bool enable); +    void slotViewFindBar(); + +    // Tools Menu slots +    void slotToggleInspector(bool enable); + +    // Settings Menu slots +    void slotShowMenubar(bool enable); +    void slotPreferences(); + +private: +    MainView *m_view; +    FindBar *m_findBar; +    SearchBar *m_searchBar; +    SidePanel *m_sidePanel; + +    KMenu *m_historyBackMenu; +    KMenu *m_windowMenu; +    KActionMenu *m_historyActionMenu; + +    KAction *m_stopReloadAction; +    KAction *m_stopAction; +    KAction *m_reloadAction; +    KAction *m_historyBackAction; +    KAction *m_historyForwardAction; + +    QString m_lastSearch; +    QString m_homePage; +}; + +#endif // MAINWINDOW_H diff --git a/src/modelmenu.cpp b/src/modelmenu.cpp new file mode 100644 index 00000000..cc43a3f3 --- /dev/null +++ b/src/modelmenu.cpp @@ -0,0 +1,228 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#include "modelmenu.h" + + +ModelMenu::ModelMenu(QWidget * parent) +        : KMenu(parent) +        , m_maxRows(7) +        , m_firstSeparator(-1) +        , m_maxWidth(-1) +        , m_hoverRole(0) +        , m_separatorRole(0) +        , m_model(0) +{ +    connect(this, SIGNAL(aboutToShow()), this, SLOT(aboutToShow())); +} + + +bool ModelMenu::prePopulated() +{ +    return false; +} + + +void ModelMenu::postPopulated() +{ +} + + +void ModelMenu::setModel(QAbstractItemModel *model) +{ +    m_model = model; +} + + +QAbstractItemModel *ModelMenu::model() const +{ +    return m_model; +} + + +void ModelMenu::setMaxRows(int max) +{ +    m_maxRows = max; +} + + +int ModelMenu::maxRows() const +{ +    return m_maxRows; +} + + +void ModelMenu::setFirstSeparator(int offset) +{ +    m_firstSeparator = offset; +} + + +int ModelMenu::firstSeparator() const +{ +    return m_firstSeparator; +} + + +void ModelMenu::setRootIndex(const QModelIndex &index) +{ +    m_root = index; +} + + +QModelIndex ModelMenu::rootIndex() const +{ +    return m_root; +} + + +void ModelMenu::setHoverRole(int role) +{ +    m_hoverRole = role; +} + + +int ModelMenu::hoverRole() const +{ +    return m_hoverRole; +} + + +void ModelMenu::setSeparatorRole(int role) +{ +    m_separatorRole = role; +} + + +int ModelMenu::separatorRole() const +{ +    return m_separatorRole; +} + + +Q_DECLARE_METATYPE(QModelIndex) +void ModelMenu::aboutToShow() +{ +    if (QMenu *menu = qobject_cast<QMenu*>(sender())) +    { +        QVariant v = menu->menuAction()->data(); +        if (v.canConvert<QModelIndex>()) +        { +            QModelIndex idx = qvariant_cast<QModelIndex>(v); +            createMenu(idx, -1, menu, menu); +            disconnect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShow())); +            return; +        } +    } + +    clear(); +    if (prePopulated()) +        addSeparator(); +    int max = m_maxRows; +    if (max != -1) +        max += m_firstSeparator; +    createMenu(m_root, max, this, this); +    postPopulated(); +} + +void ModelMenu::createMenu(const QModelIndex &parent, int max, QMenu *parentMenu, QMenu *menu) +{ +    if (!menu) +    { +        QString title = parent.data().toString(); +        menu = new QMenu(title, this); +        QIcon icon = qvariant_cast<QIcon>(parent.data(Qt::DecorationRole)); +        menu->setIcon(icon); +        parentMenu->addMenu(menu); +        QVariant v; +        v.setValue(parent); +        menu->menuAction()->setData(v); +        connect(menu, SIGNAL(aboutToShow()), this, SLOT(aboutToShow())); +        return; +    } + +    int end = m_model->rowCount(parent); +    if (max != -1) +        end = qMin(max, end); + +    connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(triggered(QAction*))); +    connect(menu, SIGNAL(hovered(QAction*)), this, SLOT(hovered(QAction*))); + +    for (int i = 0; i < end; ++i) +    { +        QModelIndex idx = m_model->index(i, 0, parent); +        if (m_model->hasChildren(idx)) +        { +            createMenu(idx, -1, menu); +        } +        else +        { +            if (m_separatorRole != 0 +                    && idx.data(m_separatorRole).toBool()) +                addSeparator(); +            else +                menu->addAction(makeAction(idx)); +        } +        if (menu == this && i == m_firstSeparator - 1) +            addSeparator(); +    } +} + +KAction *ModelMenu::makeAction(const QModelIndex &index) +{ +    QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole)); +    KAction *action = (KAction *) makeAction(KIcon(icon), index.data().toString(), this); +    QVariant v; +    v.setValue(index); +    action->setData(v); +    return action; +} + +KAction *ModelMenu::makeAction(const KIcon &icon, const QString &text, QObject *parent) +{ +    QFontMetrics fm(font()); +    if (-1 == m_maxWidth) +        m_maxWidth = fm.width(QLatin1Char('m')) * 30; +    QString smallText = fm.elidedText(text, Qt::ElideMiddle, m_maxWidth); +    return new KAction(icon, smallText, parent); +} + +void ModelMenu::triggered(QAction *action) +{ +    QVariant v = action->data(); +    if (v.canConvert<QModelIndex>()) +    { +        QModelIndex idx = qvariant_cast<QModelIndex>(v); +        emit activated(idx); +    } +} + +void ModelMenu::hovered(QAction *action) +{ +    QVariant v = action->data(); +    if (v.canConvert<QModelIndex>()) +    { +        QModelIndex idx = qvariant_cast<QModelIndex>(v); +        QString hoveredString = idx.data(m_hoverRole).toString(); +        if (!hoveredString.isEmpty()) +            emit hovered(hoveredString); +    } +} diff --git a/src/modelmenu.h b/src/modelmenu.h new file mode 100644 index 00000000..3cc657b3 --- /dev/null +++ b/src/modelmenu.h @@ -0,0 +1,92 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#ifndef MODELMENU_H +#define MODELMENU_H + +// Qt Includes +#include <QtGui> +#include <QtCore> + +// KDE Includes +#include <KIcon> +#include <KAction> +#include <KMenu> + +// A QMenu that is dynamically populated from a QAbstractItemModel +class ModelMenu : public KMenu +{ +    Q_OBJECT + +signals: +    void activated(const QModelIndex &index); +    void hovered(const QString &text); + +public: +    ModelMenu(QWidget *parent = 0); + +    void setModel(QAbstractItemModel *model); +    QAbstractItemModel *model() const; + +    void setMaxRows(int max); +    int maxRows() const; + +    void setFirstSeparator(int offset); +    int firstSeparator() const; + +    void setRootIndex(const QModelIndex &index); +    QModelIndex rootIndex() const; + +    void setHoverRole(int role); +    int hoverRole() const; + +    void setSeparatorRole(int role); +    int separatorRole() const; + +    KAction *makeAction(const KIcon &icon, const QString &text, QObject *parent); + +protected: +    // add any actions before the tree, return true if any actions are added. +    virtual bool prePopulated(); +    // add any actions after the tree +    virtual void postPopulated(); +    // put all of the children of parent into menu up to max +    void createMenu(const QModelIndex &parent, int max, QMenu *parentMenu = 0, QMenu *menu = 0); + +private slots: +    void aboutToShow(); +    void triggered(QAction *action); +    void hovered(QAction *action); + +private: +    KAction *makeAction(const QModelIndex &index); +    int m_maxRows; +    int m_firstSeparator; +    int m_maxWidth; +    int m_hoverRole; +    int m_separatorRole; +    QAbstractItemModel *m_model; +    QPersistentModelIndex m_root; +}; + +#endif // MODELMENU_H + diff --git a/src/networkaccessmanager.cpp b/src/networkaccessmanager.cpp new file mode 100644 index 00000000..d92edbd6 --- /dev/null +++ b/src/networkaccessmanager.cpp @@ -0,0 +1,165 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// Self Includes +#include "networkaccessmanager.h" +#include "networkaccessmanager.moc" + +// Local Includes +#include "application.h" +#include "mainwindow.h" + +// Auto Includes +#include "rekonq.h" + +// Ui Includes +#include "ui_password.h" +#include "ui_proxy.h" + +// KDE Includes +#include <KMessageBox> +#include <KStandardDirs> + +// Qt Includes +#include <QDialog> +#include <QStyle> +#include <QTextDocument> +#include <QAuthenticator> +#include <QNetworkProxy> +#include <QNetworkReply> +#include <QSslError> + + +NetworkAccessManager::NetworkAccessManager(QObject *parent) +        : QNetworkAccessManager(parent) +{ +    connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), +            SLOT(authenticationRequired(QNetworkReply*, QAuthenticator*))); +    connect(this, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)), +            SLOT(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*))); + +#ifndef QT_NO_OPENSSL +    connect(this, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), +            SLOT(sslErrors(QNetworkReply*, const QList<QSslError>&))); +#endif + +    loadSettings(); + +    QNetworkDiskCache *diskCache = new QNetworkDiskCache(this); +    QString location = KStandardDirs::locateLocal("cache", "", true); +    diskCache->setCacheDirectory(location); +    setCache(diskCache); +} + + +void NetworkAccessManager::loadSettings() +{ +    QNetworkProxy proxy; +    if (ReKonfig::isProxyEnabled()) +    { +        if (ReKonfig::proxyType() == 0) +        { +            proxy.setType(QNetworkProxy::Socks5Proxy); +        } +        else +        { +            proxy.setType(QNetworkProxy::HttpProxy); +        } +        proxy.setHostName(ReKonfig::proxyHostName()); +        proxy.setPort(ReKonfig::proxyPort()); +        proxy.setUser(ReKonfig::proxyUserName()); +        proxy.setPassword(ReKonfig::proxyPassword()); +    } +    setProxy(proxy); +} + + + +void NetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *auth) +{ +    MainWindow *mainWindow = Application::instance()->mainWindow(); + +    KDialog dialog(mainWindow, Qt::Sheet); +    dialog.setButtons(KDialog::Ok | KDialog::Cancel); + +    Ui::passwordWidget passwordWidget; +    QWidget widget; +    passwordWidget.setupUi(&widget); + +    dialog.setMainWidget(&widget); + +    passwordWidget.iconLabel->setText(QString()); +    passwordWidget.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32)); + +    QString introMessage = i18n("<qt>Enter username and password for ") + +                           Qt::escape(reply->url().toString()) + i18n(" at ") + Qt::escape(reply->url().toString()) + "</qt>"; +    passwordWidget.introLabel->setText(introMessage); +    passwordWidget.introLabel->setWordWrap(true); + +    if (dialog.exec() == QDialog::Accepted) +    { +        auth->setUser(passwordWidget.userNameLineEdit->text()); +        auth->setPassword(passwordWidget.passwordLineEdit->text()); +    } +} + +void NetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth) +{ +    MainWindow *mainWindow = Application::instance()->mainWindow(); + +    KDialog dialog(mainWindow, Qt::Sheet); +    dialog.setButtons(KDialog::Ok | KDialog::Cancel); + +    Ui::proxyWidget proxyWdg; +    QWidget widget; +    proxyWdg.setupUi(&widget); + +    dialog.setMainWidget(&widget); + +    proxyWdg.iconLabel->setText(QString()); +    proxyWdg.iconLabel->setPixmap(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow).pixmap(32, 32)); + +    QString introMessage = i18n("<qt>Connect to proxy ") + Qt::escape(proxy.hostName()) + i18n(" using:</qt>"); +    proxyWdg.introLabel->setText(introMessage); +    proxyWdg.introLabel->setWordWrap(true); + +    if (dialog.exec() == QDialog::Accepted) +    { +        auth->setUser(proxyWdg.userNameLineEdit->text()); +        auth->setPassword(proxyWdg.passwordLineEdit->text()); +    } +} + +#ifndef QT_NO_OPENSSL +void NetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &error) +{ +    MainWindow *mainWindow = Application::instance()->mainWindow(); + +    QStringList errorStrings; +    for (int i = 0; i < error.count(); ++i) +        errorStrings += error.at(i).errorString(); +    QString errors = errorStrings.join(QLatin1String("\n")); +    int ret = KMessageBox::warningYesNo(mainWindow, i18n("SSL Errors:\n\n") + reply->url().toString() + "\n\n" + QString(errors) + "\n\n"); +    if (ret == KMessageBox::Yes) +        reply->ignoreSslErrors(); +} +#endif + diff --git a/src/networkaccessmanager.h b/src/networkaccessmanager.h new file mode 100644 index 00000000..ebcd952d --- /dev/null +++ b/src/networkaccessmanager.h @@ -0,0 +1,47 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef NETWORKACCESSMANAGER_H +#define NETWORKACCESSMANAGER_H + + +#include <QNetworkAccessManager> + + +class NetworkAccessManager : public QNetworkAccessManager +{ +    Q_OBJECT + +public: +    NetworkAccessManager(QObject *parent = 0); + +public slots: +    void loadSettings(); + +private slots: +    void authenticationRequired(QNetworkReply *reply, QAuthenticator *auth); +    void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); +#ifndef QT_NO_OPENSSL +    void sslErrors(QNetworkReply *reply, const QList<QSslError> &error); +#endif +}; + +#endif // NETWORKACCESSMANAGER_H diff --git a/src/panelhistory.cpp b/src/panelhistory.cpp new file mode 100644 index 00000000..72507663 --- /dev/null +++ b/src/panelhistory.cpp @@ -0,0 +1,95 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// Self Includes +#include "panelhistory.h" +#include "panelhistory.moc" + +// QT Includes +#include <QLabel> + +// KDE Includes +#include <KLocalizedString> +#include <KLineEdit> +#include <KUrl> + +// Local Includes +#include "history.h" + + +PanelHistory::PanelHistory(QWidget *parent) +        : QWidget(parent) +        , m_historyTreeView(new QTreeView) +        , m_treeProxyModel(new TreeProxyModel(this)) +{ +    m_historyTreeView->setUniformRowHeights(true); +    m_historyTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); +    m_historyTreeView->setTextElideMode(Qt::ElideMiddle); +    m_historyTreeView->setAlternatingRowColors(true); + +    // add search bar +    QHBoxLayout *hBoxLayout = new QHBoxLayout; +    hBoxLayout->setContentsMargins(5, 0, 0, 0); +    QLabel *searchLabel = new QLabel(i18n("Search: ")); +    hBoxLayout->addWidget(searchLabel); +    KLineEdit *search = new KLineEdit; +    hBoxLayout->addWidget(search); +    QWidget *searchBar = new QWidget; +    searchBar->setLayout(hBoxLayout); + +    // setup view +    QVBoxLayout *vBoxLayout = new QVBoxLayout; +    vBoxLayout->setContentsMargins(0, 0, 0, 0); +    vBoxLayout->addWidget(searchBar); +    vBoxLayout->addWidget(m_historyTreeView); +    setLayout(vBoxLayout); + +    //- +    HistoryManager *historyManager = Application::historyManager(); +    QAbstractItemModel *model = historyManager->historyTreeModel(); + +    m_treeProxyModel->setSourceModel(model); +    m_historyTreeView->setModel(m_treeProxyModel); +    m_historyTreeView->setExpanded(m_treeProxyModel->index(0, 0), true); +    m_historyTreeView->header()->hideSection(1); +    QFontMetrics fm(font()); +    int header = fm.width(QLatin1Char('m')) * 40; +    m_historyTreeView->header()->resizeSection(0, header); + +    connect(search, SIGNAL(textChanged(QString)), m_treeProxyModel, SLOT(setFilterFixedString(QString))); +    connect(m_historyTreeView, SIGNAL(activated(const QModelIndex&)), this, SLOT(open())); +} + + +PanelHistory::~PanelHistory() +{ +    delete m_treeProxyModel; +    delete m_historyTreeView; +} + + +void PanelHistory::open() +{ +    QModelIndex index = m_historyTreeView->currentIndex(); +    if (!index.parent().isValid()) +        return; +    emit openUrl(index.data(HistoryModel::UrlRole).toUrl()); +} + diff --git a/src/panelhistory.h b/src/panelhistory.h new file mode 100644 index 00000000..89759a84 --- /dev/null +++ b/src/panelhistory.h @@ -0,0 +1,55 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + +#ifndef PANELHISTORY_H +#define PANELHISTORY_H + +// Qt Includes +#include <QWidget> + +// Local Includes +#include "application.h" + +class QTreeView; +class KUrl; +class TreeProxyModel; + + +class PanelHistory : public QWidget +{ +    Q_OBJECT +    Q_DISABLE_COPY(PanelHistory) + +public: +    explicit PanelHistory(QWidget *parent = 0); +    virtual ~PanelHistory(); + +signals: +    void openUrl(const KUrl &); + +private slots: +    void open(); + +private: +    QTreeView *m_historyTreeView; +    TreeProxyModel *m_treeProxyModel; + +}; + +#endif // PANELHISTORY_H diff --git a/src/password.ui b/src/password.ui new file mode 100644 index 00000000..028e1683 --- /dev/null +++ b/src/password.ui @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>passwordWidget</class> + <widget class="QWidget" name="passwordWidget"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>343</width> +    <height>193</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>Form</string> +  </property> +  <layout class="QGridLayout" name="gridLayout"> +   <item row="0" column="0" colspan="2"> +    <layout class="QHBoxLayout"> +     <item> +      <widget class="QLabel" name="iconLabel"> +       <property name="text"> +        <string>DUMMY ICON</string> +       </property> +      </widget> +     </item> +     <item> +      <widget class="QLabel" name="introLabel"> +       <property name="sizePolicy"> +        <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> +         <horstretch>0</horstretch> +         <verstretch>0</verstretch> +        </sizepolicy> +       </property> +       <property name="text"> +        <string>INTRO TEXT DUMMY</string> +       </property> +      </widget> +     </item> +    </layout> +   </item> +   <item row="1" column="0"> +    <widget class="QLabel" name="label"> +     <property name="text"> +      <string>Username:</string> +     </property> +    </widget> +   </item> +   <item row="1" column="1"> +    <widget class="QLineEdit" name="userNameLineEdit"/> +   </item> +   <item row="2" column="0"> +    <widget class="QLabel" name="lblPassword"> +     <property name="text"> +      <string>Password:</string> +     </property> +    </widget> +   </item> +   <item row="2" column="1"> +    <widget class="QLineEdit" name="passwordLineEdit"> +     <property name="echoMode"> +      <enum>QLineEdit::Password</enum> +     </property> +    </widget> +   </item> +  </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/proxy.ui b/src/proxy.ui new file mode 100644 index 00000000..e7440862 --- /dev/null +++ b/src/proxy.ui @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>proxyWidget</class> + <widget class="QWidget" name="proxyWidget"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>264</width> +    <height>153</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>Form</string> +  </property> +  <layout class="QGridLayout" name="gridLayout"> +   <item row="0" column="0"> +    <widget class="QLabel" name="iconLabel"> +     <property name="text"> +      <string>ICON</string> +     </property> +    </widget> +   </item> +   <item row="0" column="1" colspan="2"> +    <widget class="QLabel" name="introLabel"> +     <property name="text"> +      <string>Connect to proxy</string> +     </property> +     <property name="wordWrap"> +      <bool>true</bool> +     </property> +    </widget> +   </item> +   <item row="1" column="0" colspan="2"> +    <widget class="QLabel" name="usernameLabel"> +     <property name="text"> +      <string>Username:</string> +     </property> +    </widget> +   </item> +   <item row="1" column="2"> +    <widget class="QLineEdit" name="userNameLineEdit"/> +   </item> +   <item row="2" column="0" colspan="2"> +    <widget class="QLabel" name="passwordLabel"> +     <property name="text"> +      <string>Password:</string> +     </property> +    </widget> +   </item> +   <item row="2" column="2"> +    <widget class="QLineEdit" name="passwordLineEdit"> +     <property name="echoMode"> +      <enum>QLineEdit::Password</enum> +     </property> +    </widget> +   </item> +  </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/rekonq.kcfg b/src/rekonq.kcfg new file mode 100644 index 00000000..499258d2 --- /dev/null +++ b/src/rekonq.kcfg @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" +      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +      xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 +      http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" > +  <kcfgfile name="rekonqrc"/> + +<!-- Includes --> +<include>QtWebKit</include> +<include>KUrl</include> + +<!-- General Settings --> +  <group name="General"> +    <entry name="homePage" type="String"> +        <default>http://www.kde.org/</default> +    </entry> +    <entry name="downloadDir" type="Path"> +        <default>$HOME</default> +    </entry> +    <entry name="downloadToDefaultDir" type="Bool"> +        <default>false</default> +    </entry> +    <entry name="alwaysShowTabBar" type="Bool"> +        <default>true</default> +    </entry> +    <entry name="showSideBar" type="Bool"> +        <default>false</default> +    </entry> +    <entry name="openTabsBack" type="Bool"> +        <default>false</default> +    </entry> +  </group> + +<!-- Fonts Settings --> +  <group name="Fonts"> +    <entry name="standardFont" type="Font"> +    <default code="true">QFont(QWebSettings::globalSettings()->fontFamily(QWebSettings::StandardFont))</default> +    </entry> +    <entry name="fixedFont" type="Font"> +    <default code="true">QFont(QWebSettings::globalSettings()->fontFamily(QWebSettings::FixedFont))</default> +    </entry> +    <entry name="fontSize" type="Int"> +    <default>12</default> +    </entry> +  </group> + +<!-- Privacy Settings --> +    <group name="Privacy"> +        <entry name="expireHistory" type="Int"> +            <default>1</default> +        </entry>     +        <entry name="acceptCookies" type="Int"> +            <default>2</default> +        </entry> +        <entry name="keepCookiesUntil" type="Int"> +            <default>0</default> +        </entry> +    </group> + +<!-- Proxy Settings --> +  <group name="Proxy"> +    <entry name="isProxyEnabled" type="Bool"> +        <default>false</default> +    </entry> +    <entry name="proxyType" type="Int"> +        <default>0</default> +    </entry> +    <entry name="proxyHostName" type="String"> +    </entry> +    <entry name="proxyPort" type="Int"> +        <default>8080</default> +    </entry> +    <entry name="proxyUserName" type="String"> +    </entry> +    <entry name="proxyPassword" type="Password"> +    </entry> +  </group> + +<!-- WebKit Settings --> +    <group name="Webkit"> +        <entry name="autoLoadImages" type="Bool"> +            <default>true</default> +        </entry> +        <entry name="javascriptEnabled" type="Bool"> +            <default>true</default> +        </entry> +        <entry name="javaEnabled" type="Bool"> +            <default>true</default> +        </entry> +        <entry name="pluginsEnabled" type="Bool"> +            <default>true</default> +        </entry> +        <entry name="javascriptCanOpenWindows" type="Bool"> +            <default>true</default> +        </entry> +        <entry name="javascriptCanAccessClipboard" type="Bool"> +            <default>false</default> +        </entry> +        <entry name="linksIncludedInFocusChain" type="Bool"> +            <default>true</default> +        </entry> +        <entry name="zoomTextOnly" type="Bool"> +            <default>false</default> +        </entry> +        <entry name="printElementBackgrounds" type="Bool"> +            <default>true</default> +        </entry> +        <entry name="offlineStorageDatabaseEnabled" type="Bool"> +            <default>true</default> +        </entry> +        <entry name="offlineWebApplicationCacheEnabled" type="Bool"> +            <default>true</default> +        </entry> +        <entry name="localStorageDatabaseEnabled" type="Bool"> +            <default>true</default> +        </entry> +    </group> + +</kcfg> diff --git a/src/rekonq.kcfgc b/src/rekonq.kcfgc new file mode 100644 index 00000000..50a9817d --- /dev/null +++ b/src/rekonq.kcfgc @@ -0,0 +1,5 @@ +File=rekonq.kcfg +ClassName=ReKonfig +Singleton=true +Mutators=true +UseEnumTypes=true diff --git a/src/rekonqui.rc b/src/rekonqui.rc new file mode 100644 index 00000000..aa372538 --- /dev/null +++ b/src/rekonqui.rc @@ -0,0 +1,104 @@ +<?xml version="1.0"?> +<!DOCTYPE gui SYSTEM "kpartgui.dtd"> +<gui name="rekonq" version="40"> + +<MenuBar> + +<!--  ============ FILE menu =========== --> +<Menu name="file" noMerge="1"><text>&File</text> +    <Action name="file_open" /> +    <Action name="open_location" /> +    <Separator/> +    <Action name="new_tab" /> +    <Action name="close_tab" /> +    <Separator/> +    <Action name="file_save_as" /> +    <Separator/> +    <Action name="file_print_preview" /> +    <Action name="file_print" /> +    <Separator/> +    <Action name="file_quit" /> +</Menu> + +<!--  ============ EDIT menu =========== --> +<Menu name="edit" noMerge="1"><text>&Edit</text> +    <Action name="edit_undo" /> +    <Action name="edit_redo" /> +    <Separator/> +    <Action name="edit_cut" /> +    <Action name="edit_copy" /> +    <Action name="edit_paste" /> +    <Separator/> +    <Action name="edit_find" /> +    <Action name="edit_find_next" /> +    <Action name="edit_find_prev" /> +</Menu> + +<!--  ============ VIEW menu =========== --> +<Menu name="view" noMerge="1"><text>&View</text> +    <Action name="stop_reload" /> +    <Action name="go_home" /> +    <Separator/> +    <Action name="bigger_font" /> +    <Action name="normal_font" /> +    <Action name="smaller_font" /> +    <Separator/> +    <Action name="page_source" /> +</Menu> + +<!--  ============ GO menu =========== --> +<Menu name="go" deleted="true"> +</Menu> + +<!--  ============ HISTORY menu =========== --> +<Action name="history" ><text>Hi&story</text> +</Action> + +<!--  ============ BOOKMARKS menu =========== --> +<Action name="bookmarks" ><text>&Bookmarks</text> +</Action> + +<!--  ============ TOOLS menu =========== --> +<Menu name="tools" noMerge="1"><text>&Tools</text> +    <Action name="web_inspector" /> +    <Action name="private_browsing" /> +</Menu> + +<!--  ============ SETTINGS menu =========== --> +<Menu name="settings" noMerge="1"><text>&Settings</text> +    <Action name="options_show_menubar" /> +    <Action name="options_show_statusbar" /> +    <Merge name="StandardToolBarMenuHandler" /> +    <Merge/> +    <Menu name="side_panels"><text>Side &Panels</text> +        <Action name="show_history_panel" /> +    </Menu> +    <Separator/> +    <Action name="fullscreen" /> +    <Separator/> +    <Action name="options_configure_keybinding" /> +    <Action name="options_configure_toolbars" /> +    <Action name="options_configure" /> +</Menu> + +</MenuBar> + +<!--  ============ Main ToolBar =========== --> +<ToolBar name="mainToolBar" position="top" iconText="iconOnly" newline="true" noMerge="1"> +<text>Main Toolbar</text> +    <Action name="history_back" /> +    <Action name="history_forward" /> +    <Action name="stop_reload" /> +    <Action name="go_home" /> +    <Action name="new_tab" /> +    <Action name="url_bar" /> +    <Action name="search_bar" /> +</ToolBar> + +<!--  ============ Bookmarks ToolBar =========== --> +<ToolBar name="bookmarksToolBar" fullWidth="true" iconText="icontextright" iconSize="16" newline="true" hidden="true" noEdit="true"> +    <text>Bookmark Toolbar</text> +    <Action noEdit="true" name="bookmarks_bar" /> +</ToolBar> + +</gui> diff --git a/src/searchbar.cpp b/src/searchbar.cpp new file mode 100644 index 00000000..fad35748 --- /dev/null +++ b/src/searchbar.cpp @@ -0,0 +1,129 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it +* and/or modify it under the terms of the GNU General +* Public License as published by the Free Software Foundation; +* either version 2, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// Self Includes +#include "searchbar.h" +#include "searchbar.moc" + +// Local Includes +#include "application.h" +#include "mainwindow.h" + +// KDE Includes +#include <KUrl> + +// Qt Includes +#include <QtCore> +#include <QtGui> +#include <QtNetwork> + + +SearchBar::SearchBar(QWidget *parent) : +        KLineEdit(parent) +        , m_networkAccessManager(new QNetworkAccessManager(this)) +        , m_timer(new QTimer(this)) +{ +    setMinimumWidth(180); + +    setFocusPolicy(Qt::WheelFocus); +    setMouseTracking(true); +    setAcceptDrops(true); + +    QSizePolicy policy = sizePolicy(); +    setSizePolicy(QSizePolicy::Preferred, policy.verticalPolicy()); + +    setClearButtonShown(true); + +    // better solution than using QPalette(s).. +    setClickMessage(i18n("Search..")); + +    // setting QNetworkAccessManager.. +    connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(handleNetworkData(QNetworkReply*))); + +    // setting QTimer.. +    m_timer->setSingleShot(true); +    m_timer->setInterval(200); +    connect(m_timer, SIGNAL(timeout()), SLOT(autoSuggest())); +    connect(this, SIGNAL(textEdited(QString)), m_timer, SLOT(start())); + +    // connect searchNow slot.. +    connect(this, SIGNAL(returnPressed()) , this , SLOT(searchNow())); +} + + +SearchBar::~SearchBar() +{ +} + + +void SearchBar::searchNow() +{ +    m_timer->stop(); +    QString searchText = text(); + +    KUrl url(QLatin1String("http://www.google.com/search")); +    url.addQueryItem(QLatin1String("q"), searchText); +    url.addQueryItem(QLatin1String("ie"), QLatin1String("UTF-8")); +    url.addQueryItem(QLatin1String("oe"), QLatin1String("UTF-8")); +    url.addQueryItem(QLatin1String("client"), QLatin1String("rekonq")); +    emit search(url); +} + + +void SearchBar::focusInEvent(QFocusEvent *event) +{ +    KLineEdit::focusInEvent(event); +    clear(); +} + + +void SearchBar::autoSuggest() +{ +    QString str = text(); +    QString url = QString("http://google.com/complete/search?output=toolbar&q=%1").arg(str); +    m_networkAccessManager->get(QNetworkRequest(QString(url))); +} + + +void SearchBar::handleNetworkData(QNetworkReply *networkReply) +{ +    QUrl url = networkReply->url(); +    if (!networkReply->error()) +    { +        QStringList choices; + +        QString response(networkReply->readAll()); +        QXmlStreamReader xml(response); +        while (!xml.atEnd()) +        { +            xml.readNext(); +            if (xml.tokenType() == QXmlStreamReader::StartElement) +                if (xml.name() == "suggestion") +                { +                    QStringRef str = xml.attributes().value("data"); +                    choices << str.toString(); +                } +        } + +        setCompletedItems(choices, true); +    } + +    networkReply->deleteLater(); +} diff --git a/src/searchbar.h b/src/searchbar.h new file mode 100644 index 00000000..3fdf55b4 --- /dev/null +++ b/src/searchbar.h @@ -0,0 +1,67 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* This program is free software; you can redistribute it +* and/or modify it under the terms of the GNU General +* Public License as published by the Free Software Foundation; +* either version 2, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#ifndef SEARCHBAR_H +#define SEARCHBAR_H + +// KDE Includes +#include <KLineEdit> + +// Forward Declarations +class KUrl; +class QFocusEvent; +class QTimer; +class QNetworkAccessManager; +class QNetworkReply; + +/** + * This class defines an internet search bar. + */ +class SearchBar : public KLineEdit +{ +    Q_OBJECT + +public: +    SearchBar(QWidget *parent = 0); +    ~SearchBar(); + +public slots: +    void autoSuggest(); +    void handleNetworkData(QNetworkReply *networkReply); + +    /** +    *  Use this slot to perform one search in one search engine +    * +    */ +    void searchNow(); + +protected: +    void focusInEvent(QFocusEvent *); + +signals: +    void search(const KUrl &); + +private: +    QNetworkAccessManager *m_networkAccessManager; +    QTimer *m_timer; +}; + +#endif diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 00000000..1e42413f --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,212 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +// Self Includes +#include "settings.h" +#include "settings.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "application.h" +#include "mainwindow.h" +#include "cookiejar.h" +#include "history.h" +#include "networkaccessmanager.h" +#include "webview.h" + +//Ui Includes +#include "ui_settings_general.h" +#include "ui_settings_fonts.h" +#include "ui_settings_privacy.h" +#include "ui_settings_proxy.h" +#include "ui_settings_webkit.h" + +// KDE Includes +#include <KConfig> +#include <KStandardDirs> +#include <KConfigSkeleton> +#include <KPageWidgetItem> +#include <KFontDialog> +#include <KUrl> + +// Qt Includes +#include <QtGui> +#include <QtWebKit> + + +class Private +{ +private: +    Ui::general generalUi; +    Ui::fonts fontsUi; +    Ui::privacy privacyUi; +    Ui::proxy proxyUi; +    Ui::webkit webkitUi; + +    Private(SettingsDialog *parent); + +    friend class SettingsDialog; +}; + + +Private::Private(SettingsDialog *parent) +{ +    QWidget *widget; +    KPageWidgetItem *pageItem; + +    widget = new QWidget; +    generalUi.setupUi(widget); +    widget->layout()->setMargin(0); +    pageItem = parent->addPage(widget , i18n("General")); +    pageItem->setIcon(KIcon("rekonq")); + +    widget = new QWidget; +    fontsUi.setupUi(widget); +    widget->layout()->setMargin(0); +    pageItem = parent->addPage(widget , i18n("Fonts")); +    pageItem->setIcon(KIcon("preferences-desktop-font")); + +    widget = new QWidget; +    privacyUi.setupUi(widget); +    widget->layout()->setMargin(0); +    pageItem = parent->addPage(widget , i18n("Privacy")); +    pageItem->setIcon(KIcon("preferences-desktop-personal")); + +    widget = new QWidget; +    proxyUi.setupUi(widget); +    widget->layout()->setMargin(0); +    pageItem = parent->addPage(widget , i18n("Proxy")); +    pageItem->setIcon(KIcon("preferences-system-network")); + +    widget = new QWidget; +    webkitUi.setupUi(widget); +    widget->layout()->setMargin(0); +    pageItem = parent->addPage(widget , i18n("Webkit")); +    QString webkitIconPath = KStandardDirs::locate("appdata", "pics/webkit-icon.png"); +    kWarning() << webkitIconPath; +    KIcon webkitIcon = KIcon(QIcon(webkitIconPath)); +    pageItem->setIcon(webkitIcon); +} + +// ----------------------------------------------------------------------------------------------------- + +SettingsDialog::SettingsDialog(QWidget *parent) +        : KConfigDialog(parent, "rekonfig", ReKonfig::self()) +        , d(new Private(this)) +{ +    setFaceType(KPageDialog::List); +    showButtonSeparator(true); + +    setWindowTitle(i18n("rekonfig..")); +    setModal(true); + +    readConfig(); + +    connect(d->generalUi.setHomeToCurrentPageButton, SIGNAL(clicked()), this, SLOT(setHomeToCurrentPage())); +    connect(d->privacyUi.exceptionsButton, SIGNAL(clicked()), this, SLOT(showExceptions())); +    connect(d->privacyUi.cookiesButton, SIGNAL(clicked()), this, SLOT(showCookies())); + +    setWebSettingsToolTips(); +} + + + +SettingsDialog::~SettingsDialog() +{ +    delete d; +} + + +void SettingsDialog::setWebSettingsToolTips() +{ +    d->webkitUi.kcfg_autoLoadImages->setToolTip(i18n("Specifies whether images are automatically loaded in web pages")); +    d->webkitUi.kcfg_javascriptEnabled->setToolTip(i18n("Enables the running of JavaScript programs.")); +    d->webkitUi.kcfg_javaEnabled->setToolTip(i18n("Enables Java applets.")); +    d->webkitUi.kcfg_pluginsEnabled->setToolTip(i18n("Enables plugins in web pages.")); +    d->webkitUi.kcfg_javascriptCanOpenWindows->setToolTip(i18n("Allows JavaScript programs to opening new windows.")); +    d->webkitUi.kcfg_javascriptCanAccessClipboard->setToolTip(i18n("Allows JavaScript programs to reading/writing to the clipboard.")); +    d->webkitUi.kcfg_linksIncludedInFocusChain->setToolTip(i18n("Includes hyperlinks in the keyboard focus chain.")); +    d->webkitUi.kcfg_zoomTextOnly->setToolTip(i18n("Applies the zoom factor on a frame to only the text or all content.")); +    d->webkitUi.kcfg_printElementBackgrounds->setToolTip(i18n("Draws also background color and images when the page is printed.")); +    d->webkitUi.kcfg_offlineStorageDatabaseEnabled->setToolTip(i18n("Support for the HTML 5 offline storage feature.")); +    d->webkitUi.kcfg_offlineWebApplicationCacheEnabled->setToolTip(i18n("Support for the HTML 5 web application cache feature.")); +    d->webkitUi.kcfg_localStorageDatabaseEnabled->setToolTip(i18n("Support for the HTML 5 local storage feature.")); +} + + +// we need this function to UPDATE the config widget data.. +void SettingsDialog::readConfig() +{ +    // ======= General +    d->generalUi.downloadDirUrlRequester->setMode(KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly); +    d->generalUi.downloadDirUrlRequester->setUrl(ReKonfig::downloadDir()); +    connect(d->generalUi.downloadDirUrlRequester, SIGNAL(textChanged(QString)), this, SLOT(saveSettings())); + +    // ======= Fonts +    d->fontsUi.kcfg_fixedFont->setOnlyFixed(true); + +    // ======= Proxy +    bool proxyEnabled = ReKonfig::isProxyEnabled(); +    d->proxyUi.groupBox->setEnabled(proxyEnabled); +    connect(d->proxyUi.kcfg_isProxyEnabled, SIGNAL(clicked(bool)), d->proxyUi.groupBox, SLOT(setEnabled(bool))); +} + + +// we need this function to SAVE settings in rc file.. +void SettingsDialog::saveSettings() +{ +    // General +    ReKonfig::setDownloadDir(d->generalUi.downloadDirUrlRequester->url().prettyUrl()); + +    // Save +    ReKonfig::self()->writeConfig(); +} + + +// ---------------------------------------------------------------------------------------------- + + +void SettingsDialog::showCookies() +{ +    CookiesDialog *dialog = new CookiesDialog(Application::cookieJar(), this); +    dialog->exec(); +} + + +void SettingsDialog::showExceptions() +{ +    CookiesExceptionsDialog *dialog = new CookiesExceptionsDialog(Application::cookieJar(), this); +    dialog->exec(); +} + + +void SettingsDialog::setHomeToCurrentPage() +{ +    MainWindow *mw = static_cast<MainWindow*>(parent()); +    WebView *webView = mw->currentTab(); +    if (webView) +    { +        d->generalUi.kcfg_homePage->setText(webView->url().prettyUrl()); +    } +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 00000000..26fd2d16 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,55 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* +* +* 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef SETTINGS_H +#define SETTINGS_H + +// KDE Includes +#include <KConfigDialog> + +// Forward Declarations +class QWidget; +class Private; + + +class SettingsDialog : public KConfigDialog +{ +    Q_OBJECT + +public: +    SettingsDialog(QWidget *parent = 0); +    ~SettingsDialog(); + +private: +    Private* const d; + +    void setWebSettingsToolTips(); + +private slots: +    void readConfig(); +    void saveSettings(); + +    void setHomeToCurrentPage(); +    void showCookies(); +    void showExceptions(); +}; + +#endif // SETTINGS_H diff --git a/src/settings_fonts.ui b/src/settings_fonts.ui new file mode 100644 index 00000000..de258cad --- /dev/null +++ b/src/settings_fonts.ui @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>fonts</class> + <widget class="QWidget" name="fonts"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>414</width> +    <height>298</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>Appearance</string> +  </property> +  <layout class="QVBoxLayout" name="verticalLayout_3"> +   <item> +    <widget class="QGroupBox" name="groupBox"> +     <property name="title"> +      <string>Fonts</string> +     </property> +     <layout class="QVBoxLayout" name="verticalLayout"> +      <item> +       <layout class="QGridLayout" name="gridLayout"> +        <item row="0" column="0"> +         <widget class="QLabel" name="label"> +          <property name="text"> +           <string>Standard Font</string> +          </property> +         </widget> +        </item> +        <item row="1" column="0"> +         <widget class="QLabel" name="label_2"> +          <property name="text"> +           <string>Fixed Font</string> +          </property> +         </widget> +        </item> +        <item row="1" column="1"> +         <widget class="KFontComboBox" name="kcfg_fixedFont"/> +        </item> +        <item row="0" column="1"> +         <widget class="KFontComboBox" name="kcfg_standardFont"/> +        </item> +       </layout> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <widget class="QGroupBox" name="groupBox_2"> +     <property name="title"> +      <string>Dimension</string> +     </property> +     <layout class="QVBoxLayout" name="verticalLayout_2"> +      <item> +       <layout class="QHBoxLayout" name="horizontalLayout"> +        <item> +         <widget class="QLabel" name="label_3"> +          <property name="text"> +           <string>Font Size</string> +          </property> +         </widget> +        </item> +        <item> +         <widget class="QSpinBox" name="kcfg_fontSize"/> +        </item> +       </layout> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <spacer name="verticalSpacer"> +     <property name="orientation"> +      <enum>Qt::Vertical</enum> +     </property> +     <property name="sizeHint" stdset="0"> +      <size> +       <width>20</width> +       <height>40</height> +      </size> +     </property> +    </spacer> +   </item> +  </layout> + </widget> + <customwidgets> +  <customwidget> +   <class>KFontComboBox</class> +   <extends>KComboBox</extends> +   <header>kfontcombobox.h</header> +  </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/settings_general.ui b/src/settings_general.ui new file mode 100644 index 00000000..44561b02 --- /dev/null +++ b/src/settings_general.ui @@ -0,0 +1,142 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>general</class> + <widget class="QWidget" name="general"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>515</width> +    <height>415</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>General</string> +  </property> +  <layout class="QVBoxLayout" name="verticalLayout_3"> +   <item> +    <widget class="QGroupBox" name="groupBox"> +     <property name="title"> +      <string>Places</string> +     </property> +     <layout class="QGridLayout" name="gridLayout"> +      <item row="0" column="0"> +       <widget class="QLabel" name="label_3"> +        <property name="text"> +         <string>Home Page:</string> +        </property> +        <property name="alignment"> +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="0" column="1"> +       <widget class="KLineEdit" name="kcfg_homePage"> +        <property name="sizePolicy"> +         <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> +          <horstretch>0</horstretch> +          <verstretch>0</verstretch> +         </sizepolicy> +        </property> +       </widget> +      </item> +      <item row="1" column="1"> +       <layout class="QHBoxLayout" name="horizontalLayout"> +        <item> +         <widget class="QPushButton" name="setHomeToCurrentPageButton"> +          <property name="text"> +           <string>Set to current page</string> +          </property> +         </widget> +        </item> +        <item> +         <spacer name="horizontalSpacer"> +          <property name="orientation"> +           <enum>Qt::Horizontal</enum> +          </property> +          <property name="sizeHint" stdset="0"> +           <size> +            <width>40</width> +            <height>20</height> +           </size> +          </property> +         </spacer> +        </item> +       </layout> +      </item> +      <item row="2" column="1"> +       <widget class="KUrlRequester" name="downloadDirUrlRequester"/> +      </item> +      <item row="2" column="0"> +       <widget class="QLabel" name="label_7"> +        <property name="text"> +         <string>Save downloads to:</string> +        </property> +        <property name="alignment"> +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="3" column="1"> +       <widget class="QCheckBox" name="kcfg_downloadToDefaultDir"> +        <property name="text"> +         <string>ask where saving downloads</string> +        </property> +       </widget> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <widget class="QGroupBox" name="groupBox_3"> +     <property name="title"> +      <string>Tabbed Browsing</string> +     </property> +     <layout class="QVBoxLayout" name="verticalLayout"> +      <item> +       <widget class="QCheckBox" name="kcfg_alwaysShowTabBar"> +        <property name="text"> +         <string>Always show tab bar</string> +        </property> +       </widget> +      </item> +      <item> +       <widget class="QCheckBox" name="kcfg_openTabsBack"> +        <property name="text"> +         <string>Open tabs in the background</string> +        </property> +       </widget> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <spacer name="verticalSpacer"> +     <property name="orientation"> +      <enum>Qt::Vertical</enum> +     </property> +     <property name="sizeHint" stdset="0"> +      <size> +       <width>20</width> +       <height>40</height> +      </size> +     </property> +    </spacer> +   </item> +  </layout> + </widget> + <customwidgets> +  <customwidget> +   <class>KLineEdit</class> +   <extends>QLineEdit</extends> +   <header>klineedit.h</header> +  </customwidget> +  <customwidget> +   <class>KUrlRequester</class> +   <extends>QFrame</extends> +   <header>kurlrequester.h</header> +  </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/settings_privacy.ui b/src/settings_privacy.ui new file mode 100644 index 00000000..78202688 --- /dev/null +++ b/src/settings_privacy.ui @@ -0,0 +1,168 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>privacy</class> + <widget class="QWidget" name="privacy"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>461</width> +    <height>313</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>Privacy</string> +  </property> +  <layout class="QVBoxLayout" name="verticalLayout"> +   <item> +    <widget class="QGroupBox" name="groupBox_2"> +     <property name="title"> +      <string>History</string> +     </property> +     <layout class="QGridLayout" name="gridLayout_2"> +      <item row="0" column="0"> +       <widget class="QLabel" name="label_4"> +        <property name="text"> +         <string>Remove history items:</string> +        </property> +        <property name="alignment"> +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="0" column="1"> +       <widget class="QComboBox" name="kcfg_expireHistory"> +        <item> +         <property name="text"> +          <string>After one day</string> +         </property> +        </item> +        <item> +         <property name="text"> +          <string>After one week</string> +         </property> +        </item> +        <item> +         <property name="text"> +          <string>After two weeks</string> +         </property> +        </item> +        <item> +         <property name="text"> +          <string>After one month</string> +         </property> +        </item> +        <item> +         <property name="text"> +          <string>After one year</string> +         </property> +        </item> +        <item> +         <property name="text"> +          <string>Manually</string> +         </property> +        </item> +       </widget> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <widget class="QGroupBox" name="cookiesGroupBox"> +     <property name="title"> +      <string>Cookies</string> +     </property> +     <layout class="QGridLayout" name="_2"> +      <item row="0" column="0"> +       <widget class="QLabel" name="label_2"> +        <property name="text"> +         <string>Accept Cookies:</string> +        </property> +        <property name="alignment"> +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="0" column="1"> +       <widget class="QComboBox" name="kcfg_acceptCookies"> +        <item> +         <property name="text"> +          <string>Always</string> +         </property> +        </item> +        <item> +         <property name="text"> +          <string>Never</string> +         </property> +        </item> +        <item> +         <property name="text"> +          <string>Only from sites you visit</string> +         </property> +        </item> +       </widget> +      </item> +      <item row="0" column="2"> +       <widget class="QPushButton" name="exceptionsButton"> +        <property name="text"> +         <string>Exceptions...</string> +        </property> +       </widget> +      </item> +      <item row="1" column="0"> +       <widget class="QLabel" name="label"> +        <property name="text"> +         <string>Keep until:</string> +        </property> +        <property name="alignment"> +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="1" column="1"> +       <widget class="QComboBox" name="kcfg_keepCookiesUntil"> +        <item> +         <property name="text"> +          <string>They expire</string> +         </property> +        </item> +        <item> +         <property name="text"> +          <string>I exit the application</string> +         </property> +        </item> +        <item> +         <property name="text"> +          <string>At most 90 days</string> +         </property> +        </item> +       </widget> +      </item> +      <item row="1" column="2"> +       <widget class="QPushButton" name="cookiesButton"> +        <property name="text"> +         <string>Cookies...</string> +        </property> +       </widget> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <spacer name="verticalSpacer"> +     <property name="orientation"> +      <enum>Qt::Vertical</enum> +     </property> +     <property name="sizeHint" stdset="0"> +      <size> +       <width>20</width> +       <height>136</height> +      </size> +     </property> +    </spacer> +   </item> +  </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/settings_proxy.ui b/src/settings_proxy.ui new file mode 100644 index 00000000..90e308a2 --- /dev/null +++ b/src/settings_proxy.ui @@ -0,0 +1,152 @@ +<ui version="4.0" > + <class>proxy</class> + <widget class="QWidget" name="proxy" > +  <property name="geometry" > +   <rect> +    <x>0</x> +    <y>0</y> +    <width>440</width> +    <height>223</height> +   </rect> +  </property> +  <property name="windowTitle" > +   <string>Proxy</string> +  </property> +  <layout class="QVBoxLayout" name="verticalLayout" > +   <item> +    <widget class="QCheckBox" name="kcfg_isProxyEnabled" > +     <property name="text" > +      <string>Enable proxy</string> +     </property> +    </widget> +   </item> +   <item> +    <widget class="QGroupBox" name="groupBox" > +     <property name="title" > +      <string>Proxy Settings</string> +     </property> +     <layout class="QGridLayout" name="gridLayout_6" > +      <item row="1" column="0" > +       <widget class="QLabel" name="label_9" > +        <property name="text" > +         <string>Type:</string> +        </property> +        <property name="alignment" > +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="1" column="1" colspan="2" > +       <widget class="QComboBox" name="kcfg_proxyType" > +        <item> +         <property name="text" > +          <string>SOCKS 5</string> +         </property> +        </item> +        <item> +         <property name="text" > +          <string>HTTP</string> +         </property> +        </item> +       </widget> +      </item> +      <item row="2" column="0" > +       <widget class="QLabel" name="label_10" > +        <property name="text" > +         <string>Host:</string> +        </property> +        <property name="alignment" > +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="2" column="1" colspan="2" > +       <widget class="KLineEdit" name="kcfg_proxyHostName" /> +      </item> +      <item row="3" column="0" > +       <widget class="QLabel" name="label_11" > +        <property name="text" > +         <string>Port:</string> +        </property> +        <property name="alignment" > +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="3" column="1" > +       <widget class="QSpinBox" name="kcfg_proxyPort" > +        <property name="maximum" > +         <number>10000</number> +        </property> +        <property name="value" > +         <number>1080</number> +        </property> +       </widget> +      </item> +      <item row="3" column="2" > +       <spacer name="horizontalSpacer_2" > +        <property name="orientation" > +         <enum>Qt::Horizontal</enum> +        </property> +        <property name="sizeHint" stdset="0" > +         <size> +          <width>293</width> +          <height>20</height> +         </size> +        </property> +       </spacer> +      </item> +      <item row="4" column="0" > +       <widget class="QLabel" name="label_12" > +        <property name="text" > +         <string>Username:</string> +        </property> +        <property name="alignment" > +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="4" column="1" colspan="2" > +       <widget class="KLineEdit" name="kcfg_proxyUserName" /> +      </item> +      <item row="5" column="0" > +       <widget class="QLabel" name="label_13" > +        <property name="text" > +         <string>Password:</string> +        </property> +        <property name="alignment" > +         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> +        </property> +       </widget> +      </item> +      <item row="5" column="1" colspan="2" > +       <widget class="KLineEdit" name="kcfg_proxyPassword" /> +      </item> +      <item row="6" column="0" > +       <spacer name="verticalSpacer_2" > +        <property name="orientation" > +         <enum>Qt::Vertical</enum> +        </property> +        <property name="sizeHint" stdset="0" > +         <size> +          <width>20</width> +          <height>8</height> +         </size> +        </property> +       </spacer> +      </item> +     </layout> +    </widget> +   </item> +  </layout> + </widget> + <customwidgets> +  <customwidget> +   <class>KLineEdit</class> +   <extends>QLineEdit</extends> +   <header>klineedit.h</header> +  </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/settings_webkit.ui b/src/settings_webkit.ui new file mode 100644 index 00000000..362e392a --- /dev/null +++ b/src/settings_webkit.ui @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>webkit</class> + <widget class="QWidget" name="webkit"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>564</width> +    <height>360</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>Form</string> +  </property> +  <layout class="QVBoxLayout" name="verticalLayout"> +   <item> +    <widget class="QGroupBox" name="groupBox"> +     <property name="title"> +      <string>WebKit Settings</string> +     </property> +     <layout class="QGridLayout" name="gridLayout"> +      <item row="0" column="0"> +       <widget class="QCheckBox" name="kcfg_autoLoadImages"> +        <property name="text"> +         <string>Auto Load Images</string> +        </property> +       </widget> +      </item> +      <item row="0" column="1" rowspan="6"> +       <widget class="Line" name="line"> +        <property name="orientation"> +         <enum>Qt::Vertical</enum> +        </property> +       </widget> +      </item> +      <item row="0" column="2"> +       <widget class="QCheckBox" name="kcfg_linksIncludedInFocusChain"> +        <property name="text"> +         <string>Links included in focus chain</string> +        </property> +       </widget> +      </item> +      <item row="1" column="0"> +       <widget class="QCheckBox" name="kcfg_javascriptEnabled"> +        <property name="text"> +         <string>Javascript support</string> +        </property> +       </widget> +      </item> +      <item row="1" column="2"> +       <widget class="QCheckBox" name="kcfg_zoomTextOnly"> +        <property name="text"> +         <string>Zoom Text Only</string> +        </property> +       </widget> +      </item> +      <item row="2" column="0"> +       <widget class="QCheckBox" name="kcfg_javaEnabled"> +        <property name="text"> +         <string>Java support</string> +        </property> +       </widget> +      </item> +      <item row="2" column="2"> +       <widget class="QCheckBox" name="kcfg_printElementBackgrounds"> +        <property name="text"> +         <string>Print element Backgrounds</string> +        </property> +       </widget> +      </item> +      <item row="3" column="0"> +       <widget class="QCheckBox" name="kcfg_pluginsEnabled"> +        <property name="text"> +         <string>Plugins</string> +        </property> +       </widget> +      </item> +      <item row="3" column="2"> +       <widget class="QCheckBox" name="kcfg_offlineStorageDatabaseEnabled"> +        <property name="text"> +         <string>Offline storage Database</string> +        </property> +       </widget> +      </item> +      <item row="4" column="0"> +       <widget class="QCheckBox" name="kcfg_javascriptCanOpenWindows"> +        <property name="text"> +         <string>Javascript can open windows</string> +        </property> +       </widget> +      </item> +      <item row="4" column="2"> +       <widget class="QCheckBox" name="kcfg_offlineWebApplicationCacheEnabled"> +        <property name="text"> +         <string>Offline Web Application Cache </string> +        </property> +       </widget> +      </item> +      <item row="5" column="0"> +       <widget class="QCheckBox" name="kcfg_javascriptCanAccessClipboard"> +        <property name="text"> +         <string>Javascript can access clipboard</string> +        </property> +       </widget> +      </item> +      <item row="5" column="2"> +       <widget class="QCheckBox" name="kcfg_localStorageDatabaseEnabled"> +        <property name="text"> +         <string>Local storage database</string> +        </property> +       </widget> +      </item> +     </layout> +    </widget> +   </item> +   <item> +    <spacer name="verticalSpacer"> +     <property name="orientation"> +      <enum>Qt::Vertical</enum> +     </property> +     <property name="sizeHint" stdset="0"> +      <size> +       <width>20</width> +       <height>146</height> +      </size> +     </property> +    </spacer> +   </item> +  </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/sidepanel.cpp b/src/sidepanel.cpp new file mode 100644 index 00000000..0fab81c0 --- /dev/null +++ b/src/sidepanel.cpp @@ -0,0 +1,53 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + +// Self Includes +#include "sidepanel.h" +#include "sidepanel.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "panelhistory.h" + + +SidePanel::SidePanel(const QString &title, QWidget *parent, Qt::WindowFlags flags) +        : QDockWidget(title, parent, flags) +        , m_panelHistory(new PanelHistory(this)) +{ +    setObjectName("sidePanel"); +    setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + +    setShown(ReKonfig::showSideBar()); + +    connect(m_panelHistory, SIGNAL(openUrl(const KUrl&)), this, SIGNAL(openUrl(const KUrl&))); + +    setWidget(m_panelHistory); +} + + +SidePanel::~SidePanel() +{ +    // Save side panel's state +    ReKonfig::setShowSideBar(!isHidden()); + +    delete m_panelHistory; +} + diff --git a/src/sidepanel.h b/src/sidepanel.h new file mode 100644 index 00000000..c0af7827 --- /dev/null +++ b/src/sidepanel.h @@ -0,0 +1,50 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef SIDEPANEL_H +#define SIDEPANEL_H + +// Qt Includes +#include <QDockWidget> + +// Local Includes +#include "application.h" + +class KUrl; +class PanelHistory; + + +class SidePanel : public QDockWidget +{ +    Q_OBJECT +    Q_DISABLE_COPY(SidePanel) + +public: +    explicit SidePanel(const QString &title, QWidget *parent = 0, Qt::WindowFlags flags = 0); +    ~SidePanel(); + +signals: +    void openUrl(const KUrl &); + +private: +    PanelHistory *m_panelHistory; + +}; + +#endif // SIDEPANEL_H diff --git a/src/stackedurlbar.cpp b/src/stackedurlbar.cpp new file mode 100644 index 00000000..113c8769 --- /dev/null +++ b/src/stackedurlbar.cpp @@ -0,0 +1,152 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// Self Includes +#include "stackedurlbar.h" +#include "stackedurlbar.moc" + +// KDE Includes +#include "kdebug.h" + +// Local Includes +#include "application.h" +#include "history.h" +#include "urlbar.h" + + +StackedUrlBar::StackedUrlBar(QWidget *parent) +        : QStackedWidget(parent) +        , m_completion(0) +        , m_completionModel(0) +{ +} + + +StackedUrlBar::~StackedUrlBar() +{ +    delete m_completion; +    delete m_completionModel; +} + + +UrlBar *StackedUrlBar::currentUrlBar() +{ +    return urlBar(currentIndex()); +} + + +UrlBar *StackedUrlBar::urlBar(int index) +{ +    UrlBar *urlBar = qobject_cast<UrlBar*>(QStackedWidget::widget(index)); +    if (!urlBar) +    { +        kWarning() << "URL bar with index" << index << "not found. Returning NULL.  line:" << __LINE__; +    } + +    return urlBar; +} + + +void StackedUrlBar::addUrlBar(UrlBar* urlBar) +{ +    QStackedWidget::addWidget(urlBar); + +    // setup completion objects +    urlBar->setCompletionObject(completion()); +} + + +void StackedUrlBar::setCurrentUrlBar(UrlBar* urlBar) +{ +    QStackedWidget::setCurrentWidget(urlBar); +} + + +void StackedUrlBar::removeUrlBar(UrlBar* urlBar) +{ +    QStackedWidget::removeWidget(urlBar); +} + + +void StackedUrlBar::clear() +{ +    currentUrlBar()->clearHistory(); + +    for (int i = 0; i < count(); ++i) +    { +        urlBar(i)->clear(); +    } +} + + +QList<const UrlBar* > StackedUrlBar::urlBars() +{ +    QList<const UrlBar *> list; +    for (int i = 0; i < count(); ++i) +    { +        const UrlBar* u = urlBar(i); +        list.append(u); +    } +    return list; +} + + +KCompletion *StackedUrlBar::completion() +{ +    // make sure completion was created +    if (!m_completion) +    { +        m_completion = new KCompletion(); +        m_completion->setCompletionMode(KGlobalSettings::CompletionPopupAuto); +        m_completion->setOrder(KCompletion::Weighted); +        m_completion->setIgnoreCase(true); + +        kDebug() << "Initialize completion list..."; + +        HistoryCompletionModel *model = completionModel(); +        int count = model->rowCount(); + +        kDebug() << "...initialize history items" << count; + +        // change order to insertion to avoid confusion of the addItem method +        // in weighted it expects format string:number and it thinks http it the whole string +        m_completion->setOrder(KCompletion::Insertion); +        for (int i = 0; i < count; ++i) +        { +            QString item = model->data(model->index(i, 0)).toString(); +            item.remove(QRegExp("^http://|/$")); +            m_completion->addItem(item); +        } +        m_completion->setOrder(KCompletion::Weighted); +    } + +    return m_completion; +} + + +HistoryCompletionModel *StackedUrlBar::completionModel() +{ +    if (!m_completionModel) +    { +        m_completionModel = new HistoryCompletionModel(this); +        m_completionModel->setSourceModel(Application::historyManager()->historyFilterModel()); +    } +    return m_completionModel; +} diff --git a/src/stackedurlbar.h b/src/stackedurlbar.h new file mode 100644 index 00000000..d3aea16f --- /dev/null +++ b/src/stackedurlbar.h @@ -0,0 +1,64 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + + +#ifndef STACKEDURLBAR_H +#define STACKEDURLBAR_H + +// Qt Includes +#include <QStackedWidget> + +class KCompletion; +class HistoryCompletionModel; +class UrlBar; + +class StackedUrlBar : public QStackedWidget +{ +    Q_OBJECT + +public: +    StackedUrlBar(QWidget *parent = 0); +    ~StackedUrlBar(); + +public: +    UrlBar *currentUrlBar(); +    UrlBar *urlBar(int index); +    void addUrlBar(UrlBar *urlBar); +    void setCurrentUrlBar(UrlBar *urlBar); +    void removeUrlBar(UrlBar *urlBar); + +    QList<const UrlBar *> urlBars(); + +    KCompletion *completion(); +    HistoryCompletionModel *completionModel(); + +public slots: +    void clear(); + +private: +    Q_DISABLE_COPY(StackedUrlBar) + +    KCompletion *m_completion; +    HistoryCompletionModel *m_completionModel; +}; + +#endif // STACKEDURLBAR_H + diff --git a/src/tabbar.cpp b/src/tabbar.cpp new file mode 100644 index 00000000..be1b05fd --- /dev/null +++ b/src/tabbar.cpp @@ -0,0 +1,145 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + +//Self Includes +#include "tabbar.h" +#include "tabbar.moc" + +// Local Includes +#include "application.h" +#include "mainwindow.h" +#include "history.h" +#include "urlbar.h" +#include "webview.h" + +// KDE Includes +#include <KShortcut> +#include <KStandardShortcut> +#include <KMessageBox> +#include <KAction> +#include <KDebug> +#include <KGlobalSettings> + +// Qt Includes +#include <QtGui> + + +TabBar::TabBar(QWidget *parent) +        : KTabBar(parent) +        , m_parent(parent) +{ +    setElideMode(Qt::ElideRight); +    setContextMenuPolicy(Qt::CustomContextMenu); +    setMovable(true); +    connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, +            SLOT(contextMenuRequested(const QPoint &))); + +    // tabbar font +    QFont standardFont = KGlobalSettings::generalFont(); +    QString fontFamily = standardFont.family(); +    int dim = standardFont.pointSize(); +    setFont(QFont(fontFamily, dim - 1)); +} + + +TabBar::~TabBar() +{ +} + + +QSize TabBar::tabSizeHint(int index) const +{ +    QSize s = m_parent->sizeHint(); +    int w; + +    int n = count(); + +    if (n > 6) +    { +        w = s.width() / 5; +    } +    else +    { +        if (n > 3) +        { +            w = s.width() / 4; +        } +        else +        { +            w = s.width() / 3; +        } +    } +    int h = KTabBar::tabSizeHint(index).height(); + +    QSize ts = QSize(w, h); +    return ts; +} + + +void TabBar::contextMenuRequested(const QPoint &position) +{ +    KMenu menu; +    MainWindow *mainWindow = Application::instance()->mainWindow(); + +    menu.addAction(mainWindow->actionByName(QLatin1String("new_tab"))); +    int index = tabAt(position); +    if (-1 != index) +    { +        m_actualIndex = index; + +        menu.addAction(KIcon("tab-duplicate"), i18n("Clone Tab"), this, SLOT(cloneTab())); +        menu.addSeparator(); +        menu.addAction(KIcon("tab-close"), i18n("&Close Tab"), this, SLOT(closeTab())); +        menu.addAction(KIcon("tab-close-other"), i18n("Close &Other Tabs"), this, SLOT(closeOtherTabs())); +        menu.addSeparator(); +        menu.addAction(KIcon("view-refresh"), i18n("Reload Tab"), this, SLOT(reloadTab())); +    } +    else +    { +        menu.addSeparator(); +    } +    menu.addAction(i18n("Reload All Tabs"), this, SIGNAL(reloadAllTabs())); +    menu.exec(QCursor::pos()); +} + + +void TabBar::cloneTab() +{ +    emit cloneTab(m_actualIndex); +} + + +void TabBar::closeTab() +{ +    emit closeTab(m_actualIndex); +} + + +void TabBar::closeOtherTabs() +{ +    emit closeOtherTabs(m_actualIndex); +} + + +void TabBar::reloadTab() +{ +    emit reloadTab(m_actualIndex); +} diff --git a/src/tabbar.h b/src/tabbar.h new file mode 100644 index 00000000..8563793f --- /dev/null +++ b/src/tabbar.h @@ -0,0 +1,78 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef TABBAR_H +#define TABBAR_H + +// KDE Includes +#include <KTabBar> + +// Qt Includes +#include <QShortcut> + +/** + * Tab bar with a few more features such as + * a context menu and shortcuts + * + */ + +class TabBar : public KTabBar +{ +    Q_OBJECT + + +public: +    TabBar(QWidget *parent = 0); +    ~TabBar(); + +signals: +    void cloneTab(int index); +    void closeTab(int index); +    void closeOtherTabs(int index); +    void reloadTab(int index); +    void reloadAllTabs(); + +protected: +    /** +     * Added to fix tab dimension +     */ +    virtual QSize tabSizeHint(int index) const; + +private slots: +    void cloneTab(); +    void closeTab(); +    void closeOtherTabs(); +    void reloadTab(); +    void contextMenuRequested(const QPoint &position); + +private: +    friend class MainView; + +    QWidget *m_parent; + +    /** +     * the index in which we are seeing a Context menu +     */ +    int m_actualIndex; +}; + +#endif diff --git a/src/urlbar.cpp b/src/urlbar.cpp new file mode 100644 index 00000000..29eaed70 --- /dev/null +++ b/src/urlbar.cpp @@ -0,0 +1,240 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@gmail.com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// Self Includes +#include "urlbar.h" +#include "urlbar.moc" + +// Qt Includes +#include <QtCore> +#include <QtGui> + +// KDE Includes +#include <KDebug> +#include <KCompletionBox> +#include <KUrl> + +// Local Includes +#include "application.h" +#include "history.h" +#include "lineedit.h" +#include "mainwindow.h" +#include "webview.h" + + +QColor UrlBar::s_defaultBaseColor; + +UrlBar::UrlBar(QWidget *parent) +        : KHistoryComboBox(true, parent) +        , m_lineEdit(new LineEdit) +        , m_progress(0) +{ +    setUrlDropsEnabled(true); +    setAutoDeleteCompletionObject(true); +    setMinimumWidth(180); + +    setTrapReturnKey(true); + +    setupLineEdit(); + +    // add every item to history +    connect(this, SIGNAL(returnPressed(const QString&)), SLOT(slotActivated(const QString&))); +    connect(completionBox(), SIGNAL(activated(const QString&)), SLOT(slotActivated(const QString&))); + +    connect(this, SIGNAL(cleared()), SLOT(slotCleared())); + +    // setup completion box +    completionBox()->setTabHandling(true);  // Konqueror bug #167135 + +    // set dropdown list background +    QPalette p = view()->palette(); +    p.setColor(QPalette::Base, palette().color(QPalette::Base)); +    view()->setPalette(p); + +    // set empty item with default icon +    slotUpdateUrl(); +} + + +UrlBar::~UrlBar() +{ +} + + +void UrlBar::setupLineEdit() +{ +    // Make m_lineEdit background transparent +    QPalette p = m_lineEdit->palette(); +    p.setColor(QPalette::Base, Qt::transparent); +    m_lineEdit->setPalette(p); + +    if (!s_defaultBaseColor.isValid()) +    { +        s_defaultBaseColor = palette().color(QPalette::Base); +    } + +    setLineEdit(m_lineEdit); + +    // Make the lineedit consume the Qt::Key_Enter event... +    lineEdit()->setTrapReturnKey(true); + +    lineEdit()->setHandleSignals(true); + +    // clear the URL bar +    lineEdit()->clear(); +} + + +void UrlBar::setUrl(const QUrl& url) +{ +    if (url.isEmpty()) +        return; + +    m_currentUrl = url; +    slotUpdateUrl(); +} + + +void UrlBar::slotUpdateUrl() +{ +    if (count()) +    { +        changeUrl(0, Application::instance()->icon(m_currentUrl), m_currentUrl); +    } +    else +    { +        insertUrl(0, Application::instance()->icon(m_currentUrl), m_currentUrl); +    } + +    setCurrentIndex(0); + +    // important security consideration: always display the beginning +    // of the url rather than its end to prevent spoofing attempts. +    // Must be AFTER setCurrentIndex +    if (!hasFocus()) +    { +        lineEdit()->setCursorPosition(0); +    } +} + + +inline void UrlBar::slotActivated(const QString& url) +{ +    if (url.isEmpty()) +        return; + +    setUrl(url); + +    Application::historyManager()->addHistoryEntry(url); + +    emit activated(m_currentUrl); +} + + +inline void UrlBar::slotCleared() +{ +    // clear the history on user's request from context menu +    clear(); +    Application::historyManager()->clear(); +} + + +inline void UrlBar::slotLoadFinished(bool) +{ +    // reset progress bar after small delay +    m_progress = 0; +    QTimer::singleShot(200, this, SLOT(repaint())); +} + + +inline void UrlBar::slotUpdateProgress(int progress) +{ +    m_progress = progress; +    repaint(); +} + + +void UrlBar::paintEvent(QPaintEvent *event) +{ +    // set background color of UrlBar +    QPalette p = palette(); +    p.setColor(QPalette::Base, s_defaultBaseColor); +    setPalette(p); + +    KHistoryComboBox::paintEvent(event); + +    if (!hasFocus()) +    { +        QPainter painter(this); + +        QColor loadingColor; +        if (m_currentUrl.scheme() == QLatin1String("https")) +        { +            loadingColor = QColor(248, 248, 100); +        } +        else +        { +            loadingColor = QColor(116, 192, 250); +        } +        painter.setBrush(generateGradient(loadingColor, height())); +        painter.setPen(Qt::transparent); + +        QRect backgroundRect = lineEdit()->frameGeometry(); +        int mid = backgroundRect.width() / 100 * m_progress; +        QRect progressRect(backgroundRect.x(), backgroundRect.y(), mid, backgroundRect.height()); +        painter.drawRect(progressRect); +        painter.end(); +    } +} + + +void UrlBar::focusOutEvent(QFocusEvent *event) +{ +    // set back last loaded url in case user cleared it +    setUrl(m_currentUrl); + +    KHistoryComboBox::focusOutEvent(event); +} + + +QSize UrlBar::sizeHint() const +{ +    QSize size(lineEdit()->sizeHint()); +    // make it (more or less) the same height with search bar (at least on oxygen) +//     size.setHeight(size.height() + 2); +    return size; +} + +QLinearGradient UrlBar::generateGradient(const QColor &color, int height) +{ +    QColor base = s_defaultBaseColor; +    base.setAlpha(0); +    QColor barColor = color; +    barColor.setAlpha(200); +    QLinearGradient gradient(0, 0, 0, height); +    gradient.setColorAt(0, base); +    gradient.setColorAt(0.25, barColor.lighter(120)); +    gradient.setColorAt(0.5, barColor); +    gradient.setColorAt(0.75, barColor.lighter(120)); +    gradient.setColorAt(1, base); +    return gradient; +} diff --git a/src/urlbar.h b/src/urlbar.h new file mode 100644 index 00000000..236792bd --- /dev/null +++ b/src/urlbar.h @@ -0,0 +1,99 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Domrachev Alexandr <alexandr.domrachev@gmail.com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef URLBAR_H +#define URLBAR_H + +// Qt Includes +#include <QIcon> +#include <QPointer> +#include <QUrl> + +// KDE Includes +#include <KUrl> +#include <KHistoryComboBox> + +// Local Includes +#include "lineedit.h" + + +// Forward Declarations +class QLinearGradient; +class QWidget; + + +class UrlBar : public KHistoryComboBox +{ +    Q_OBJECT + +public: +    UrlBar(QWidget *parent = 0); +    ~UrlBar(); + +    void selectAll() const +    { +        lineEdit()->selectAll(); +    } +    KUrl url() const +    { +        return m_currentUrl; +    } + +    QSize sizeHint() const; + +signals: +    void activated(const KUrl&); + +public slots: +    void setUrl(const QUrl &url); +    void slotUpdateProgress(int progress); + +private slots: +    void slotActivated(const QString&); +    void slotLoadFinished(bool); +    void slotCleared(); +    void slotUpdateUrl(); + +protected: +    virtual void paintEvent(QPaintEvent *event); +    virtual void focusOutEvent(QFocusEvent *event); + +private: +    void setupLineEdit(); + +    KLineEdit *lineEdit() const +    { +        return m_lineEdit; +    } + +    static QLinearGradient generateGradient(const QColor &color, int height); + +    static QColor s_defaultBaseColor; + +    LineEdit *m_lineEdit; + +    QIcon m_currentIcon; +    KUrl m_currentUrl; +    int m_progress; +}; + +#endif diff --git a/src/webview.cpp b/src/webview.cpp new file mode 100644 index 00000000..5f42112b --- /dev/null +++ b/src/webview.cpp @@ -0,0 +1,504 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +// Self Includes +#include "webview.h" +#include "webview.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "application.h" +#include "mainwindow.h" +#include "mainview.h" +#include "cookiejar.h" +#include "networkaccessmanager.h" +#include "download.h" +#include "history.h" + + +// KDE Includes +#include <KStandardDirs> +#include <KUrl> +#include <KActionCollection> +#include <KDebug> +#include <KToolInvocation> + +// Qt Includes +#include <QtCore> +#include <QtGui> +#include <QtWebKit> +#include <QUiLoader> + + +WebPage::WebPage(QObject *parent) +        : QWebPage(parent) +        , m_keyboardModifiers(Qt::NoModifier) +        , m_pressedButtons(Qt::NoButton) +        , m_openInNewTab(false) +{ +    setNetworkAccessManager(Application::networkAccessManager()); + +    setForwardUnsupportedContent(true); +    connect(this, SIGNAL(unsupportedContent(QNetworkReply *)), this, SLOT(handleUnsupportedContent(QNetworkReply *))); +} + + +WebPage::~WebPage() +{ +} + + +bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type) +{ +    QString scheme = request.url().scheme(); +    if (scheme == QLatin1String("mailto")) +    { +        KToolInvocation::invokeMailer(request.url()); +        return false; +    } + +    WebView *webView; + +    switch (type) +    { + +        // user clicked on a link or pressed return on a focused link. +    case QWebPage::NavigationTypeLinkClicked: + +        if (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton) +        { +            webView = Application::instance()->newWebView(); +            webView->setFocus(); +            webView->load(request); +            m_keyboardModifiers = Qt::NoModifier; +            m_pressedButtons = Qt::NoButton; +            return false; +        } + +        if (frame == mainFrame()) +        { +            m_loadingUrl = request.url(); +            emit loadingUrl(m_loadingUrl); +        } +        else +        { +            // if frame doesn't exists (perhaps) we are pointing to a blank target.. +            if (!frame) +            { +                webView = Application::instance()->newWebView(); +                webView->setFocus(); +                webView->load(request); +                return false; +            } +        } +        break; + +        // user activated a submit button for an HTML form. +    case QWebPage::NavigationTypeFormSubmitted: +        break; + +        // Navigation to a previously shown document in the back or forward history is requested. +    case QWebPage::NavigationTypeBackOrForward: +        break; + +        // user activated the reload action. +    case QWebPage::NavigationTypeReload: + +#if QT_VERSION <= 040500 +        // HACK Ported from Arora +        // A short term hack until QtWebKit can get a reload without cache QAction +        // *FYI* currently type is never NavigationTypeReload +        // See: https://bugs.webkit.org/show_bug.cgi?id=24283 +        if (qApp->keyboardModifiers() & Qt::ShiftModifier) +        { +            QNetworkRequest newRequest(request); +            newRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, +                                    QNetworkRequest::AlwaysNetwork); +            mainFrame()->load(request); +            return false; +        } +#endif + +        break; + +        // An HTML form was submitted a second time. +    case QWebPage::NavigationTypeFormResubmitted: +        break; + +        // A navigation to another document using a method not listed above. +    case QWebPage::NavigationTypeOther: +        break; + +        // should be nothing.. +    default: +        break; +    } + +    return QWebPage::acceptNavigationRequest(frame, request, type); +} + + +QWebPage *WebPage::createWindow(QWebPage::WebWindowType type) +{ +    // added to manage web modal dialogs +    if (type == QWebPage::WebModalDialog) +    { +        // FIXME : need a "real" implementation.. +        kWarning() << "Modal Dialog ---------------------------------------"; +        QWebView *w = new QWebView(); +        w->show(); +        return w->page(); +    } + +    if (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton) +    { +        m_openInNewTab = true; +    } + +    if (m_openInNewTab) +    { +        m_openInNewTab = false; +        return Application::instance()->newWebView()->page(); +    } + +    MainWindow *mainWindow = Application::instance()->mainWindow(); +    return mainWindow->currentTab()->page(); +} + + +QObject *WebPage::createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues) +{ +    kWarning() << "creating PLUGIN for rekonq "; +    kWarning() << "classId = " << classId; +    kWarning() << "url = " << url; +    kWarning() << "Param Names = " << paramNames; +    kWarning() << "Param Values = " << paramValues; + +    QUiLoader loader; +    return loader.createWidget(classId, view()); +} + + +void WebPage::handleUnsupportedContent(QNetworkReply *reply) +{ +    // create convenience fake api:// protocol for KDE apidox search and Qt docs +    if (reply->url().scheme() == "api") +    { +        QString path; +        QString className = reply->url().host().toLower(); +        if (className[0] == 'k') +        { +            path = QString("http://api.kde.org/new.classmapper.php?class=%1").arg(className); +        } +        else if (className[0] == 'q') +        { +            path = QString("http://doc.trolltech.com/4.5/%1.html").arg(className); +        } +        QUrl url(path); + +        Application::instance()->mainWindow()->loadUrl(url); +        return; +    } + +    if (reply->error() == QNetworkReply::NoError) +    { +        // st iframe unwanted download fix +        if (reply->header(QNetworkRequest::ContentTypeHeader).isValid()) +        { +            KUrl srcUrl = reply->url(); +            Application::downloadManager()->newDownload(srcUrl); +        } +        return; +    } + +    // display "not found" page +    QString notfoundFilePath =  KStandardDirs::locate("data", "rekonq/htmls/notfound.html"); +    QFile file(notfoundFilePath); +    bool isOpened = file.open(QIODevice::ReadOnly); +    if (!isOpened) +    { +        kWarning() << "Couldn't open the notfound.html file"; +        return; +    } +    QString title = i18n("Error loading page: ") + reply->url().toString(); + +    QString imagePath = KIconLoader::global()->iconPath("rekonq", KIconLoader::NoGroup, false); + +    QString html = QString(QLatin1String(file.readAll())) +                   .arg(title) +                   .arg("file://" + imagePath) +                   .arg(reply->errorString()) +                   .arg(reply->url().toString()); + +    QList<QWebFrame*> frames; +    frames.append(mainFrame()); +    while (!frames.isEmpty()) +    { +        QWebFrame *firstFrame = frames.takeFirst(); +        if (firstFrame->url() == reply->url()) +        { +            firstFrame->setHtml(html, reply->url()); +            return; +        } +        QList<QWebFrame *> children = firstFrame->childFrames(); +        foreach(QWebFrame *frame, children) +        { +            frames.append(frame); +        } +    } +    if (m_loadingUrl == reply->url()) +    { +        mainFrame()->setHtml(html, reply->url()); +        // Don't put error pages to the history. +        Application::historyManager()->removeHistoryEntry(reply->url(), mainFrame()->title()); +    } +} + + +// ----------------------------------------------------------------------------------------------------------------- + + +KActionCollection* WebView::s_webActionCollection; + + +WebView::WebView(QWidget* parent) +        : QWebView(parent) +        , m_page(new WebPage(this)) +        , m_progress(0) +{ +    setPage(m_page); +    connect(page(), SIGNAL(statusBarMessage(const QString&)), this, SLOT(setStatusBarText(const QString&))); +    connect(this, SIGNAL(loadProgress(int)), this, SLOT(setProgress(int))); +    connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished())); +    connect(page(), SIGNAL(loadingUrl(const QUrl&)),  this, SIGNAL(urlChanged(const QUrl &))); +    connect(page(), SIGNAL(downloadRequested(const QNetworkRequest &)), this, SLOT(downloadRequested(const QNetworkRequest &))); +    page()->setForwardUnsupportedContent(true); +} + + +KActionCollection* WebView::webActions() +{ +    if (!s_webActionCollection) +    { +        s_webActionCollection = new KActionCollection(this); + +        QAction *a; + +        a = new KAction(KIcon("tab-new"), i18n("Open Link in New &Tab"), this); +        connect(a, SIGNAL(triggered()), this, SLOT(openLinkInNewTab())); +        s_webActionCollection->addAction(QLatin1String("open_link_in_new_tab"), a); + +        a = pageAction(QWebPage::Cut); +        a->setIcon(KIcon("edit-cut")); +        a->setText(i18n("Cu&t")); +        s_webActionCollection->addAction(QLatin1String("edit_cut"), a); + +        a = pageAction(QWebPage::Copy); +        a->setIcon(KIcon("edit-copy")); +        a->setText(i18n("&Copy")); +        s_webActionCollection->addAction(QLatin1String("edit_copy"), a); + +        a = pageAction(QWebPage::Paste); +        a->setIcon(KIcon("edit-paste")); +        a->setText(i18n("&Paste")); +        s_webActionCollection->addAction(QLatin1String("edit_paste"), a); + +        a = pageAction(QWebPage::DownloadImageToDisk); +        a->setIcon(KIcon("folder-image")); +        a->setText(i18n("&Save Image As...")); +        s_webActionCollection->addAction(QLatin1String("save_image_as"), a); + +        a = pageAction(QWebPage::CopyImageToClipboard); +        a->setIcon(KIcon("insert-image")); +        a->setText(i18n("&Copy This Image")); +        s_webActionCollection->addAction(QLatin1String("copy_this_image"), a); + +        a = pageAction(QWebPage::DownloadLinkToDisk); +        a->setIcon(KIcon("folder-downloads")); +        a->setText(i18n("&Save Link As...")); +        s_webActionCollection->addAction(QLatin1String("save_link_as"), a); + +        a = pageAction(QWebPage::CopyLinkToClipboard); +        a->setIcon(KIcon("insert-link")); +        a->setText(i18n("&Copy Link Location")); +        s_webActionCollection->addAction(QLatin1String("copy_link_location"), a); + +        a = pageAction(QWebPage::InspectElement); +        a->setIcon(KIcon("tools-report-bug")); +        a->setText(i18n("&Inspect Element")); +        s_webActionCollection->addAction(QLatin1String("inspect_element"), a); +    } + +    return s_webActionCollection; +} + + +void WebView::contextMenuEvent(QContextMenuEvent *event) +{ +    QWebHitTestResult result = page()->mainFrame()->hitTestContent(event->pos()); +    MainWindow *mainwindow = Application::instance()->mainWindow(); + +    QAction *addBookmarkAction = Application::bookmarkProvider()->actionByName("add_bookmark_payload"); +    addBookmarkAction->setText(i18n("Bookmark This Page")); +    addBookmarkAction->setData(QVariant()); +    KMenu menu(this); + +    bool linkIsEmpty = result.linkUrl().isEmpty(); +    if (!linkIsEmpty) +    { +        menu.addAction(webActions()->action("open_link_in_new_tab")); +    } +    else +    { +        menu.addAction(mainwindow->actionByName("new_tab")); +    } +    menu.addAction(mainwindow->actionByName("view_redisplay")); +    menu.addSeparator(); + +    if (page()->settings()->testAttribute(QWebSettings::DeveloperExtrasEnabled)) +    { +        menu.addAction(webActions()->action("inspect_element")); +        menu.addSeparator(); +    } + +    menu.addAction(mainwindow->actionByName("history_back")); +    menu.addAction(mainwindow->actionByName("history_forward")); +    menu.addSeparator(); + +    if (result.isContentSelected() && result.isContentEditable()) +    { +        menu.addAction(webActions()->action("edit_cut")); +    } + +    if (result.isContentSelected()) +    { +        menu.addAction(webActions()->action("edit_copy")); +    } + +    if (result.isContentEditable()) +    { +        menu.addAction(webActions()->action("edit_paste")); +    } + +    if (!linkIsEmpty) +    { +        menu.addSeparator(); +        if (!result.pixmap().isNull()) +        { +            // TODO Add "View Image" +            menu.addAction(webActions()->action("save_image_as")); +            menu.addAction(webActions()->action("copy_this_image")); +        } +        menu.addAction(webActions()->action("save_link_as")); +        menu.addAction(webActions()->action("copy_link_location")); +        addBookmarkAction->setData(result.linkUrl()); +        addBookmarkAction->setText(i18n("&Bookmark This Link")); +    } +    menu.addSeparator(); + +    menu.addAction(addBookmarkAction); +    menu.exec(mapToGlobal(event->pos())); +} + + +void WebView::wheelEvent(QWheelEvent *event) +{ +    if (QApplication::keyboardModifiers() & Qt::ControlModifier) +    { +        int numDegrees = event->delta() / 8; +        int numSteps = numDegrees / 15; +        setTextSizeMultiplier(textSizeMultiplier() + numSteps * 0.1); +        event->accept(); +        return; +    } +    QWebView::wheelEvent(event); +} + + +void WebView::openLinkInNewTab() +{ +    m_page->m_openInNewTab = true; +    pageAction(QWebPage::OpenLinkInNewWindow)->trigger(); +} + + +void WebView::loadFinished() +{ +    if (m_progress != 100) +    { +        kWarning() << "Recieved finished signal while progress is still:" << progress() +        << "Url:" << url(); +    } +    m_progress = 0; +} + + +void WebView::mousePressEvent(QMouseEvent *event) +{ +    m_page->m_pressedButtons = event->buttons(); +    m_page->m_keyboardModifiers = event->modifiers(); +    QWebView::mousePressEvent(event); +} + + +void WebView::mouseReleaseEvent(QMouseEvent *event) +{ +    QWebView::mouseReleaseEvent(event); +    if (!event->isAccepted() && (m_page->m_pressedButtons & Qt::MidButton)) +    { +        KUrl url(QApplication::clipboard()->text(QClipboard::Selection)); +        if (!url.isEmpty() && url.isValid() && !url.scheme().isEmpty()) +        { +            setUrl(url); +        } +    } +} + + +void WebView::downloadRequested(const QNetworkRequest &request) +{ +    KUrl srcUrl = request.url(); +    QString path = ReKonfig::downloadDir() + QString("/") + srcUrl.fileName(); +    KUrl destUrl = KUrl(path); +    Application::downloadManager()->newDownload(srcUrl); +} + + +void WebView::keyPressEvent(QKeyEvent *event) +{ +    if ((event->modifiers() == Qt::ControlModifier) && (event->key() == Qt::Key_Tab)) +    { +        emit ctrlTabPressed(); +        return; +    } + +    if ((event->modifiers() == Qt::ControlModifier + Qt::ShiftModifier) && (event->key() == Qt::Key_Backtab)) +    { +        emit shiftCtrlTabPressed(); +        return; +    } + +    QWebView::keyPressEvent(event); +} diff --git a/src/webview.h b/src/webview.h new file mode 100644 index 00000000..11f04571 --- /dev/null +++ b/src/webview.h @@ -0,0 +1,155 @@ +/* ============================================================ +* +* This file is a part of the rekonq project +* +* Copyright (C) 2007-2008 Trolltech ASA. All rights reserved +* Copyright (C) 2008 Benjamin C. Meyer <ben@meyerhome.net> +* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2009 by Paweł Prażak <pawelprazak 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, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* ============================================================ */ + + +#ifndef WEBVIEW_H +#define WEBVIEW_H + +// KDE Includes +#include <KUrl> + +// Qt Includes +#include <QWebPage> + +// Forward Declarations +class MainWindow; +class Application; + +class KActionCollection; + +class QWebFrame; +class QAuthenticator; +class QMouseEvent; +class QNetworkProxy; +class QNetworkReply; +class QSslError; + + +class WebPage : public QWebPage +{ +    Q_OBJECT + +signals: +    void loadingUrl(const QUrl &url);   // WARNING has to be QUrl!! + +public: +    WebPage(QObject *parent = 0); +    ~WebPage(); + +protected: +    bool acceptNavigationRequest(QWebFrame *frame, +                                 const QNetworkRequest &request, +                                 NavigationType type); + +    QWebPage *createWindow(QWebPage::WebWindowType type); +    QObject *createPlugin(const QString &classId, +                          const QUrl &url, +                          const QStringList ¶mNames, +                          const QStringList ¶mValues); + +private slots: +    void handleUnsupportedContent(QNetworkReply *reply); + +private: +    friend class WebView; + +    // set the webview mousepressedevent +    Qt::KeyboardModifiers m_keyboardModifiers; +    Qt::MouseButtons m_pressedButtons; +    bool m_openInNewTab; +    KUrl m_loadingUrl; +}; + + +// ---------------------------------------------------------------------------------------------------- + +// Qt Includes +#include <QWebView> + + +class WebView : public QWebView +{ +    Q_OBJECT + +public: +    WebView(QWidget *parent = 0); + +    KActionCollection* webActions(); + +    // inline +    WebPage *webPage() const +    { +        return m_page; +    } +    KUrl url() const +    { +        return KUrl(QWebView::url()); +    } +    QString lastStatusBarText() const +    { +        return m_statusBarText; +    } +    int progress() const +    { +        return m_progress; +    } + +signals: +    // switching tabs +    void ctrlTabPressed(); +    void shiftCtrlTabPressed(); + +protected: +    void mousePressEvent(QMouseEvent *event); +    void mouseReleaseEvent(QMouseEvent *event); +    void contextMenuEvent(QContextMenuEvent *event); +    void wheelEvent(QWheelEvent *event); + +    /** +    * Filters (SHIFT + ) CTRL + TAB events and emit (shift)ctrlTabPressed() +    * to make switch tab +    */ +    void keyPressEvent(QKeyEvent *event); + +private slots: +    void setProgress(int progress) +    { +        m_progress = progress; +    } +    void loadFinished(); +    void setStatusBarText(const QString &string) +    { +        m_statusBarText = string; +    } +    void downloadRequested(const QNetworkRequest &request); +    void openLinkInNewTab(); + +private: +    static KActionCollection* s_webActionCollection; + +    WebPage *m_page; + +    int m_progress; +    QString m_statusBarText; +}; + +#endif  | 
