Messagelib

attachmentpropertiesdialog.cpp
1/*
2 SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com>
3
4 Based on KMail code by various authors (kmmsgpartdlg).
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "attachmentpropertiesdialog.h"
10
11#include "attachmentfrommimecontentjob.h"
12#include "ui_attachmentpropertiesdialog.h"
13#include "ui_attachmentpropertiesdialog_readonly.h"
14
15#include "messagecore_debug.h"
16#include <KAboutData>
17
18#include <KMime/Content>
19#include <KMime/Headers>
20
21#include <KIO/Global>
22#include <KLocalizedString>
23#include <QDesktopServices>
24#include <QDialogButtonBox>
25#include <QMimeDatabase>
26#include <QMimeType>
27#include <QPushButton>
28#include <QUrlQuery>
29#include <QVBoxLayout>
30
31using namespace MessageCore;
32
33class Q_DECL_HIDDEN MessageCore::AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate
34{
35public:
36 AttachmentPropertiesDialogPrivate(AttachmentPropertiesDialog *qq)
37 : q(qq)
38 {
39 }
40
41 ~AttachmentPropertiesDialogPrivate()
42 {
43 delete ui;
44 delete uiReadOnly;
45 }
46
47 void init(const AttachmentPart::Ptr &part, bool readOnly);
48 void polishUi();
49 void mimeTypeChanged(const QString &type); // slot
50 void populateEncodings();
51 void populateMimeTypes();
52 void populateWhatsThis();
53 void loadFromPart();
54 void saveToPart();
55
58
59 Ui::AttachmentPropertiesDialog *ui = nullptr;
60 Ui::AttachmentPropertiesDialogReadOnly *uiReadOnly = nullptr;
61 QVBoxLayout *mainLayout = nullptr;
62 bool mReadOnly = false;
63};
64
65void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::init(const AttachmentPart::Ptr &part, bool readOnly)
66{
67 mReadOnly = readOnly;
68 mPart = part;
69
70 auto widget = new QWidget(q);
71 mainLayout = new QVBoxLayout;
72 q->setLayout(mainLayout);
73
74 mainLayout->addWidget(widget);
75 if (mReadOnly) {
76 uiReadOnly = new Ui::AttachmentPropertiesDialogReadOnly;
77 uiReadOnly->setupUi(widget);
78 } else {
79 ui = new Ui::AttachmentPropertiesDialog;
80 ui->setupUi(widget);
81 }
82 polishUi();
83 q->setModal(true);
84
85 loadFromPart();
86}
87
88void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::polishUi()
89{
90 // Tweak the dialog, depending on whether it is read-only or not.
91 QDialogButtonBox *buttonBox = nullptr;
92
93 if (mReadOnly) {
95 } else {
96 // Update the icon when the selected mime type changes.
97
98 connect(ui->mimeType, &QComboBox::currentTextChanged, q, [this](const QString &str) {
99 mimeTypeChanged(str);
100 });
101 populateMimeTypes();
102 populateEncodings();
104 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
105 okButton->setDefault(true);
107 }
108 q->connect(buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, q, &AttachmentPropertiesDialog::slotHelp);
109 q->connect(buttonBox, &QDialogButtonBox::accepted, q, &QDialog::accept);
110 q->connect(buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject);
111 mainLayout->addWidget(buttonBox);
112 populateWhatsThis();
113}
114
115void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::mimeTypeChanged(const QString &type)
116{
117 QMimeDatabase db;
118 const QMimeType mimeType = db.mimeTypeForName(type);
119 QPixmap pix =
120 QIcon::fromTheme(mimeType.iconName(), QIcon::fromTheme(QStringLiteral("unknown"))).pixmap(q->style()->pixelMetric(QStyle::PM_MessageBoxIconSize));
121
122 if (mReadOnly) {
123 uiReadOnly->mimeIcon->setPixmap(pix);
124 } else {
125 ui->mimeIcon->setPixmap(pix);
126 }
127}
128
129void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::populateWhatsThis()
130{
131 // FIXME These are such a mess... Make them straightforward and pretty.
132
133 const QString msgMimeType = i18n(
134 "<p>The <em>MIME type</em> of the file:</p>"
135 "<p>Normally, you do not need to touch this setting, since the "
136 "type of the file is automatically checked; but, sometimes, %1 "
137 "may not detect the type correctly -- here is where you can fix "
138 "that.</p>",
139 KAboutData::applicationData().componentName());
140
141 const QString msgSize = i18n(
142 "<p>The estimated size of the attachment:</p>"
143 "<p>Note that, in an email message, a binary file encoded with "
144 "base64 will take up four thirds the actual size of the file.</p>");
145
146 const QString msgName = i18n(
147 "<p>The file name of the part:</p>"
148 "<p>Although this defaults to the name of the attached file, "
149 "it does not specify the file to be attached; rather, it "
150 "suggests a file name to be used by the recipient's mail agent "
151 "when saving the part to disk.</p>");
152
153 const QString msgDescription = i18n(
154 "<p>A description of the part:</p>"
155 "<p>This is just an informational description of the part, "
156 "much like the Subject is for the whole message; most "
157 "mail agents will show this information in their message "
158 "previews alongside the attachment's icon.</p>");
159
160 const QString msgEncoding = i18n(
161 "<p>The transport encoding of this part:</p>"
162 "<p>Normally, you do not need to change this, since %1 will use "
163 "a decent default encoding, depending on the MIME type; yet, "
164 "sometimes, you can significantly reduce the size of the "
165 "resulting message, e.g. if a PostScript file does not contain "
166 "binary data, but consists of pure text -- in this case, choosing "
167 "\"quoted-printable\" over the default \"base64\" will save up "
168 "to 25% in resulting message size.</p>",
169 KAboutData::applicationData().componentName());
170
171 const QString msgAutoDisplay = i18n(
172 "<p>Check this option if you want to suggest to the "
173 "recipient the automatic (inline) display of this part in the "
174 "message preview, instead of the default icon view;</p>"
175 "<p>Technically, this is carried out by setting this part's "
176 "<em>Content-Disposition</em> header field to \"inline\" "
177 "instead of the default \"attachment\".</p>");
178
179 const QString msgSign = i18n(
180 "<p>Check this option if you want this message part to be "
181 "signed.</p>"
182 "<p>The signature will be made with the key that you associated "
183 "with the currently-selected identity.</p>");
184
185 const QString msgEncrypt = i18n(
186 "<p>Check this option if you want this message part to be "
187 "encrypted.</p>"
188 "<p>The part will be encrypted for the recipients of this "
189 "message.</p>");
190
191 if (mReadOnly) {
192 uiReadOnly->size->setWhatsThis(msgSize);
193 uiReadOnly->name->setWhatsThis(msgName);
194 uiReadOnly->encoding->setWhatsThis(msgEncoding);
195 } else {
196 ui->mimeType->setWhatsThis(msgMimeType);
197 ui->size->setWhatsThis(msgSize);
198 ui->name->setWhatsThis(msgName);
199 ui->encrypt->setWhatsThis(msgEncrypt);
200 ui->sign->setWhatsThis(msgSign);
201 ui->autoDisplay->setWhatsThis(msgAutoDisplay);
202 ui->encoding->setWhatsThis(msgEncoding);
203 ui->description->setWhatsThis(msgDescription);
204 }
205}
206
207void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::populateEncodings()
208{
209 using namespace KMime;
210 using namespace KMime::Headers;
211
212 ui->encoding->clear();
213 ui->encoding->addItem(nameForEncoding(CE7Bit), int(CE7Bit));
214 ui->encoding->addItem(nameForEncoding(CE8Bit), int(CE8Bit));
215 ui->encoding->addItem(nameForEncoding(CEquPr), int(CEquPr));
216 ui->encoding->addItem(nameForEncoding(CEbase64), int(CEbase64));
217
218 // TODO 8bit should be disabled if it is disabled in Settings.
219 // Also, if it's a message/* part, base64 and qp should be disabled.
220 // But since this is a dialog for power users anyway, let them shoot
221 // themselves in the foot. (The AttachmentJob will fail when they
222 // try to compose the message.)
223}
224
225void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::populateMimeTypes()
226{
227 const QStringList list = QStringList() << QStringLiteral("text/html") << QStringLiteral("text/plain") << QStringLiteral("image/gif")
228 << QStringLiteral("image/jpeg") << QStringLiteral("image/png") << QStringLiteral("application/octet-stream")
229 << QStringLiteral("application/x-gunzip") << QStringLiteral("application/zip");
230
231 ui->mimeType->addItems(list);
232}
233
234void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::loadFromPart()
235{
236 Q_ASSERT(mPart);
237
238 if (mReadOnly) {
239 uiReadOnly->mimeType->setText(QString::fromLatin1(mPart->mimeType()));
240 mimeTypeChanged(QString::fromLatin1(mPart->mimeType()));
241 uiReadOnly->size->setText(KIO::convertSize(mPart->size()));
242 uiReadOnly->name->setText(mPart->name().isEmpty() ? mPart->fileName() : mPart->name());
243 if (mPart->description().isEmpty()) {
244 uiReadOnly->description->hide();
245 uiReadOnly->descriptionLabel->hide();
246 } else {
247 uiReadOnly->description->setText(mPart->description());
248 }
249 uiReadOnly->encoding->setText(KMime::nameForEncoding(mPart->encoding()));
250 } else {
251 const QString mimeType = QString::fromLatin1(mPart->mimeType());
252 const int index = ui->mimeType->findText(mimeType);
253 if (index == -1) {
254 ui->mimeType->insertItem(0, mimeType);
255 ui->mimeType->setCurrentIndex(0);
256 } else {
257 ui->mimeType->setCurrentIndex(index);
258 }
259 ui->size->setText(KIO::convertSize(mPart->size()));
260 ui->name->setText(mPart->name().isEmpty() ? mPart->fileName() : mPart->name());
261 ui->description->setText(mPart->description());
262 ui->encoding->setCurrentIndex(int(mPart->encoding()));
263 ui->autoDisplay->setChecked(mPart->isInline());
264 ui->encrypt->setChecked(mPart->isEncrypted());
265 ui->sign->setChecked(mPart->isSigned());
266 }
267}
268
269static QString removeNewlines(const QString &input)
270{
271 QString ret(input);
272 ret.replace(QLatin1Char('\n'), QLatin1Char(' '));
273 return ret;
274}
275
276void AttachmentPropertiesDialog::AttachmentPropertiesDialogPrivate::saveToPart()
277{
278 Q_ASSERT(mPart);
279 Q_ASSERT(!mReadOnly);
280
281 if (mReadOnly) {
282 return;
283 }
284 mPart->setMimeType(ui->mimeType->currentText().toLatin1());
285 const QString name = removeNewlines(ui->name->text());
286 mPart->setName(name);
287 mPart->setFileName(name);
288 mPart->setDescription(removeNewlines(ui->description->text()));
289 mPart->setInline(ui->autoDisplay->isChecked());
290 mPart->setSigned(ui->sign->isChecked());
291 mPart->setEncrypted(ui->encrypt->isChecked());
292 mPart->setInline(ui->autoDisplay->isChecked());
293
294 if (ui->mimeType->currentText().startsWith(QLatin1StringView("message")) && ui->encoding->itemData(ui->encoding->currentIndex()) != KMime::Headers::CE7Bit
295 && ui->encoding->itemData(ui->encoding->currentIndex()) != KMime::Headers::CE8Bit) {
296 qCWarning(MESSAGECORE_LOG) << R"(Encoding on message/rfc822 must be "7bit" or "8bit".)";
297 }
298
299 mPart->setEncoding(KMime::Headers::contentEncoding(ui->encoding->itemData(ui->encoding->currentIndex()).toInt()));
300}
301
303 : QDialog(parent)
304 , d(new AttachmentPropertiesDialogPrivate(this))
305{
306 d->init(part, readOnly);
307 setWindowTitle(i18nc("@title:window", "Attachment Properties"));
308}
309
311 : QDialog(parent)
312 , d(new AttachmentPropertiesDialogPrivate(this))
313{
314 auto job = new AttachmentFromMimeContentJob(content, this);
315 job->exec();
316 if (job->error()) {
317 qCCritical(MESSAGECORE_LOG) << "AttachmentFromMimeContentJob failed." << job->errorString();
318 }
319
320 const AttachmentPart::Ptr part = job->attachmentPart();
321 d->init(part, true);
322 setWindowTitle(i18nc("@title:window", "Attachment Properties"));
323}
324
326
331
333{
334 if (d->ui) {
335 return d->ui->encrypt->isEnabled();
336 }
337 return false;
338}
339
341{
342 if (d->ui) {
343 d->ui->encrypt->setEnabled(enabled);
344 }
345}
346
348{
349 if (d->ui) {
350 return d->ui->sign->isEnabled();
351 }
352 return false;
353}
354
356{
357 if (d->ui) {
358 d->ui->sign->setEnabled(enabled);
359 }
360}
361
362void AttachmentPropertiesDialog::accept()
363{
364 if (!d->mReadOnly) {
365 d->saveToPart();
366 }
367
369}
370
371// Copy from PimCommon::Util::invokeHelp
372// Avoid to add PimCommon dep for this method
373void invokeHelp(const QString &docfile, const QString &anchor)
374{
375 if (!docfile.isEmpty()) {
376 QUrl url;
377 url = QUrl(QStringLiteral("help:/")).resolved(QUrl(docfile));
378 if (!anchor.isEmpty()) {
379 QUrlQuery query(url);
380 query.addQueryItem(QStringLiteral("anchor"), anchor);
381 url.setQuery(query);
382 }
383 // launch khelpcenter, or a browser for URIs not handled by khelpcenter
385 }
386}
387
388void AttachmentPropertiesDialog::slotHelp()
389{
390 invokeHelp(QStringLiteral("kmail2/the-composer-window.html"), QStringLiteral("attachments"));
391}
392
393#include "moc_attachmentpropertiesdialog.cpp"
static KAboutData applicationData()
A job to load an attachment from a mime content.
A dialog for editing attachment properties.
AttachmentPart::Ptr attachmentPart() const
Returns the modified attachment.
bool isEncryptEnabled() const
Returns whether the encryption status of the attachment can be changed.
AttachmentPropertiesDialog(const AttachmentPart::Ptr &part, bool readOnly=false, QWidget *parent=nullptr)
Creates a new attachment properties dialog.
void setSignEnabled(bool enabled)
Sets whether the signature status of the attachment can be changed.
~AttachmentPropertiesDialog() override
Destroys the attachment properties dialog.
void setEncryptEnabled(bool enabled)
Sets whether the encryption status of the attachment can be changed.
bool isSignEnabled() const
Returns whether the signature status of the attachment can be changed.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
KCALUTILS_EXPORT QString mimeType()
void invokeHelp(const QString &anchor=QString(), const QString &appname=QString())
KIOCORE_EXPORT QString convertSize(KIO::filesize_t size)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardAction id)
QCA_EXPORT void init()
void clicked(bool checked)
void setShortcut(const QKeySequence &key)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void currentTextChanged(const QString &text)
bool openUrl(const QUrl &url)
virtual void accept()
void setModal(bool modal)
virtual void reject()
QPushButton * button(StandardButton which) const const
QPixmap pixmap(QWindow *window, const QSize &size, Mode mode, State state) const const
QIcon fromTheme(const QString &name)
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
void setDefault(bool)
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const
PM_MessageBoxIconSize
Key_Return
QUrl resolved(const QUrl &relative) const const
void setQuery(const QString &query, ParsingMode mode)
QWidget(QWidget *parent, Qt::WindowFlags f)
void setLayout(QLayout *layout)
void setWindowTitle(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:07:25 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.