File indexing completed on 2024-04-28 15:52:03

0001 /*
0002     SPDX-FileCopyrightText: 2021 Jiří Wolker <woljiri@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "welcomescreen.h"
0008 
0009 #include <KConfigGroup>
0010 #include <KIO/OpenFileManagerWindowJob>
0011 #include <KIconLoader>
0012 #include <KSharedConfig>
0013 
0014 #include <QAction>
0015 #include <QClipboard>
0016 #include <QGraphicsOpacityEffect>
0017 #include <QGuiApplication>
0018 #include <QMenu>
0019 #include <QResizeEvent>
0020 #include <QStyledItemDelegate>
0021 
0022 #include "recentitemsmodel.h"
0023 
0024 class RecentsListItemDelegate : public QStyledItemDelegate
0025 {
0026     Q_OBJECT
0027 
0028 public:
0029     explicit RecentsListItemDelegate(WelcomeScreen *welcomeScreen)
0030         : m_welcomeScreen(welcomeScreen)
0031     {
0032     }
0033 
0034     WelcomeScreen *welcomeScreen() const
0035     {
0036         return m_welcomeScreen;
0037     }
0038 
0039     bool editorEvent(QEvent *event, QAbstractItemModel *aModel, const QStyleOptionViewItem &styleOptionViewItem, const QModelIndex &index) override
0040     {
0041         const RecentItemsModel *model = static_cast<RecentItemsModel *>(aModel);
0042         const RecentItemsModel::RecentItem *item = model->getItem(index);
0043 
0044         QPoint menuPosition;
0045 
0046         if (item != nullptr) {
0047             bool willOpenMenu = false;
0048             if (event->type() == QEvent::ContextMenu) {
0049                 willOpenMenu = true;
0050                 menuPosition = static_cast<QContextMenuEvent *>(event)->globalPos();
0051             }
0052             if (event->type() == QEvent::MouseButtonPress) {
0053                 if (static_cast<QMouseEvent *>(event)->button() == Qt::MouseButton::RightButton) {
0054                     willOpenMenu = true;
0055                     menuPosition = static_cast<QMouseEvent *>(event)->globalPosition().toPoint();
0056                 }
0057             }
0058 
0059             if (willOpenMenu) {
0060                 event->accept();
0061 
0062                 QMenu menu;
0063 
0064                 QAction *copyPathAction = new QAction(i18n("&Copy Path"));
0065                 copyPathAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
0066                 connect(copyPathAction, &QAction::triggered, this, [item]() {
0067                     QString path;
0068                     if (item->url.isLocalFile()) {
0069                         path = item->url.toLocalFile();
0070                     } else {
0071                         path = item->url.toString();
0072                     }
0073                     QGuiApplication::clipboard()->setText(path);
0074                 });
0075                 menu.addAction(copyPathAction);
0076 
0077                 QAction *showDirectoryAction = new QAction(i18n("&Open Containing Folder"));
0078                 showDirectoryAction->setIcon(QIcon::fromTheme(QStringLiteral("document-open-folder")));
0079                 connect(showDirectoryAction, &QAction::triggered, this, [item]() {
0080                     if (item->url.isLocalFile()) {
0081                         KIO::highlightInFileManager({item->url});
0082                     }
0083                 });
0084                 menu.addAction(showDirectoryAction);
0085                 if (!item->url.isLocalFile()) {
0086                     showDirectoryAction->setEnabled(false);
0087                 }
0088 
0089                 QAction *forgetItemAction = new QAction(i18nc("recent items context menu", "&Forget This Item"));
0090                 forgetItemAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear-history")));
0091                 connect(forgetItemAction, &QAction::triggered, this, [this, item]() { Q_EMIT welcomeScreen()->forgetRecentItem(item->url); });
0092                 menu.addAction(forgetItemAction);
0093 
0094                 menu.exec(menuPosition);
0095 
0096                 return true;
0097             }
0098         }
0099 
0100         return QStyledItemDelegate::editorEvent(event, aModel, styleOptionViewItem, index);
0101     }
0102 
0103 private:
0104     WelcomeScreen *m_welcomeScreen;
0105 };
0106 
0107 WelcomeScreen::WelcomeScreen(QWidget *parent)
0108     : QWidget(parent)
0109     , m_recentsModel(new RecentItemsModel)
0110     , m_recentsItemDelegate(new RecentsListItemDelegate(this))
0111 {
0112     Q_ASSERT(parent);
0113 
0114     setupUi(this);
0115 
0116     connect(openButton, &QPushButton::clicked, this, &WelcomeScreen::openClicked);
0117     connect(closeButton, &QPushButton::clicked, this, &WelcomeScreen::closeClicked);
0118 
0119     recentsListView->setContextMenuPolicy(Qt::DefaultContextMenu);
0120     recentsListView->setModel(m_recentsModel);
0121     recentsListView->setItemDelegate(m_recentsItemDelegate);
0122     connect(recentsListView, &QListView::activated, this, &WelcomeScreen::recentsItemActivated);
0123 
0124     connect(m_recentsModel, &RecentItemsModel::layoutChanged, this, &WelcomeScreen::recentListChanged);
0125 
0126     QVBoxLayout *noRecentsLayout = new QVBoxLayout(recentsListView);
0127     recentsListView->setLayout(noRecentsLayout);
0128     m_noRecentsLabel = new QLabel(recentsListView);
0129     QFont placeholderLabelFont;
0130     // To match the size of a level 2 Heading/KTitleWidget
0131     placeholderLabelFont.setPointSize(qRound(placeholderLabelFont.pointSize() * 1.3));
0132     noRecentsLayout->addWidget(m_noRecentsLabel);
0133     m_noRecentsLabel->setFont(placeholderLabelFont);
0134     m_noRecentsLabel->setTextInteractionFlags(Qt::NoTextInteraction);
0135     m_noRecentsLabel->setWordWrap(true);
0136     m_noRecentsLabel->setAlignment(Qt::AlignCenter);
0137     m_noRecentsLabel->setText(i18nc("on welcome screen", "No recent documents"));
0138     // Match opacity of QML placeholder label component
0139     auto *effect = new QGraphicsOpacityEffect(m_noRecentsLabel);
0140     effect->setOpacity(0.5);
0141     m_noRecentsLabel->setGraphicsEffect(effect);
0142 
0143     connect(forgetAllButton, &QToolButton::clicked, this, &WelcomeScreen::forgetAllRecents);
0144 }
0145 
0146 WelcomeScreen::~WelcomeScreen()
0147 {
0148     delete m_recentsModel;
0149     delete m_recentsItemDelegate;
0150 }
0151 
0152 void WelcomeScreen::showEvent(QShowEvent *e)
0153 {
0154     if (appIcon->pixmap(Qt::ReturnByValue).isNull()) {
0155         appIcon->setPixmap(QIcon::fromTheme(QStringLiteral("okular")).pixmap(KIconLoader::SizeEnormous));
0156     }
0157 
0158     QWidget::showEvent(e);
0159 }
0160 
0161 void WelcomeScreen::loadRecents()
0162 {
0163     m_recentsModel->loadEntries(KSharedConfig::openConfig()->group(QStringLiteral("Recent Files")));
0164 }
0165 
0166 int WelcomeScreen::recentsCount()
0167 {
0168     return m_recentsModel->rowCount();
0169 }
0170 
0171 void WelcomeScreen::recentsItemActivated(const QModelIndex &index)
0172 {
0173     const RecentItemsModel::RecentItem *item = m_recentsModel->getItem(index);
0174     if (item != nullptr) {
0175         Q_EMIT recentItemClicked(item->url);
0176     }
0177 }
0178 
0179 void WelcomeScreen::recentListChanged()
0180 {
0181     if (recentsCount() == 0) {
0182         m_noRecentsLabel->show();
0183         forgetAllButton->setEnabled(false);
0184     } else {
0185         m_noRecentsLabel->hide();
0186         forgetAllButton->setEnabled(true);
0187     }
0188 }
0189 
0190 #include "welcomescreen.moc"