diff options
| author | Andrea Diamantini <adjam7@gmail.com> | 2009-08-27 00:54:58 +0200 | 
|---|---|---|
| committer | Andrea Diamantini <adjam7@gmail.com> | 2009-08-27 00:54:58 +0200 | 
| commit | 3d21fd31fddfc1260d44b5b3507bb6a6e8b8a243 (patch) | |
| tree | 80f8d9933361d51f4a1aaadd8b9d993896b66321 /src | |
| parent | Some fixes icon related (diff) | |
| parent | Adding comments (diff) | |
| download | rekonq-3d21fd31fddfc1260d44b5b3507bb6a6e8b8a243.tar.xz | |
Merge branch 'historyKDE' into develop
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/history.cpp | 924 | ||||
| -rw-r--r-- | src/history.h | 209 | ||||
| -rw-r--r-- | src/historymenu.h | 1 | ||||
| -rw-r--r-- | src/historymodels.cpp | 977 | ||||
| -rw-r--r-- | src/historymodels.h | 255 | ||||
| -rw-r--r-- | src/main.cpp | 3 | ||||
| -rw-r--r-- | src/panelhistory.h | 2 | ||||
| -rw-r--r-- | src/urlbar.cpp | 2 | 
9 files changed, 1240 insertions, 1134 deletions
| diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67a0c8df..7a6c93e5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,7 @@ SET( rekonq_SRCS      tabbar.cpp      cookiejar.cpp      history.cpp +    historymodels.cpp      historymenu.cpp      bookmarks.cpp      modelmenu.cpp  diff --git a/src/history.cpp b/src/history.cpp index da13b3d0..574b0cf2 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -34,6 +34,7 @@  #include "rekonq.h"  // Local Includes +#include "historymodels.h"  #include "autosaver.h"  #include "application.h" @@ -97,12 +98,14 @@ QList<HistoryItem> HistoryManager::history() const  } +// TODO port to KDE history  bool HistoryManager::historyContains(const QString &url) const  {      return m_historyFilterModel->historyContains(url);  } +// TODO port to KDE history  void HistoryManager::addHistoryEntry(const QString &url)  {      QUrl cleanUrl(url); @@ -418,924 +421,3 @@ void HistoryManager::save()      }      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::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 20 - - -/* -    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); -} - - -// -------------------------------------------------------------------------------------------------------------- - - -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); -} - - -// ------------------------------------------------------------------------------------------------------------- - - -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 index d127402a..24e4fea9 100644 --- a/src/history.h +++ b/src/history.h @@ -146,213 +146,4 @@ private:  }; -// -------------------------------------------------------------------------------------------------------- - - -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 -    }; - -    explicit 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: -    explicit 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: -    explicit 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; -}; - - -// ---------------------------------------------------------------------------------------- - -/** - * 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: -    explicit 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; -}; - -  #endif // HISTORY_H diff --git a/src/historymenu.h b/src/historymenu.h index a6bb77d6..0237777f 100644 --- a/src/historymenu.h +++ b/src/historymenu.h @@ -30,6 +30,7 @@  // Local Includes  #include "history.h" +#include "historymodels.h"  // Qt Includes  #include <QtCore/QList> diff --git a/src/historymodels.cpp b/src/historymodels.cpp new file mode 100644 index 00000000..5209670b --- /dev/null +++ b/src/historymodels.cpp @@ -0,0 +1,977 @@ +/* ============================================================ +* +* 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 "historymodels.h" +#include "historymodels.moc" + +// Auto Includes +#include "rekonq.h" + +// Local Includes +#include "application.h" + +// KDE Includes +#include <KDebug> +#include <KStandardDirs> +#include <KLocale> + +// 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> + + + +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::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 20 + + +/* +    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); +} + + +// -------------------------------------------------------------------------------------------------------------- + + +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); +} + + +// ------------------------------------------------------------------------------------------------------------- + + +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/historymodels.h b/src/historymodels.h new file mode 100644 index 00000000..d6a04826 --- /dev/null +++ b/src/historymodels.h @@ -0,0 +1,255 @@ +/* ============================================================ +* +* 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/>. +* +* ============================================================ */ + + +#ifndef HISTORYMODELS_H +#define HISTORYMODELS_H + +// Local Includes +#include "history.h" +#include "modelmenu.h" + +// KDE Includes +#include <KUrl> + +// Qt Includes +#include <QDateTime> +#include <QHash> +#include <QObject> +#include <QTimer> +#include <QSortFilterProxyModel> +#include <QWebHistoryInterface> + + + +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 +    }; + +    explicit 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: +    explicit 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: +    explicit 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; +}; + + +// ---------------------------------------------------------------------------------------- + +/** + * 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: +    explicit 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; +}; + + +#endif // HISTORYMODELS_H diff --git a/src/main.cpp b/src/main.cpp index 2c3d797c..a6654774 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,8 +50,7 @@ int main(int argc, char **argv)                       KAboutData::License_GPL_V3,                       ki18n("(C) 2008-2009 Andrea Diamantini"),                       KLocalizedString(), -                     "http://rekonq.sourceforge.net", -                     "rekonq@kde.org" +                     "http://rekonq.sourceforge.net"                      );      // --------------- about authors ----------------------------- diff --git a/src/panelhistory.h b/src/panelhistory.h index 84aceba1..81beefb5 100644 --- a/src/panelhistory.h +++ b/src/panelhistory.h @@ -30,7 +30,7 @@  // Local Includes  #include "application.h" -#include "history.h" +#include "historymodels.h"  // Qt Includes  #include <QtGui/QWidget> diff --git a/src/urlbar.cpp b/src/urlbar.cpp index 05a4ad9a..24df96f7 100644 --- a/src/urlbar.cpp +++ b/src/urlbar.cpp @@ -33,7 +33,7 @@  // Local Includes  #include "application.h" -#include "history.h" +#include "historymodels.h"  #include "lineedit.h"  #include "mainwindow.h"  #include "webview.h" | 
