summaryrefslogtreecommitdiffstats
path: root/examples/webenginewidgets/demobrowser/history.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/webenginewidgets/demobrowser/history.cpp')
-rw-r--r--examples/webenginewidgets/demobrowser/history.cpp1314
1 files changed, 0 insertions, 1314 deletions
diff --git a/examples/webenginewidgets/demobrowser/history.cpp b/examples/webenginewidgets/demobrowser/history.cpp
deleted file mode 100644
index 22bb243e9..000000000
--- a/examples/webenginewidgets/demobrowser/history.cpp
+++ /dev/null
@@ -1,1314 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "history.h"
-
-#include "autosaver.h"
-#include "browserapplication.h"
-
-#include <QtCore/QBuffer>
-#include <QtCore/QDir>
-#include <QtCore/QFile>
-#include <QtCore/QFileInfo>
-#include <QtCore/QSettings>
-#include <QtCore/QTemporaryFile>
-#include <QtCore/QTextStream>
-
-#include <QtCore/QtAlgorithms>
-
-#include <QtGui/QClipboard>
-#include <QtGui/QDesktopServices>
-#include <QtWidgets/QHeaderView>
-#include <QtWidgets/QStyle>
-
-#include <QWebEngineSettings>
-
-#include <QtCore/QDebug>
-
-static const unsigned int HISTORY_VERSION = 23;
-
-HistoryManager::HistoryManager(QObject *parent)
- : QObject(parent)
- , m_saveTimer(new AutoSaver(this))
- , m_historyLimit(30)
- , m_historyModel(0)
- , m_historyFilterModel(0)
- , m_historyTreeModel(0)
-{
- m_expiredTimer.setSingleShot(true);
- connect(&m_expiredTimer, SIGNAL(timeout()),
- this, SLOT(checkForExpired()));
- connect(this, SIGNAL(entryAdded(HistoryItem)),
- m_saveTimer, SLOT(changeOccurred()));
- connect(this, SIGNAL(entryRemoved(HistoryItem)),
- m_saveTimer, SLOT(changeOccurred()));
- load();
-
- m_historyModel = new HistoryModel(this, this);
- m_historyFilterModel = new HistoryFilterModel(m_historyModel, this);
- m_historyTreeModel = new HistoryTreeModel(m_historyFilterModel, this);
-}
-
-HistoryManager::~HistoryManager()
-{
- m_saveTimer->saveIfNeccessary();
-}
-
-QList<HistoryItem> &HistoryManager::history()
-{
- return m_history;
-}
-
-bool HistoryManager::historyContains(const QString &url) const
-{
- return m_historyFilterModel->historyContains(url);
-}
-
-void HistoryManager::addHistoryEntry(const QString &url)
-{
- QUrl cleanUrl(url);
- cleanUrl.setPassword(QString());
- cleanUrl.setHost(cleanUrl.host().toLower());
- HistoryItem item(cleanUrl.toString(), QDateTime::currentDateTime());
- addHistoryItem(item);
-}
-
-void HistoryManager::removeHistoryEntry(const QString &url)
-{
- QUrl cleanUrl(url);
- cleanUrl.setPassword(QString());
- cleanUrl.setHost(cleanUrl.host().toLower());
- HistoryItem item(cleanUrl.toString(), QDateTime::currentDateTime());
- removeHistoryItem(item);
-}
-
-void HistoryManager::setHistory(const QList<HistoryItem> &history, bool loadedAndSorted)
-{
- m_history = history;
-
- // verify that it is sorted by date
- if (!loadedAndSorted)
- qSort(m_history.begin(), m_history.end());
-
- checkForExpired(loadedAndSorted);
-
- if (loadedAndSorted) {
- m_lastSavedUrl = m_history.value(0).url;
- } else {
- m_lastSavedUrl = QString();
- m_saveTimer->changeOccurred();
- }
- emit historyReset();
-}
-
-HistoryModel *HistoryManager::historyModel() const
-{
- return m_historyModel;
-}
-
-HistoryFilterModel *HistoryManager::historyFilterModel() const
-{
- return m_historyFilterModel;
-}
-
-HistoryTreeModel *HistoryManager::historyTreeModel() const
-{
- return m_historyTreeModel;
-}
-
-void HistoryManager::checkForExpired(bool removeEntriesDirectly)
-{
- if (m_historyLimit < 0 || m_history.isEmpty())
- return;
-
- QDateTime now = QDateTime::currentDateTime();
- int nextTimeout = 0;
-
- while (!m_history.isEmpty()) {
- QDateTime checkForExpired = m_history.last().dateTime;
- checkForExpired.setDate(checkForExpired.date().addDays(m_historyLimit));
- if (now.daysTo(checkForExpired) > 7) {
- // check at most in a week to prevent int overflows on the timer
- nextTimeout = 7 * 86400;
- } else {
- nextTimeout = now.secsTo(checkForExpired);
- }
- if (nextTimeout > 0)
- break;
- const HistoryItem& item = m_history.last();
- // remove from saved file also
- m_lastSavedUrl = QString();
-
- if (removeEntriesDirectly)
- m_history.takeLast();
- else
- emit entryRemoved(item);
- }
-
- if (nextTimeout > 0)
- m_expiredTimer.start(nextTimeout * 1000);
-}
-
-void HistoryManager::addHistoryItem(const HistoryItem &item)
-{
- if (BrowserApplication::instance()->privateBrowsing())
- return;
-
- emit entryAdded(item);
- if (m_history.count() == 1)
- checkForExpired();
-}
-
-void HistoryManager::removeHistoryItem(const HistoryItem &item)
-{
- for (int i = m_history.count() - 1 ; i >= 0; --i) {
- if (item.url == m_history.at(i).url) {
- //delete all related entries with that url
- emit entryRemoved(m_history.at(i));
- }
- }
-}
-
-void HistoryManager::updateHistoryItem(const QUrl &url, const QString &title)
-{
- for (int i = 0; i < m_history.count(); ++i) {
- if (url == m_history.at(i).url) {
- m_history[i].title = title;
- m_saveTimer->changeOccurred();
- if (m_lastSavedUrl.isEmpty())
- m_lastSavedUrl = m_history.at(i).url;
- emit entryUpdated(i);
- break;
- }
- }
-}
-
-int HistoryManager::historyLimit() const
-{
- return m_historyLimit;
-}
-
-void HistoryManager::setHistoryLimit(int limit)
-{
- if (m_historyLimit == limit)
- return;
- m_historyLimit = limit;
- checkForExpired();
- m_saveTimer->changeOccurred();
-}
-
-void HistoryManager::clear()
-{
- m_lastSavedUrl = QString();
- emit historyReset();
- m_saveTimer->changeOccurred();
- m_saveTimer->saveIfNeccessary();
-}
-
-void HistoryManager::loadSettings()
-{
- // load settings
- QSettings settings;
- settings.beginGroup(QLatin1String("history"));
- m_historyLimit = settings.value(QLatin1String("historyLimit"), 30).toInt();
-}
-
-void HistoryManager::load()
-{
- loadSettings();
-
- QFile historyFile(QStandardPaths::writableLocation(QStandardPaths::DataLocation)
- + QLatin1String("/history"));
- if (!historyFile.exists())
- return;
- if (!historyFile.open(QFile::ReadOnly)) {
- qWarning() << "Unable to open history file" << historyFile.fileName();
- return;
- }
-
- QList<HistoryItem> list;
- QDataStream in(&historyFile);
- // Double check that the history file is sorted as it is read in
- bool needToSort = false;
- HistoryItem lastInsertedItem;
- QByteArray data;
- QDataStream stream;
- QBuffer buffer;
- stream.setDevice(&buffer);
- while (!historyFile.atEnd()) {
- in >> data;
- buffer.close();
- buffer.setBuffer(&data);
- buffer.open(QIODevice::ReadOnly);
- quint32 ver;
- stream >> ver;
- if (ver != HISTORY_VERSION)
- continue;
- HistoryItem item;
- stream >> item.url;
- stream >> item.dateTime;
- stream >> item.title;
-
- if (!item.dateTime.isValid())
- continue;
-
- if (item == lastInsertedItem) {
- if (lastInsertedItem.title.isEmpty() && !list.isEmpty())
- list[0].title = item.title;
- continue;
- }
-
- if (!needToSort && !list.isEmpty() && lastInsertedItem < item)
- needToSort = true;
-
- list.prepend(item);
- lastInsertedItem = item;
- }
- if (needToSort)
- qSort(list.begin(), list.end());
-
- setHistory(list, true);
-
- // If we had to sort re-write the whole history sorted
- if (needToSort) {
- m_lastSavedUrl = QString();
- m_saveTimer->changeOccurred();
- }
-}
-
-void HistoryManager::save()
-{
- QSettings settings;
- settings.beginGroup(QLatin1String("history"));
- settings.setValue(QLatin1String("historyLimit"), m_historyLimit);
-
- bool saveAll = m_lastSavedUrl.isEmpty();
- int first = m_history.count() - 1;
- if (!saveAll) {
- // find the first one to save
- for (int i = 0; i < m_history.count(); ++i) {
- if (m_history.at(i).url == m_lastSavedUrl) {
- first = i - 1;
- break;
- }
- }
- }
- if (first == m_history.count() - 1)
- saveAll = true;
-
- QString directory = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
- if (directory.isEmpty())
- directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
- if (!QFile::exists(directory)) {
- QDir dir;
- dir.mkpath(directory);
- }
-
- QFile historyFile(directory + QLatin1String("/history"));
- // When saving everything use a temporary file to prevent possible data loss.
- QTemporaryFile tempFile;
- tempFile.setAutoRemove(false);
- bool open = false;
- if (saveAll) {
- open = tempFile.open();
- } else {
- open = historyFile.open(QFile::Append);
- }
-
- if (!open) {
- qWarning() << "Unable to open history file for saving"
- << (saveAll ? tempFile.fileName() : historyFile.fileName());
- return;
- }
-
- QDataStream out(saveAll ? &tempFile : &historyFile);
- for (int i = first; i >= 0; --i) {
- QByteArray data;
- QDataStream stream(&data, QIODevice::WriteOnly);
- HistoryItem item = m_history.at(i);
- stream << HISTORY_VERSION << item.url << item.dateTime << item.title;
- out << data;
- }
- tempFile.close();
-
- if (saveAll) {
- if (historyFile.exists() && !historyFile.remove())
- qWarning() << "History: error removing old history." << historyFile.errorString();
- if (!tempFile.rename(historyFile.fileName()))
- qWarning() << "History: error moving new history over old." << tempFile.errorString() << historyFile.fileName();
- }
- 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(HistoryItem)),
- this, SLOT(entryRemoved(HistoryItem)));
-
- connect(m_history, SIGNAL(entryAdded(HistoryItem)),
- this, SLOT(entryAdded(HistoryItem)));
- connect(m_history, SIGNAL(entryUpdated(int)),
- this, SLOT(entryUpdated(int)));
-}
-
-void HistoryModel::historyReset()
-{
- beginResetModel();
- m_history->history().clear();
- endResetModel();
-}
-
-void HistoryModel::entryAdded(const HistoryItem &item)
-{
- beginInsertRows(QModelIndex(), 0, 0);
- m_history->history().prepend(item);
- endInsertRows();
-}
-
-void HistoryModel::entryRemoved(const HistoryItem &item)
-{
- int index = m_history->history().indexOf(item);
- Q_ASSERT(index > -1);
- beginRemoveRows(QModelIndex(),index, index);
- m_history->history().takeAt(index);
- endRemoveRows();
-}
-
-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 tr("Title");
- case 1: return tr("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 BrowserApplication::instance()->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);
- endRemoveRows();
- return true;
-}
-
-#define MOVEDROWS 15
-
-/*
- 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() == quintptr(-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() == quintptr(-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, quintptr(-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);
-}
-
-
-HistoryMenu::HistoryMenu(QWidget *parent)
- : ModelMenu(parent)
- , m_history(0)
-{
- connect(this, SIGNAL(activated(QModelIndex)),
- this, SLOT(activated(QModelIndex)));
- setHoverRole(HistoryModel::UrlStringRole);
-}
-
-void HistoryMenu::activated(const QModelIndex &index)
-{
- emit openUrl(index.data(HistoryModel::UrlRole).toUrl());
-}
-
-bool HistoryMenu::prePopulated()
-{
- if (!m_history) {
- m_history = BrowserApplication::historyManager();
- m_historyMenuModel = new HistoryMenuModel(m_history->historyTreeModel(), this);
- setModel(m_historyMenuModel);
- }
- // initial actions
- for (int i = 0; i < m_initialActions.count(); ++i)
- addAction(m_initialActions.at(i));
- if (!m_initialActions.isEmpty())
- addSeparator();
- setFirstSeparator(m_historyMenuModel->bumpedRows());
-
- return false;
-}
-
-void HistoryMenu::postPopulated()
-{
- if (m_history->history().count() > 0)
- addSeparator();
-
- QAction *showAllAction = new QAction(tr("Show All History"), this);
- connect(showAllAction, SIGNAL(triggered()), this, SLOT(showHistoryDialog()));
- addAction(showAllAction);
-
- QAction *clearAction = new QAction(tr("Clear History"), this);
- connect(clearAction, SIGNAL(triggered()), m_history, SLOT(clear()));
- addAction(clearAction);
-}
-
-void HistoryMenu::showHistoryDialog()
-{
- HistoryDialog *dialog = new HistoryDialog(this);
- connect(dialog, SIGNAL(openUrl(QUrl)),
- this, SIGNAL(openUrl(QUrl)));
- dialog->show();
-}
-
-void HistoryMenu::setInitialActions(QList<QAction*> actions)
-{
- m_initialActions = actions;
- for (int i = 0; i < m_initialActions.count(); ++i)
- addAction(m_initialActions.at(i));
-}
-
-TreeProxyModel::TreeProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
-{
- setSortRole(HistoryModel::DateTimeRole);
- setFilterCaseSensitivity(Qt::CaseInsensitive);
-}
-
-bool TreeProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
-{
- return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
-}
-
-HistoryDialog::HistoryDialog(QWidget *parent, HistoryManager *setHistory) : QDialog(parent)
-{
- HistoryManager *history = setHistory;
- if (!history)
- history = BrowserApplication::historyManager();
- setupUi(this);
- tree->setUniformRowHeights(true);
- tree->setSelectionBehavior(QAbstractItemView::SelectRows);
- tree->setTextElideMode(Qt::ElideMiddle);
- QAbstractItemModel *model = history->historyFilterModel();
- TreeProxyModel *proxyModel = new TreeProxyModel(this);
- connect(search, SIGNAL(textChanged(QString)),
- proxyModel, SLOT(setFilterFixedString(QString)));
- connect(removeButton, SIGNAL(clicked()), tree, SLOT(removeOne()));
- connect(removeAllButton, SIGNAL(clicked()), tree, SLOT(removeAll()));
- proxyModel->setSourceModel(model);
- proxyModel->setFilterKeyColumn(1);
- tree->setModel(proxyModel);
- tree->setSortingEnabled(true);
- tree->setExpanded(proxyModel->index(0, 0), true);
- tree->setAlternatingRowColors(true);
- QFontMetrics fm(font());
- int header = fm.width(QLatin1Char('m')) * 40;
- tree->header()->resizeSection(0, header);
- tree->header()->setStretchLastSection(true);
- connect(tree, SIGNAL(activated(QModelIndex)),
- this, SLOT(open()));
- tree->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(tree, SIGNAL(customContextMenuRequested(QPoint)),
- this, SLOT(customContextMenuRequested(QPoint)));
-}
-
-void HistoryDialog::customContextMenuRequested(const QPoint &pos)
-{
- QMenu menu;
- QModelIndex index = tree->indexAt(pos);
- index = index.sibling(index.row(), 0);
- if (index.isValid() && !tree->model()->hasChildren(index)) {
- menu.addAction(tr("Open"), this, SLOT(open()));
- menu.addSeparator();
- menu.addAction(tr("Copy"), this, SLOT(copy()));
- }
- menu.addAction(tr("Delete"), tree, SLOT(removeOne()));
- menu.exec(QCursor::pos());
-}
-
-void HistoryDialog::open()
-{
- QModelIndex index = tree->currentIndex();
- if (!index.parent().isValid())
- return;
- emit openUrl(index.data(HistoryModel::UrlRole).toUrl());
-}
-
-void HistoryDialog::copy()
-{
- QModelIndex index = tree->currentIndex();
- if (!index.parent().isValid())
- return;
- QString url = index.data(HistoryModel::UrlStringRole).toString();
-
- QClipboard *clipboard = QApplication::clipboard();
- clipboard->setText(url);
-}
-
-HistoryFilterModel::HistoryFilterModel(QAbstractItemModel *sourceModel, QObject *parent)
- : QAbstractProxyModel(parent),
- m_loaded(false)
-{
- setSourceModel(sourceModel);
-}
-
-void HistoryFilterModel::setSourceModel(QAbstractItemModel *newSourceModel)
-{
- beginResetModel();
- if (sourceModel()) {
- disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
- disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
- disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
- }
-
- QAbstractProxyModel::setSourceModel(newSourceModel);
-
- if (sourceModel()) {
- connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
- connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
- connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
- }
- load();
- endResetModel();
-}
-
-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()
-{
- beginResetModel();
- load();
- endResetModel();
-}
-
-int HistoryFilterModel::rowCount(const QModelIndex &parent) const
-{
- 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
-{
- int sourceRow = sourceModel()->rowCount() - proxyIndex.internalId();
- return sourceModel()->index(sourceRow, proxyIndex.column());
-}
-
-QModelIndex HistoryFilterModel::mapFromSource(const QModelIndex &sourceIndex) const
-{
- 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
-{
- 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
-{
- 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;
- }
- }
-}
-
-void HistoryFilterModel::sourceRowsInserted(const QModelIndex &parent, int start, int end)
-{
- Q_ASSERT(start == end && start == 0);
- Q_UNUSED(end);
- 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(QModelIndex,int,int)),
- this, SLOT(sourceRowsRemoved(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(QModelIndex,int,int)),
- this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
- m_loaded = false;
- if (oldCount - count != rowCount()) {
- beginResetModel();
- endResetModel();
- }
- 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);
-}
-
-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(QModelIndex,int,int)),
- this, SLOT(sourceReset()));
- disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(sourceReset()));
- }
-
- QAbstractProxyModel::setSourceModel(newSourceModel);
-
- if (newSourceModel) {
- connect(newSourceModel, SIGNAL(modelReset()), this, SLOT(sourceReset()));
- connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(sourceReset()));
- connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(sourceReset()));
- }
-
- beginResetModel();
- endResetModel();
-}
-
-void HistoryCompletionModel::sourceReset()
-{
- beginResetModel();
- endResetModel();
-}
-
-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 tr("Earlier Today");
- return date.toString(QLatin1String("dddd, MMMM d, yyyy"));
- }
- if (index.column() == 1) {
- return tr("%1 items").arg(rowCount(index.sibling(index.row(), 0)));
- }
- }
- }
- if (role == Qt::DecorationRole && index.column() == 0 && !index.parent().isValid())
- return QIcon(QLatin1String(":history.png"));
- 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);
- 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);
-}
-
-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)
-{
- beginResetModel();
- if (sourceModel()) {
- disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
- disconnect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(sourceReset()));
- disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
- disconnect(sourceModel(), &QAbstractItemModel::dataChanged, this,
- &HistoryTreeModel::sourceDataChanged);
- }
-
- QAbstractProxyModel::setSourceModel(newSourceModel);
-
- if (newSourceModel) {
- connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset()));
- connect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(sourceReset()));
- connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
- connect(sourceModel(), &QAbstractItemModel::dataChanged, this,
- &HistoryTreeModel::sourceDataChanged);
- }
- endResetModel();
-}
-
-void HistoryTreeModel::sourceReset()
-{
- beginResetModel();
- m_sourceRowCache.clear();
- endResetModel();
-}
-
-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) {
- beginResetModel();
- m_sourceRowCache.clear();
- endResetModel();
- 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());
- 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()) {
- beginResetModel();
- m_sourceRowCache.clear();
- endResetModel();
- 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();
- }
-}
-
-void HistoryTreeModel::sourceDataChanged(const QModelIndex &topLeft,
- const QModelIndex &bottomRight,
- const QVector<int> roles)
-{
- emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles);
-}