/**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the demonstration applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef HISTORY_H #define HISTORY_H #include "modelmenu.h" #include #include #include #include #include #include #include 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 updateHistoryItem(const QUrl &url, const QString &title); int historyLimit() const; void setHistoryLimit(int limit); QList history() const; void setHistory(const QList &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 addHistoryItem(const HistoryItem &item); private: void load(); AutoSaver *m_saveTimer; int m_historyLimit; QTimer m_expiredTimer; QList 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 m_sourceRow; mutable QHash 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 QUrl &url); public: HistoryMenu(QWidget *parent = 0); void setInitialActions(QList actions); protected: bool prePopulated(); void postPopulated(); private slots: void activated(const QModelIndex &index); void showHistoryDialog(); private: HistoryManager *m_history; HistoryMenuModel *m_historyMenuModel; QList 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 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 QUrl &url); public: HistoryDialog(QWidget *parent = 0, HistoryManager *history = 0); private slots: void customContextMenuRequested(const QPoint &pos); void open(); void copy(); }; #endif // HISTORY_H