1 | /* |
2 | This file is part of the KDE libraries |
3 | SPDX-FileCopyrightText: 2014 Arjun A.K. <arjunak234@gmail.com> |
4 | SPDX-FileCopyrightText: 2025 Kai Uwe Broulik <kde@broulik.de> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.0-or-later |
7 | */ |
8 | |
9 | #include "executablefileopendialog_p.h" |
10 | |
11 | #include <QDialogButtonBox> |
12 | #include <QLabel> |
13 | #include <QMimeType> |
14 | #include <QPushButton> |
15 | #include <QShowEvent> |
16 | |
17 | #include <KApplicationTrader> |
18 | #include <KFileItem> |
19 | #include <KIconLoader> |
20 | #include <KLocalizedString> |
21 | #include <KMessageDialog> |
22 | |
23 | #include <KIO/PreviewJob> |
24 | |
25 | ExecutableFileOpenDialog::ExecutableFileOpenDialog(const QUrl &url, const QMimeType &mimeType, ExecutableFileOpenDialog::Mode mode, QWidget *parent) |
26 | : QDialog(parent) |
27 | { |
28 | m_ui.setupUi(this); |
29 | |
30 | std::optional<KFileItem> fileItem; |
31 | |
32 | if (url.isValid()) { |
33 | fileItem = KFileItem{url, mimeType.name()}; |
34 | |
35 | m_ui.nameLabel->setText(fileItem->name()); |
36 | m_ui.nameLabel->setToolTip(url.toDisplayString(options: QUrl::PreferLocalFile)); |
37 | } else { |
38 | m_ui.nameLabel->hide(); |
39 | } |
40 | |
41 | m_ui.mimeTypeLabel->setForegroundRole(QPalette::PlaceholderText); |
42 | // Not using KFileItem::comment() since that also reads the Comment from the .desktop file |
43 | // which could spoof the user. |
44 | m_ui.mimeTypeLabel->setText(mimeType.comment()); |
45 | m_ui.mimeTypeLabel->setToolTip(mimeType.name()); |
46 | |
47 | const QSize iconSize{KIconLoader::SizeHuge, KIconLoader::SizeHuge}; |
48 | QIcon icon; |
49 | |
50 | if (fileItem) { |
51 | icon = QIcon::fromTheme(name: fileItem->iconName()); |
52 | |
53 | auto *previewJob = KIO::filePreview(items: {*fileItem}, size: iconSize); |
54 | previewJob->setDevicePixelRatio(devicePixelRatioF()); |
55 | connect(sender: previewJob, signal: &KIO::PreviewJob::gotPreview, context: this, slot: [this](const KFileItem &item, const QPixmap &pixmap) { |
56 | Q_UNUSED(item); |
57 | m_ui.iconLabel->setPixmap(pixmap); |
58 | }); |
59 | } |
60 | |
61 | if (icon.isNull()) { |
62 | icon = QIcon::fromTheme(name: mimeType.iconName()); |
63 | } |
64 | if (icon.isNull()) { |
65 | icon = QIcon::fromTheme(QStringLiteral("unknown" )); |
66 | } |
67 | |
68 | m_ui.iconLabel->setPixmap(icon.pixmap(size: iconSize, devicePixelRatio: devicePixelRatioF())); |
69 | |
70 | connect(sender: m_ui.buttonBox, signal: &QDialogButtonBox::rejected, context: this, slot: &ExecutableFileOpenDialog::reject); |
71 | |
72 | QPushButton *launchButton = new QPushButton(i18nc("@action:button Launch script" , "&Launch" ), this); |
73 | launchButton->setIcon(QIcon::fromTheme(QStringLiteral("system-run" ))); |
74 | |
75 | // Script execution settings UI is in Dolphin, not KIO, only show the explanation |
76 | // on how to undo "dont ask again" when Dolphin is the default file manager. |
77 | const auto fileManagerService = KApplicationTrader::preferredService(QStringLiteral("inode/directory" )); |
78 | m_ui.dontAgainHelpButton->setVisible(fileManagerService && fileManagerService->desktopEntryName() == QLatin1String("org.kde.dolphin" )); |
79 | |
80 | if (mode == OnlyExecute) { |
81 | m_ui.dontAgainCheckBox->setText(i18nc("@option:check" , "Launch executable files without asking" )); |
82 | connect(sender: launchButton, signal: &QPushButton::clicked, context: this, slot: &ExecutableFileOpenDialog::executeFile); |
83 | } else if (mode == OpenAsExecute) { |
84 | m_ui.dontAgainCheckBox->setText(i18nc("@option:check Open in the associated app" , "Open executable files in the default application without asking" )); |
85 | connect(sender: launchButton, signal: &QPushButton::clicked, context: this, slot: &ExecutableFileOpenDialog::openFile); |
86 | } else { // mode == OpenOrExecute |
87 | m_ui.label->setText(i18n("What do you wish to do with this file?" )); |
88 | connect(sender: launchButton, signal: &QPushButton::clicked, context: this, slot: &ExecutableFileOpenDialog::executeFile); |
89 | |
90 | QPushButton *openButton = new QPushButton(QIcon::fromTheme(QStringLiteral("document-preview" )), i18nc("@action:button" , "&Open" ), this); |
91 | if (KService::Ptr service = KApplicationTrader::preferredService(mimeType: mimeType.name())) { |
92 | openButton->setText(i18nc("@action:button" , "&Open with %1" , service->name())); |
93 | const QIcon serviceIcon = QIcon::fromTheme(name: service->icon()); |
94 | if (!serviceIcon.isNull()) { |
95 | openButton->setIcon(serviceIcon); |
96 | } |
97 | } |
98 | m_ui.buttonBox->addButton(button: openButton, role: QDialogButtonBox::AcceptRole); |
99 | |
100 | connect(sender: openButton, signal: &QPushButton::clicked, context: this, slot: &ExecutableFileOpenDialog::openFile); |
101 | } |
102 | |
103 | // Add Execute button last so that Open is first in the button box |
104 | m_ui.buttonBox->addButton(button: launchButton, role: QDialogButtonBox::AcceptRole); |
105 | m_ui.buttonBox->button(which: QDialogButtonBox::Cancel)->setFocus(); |
106 | } |
107 | |
108 | bool ExecutableFileOpenDialog::isDontAskAgainChecked() const |
109 | { |
110 | return m_ui.dontAgainCheckBox->isChecked(); |
111 | } |
112 | |
113 | void ExecutableFileOpenDialog::executeFile() |
114 | { |
115 | done(ExecuteFile); |
116 | } |
117 | |
118 | void ExecutableFileOpenDialog::openFile() |
119 | { |
120 | done(OpenFile); |
121 | } |
122 | |
123 | void ExecutableFileOpenDialog::showEvent(QShowEvent *event) |
124 | { |
125 | if (!event->spontaneous()) { |
126 | KMessageDialog::beep(type: KMessageDialog::QuestionTwoActionsCancel, text: m_ui.label->text(), dialog: this); |
127 | } |
128 | QDialog::showEvent(event); |
129 | } |
130 | |
131 | #include "moc_executablefileopendialog_p.cpp" |
132 | |