23#include <QApplication>
28static QString dateTimeToString(
const QDateTime &dateTime)
30 const QDateTime current = QDateTime::currentDateTime();
31 if (current.date() == dateTime.date()) {
32 return dateTime.time().toString(
QSL(
"h:mm"));
35 return dateTime.toString(
QSL(
"d.M.yyyy h:mm"));
39 : QAbstractItemModel(history)
41 , m_todayItem(nullptr)
54 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
61 return tr(
"Visit Date");
63 return tr(
"Visit Count");
67 return QAbstractItemModel::headerData(section, orientation, role);
74 if (
index.row() < 0 || !item) {
88 return index.column() == 0 ? item->
title : QVariant();
89 case Qt::DecorationRole:
90 return index.column() == 0 ? QIcon::fromTheme(
QSL(
"view-calendar"), QIcon(
QSL(
":/icons/menu/history_entry.svg"))) : QVariant();
115 case Qt::ToolTipRole:
116 if (
index.column() == 0) {
120 case Qt::DisplayRole:
122 switch (
index.column()) {
128 return dateTimeToString(entry.
date);
133 case Qt::DecorationRole:
134 if (
index.column() == 0) {
161 if (!hasIndex(row, column,
parent)) {
168 return childItem ? createIndex(row, column, childItem) : QModelIndex();
173 if (!
index.isValid()) {
180 if (!parentItem || parentItem == m_rootItem) {
184 return createIndex(parentItem->
row(), 0, parentItem);
189 if (!
index.isValid()) {
190 return Qt::NoItemFlags;
193 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
198 if (
parent.column() > 0) {
227 if (
index.isValid()) {
240 for (
const QPersistentModelIndex &
index : indexes) {
241 if (
index.parent().isValid()) {
245 int row =
index.row();
252 beginRemoveRows(QModelIndex(), row, row);
256 if (item == m_todayItem) {
257 m_todayItem =
nullptr;
262void HistoryModel::resetHistory()
267 m_todayItem =
nullptr;
286 if (!
parent.isValid() || !parentItem) {
298 query.prepare(
QSL(
"SELECT id, count, title, url, date FROM history WHERE date BETWEEN ? AND ? ORDER BY date DESC"));
303 QVector<HistoryEntry> list;
305 while (query.next()) {
307 entry.
id = query.value(0).toInt();
308 entry.
count = query.value(1).toInt();
309 entry.
title = query.value(2).toString();
310 entry.
url = query.value(3).toUrl();
311 entry.
date = QDateTime::fromMSecsSinceEpoch(query.value(4).toLongLong());
312 entry.
urlString = QString::fromUtf8(entry.
url.toEncoded());
314 if (!idList.contains(entry.
id)) {
319 if (list.isEmpty()) {
323 beginInsertRows(
parent, 0, list.size() - 1);
327 newItem->historyEntry = entry;
333void HistoryModel::historyEntryAdded(
const HistoryEntry &entry)
336 beginInsertRows(QModelIndex(), 0, 0);
340 m_todayItem->
setEndTimestamp(QDateTime(QDate::currentDate(), QTime(), QTimeZone::systemTimeZone()).toMSecsSinceEpoch());
341 m_todayItem->
title = tr(
"Today");
348 beginInsertRows(createIndex(0, 0, m_todayItem), 0, 0);
351 item->historyEntry = entry;
358void HistoryModel::historyEntryDeleted(
const HistoryEntry &entry)
366 int row = item->
row();
368 beginRemoveRows(createIndex(parentItem->
row(), 0, parentItem), row, row);
372 checkEmptyParentItem(parentItem);
382 const QModelIndex sourceParent = createIndex(parentItem->
row(), 0, parentItem);
383 const QModelIndex destinationParent = createIndex(m_todayItem->
row(), 0, m_todayItem);
384 int row = item->
row();
386 beginMoveRows(sourceParent, row, row, destinationParent, 0);
392 checkEmptyParentItem(parentItem);
395 historyEntryAdded(after);
398 historyEntryDeleted(before);
399 historyEntryAdded(after);
405 qint64 timestamp = entry.
date.toMSecsSinceEpoch();
430void HistoryModel::checkEmptyParentItem(
HistoryItem* item)
433 int row = item->
row();
435 beginRemoveRows(QModelIndex(), row, row);
439 if (item == m_todayItem) {
440 m_todayItem =
nullptr;
445void HistoryModel::init()
448 query.exec(
QSL(
"SELECT MIN(date) FROM history"));
453 const qint64 minTimestamp = query.value(0).toLongLong();
454 if (minTimestamp <= 0) {
458 const QDate today = QDate::currentDate();
459 const QDate week = today.addDays(1 - today.dayOfWeek());
460 const QDate month = QDate(today.year(), today.month(), 1);
461 const qint64 currentTimestamp = QDateTime::currentMSecsSinceEpoch();
463 qint64 timestamp = currentTimestamp;
464 while (timestamp > minTimestamp) {
465 QDate timestampDate = QDateTime::fromMSecsSinceEpoch(timestamp).date();
469 if (timestampDate == today) {
470 endTimestamp = QDateTime(today, QTime(), QTimeZone::systemTimeZone()).toMSecsSinceEpoch();
472 itemName = tr(
"Today");
474 else if (timestampDate >= week) {
475 endTimestamp = QDateTime(week, QTime(), QTimeZone::systemTimeZone()).toMSecsSinceEpoch();
477 itemName = tr(
"This Week");
479 else if (timestampDate.month() == month.month() && timestampDate.year() == month.year()) {
480 endTimestamp = QDateTime(month, QTime(), QTimeZone::systemTimeZone()).toMSecsSinceEpoch();
482 itemName = tr(
"This Month");
485 QDate startDate(timestampDate.year(), timestampDate.month(), timestampDate.daysInMonth());
486 QDate endDate(startDate.year(), startDate.month(), 1);
488 timestamp = QDateTime(startDate, QTime(23, 59, 59), QTimeZone::systemTimeZone()).toMSecsSinceEpoch();
489 endTimestamp = QDateTime(endDate, QTime(), QTimeZone::systemTimeZone()).toMSecsSinceEpoch();
494 query.prepare(
QSL(
"SELECT id FROM history WHERE date BETWEEN ? AND ? LIMIT 1"));
495 query.addBindValue(endTimestamp);
496 query.addBindValue(timestamp);
503 item->
title = itemName;
506 if (timestamp == currentTimestamp) {
511 timestamp = endTimestamp - 1;
517 : QSortFilterProxyModel(parent)
519 setSourceModel(parent);
520 setFilterCaseSensitivity(Qt::CaseInsensitive);
522 m_filterTimer =
new QTimer(
this);
523 m_filterTimer->setSingleShot(
true);
524 m_filterTimer->setInterval(300);
526 connect(m_filterTimer, &QTimer::timeout,
this, &HistoryFilterModel::startFiltering);
533 m_filterTimer->start();
536void HistoryFilterModel::startFiltering()
538 if (m_pattern.isEmpty()) {
540 QSortFilterProxyModel::setFilterFixedString(m_pattern);
544 QApplication::setOverrideCursor(Qt::WaitCursor);
549 QSortFilterProxyModel::setFilterFixedString(m_pattern);
551 QApplication::restoreOverrideCursor();
556 const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
568 return m_pattern.isEmpty();
HistoryFilterModel(QAbstractItemModel *parent)
bool isPatternEmpty() const
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
void setFilterFixedString(const QString &pattern)
void historyEntryDeleted(const HistoryEntry &entry)
void historyEntryEdited(const HistoryEntry &before, const HistoryEntry &after)
static QString titleCaseLocalizedMonth(int month)
void historyEntryAdded(const HistoryEntry &entry)
void setIcon(const QIcon &icon)
HistoryItem * parent() const
qint64 startTimestamp() const
qint64 endTimestamp() const
void setStartTimestamp(qint64 start)
HistoryItem * child(int row) const
void changeParent(HistoryItem *parent)
void setEndTimestamp(qint64 end)
HistoryEntry historyEntry
void prependChild(HistoryItem *child)
QModelIndex parent(const QModelIndex &child) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
HistoryModel(History *history)
QVariant data(const QModelIndex &index, int role) const override
void fetchMore(const QModelIndex &parent) override
bool canFetchMore(const QModelIndex &parent) const override
void removeTopLevelIndexes(const QList< QPersistentModelIndex > &indexes)
bool hasChildren(const QModelIndex &parent) const override
HistoryItem * itemFromIndex(const QModelIndex &index) const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
static QIcon emptyWebIcon()
static SqlDatabase * instance()
int value(const QColor &c)