File indexing completed on 2024-05-12 04:58:06

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2010-2014  David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "historytreeview.h"
0019 #include "historymodel.h"
0020 #include "historyitem.h"
0021 #include "headerview.h"
0022 #include "mainapplication.h"
0023 #include "iconprovider.h"
0024 
0025 #include <QClipboard>
0026 #include <QKeyEvent>
0027 #include <QLineEdit>
0028 #include <QMenu>
0029 
0030 HistoryTreeView::HistoryTreeView(QWidget* parent)
0031     : QTreeView(parent)
0032     , m_history(mApp->history())
0033     , m_filter(new HistoryFilterModel(m_history->model()))
0034     , m_type(HistoryManagerViewType)
0035 {
0036     setModel(m_filter);
0037     setUniformRowHeights(true);
0038     setAllColumnsShowFocus(true);
0039 
0040     m_header = new HeaderView(this);
0041     m_header->setDefaultSectionSizes(QList<double>() << 0.4 << 0.35 << 0.10 << 0.08);
0042     m_header->setSectionHidden(4, true);
0043     setHeader(m_header);
0044 
0045     connect(m_filter, &HistoryFilterModel::expandAllItems, this, &QTreeView::expandAll);
0046     connect(m_filter, &HistoryFilterModel::collapseAllItems, this, &QTreeView::collapseAll);
0047 }
0048 
0049 HistoryTreeView::ViewType HistoryTreeView::viewType() const
0050 {
0051     return m_type;
0052 }
0053 
0054 void HistoryTreeView::setViewType(HistoryTreeView::ViewType type)
0055 {
0056     m_type = type;
0057 
0058     switch (m_type) {
0059     case HistoryManagerViewType:
0060         setColumnHidden(1, false);
0061         setColumnHidden(2, false);
0062         setColumnHidden(3, false);
0063         setHeaderHidden(false);
0064         setMouseTracking(false);
0065         setSelectionMode(QAbstractItemView::ExtendedSelection);
0066         break;
0067     case HistorySidebarViewType:
0068         setColumnHidden(1, true);
0069         setColumnHidden(2, true);
0070         setColumnHidden(3, true);
0071         setHeaderHidden(true);
0072         setMouseTracking(true);
0073         setSelectionMode(QAbstractItemView::SingleSelection);
0074         break;
0075     default:
0076         break;
0077     }
0078 }
0079 
0080 QUrl HistoryTreeView::selectedUrl() const
0081 {
0082     const QList<QModelIndex> indexes = selectionModel()->selectedRows();
0083 
0084     if (indexes.count() != 1)
0085         return {};
0086 
0087     // TopLevelItems have invalid (empty) UrlRole data
0088     return indexes.at(0).data(HistoryModel::UrlRole).toUrl();
0089 }
0090 
0091 HeaderView* HistoryTreeView::header() const
0092 {
0093     return m_header;
0094 }
0095 
0096 void HistoryTreeView::search(const QString &string)
0097 {
0098     m_filter->setFilterFixedString(string);
0099 }
0100 
0101 void HistoryTreeView::removeSelectedItems()
0102 {
0103     QList<int> list;
0104     QApplication::setOverrideCursor(Qt::WaitCursor);
0105 
0106     QList<QPersistentModelIndex> topLevelIndexes;
0107 
0108     const auto indexes = selectedIndexes();
0109     for (const QModelIndex &index : indexes) {
0110         if (index.column() > 0) {
0111             continue;
0112         }
0113 
0114         if ((index.data(HistoryModel::IsTopLevelRole).toBool()) && (m_filter->isPatternEmpty())) {
0115             qint64 start = index.data(HistoryModel::TimestampStartRole).toLongLong();
0116             qint64 end = index.data(HistoryModel::TimestampEndRole).toLongLong();
0117 
0118             list.append(m_history->indexesFromTimeRange(start, end));
0119 
0120             topLevelIndexes.append(index);
0121         }
0122         else {
0123             int id = index.data(HistoryModel::IdRole).toInt();
0124             if (!list.contains(id)) {
0125                 list.append(id);
0126             }
0127         }
0128     }
0129 
0130     m_history->deleteHistoryEntry(list);
0131     m_history->model()->removeTopLevelIndexes(topLevelIndexes);
0132 
0133     QApplication::restoreOverrideCursor();
0134 }
0135 
0136 void HistoryTreeView::contextMenuEvent(QContextMenuEvent* event)
0137 {
0138     Q_EMIT contextMenuRequested(viewport()->mapToGlobal(event->pos()));
0139 }
0140 
0141 void HistoryTreeView::mouseMoveEvent(QMouseEvent* event)
0142 {
0143     QTreeView::mouseMoveEvent(event);
0144 
0145     if (m_type == HistorySidebarViewType) {
0146         QCursor cursor = Qt::ArrowCursor;
0147         if (event->buttons() == Qt::NoButton) {
0148             QModelIndex index = indexAt(event->position().toPoint());
0149             if (index.isValid() && !index.data(HistoryModel::IsTopLevelRole).toBool()) {
0150                 cursor = Qt::PointingHandCursor;
0151             }
0152         }
0153         viewport()->setCursor(cursor);
0154     }
0155 }
0156 
0157 void HistoryTreeView::mousePressEvent(QMouseEvent* event)
0158 {
0159     QTreeView::mousePressEvent(event);
0160 
0161     if (selectionModel()->selectedRows().count() == 1) {
0162         QModelIndex index = indexAt(event->position().toPoint());
0163         Qt::MouseButtons buttons = event->buttons();
0164         Qt::KeyboardModifiers modifiers = event->modifiers();
0165 
0166         if (index.isValid() && !index.data(HistoryModel::IsTopLevelRole).toBool()) {
0167             const QUrl url = index.data(HistoryModel::UrlRole).toUrl();
0168 
0169             if (buttons == Qt::LeftButton && modifiers == Qt::ShiftModifier) {
0170                 Q_EMIT urlShiftActivated(url);
0171             }
0172             else if (buttons == Qt::MiddleButton || (buttons == Qt::LeftButton && modifiers == Qt::ControlModifier)) {
0173                 Q_EMIT urlCtrlActivated(url);
0174             }
0175         }
0176     }
0177 }
0178 
0179 void HistoryTreeView::mouseReleaseEvent(QMouseEvent* event)
0180 {
0181     QTreeView::mouseReleaseEvent(event);
0182 
0183     if (selectionModel()->selectedRows().count() == 1) {
0184         QModelIndex index = indexAt(event->position().toPoint());
0185 
0186         if (index.isValid() && !index.data(HistoryModel::IsTopLevelRole).toBool()) {
0187             const QUrl url = index.data(HistoryModel::UrlRole).toUrl();
0188 
0189             // Activate urls with single mouse click in Sidebar
0190             if (m_type == HistorySidebarViewType && event->button() == Qt::LeftButton && event->modifiers() == Qt::NoModifier) {
0191                 Q_EMIT urlActivated(url);
0192             }
0193         }
0194     }
0195 }
0196 
0197 void HistoryTreeView::mouseDoubleClickEvent(QMouseEvent* event)
0198 {
0199     QTreeView::mouseDoubleClickEvent(event);
0200 
0201     if (selectionModel()->selectedRows().count() == 1) {
0202         QModelIndex index = indexAt(event->position().toPoint());
0203 
0204         if (index.isValid() && !index.data(HistoryModel::IsTopLevelRole).toBool()) {
0205             const QUrl url = index.data(HistoryModel::UrlRole).toUrl();
0206             Qt::MouseButtons buttons = event->buttons();
0207             Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
0208 
0209             if (buttons == Qt::LeftButton && modifiers == Qt::NoModifier) {
0210                 Q_EMIT urlActivated(url);
0211             }
0212             else if (buttons == Qt::LeftButton && modifiers == Qt::ShiftModifier) {
0213                 Q_EMIT urlShiftActivated(url);
0214             }
0215         }
0216     }
0217 }
0218 
0219 void HistoryTreeView::keyPressEvent(QKeyEvent* event)
0220 {
0221     QTreeView::keyPressEvent(event);
0222 
0223     if (selectionModel()->selectedRows().count() == 1) {
0224         QModelIndex index = selectionModel()->selectedRows().at(0);
0225         const QUrl url = index.data(HistoryModel::UrlRole).toUrl();
0226         const bool isTopLevel = index.data(HistoryModel::IsTopLevelRole).toBool();
0227 
0228         switch (event->key()) {
0229         case Qt::Key_Return:
0230         case Qt::Key_Enter:
0231             if (isTopLevel && (event->modifiers() == Qt::NoModifier || event->modifiers() == Qt::KeypadModifier)) {
0232                 setExpanded(index, !isExpanded(index));
0233             }
0234             else {
0235                 Qt::KeyboardModifiers modifiers = event->modifiers();
0236 
0237                 if (modifiers == Qt::NoModifier || modifiers == Qt::KeypadModifier) {
0238                     Q_EMIT urlActivated(url);
0239                 }
0240                 else if (modifiers == Qt::ControlModifier) {
0241                     Q_EMIT urlCtrlActivated(url);
0242                 }
0243                 else if (modifiers == Qt::ShiftModifier) {
0244                     Q_EMIT urlShiftActivated(url);
0245                 }
0246             }
0247             break;
0248 
0249         case Qt::Key_Delete:
0250             removeSelectedItems();
0251             break;
0252         }
0253     }
0254 }
0255 
0256 void HistoryTreeView::drawRow(QPainter* painter, const QStyleOptionViewItem &options, const QModelIndex &index) const
0257 {
0258     bool itemTopLevel = index.data(HistoryModel::IsTopLevelRole).toBool();
0259     bool iconLoaded = !index.data(HistoryModel::IconRole).value<QIcon>().isNull();
0260 
0261     if (index.isValid() && !itemTopLevel && !iconLoaded) {
0262         const QPersistentModelIndex idx = index;
0263         model()->setData(idx, IconProvider::iconForUrl(index.data(HistoryModel::UrlRole).toUrl()), HistoryModel::IconRole);
0264     }
0265 
0266     QTreeView::drawRow(painter, options, index);
0267 }