File indexing completed on 2024-04-21 04:58:16

0001 /* This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2009 Pino Toscano <pino@kde.org>
0003     SPDX-FileCopyrightText: 2009 Daivd Faure <faure@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "konqhistoryview.h"
0009 #include "konqhistory.h"
0010 #include "konq_historyprovider.h"
0011 #include "konqhistorymodel.h"
0012 #include "konqhistoryproxymodel.h"
0013 #include "konqhistorysettings.h"
0014 
0015 #include <KDialogJobUiDelegate>
0016 #include <QAction>
0017 #include <QApplication>
0018 #include <QClipboard>
0019 #include <QIcon>
0020 #include <QLineEdit>
0021 #include <QMenu>
0022 #include <QMimeData>
0023 #include <QTimer>
0024 #include <QTreeView>
0025 #include <QVBoxLayout>
0026 #include <QActionGroup>
0027 
0028 #include <kactioncollection.h>
0029 #include "konqdebug.h"
0030 #include <KLocalizedString>
0031 #include <kmessagebox.h>
0032 
0033 #include <KIO/CommandLauncherJob>
0034 
0035 KonqHistoryView::KonqHistoryView(QWidget *parent)
0036     : QWidget(parent)
0037     , m_searchTimer(nullptr)
0038 {
0039     m_treeView = new QTreeView(this);
0040     m_treeView->setContextMenuPolicy(Qt::CustomContextMenu);
0041     m_treeView->setHeaderHidden(true);
0042 
0043     m_historyProxyModel = new KonqHistoryProxyModel(KonqHistorySettings::self(), m_treeView);
0044     connect(m_treeView, &QTreeView::customContextMenuRequested, this, &KonqHistoryView::slotContextMenu);
0045     m_historyModel = new KonqHistoryModel(m_historyProxyModel);
0046     m_treeView->setModel(m_historyProxyModel);
0047     m_historyProxyModel->setSourceModel(m_historyModel);
0048     m_historyProxyModel->sort(0);
0049 
0050     m_collection = new KActionCollection(this);
0051     m_collection->addAssociatedWidget(m_treeView); // make shortcuts work
0052     QAction *action = m_collection->addAction(QStringLiteral("open_new"));
0053     action->setIcon(QIcon::fromTheme(QStringLiteral("window-new")));
0054     action->setText(i18n("Open in New &Window"));
0055     connect(action, &QAction::triggered, this, &KonqHistoryView::slotNewWindow);
0056 
0057     action = m_collection->addAction(QStringLiteral("open_tab"));
0058     action->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
0059     action->setText(i18n("Open in New Tab"));
0060     connect(action, &QAction::triggered, this, &KonqHistoryView::slotNewTab);
0061 
0062     action = m_collection->addAction(QStringLiteral("open_current_tab"));
0063     action->setIcon(QIcon::fromTheme(QStringLiteral("window")));
0064     action->setText(i18n("Open in Current Tab"));
0065     connect(action, &QAction::triggered, this, &KonqHistoryView::slotCurrentTab);
0066 
0067     action = m_collection->addAction(QStringLiteral("copylinklocation"));
0068     action->setText(i18n("&Copy Link Address"));
0069     connect(action, &QAction::triggered, this, &KonqHistoryView::slotCopyLinkLocation);
0070 
0071     action = m_collection->addAction(QStringLiteral("remove"));
0072     action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
0073     action->setText(i18n("&Remove Entry"));
0074     m_collection->setDefaultShortcut(action, QKeySequence(Qt::Key_Delete)); // #135966
0075     action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
0076     connect(action, &QAction::triggered, this, &KonqHistoryView::slotRemoveEntry);
0077 
0078     action = m_collection->addAction(QStringLiteral("clear"));
0079     action->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear-history")));
0080     action->setText(i18n("C&lear History"));
0081     connect(action, &QAction::triggered, this, &KonqHistoryView::slotClearHistory);
0082 
0083     action = m_collection->addAction(QStringLiteral("preferences"));
0084     action->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
0085     action->setText(i18n("&Preferences..."));
0086     connect(action, &QAction::triggered, this, &KonqHistoryView::slotPreferences);
0087 
0088     QActionGroup *sortGroup = new QActionGroup(this);
0089     sortGroup->setExclusive(true);
0090 
0091     action = m_collection->addAction(QStringLiteral("byName"));
0092     action->setText(i18n("By &Name"));
0093     action->setCheckable(true);
0094     action->setData(QVariant::fromValue(0));
0095     sortGroup->addAction(action);
0096 
0097     action = m_collection->addAction(QStringLiteral("byDate"));
0098     action->setText(i18n("By &Date"));
0099     action->setCheckable(true);
0100     action->setData(QVariant::fromValue(1));
0101     sortGroup->addAction(action);
0102 
0103     KonqHistorySettings *settings = KonqHistorySettings::self();
0104     sortGroup->actions().at(settings->m_sortsByName ? 0 : 1)->setChecked(true);
0105     connect(sortGroup, &QActionGroup::triggered, this, &KonqHistoryView::slotSortChange);
0106 
0107     m_searchLineEdit = new QLineEdit(this);
0108     m_searchLineEdit->setPlaceholderText(i18n("Search in history"));
0109     m_searchLineEdit->setClearButtonEnabled(true);
0110 
0111     connect(m_searchLineEdit, &QLineEdit::textChanged, this, &KonqHistoryView::slotFilterTextChanged);
0112 
0113     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0114     mainLayout->setContentsMargins(0, 0, 0, 0);
0115     mainLayout->addWidget(m_searchLineEdit);
0116     mainLayout->addWidget(m_treeView);
0117 }
0118 
0119 void KonqHistoryView::slotContextMenu(const QPoint &pos)
0120 {
0121     const QModelIndex index = m_treeView->indexAt(pos);
0122     if (!index.isValid()) {
0123         return;
0124     }
0125 
0126     const int nodeType = index.data(KonqHistory::TypeRole).toInt();
0127 
0128     QMenu *menu = new QMenu(this);
0129 
0130     if (nodeType == KonqHistory::HistoryType) {
0131         menu->addAction(m_collection->action(QStringLiteral("open_new")));
0132         menu->addAction(m_collection->action(QStringLiteral("open_tab")));
0133         menu->addAction(m_collection->action(QStringLiteral("open_current_tab")));
0134         menu->addAction(m_collection->action(QStringLiteral("copylinklocation")));
0135         menu->addSeparator();
0136     }
0137 
0138     menu->addAction(m_collection->action(QStringLiteral("remove")));
0139     menu->addAction(m_collection->action(QStringLiteral("clear")));
0140     menu->addSeparator();
0141     QMenu *sortMenu = menu->addMenu(i18nc("@action:inmenu Parent of 'By Name' and 'By Date'", "Sort"));
0142     sortMenu->addAction(m_collection->action(QStringLiteral("byName")));
0143     sortMenu->addAction(m_collection->action(QStringLiteral("byDate")));
0144     menu->addSeparator();
0145     menu->addAction(m_collection->action(QStringLiteral("preferences")));
0146 
0147     menu->exec(m_treeView->viewport()->mapToGlobal(pos));
0148 
0149     delete menu;
0150 }
0151 
0152 void KonqHistoryView::slotRemoveEntry()
0153 {
0154     const QModelIndex index = m_treeView->currentIndex();
0155     if (!index.isValid()) {
0156         return;
0157     }
0158 
0159     // TODO undo/redo support
0160     m_historyModel->deleteItem(m_historyProxyModel->mapToSource(index));
0161 }
0162 
0163 void KonqHistoryView::slotClearHistory()
0164 {
0165     KGuiItem guiitem = KStandardGuiItem::clear();
0166     guiitem.setIcon(QIcon::fromTheme(QStringLiteral("edit-clear-history")));
0167 
0168     if (KMessageBox::warningContinueCancel(this,
0169                                            i18n("Do you really want to clear the entire history?"),
0170                                            i18nc("@title:window", "Clear History?"), guiitem)
0171             == KMessageBox::Continue) {
0172         KonqHistoryProvider::self()->emitClear();
0173     }
0174 }
0175 
0176 void KonqHistoryView::slotPreferences()
0177 {
0178     // Run the history sidebar settings.
0179     KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(QStringLiteral("kcmshell5 kcmhistory"));
0180     job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0181     job->start();
0182 }
0183 
0184 void KonqHistoryView::slotSortChange(QAction *action)
0185 {
0186     if (!action) {
0187         return;
0188     }
0189 
0190     const int which = action->data().toInt();
0191     KonqHistorySettings *settings = KonqHistorySettings::self();
0192     settings->m_sortsByName = (which == 0);
0193     settings->applySettings();
0194 }
0195 
0196 void KonqHistoryView::slotFilterTextChanged(const QString &text)
0197 {
0198     Q_UNUSED(text);
0199     if (!m_searchTimer) {
0200         m_searchTimer = new QTimer(this);
0201         m_searchTimer->setSingleShot(true);
0202         connect(m_searchTimer, &QTimer::timeout, this, &KonqHistoryView::slotTimerTimeout);
0203     }
0204     m_searchTimer->start(600);
0205 }
0206 
0207 void KonqHistoryView::slotTimerTimeout()
0208 {
0209     m_historyProxyModel->setFilterFixedString(m_searchLineEdit->text());
0210 }
0211 
0212 QTreeView *KonqHistoryView::treeView() const
0213 {
0214     return m_treeView;
0215 }
0216 
0217 QLineEdit *KonqHistoryView::lineEdit() const
0218 {
0219     return m_searchLineEdit;
0220 }
0221 
0222 void KonqHistoryView::slotNewWindow()
0223 {
0224     const QUrl url = urlForIndex(m_treeView->currentIndex());
0225     if (url.isValid()) {
0226         emit openUrlInNewWindow(url);
0227     }
0228 }
0229 
0230 void KonqHistoryView::slotNewTab()
0231 {
0232     const QUrl url = urlForIndex(m_treeView->currentIndex());
0233     if (url.isValid()) {
0234         emit openUrlInNewTab(url);
0235     }
0236 }
0237 
0238 void KonqHistoryView::slotCurrentTab()
0239 {
0240     const QUrl url = urlForIndex(m_treeView->currentIndex());
0241     if (url.isValid()) {
0242         emit openUrlInCurrentTab(url);
0243     }
0244 }
0245 
0246 QUrl KonqHistoryView::urlForIndex(const QModelIndex &index) const
0247 {
0248     if (!index.isValid() || (index.data(KonqHistory::TypeRole).toInt() != KonqHistory::HistoryType)) {
0249         return QUrl();
0250     }
0251 
0252     return index.data(KonqHistory::UrlRole).toUrl();
0253 }
0254 
0255 // Code taken from KHTMLPopupGUIClient::slotCopyLinkLocation
0256 void KonqHistoryView::slotCopyLinkLocation()
0257 {
0258     QUrl safeURL = urlForIndex(m_treeView->currentIndex()).adjusted(QUrl::RemovePassword);
0259 
0260     // Set it in both the mouse selection and in the clipboard
0261     QMimeData *mimeData = new QMimeData;
0262     mimeData->setUrls(QList<QUrl>() << safeURL);
0263     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
0264     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection);
0265 }