1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2015 The Qt Company Ltd. 4 ** Contact: http://www.qt.io/licensing/ 5 ** 6 ** This file is part of the demonstration applications of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:LGPL$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see http://www.qt.io/terms-conditions. For further 15 ** information use the contact form at http://www.qt.io/contact-us. 16 ** 17 ** GNU Lesser General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU Lesser 19 ** General Public License version 2.1 or version 3 as published by the Free 20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 22 ** following information to ensure the GNU Lesser General Public License 23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 25 ** 26 ** As a special exception, The Qt Company gives you certain additional 27 ** rights. These rights are described in The Qt Company LGPL Exception 28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 29 ** 30 ** GNU General Public License Usage 31 ** Alternatively, this file may be used under the terms of the GNU 32 ** General Public License version 3.0 as published by the Free Software 33 ** Foundation and appearing in the file LICENSE.GPL included in the 34 ** packaging of this file. Please review the following information to 35 ** ensure the GNU General Public License version 3.0 requirements will be 36 ** met: http://www.gnu.org/copyleft/gpl.html. 37 ** 38 ** $QT_END_LICENSE$ 39 ** 40 ****************************************************************************/ 41 42 #ifndef HISTORY_H 43 #define HISTORY_H 44 45 #include "modelmenu.h" 46 47 #include <QtCore/QDateTime> 48 #include <QtCore/QHash> 49 #include <QtCore/QObject> 50 #include <QtCore/QTimer> 51 #include <QtCore/QUrl> 52 53 #include <QtGui/QSortFilterProxyModel> 54 55 #include <QWebHistoryInterface> 56 57 class HistoryItem 58 { 59 public: HistoryItem()60 HistoryItem() {} 61 HistoryItem(const QString &u, 62 const QDateTime &d = QDateTime(), const QString &t = QString()) title(t)63 : title(t), url(u), dateTime(d) {} 64 65 inline bool operator==(const HistoryItem &other) const 66 { return other.title == title 67 && other.url == url && other.dateTime == dateTime; } 68 69 // history is sorted in reverse 70 inline bool operator <(const HistoryItem &other) const 71 { return dateTime > other.dateTime; } 72 73 QString title; 74 QString url; 75 QDateTime dateTime; 76 }; 77 78 class AutoSaver; 79 class HistoryModel; 80 class HistoryFilterModel; 81 class HistoryTreeModel; 82 class HistoryManager : public QWebHistoryInterface 83 { 84 Q_OBJECT 85 Q_PROPERTY(int historyLimit READ historyLimit WRITE setHistoryLimit) 86 87 signals: 88 void historyReset(); 89 void entryAdded(const HistoryItem &item); 90 void entryRemoved(const HistoryItem &item); 91 void entryUpdated(int offset); 92 93 public: 94 HistoryManager(QObject *parent = 0); 95 ~HistoryManager(); 96 97 bool historyContains(const QString &url) const; 98 void addHistoryEntry(const QString &url); 99 100 void updateHistoryItem(const QUrl &url, const QString &title); 101 102 int historyLimit() const; 103 void setHistoryLimit(int limit); 104 105 QList<HistoryItem> history() const; 106 void setHistory(const QList<HistoryItem> &history, bool loadedAndSorted = false); 107 108 // History manager keeps around these models for use by the completer and other classes 109 HistoryModel *historyModel() const; 110 HistoryFilterModel *historyFilterModel() const; 111 HistoryTreeModel *historyTreeModel() const; 112 113 public slots: 114 void clear(); 115 void loadSettings(); 116 117 private slots: 118 void save(); 119 void checkForExpired(); 120 121 protected: 122 void addHistoryItem(const HistoryItem &item); 123 124 private: 125 void load(); 126 127 AutoSaver *m_saveTimer; 128 int m_historyLimit; 129 QTimer m_expiredTimer; 130 QList<HistoryItem> m_history; 131 QString m_lastSavedUrl; 132 133 HistoryModel *m_historyModel; 134 HistoryFilterModel *m_historyFilterModel; 135 HistoryTreeModel *m_historyTreeModel; 136 }; 137 138 class HistoryModel : public QAbstractTableModel 139 { 140 Q_OBJECT 141 142 public slots: 143 void historyReset(); 144 void entryAdded(); 145 void entryUpdated(int offset); 146 147 public: 148 enum Roles { 149 DateRole = Qt::UserRole + 1, 150 DateTimeRole = Qt::UserRole + 2, 151 UrlRole = Qt::UserRole + 3, 152 UrlStringRole = Qt::UserRole + 4 153 }; 154 155 HistoryModel(HistoryManager *history, QObject *parent = 0); 156 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; 157 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 158 int columnCount(const QModelIndex &parent = QModelIndex()) const; 159 int rowCount(const QModelIndex &parent = QModelIndex()) const; 160 bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); 161 162 private: 163 HistoryManager *m_history; 164 }; 165 166 /*! 167 Proxy model that will remove any duplicate entries. 168 Both m_sourceRow and m_historyHash store their offsets not from 169 the front of the list, but as offsets from the back. 170 */ 171 class HistoryFilterModel : public QAbstractProxyModel 172 { 173 Q_OBJECT 174 175 public: 176 HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent = 0); 177 historyContains(const QString & url)178 inline bool historyContains(const QString &url) const 179 { load(); return m_historyHash.contains(url); } 180 int historyLocation(const QString &url) const; 181 182 QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; 183 QModelIndex mapToSource(const QModelIndex &proxyIndex) const; 184 void setSourceModel(QAbstractItemModel *sourceModel); 185 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; 186 int rowCount(const QModelIndex &parent = QModelIndex()) const; 187 int columnCount(const QModelIndex &parent = QModelIndex()) const; 188 QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const; 189 QModelIndex parent(const QModelIndex& index= QModelIndex()) const; 190 bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); 191 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 192 193 private slots: 194 void sourceReset(); 195 void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); 196 void sourceRowsInserted(const QModelIndex &parent, int start, int end); 197 void sourceRowsRemoved(const QModelIndex &, int, int); 198 199 private: 200 void load() const; 201 202 mutable QList<int> m_sourceRow; 203 mutable QHash<QString, int> m_historyHash; 204 mutable bool m_loaded; 205 }; 206 207 /* 208 The history menu 209 - Removes the first twenty entries and puts them as children of the top level. 210 - If there are less then twenty entries then the first folder is also removed. 211 212 The mapping is done by knowing that HistoryTreeModel is over a table 213 We store that row offset in our index's private data. 214 */ 215 class HistoryMenuModel : public QAbstractProxyModel 216 { 217 Q_OBJECT 218 219 public: 220 HistoryMenuModel(HistoryTreeModel *sourceModel, QObject *parent = 0); 221 int columnCount(const QModelIndex &parent) const; 222 int rowCount(const QModelIndex &parent = QModelIndex()) const; 223 QModelIndex mapFromSource(const QModelIndex & sourceIndex) const; 224 QModelIndex mapToSource(const QModelIndex & proxyIndex) const; 225 QModelIndex index(int, int, const QModelIndex &parent = QModelIndex()) const; 226 QModelIndex parent(const QModelIndex &index = QModelIndex()) const; 227 228 int bumpedRows() const; 229 230 private: 231 HistoryTreeModel *m_treeModel; 232 }; 233 234 // Menu that is dynamically populated from the history 235 class HistoryMenu : public ModelMenu 236 { 237 Q_OBJECT 238 239 signals: 240 void openUrl(const QUrl &url); 241 242 public: 243 HistoryMenu(QWidget *parent = 0); 244 void setInitialActions(QList<QAction*> actions); 245 246 protected: 247 bool prePopulated(); 248 void postPopulated(); 249 250 private slots: 251 void activated(const QModelIndex &index); 252 void showHistoryDialog(); 253 254 private: 255 HistoryManager *m_history; 256 HistoryMenuModel *m_historyMenuModel; 257 QList<QAction*> m_initialActions; 258 }; 259 260 // proxy model for the history model that 261 // exposes each url http://www.foo.com and it url starting at the host www.foo.com 262 class HistoryCompletionModel : public QAbstractProxyModel 263 { 264 Q_OBJECT 265 266 public: 267 HistoryCompletionModel(QObject *parent = 0); 268 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 269 int rowCount(const QModelIndex &parent = QModelIndex()) const; 270 int columnCount(const QModelIndex &parent = QModelIndex()) const; 271 QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; 272 QModelIndex mapToSource(const QModelIndex &proxyIndex) const; 273 QModelIndex index(int, int, const QModelIndex& = QModelIndex()) const; 274 QModelIndex parent(const QModelIndex& index= QModelIndex()) const; 275 void setSourceModel(QAbstractItemModel *sourceModel); 276 277 private slots: 278 void sourceReset(); 279 280 }; 281 282 // proxy model for the history model that converts the list 283 // into a tree, one top level node per day. 284 // Used in the HistoryDialog. 285 class HistoryTreeModel : public QAbstractProxyModel 286 { 287 Q_OBJECT 288 289 public: 290 HistoryTreeModel(QAbstractItemModel *sourceModel, QObject *parent = 0); 291 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 292 int columnCount(const QModelIndex &parent) const; 293 int rowCount(const QModelIndex &parent = QModelIndex()) const; 294 QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; 295 QModelIndex mapToSource(const QModelIndex &proxyIndex) const; 296 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; 297 QModelIndex parent(const QModelIndex &index= QModelIndex()) const; 298 bool hasChildren(const QModelIndex &parent = QModelIndex()) const; 299 Qt::ItemFlags flags(const QModelIndex &index) const; 300 bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); 301 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; 302 303 void setSourceModel(QAbstractItemModel *sourceModel); 304 305 private slots: 306 void sourceReset(); 307 void sourceRowsInserted(const QModelIndex &parent, int start, int end); 308 void sourceRowsRemoved(const QModelIndex &parent, int start, int end); 309 310 private: 311 int sourceDateRow(int row) const; 312 mutable QList<int> m_sourceRowCache; 313 314 }; 315 316 // A modified QSortFilterProxyModel that always accepts the root nodes in the tree 317 // so filtering is only done on the children. 318 // Used in the HistoryDialog 319 class TreeProxyModel : public QSortFilterProxyModel 320 { 321 Q_OBJECT 322 323 public: 324 TreeProxyModel(QObject *parent = 0); 325 326 protected: 327 bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; 328 }; 329 330 #include "ui_history.h" 331 332 class HistoryDialog : public QDialog, public Ui_HistoryDialog 333 { 334 Q_OBJECT 335 336 signals: 337 void openUrl(const QUrl &url); 338 339 public: 340 HistoryDialog(QWidget *parent = 0, HistoryManager *history = 0); 341 342 private slots: 343 void customContextMenuRequested(const QPoint &pos); 344 void open(); 345 void copy(); 346 347 }; 348 349 #endif // HISTORY_H 350 351