/******************************************************************************** Copyright (C) 2010 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$** No Commercial Usage** This file contains pre-release code and may not be distributed.** You may use this file in accordance with the terms and conditions** contained in the Technology Preview License Agreement accompanying** this package.**** GNU Lesser General Public License Usage** Alternatively, 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.**** If you have questions regarding the use of this file, please contact** Nokia at qt-info@nokia.com.****************** $QT_END_LICENSE$******************************************************************************/#ifndef HISTORY_H#define HISTORY_H#include "modelmenu.h"#include <QtCore/QDateTime>#include <QtCore/QHash>#include <QtCore/QObject>#include <QtCore/QTimer>#include <QtCore/QUrl>#include <QtGui/QSortFilterProxyModel>#include <QWebHistoryInterface>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<HistoryItem> history() const; void setHistory(const QList<HistoryItem> &history, bool loadedAndSorted = false); // History manager keeps around these models for use by the completer and other classes HistoryModel *historyModel() const; HistoryFilterModel *historyFilterModel() const; HistoryTreeModel *historyTreeModel() const;public slots: void clear(); void loadSettings();private slots: void save(); void checkForExpired();protected: void addHistoryItem(const HistoryItem &item);private: void load(); AutoSaver *m_saveTimer; int m_historyLimit; QTimer m_expiredTimer; QList<HistoryItem> m_history; QString m_lastSavedUrl; HistoryModel *m_historyModel; HistoryFilterModel *m_historyFilterModel; HistoryTreeModel *m_historyTreeModel;};class HistoryModel : public QAbstractTableModel{ Q_OBJECTpublic 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_OBJECTpublic: 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_OBJECTpublic: 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 historyclass HistoryMenu : public ModelMenu{ Q_OBJECTsignals: void openUrl(const QUrl &url);public: HistoryMenu(QWidget *parent = 0); void setInitialActions(QList<QAction*> actions);protected: bool prePopulated(); void postPopulated();private slots: void activated(const QModelIndex &index); void showHistoryDialog();private: HistoryManager *m_history; HistoryMenuModel *m_historyMenuModel; QList<QAction*> m_initialActions;};// proxy model for the history model that// exposes each url http://www.foo.com and it url starting at the host www.foo.comclass HistoryCompletionModel : public QAbstractProxyModel{ Q_OBJECTpublic: 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_OBJECTpublic: 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 HistoryDialogclass TreeProxyModel : public QSortFilterProxyModel{ Q_OBJECTpublic: 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_OBJECTsignals: 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