diff options
| author | Andrea Diamantini <adjam7@gmail.com> | 2009-11-27 02:21:04 +0100 | 
|---|---|---|
| committer | Andrea Diamantini <adjam7@gmail.com> | 2009-11-27 02:21:04 +0100 | 
| commit | 997d64c9743149b2b400891b09ab99e9613bf273 (patch) | |
| tree | 98cb23b7331e4ffd2e760fb37b682df3ad7589db /src/history/historymanager.cpp | |
| parent | rekonq 0.3.14 (diff) | |
| download | rekonq-997d64c9743149b2b400891b09ab99e9613bf273.tar.xz | |
Last structure change, promised!
Anyway, this moving/renaming helped me finding lots of strange circulary
dependencies and easily solve them :)
We have also a more organized structure, hopefully letting people work on different areas
altogether.
Diffstat (limited to 'src/history/historymanager.cpp')
| -rw-r--r-- | src/history/historymanager.cpp | 454 | 
1 files changed, 454 insertions, 0 deletions
| diff --git a/src/history/historymanager.cpp b/src/history/historymanager.cpp new file mode 100644 index 00000000..29bdb45b --- /dev/null +++ b/src/history/historymanager.cpp @@ -0,0 +1,454 @@ +/* ============================================================ +* +* 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 of +* the License or (at your option) version 3 or any later version +* accepted by the membership of KDE e.V. (or its successor approved +* by the membership of KDE e.V.), which shall act as a proxy  +* defined in Section 14 of version 3 of the license. +*  +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program.  If not, see <http://www.gnu.org/licenses/>. +* +* ============================================================ */ + + +// Self Includes +#include "historymanager.h" +#include "historymanager.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "historymodels.h" +#include "autosaver.h" +#include "application.h" + +// KDE Includes +#include <KStandardDirs> +#include <KLocale> +#include <KCompletion> + +// Qt Includes +#include <QtCore/QList> +#include <QtCore/QUrl> +#include <QtCore/QDate> +#include <QtCore/QDateTime> +#include <QtCore/QString> +#include <QtCore/QFile> +#include <QtCore/QDataStream> +#include <QtCore/QBuffer> + +#include <QtGui/QClipboard> + +// generic algorithms +#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_completion(0) +{ +    // take care of the completion object +    m_completion = new KCompletion; +    m_completion->setOrder( KCompletion::Weighted ); +     +    m_expiredTimer.setSingleShot(true); +    connect(&m_expiredTimer, SIGNAL(timeout()), this, SLOT(checkForExpired())); +    connect(this, SIGNAL(entryAdded(const HistoryItem &)), m_saveTimer, SLOT(changeOccurred())); +    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(); +    delete m_completion; +} + + +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); +     +    // don't store about: urls (home page related) +    if(cleanUrl.scheme() == QString("about")) +        return; +     +    cleanUrl.setPassword(QString()); +    cleanUrl.setHost(cleanUrl.host().toLower()); +    HistoryItem item(cleanUrl.toString(), QDateTime::currentDateTime()); +    addHistoryEntry(item); + +    // Add item to completion object +    QString _url(url); +    _url.remove(QRegExp("^http://|/$")); +    m_completion->addItem(_url); +} + + +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.clear(); +        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.clear(); +        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; +        } +    } +     +    // Remove item from completion object +    QString _url = url.path(); +    _url.remove(QRegExp("^http://|/$")); +    m_completion->removeItem(_url); +} + + +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.clear(); +    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; + +        // Add item to completion object +        QString _url = item.url; +        _url.remove(QRegExp("^http://|/$")); +        m_completion->addItem(_url); +    } +    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.clear(); +        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; +} + + +KCompletion * HistoryManager::completionObject() const +{ +    return m_completion; +} | 
