Incidenceeditor

incidenceattachment.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Bertjan Broeksema <broeksema@kde.org>
3 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "incidenceattachment.h"
9using namespace Qt::Literals::StringLiterals;
10
11#include "attachmenteditdialog.h"
12#include "attachmenticonview.h"
13#include "ui_dialogdesktop.h"
14
15#include <CalendarSupport/UriHandler>
16
17#include <KContacts/VCardDrag>
18
19#include <KMime/Message>
20
21#include <KActionCollection>
22#include <KIO/FileCopyJob>
23#include <KIO/JobUiDelegate>
24#include <KIO/JobUiDelegateFactory>
25#include <KIO/OpenUrlJob>
26#include <KIO/StoredTransferJob>
27#include <KJobWidgets>
28#include <KLocalizedString>
29#include <KMessageBox>
30#include <KProtocolManager>
31#include <QAction>
32#include <QFileDialog>
33#include <QIcon>
34#include <QMenu>
35#include <QUrl>
36
37#include <QClipboard>
38#include <QMimeData>
39#include <QMimeDatabase>
40#include <QMimeType>
41
42using namespace IncidenceEditorNG;
43
44IncidenceAttachment::IncidenceAttachment(Ui::EventOrTodoDesktop *ui)
45 : IncidenceEditor(nullptr)
46 , mUi(ui)
47 , mPopupMenu(new QMenu)
48{
49 setupActions();
50 setupAttachmentIconView();
51 setObjectName("IncidenceAttachment"_L1);
52
53 connect(mUi->mAddButton, &QPushButton::clicked, this, &IncidenceAttachment::addAttachment);
54 connect(mUi->mRemoveButton, &QPushButton::clicked, this, &IncidenceAttachment::removeSelectedAttachments);
55}
56
57IncidenceAttachment::~IncidenceAttachment()
58{
59 delete mPopupMenu;
60}
61
62void IncidenceAttachment::load(const KCalendarCore::Incidence::Ptr &incidence)
63{
64 mLoadedIncidence = incidence;
65 mAttachmentView->clear();
66
67 KCalendarCore::Attachment::List attachments = incidence->attachments();
68 for (KCalendarCore::Attachment::List::ConstIterator it = attachments.constBegin(), end = attachments.constEnd(); it != end; ++it) {
69 new AttachmentIconItem((*it), mAttachmentView);
70 }
71
72 mWasDirty = false;
73}
74
75void IncidenceAttachment::save(const KCalendarCore::Incidence::Ptr &incidence)
76{
77 incidence->clearAttachments();
78
79 for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
80 QListWidgetItem *item = mAttachmentView->item(itemIndex);
81 auto attitem = dynamic_cast<AttachmentIconItem *>(item);
82 Q_ASSERT(item);
83 incidence->addAttachment(attitem->attachment());
84 }
85}
86
87bool IncidenceAttachment::isDirty() const
88{
89 if (mLoadedIncidence) {
90 if (mAttachmentView->count() != mLoadedIncidence->attachments().count()) {
91 return true;
92 }
93
94 KCalendarCore::Attachment::List origAttachments = mLoadedIncidence->attachments();
95 for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
96 QListWidgetItem *item = mAttachmentView->item(itemIndex);
97 Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
98
99 const KCalendarCore::Attachment listAttachment = static_cast<AttachmentIconItem *>(item)->attachment();
100
101 for (int i = 0; i < origAttachments.count(); ++i) {
102 const KCalendarCore::Attachment attachment = origAttachments.at(i);
103
104 if (attachment == listAttachment) {
105 origAttachments.remove(i);
106 break;
107 }
108 }
109 }
110 // All attachments are removed from the list, meaning, the items in mAttachmentView
111 // are equal to the attachments set on mLoadedIncidence.
112 return !origAttachments.isEmpty();
113 } else {
114 // No incidence loaded, so if the user added attachments we're dirty.
115 return mAttachmentView->count() != 0;
116 }
117}
118
119int IncidenceAttachment::attachmentCount() const
120{
121 return mAttachmentView->count();
122}
123
124/// Private slots
125
126void IncidenceAttachment::addAttachment()
127{
129 auto item = new AttachmentIconItem(KCalendarCore::Attachment(), mAttachmentView);
130
131 QPointer<AttachmentEditDialog> dialog(new AttachmentEditDialog(item, mAttachmentView));
132 dialog->setWindowTitle(i18nc("@title", "Add Attachment"));
133 auto dialogResult = dialog->exec();
134 if (!that) {
135 return;
136 }
137
139 delete item;
140 } else {
141 Q_EMIT attachmentCountChanged(mAttachmentView->count());
142 }
143 delete dialog;
144
146}
147
148void IncidenceAttachment::copyToClipboard()
149{
150#ifndef QT_NO_CLIPBOARD
151 QApplication::clipboard()->setMimeData(mAttachmentView->mimeData(), QClipboard::Clipboard);
152#endif
153}
154
155void IncidenceAttachment::openURL(const QUrl &url)
156{
157 QString uri = url.url();
159}
160
161void IncidenceAttachment::pasteFromClipboard()
162{
163#ifndef QT_NO_CLIPBOARD
164 handlePasteOrDrop(QApplication::clipboard()->mimeData());
165#endif
166}
167
168void IncidenceAttachment::removeSelectedAttachments()
169{
171 QStringList labels;
172 selected.reserve(mAttachmentView->count());
173 labels.reserve(mAttachmentView->count());
174
175 for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
176 QListWidgetItem *it = mAttachmentView->item(itemIndex);
177 if (it->isSelected()) {
178 auto attitem = static_cast<AttachmentIconItem *>(it);
179 if (attitem) {
180 const KCalendarCore::Attachment att = attitem->attachment();
181 labels << att.label();
182 selected << it;
183 }
184 }
185 }
186
187 if (selected.isEmpty()) {
188 return;
189 }
190
191 QString labelsStr = labels.join("<nl/>"_L1);
192
194 xi18nc("@info", "Do you really want to remove these attachments?<nl/>%1", labelsStr),
195 i18nc("@title:window", "Remove Attachments?"),
198 QStringLiteral("calendarRemoveAttachments"))
199 != KMessageBox::ButtonCode::PrimaryAction) {
200 return;
201 }
202
203 for (QList<QListWidgetItem *>::iterator it(selected.begin()), end(selected.end()); it != end; ++it) {
204 int row = mAttachmentView->row(*it);
205 QListWidgetItem *next = mAttachmentView->item(++row);
206 QListWidgetItem *prev = mAttachmentView->item(--row);
207 if (next) {
208 next->setSelected(true);
209 } else if (prev) {
210 prev->setSelected(true);
211 }
212 delete *it;
213 }
214
215 mAttachmentView->update();
216 Q_EMIT attachmentCountChanged(mAttachmentView->count());
218}
219
220void IncidenceAttachment::saveAttachment(QListWidgetItem *item)
221{
222 Q_ASSERT(item);
223 Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
224
225 auto attitem = static_cast<AttachmentIconItem *>(item);
226 if (attitem->attachment().isEmpty()) {
227 return;
228 }
229
230 KCalendarCore::Attachment att = attitem->attachment();
231
232 // get the saveas file name
233 const QString saveAsFile = QFileDialog::getSaveFileName(nullptr, i18nc("@title", "Save Attachment"), att.label());
234
235 if (saveAsFile.isEmpty()) {
236 return;
237 }
238
240 if (att.isUri()) {
241 sourceUrl = QUrl(att.uri());
242 } else {
243 sourceUrl = attitem->tempFileForAttachment();
244 }
245 // save the attachment url
247 if (!job->exec() && job->error()) {
248 KMessageBox::error(nullptr, job->errorString());
249 }
250}
251
252void IncidenceAttachment::saveSelectedAttachments()
253{
254 for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
255 QListWidgetItem *item = mAttachmentView->item(itemIndex);
256 if (item->isSelected()) {
257 saveAttachment(item);
258 }
259 }
260}
261
262void IncidenceAttachment::showAttachment(QListWidgetItem *item)
263{
264 Q_ASSERT(item);
265 Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
266 auto attitem = static_cast<AttachmentIconItem *>(item);
267 if (attitem->attachment().isEmpty()) {
268 return;
269 }
270
271 const KCalendarCore::Attachment att = attitem->attachment();
272 if (att.isUri()) {
273 openURL(QUrl(att.uri()));
274 } else {
275 auto job = new KIO::OpenUrlJob(attitem->tempFileForAttachment(), att.mimeType());
276 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, mAttachmentView));
277 job->setDeleteTemporaryFile(true);
278 job->start();
279 }
280}
281
282void IncidenceAttachment::showContextMenu(const QPoint &pos) // clazy:exclude=function-args-by-value
283{
284 const bool enable = mAttachmentView->itemAt(pos) != nullptr;
285
286 int numSelected = 0;
287 for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
288 QListWidgetItem *item = mAttachmentView->item(itemIndex);
289 if (item->isSelected()) {
290 numSelected++;
291 }
292 }
293
294 mOpenAction->setEnabled(enable);
295 // TODO: support saving multiple attachments into a directory
296 mSaveAsAction->setEnabled(enable && numSelected == 1);
297#ifndef QT_NO_CLIPBOARD
298 mCopyAction->setEnabled(enable && numSelected == 1);
299 mCutAction->setEnabled(enable && numSelected == 1);
300#endif
301 mDeleteAction->setEnabled(enable);
302 mEditAction->setEnabled(enable);
303 mPopupMenu->exec(mAttachmentView->mapToGlobal(pos));
304}
305
306void IncidenceAttachment::showSelectedAttachments()
307{
308 for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
309 QListWidgetItem *item = mAttachmentView->item(itemIndex);
310 if (item->isSelected()) {
311 showAttachment(item);
312 }
313 }
314}
315
316void IncidenceAttachment::cutToClipboard()
317{
318#ifndef QT_NO_CLIPBOARD
319 copyToClipboard();
320 removeSelectedAttachments();
321#endif
322}
323
324void IncidenceAttachment::editSelectedAttachments()
325{
326 for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
327 QListWidgetItem *item = mAttachmentView->item(itemIndex);
328 if (item->isSelected()) {
329 Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
330
331 auto attitem = static_cast<AttachmentIconItem *>(item);
332 if (attitem->attachment().isEmpty()) {
333 return;
334 }
335
336 QPointer<AttachmentEditDialog> dialog(new AttachmentEditDialog(attitem, mAttachmentView, false));
337 dialog->setModal(false);
338 dialog->setAttribute(Qt::WA_DeleteOnClose, true);
339 dialog->show();
340 }
341 }
342}
343
344void IncidenceAttachment::slotItemRenamed(QListWidgetItem *item)
345{
346 Q_ASSERT(item);
347 Q_ASSERT(dynamic_cast<AttachmentIconItem *>(item));
348 static_cast<AttachmentIconItem *>(item)->setLabel(item->text());
350}
351
352void IncidenceAttachment::slotSelectionChanged()
353{
354 bool selected = false;
355 for (int itemIndex = 0; itemIndex < mAttachmentView->count(); ++itemIndex) {
356 QListWidgetItem *item = mAttachmentView->item(itemIndex);
357 if (item->isSelected()) {
358 selected = true;
359 break;
360 }
361 }
362 mUi->mRemoveButton->setEnabled(selected);
363}
364
365/// Private functions
366
367void IncidenceAttachment::handlePasteOrDrop(const QMimeData *mimeData)
368{
369 if (!mimeData) {
370 return;
371 }
372 QList<QUrl> urls;
373 bool probablyWeHaveUris = false;
374 QStringList labels;
375
376 if (KContacts::VCardDrag::canDecode(mimeData)) {
379 urls.reserve(addressees.count());
380 labels.reserve(addressees.count());
381 const KContacts::Addressee::List::ConstIterator end(addressees.constEnd());
382 for (KContacts::Addressee::List::ConstIterator it = addressees.constBegin(); it != end; ++it) {
383 urls.append(QUrl(QStringLiteral("uid:") + (*it).uid()));
384 // there is some weirdness about realName(), hence fromUtf8
385 labels.append(QString::fromUtf8((*it).realName().toLatin1()));
386 }
387 probablyWeHaveUris = true;
388 } else if (mimeData->hasUrls()) {
389 QMap<QString, QString> metadata;
390
391 // QT5
392 // urls = QList<QUrl>::fromMimeData( mimeData, &metadata );
393 probablyWeHaveUris = true;
394 labels = metadata[QStringLiteral("labels")].split(QLatin1Char(':'), Qt::SkipEmptyParts);
395 const QStringList::Iterator end(labels.end());
396 for (QStringList::Iterator it = labels.begin(); it != end; ++it) {
397 *it = QUrl::fromPercentEncoding((*it).toLatin1());
398 }
399 } else if (mimeData->hasText()) {
400 const QString text = mimeData->text();
402 urls.reserve(lst.count());
404 for (QStringList::ConstIterator it = lst.constBegin(); it != end; ++it) {
405 urls.append(QUrl(*it));
406 }
407 probablyWeHaveUris = true;
408 }
409 QMenu menu;
410 QAction *linkAction = nullptr;
411 QAction *cancelAction = nullptr;
412 if (probablyWeHaveUris) {
413 linkAction = menu.addAction(QIcon::fromTheme(QStringLiteral("insert-link")), i18nc("@action:inmenu", "&Link here"));
414 // we need to check if we can reasonably expect to copy the objects
415 bool weCanCopy = true;
417 for (QList<QUrl>::ConstIterator it = urls.constBegin(); it != end; ++it) {
419 break; // either we can copy them all, or no copying at all
420 }
421 }
422 if (weCanCopy) {
423 menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action:inmenu", "&Copy here"));
424 }
425 } else {
426 menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action:inmenu", "&Copy here"));
427 }
428
429 menu.addSeparator();
430 cancelAction = menu.addAction(QIcon::fromTheme(QStringLiteral("process-stop")), i18nc("@action:inmenu", "C&ancel"));
431
432 QByteArray data;
435
436 if (!mimeData->formats().isEmpty() && !probablyWeHaveUris) {
437 mimeType = mimeData->formats().first();
438 data = mimeData->data(mimeType);
439 QMimeDatabase db;
440 QMimeType mime = db.mimeTypeForName(mimeType);
441 if (mime.isValid()) {
442 label = mime.comment();
443 }
444 }
445
446 QAction *ret = menu.exec(QCursor::pos());
447 if (linkAction == ret) {
450 for (QList<QUrl>::ConstIterator it = urls.constBegin(); it != jtEnd; ++it) {
451 addUriAttachment((*it).url(), QString(), (jt == labels.constEnd() ? QString() : *(jt++)), true);
452 }
453 } else if (cancelAction != ret) {
454 if (probablyWeHaveUris) {
456 for (QList<QUrl>::ConstIterator it = urls.constBegin(); it != end; ++it) {
457 KIO::Job *job = KIO::storedGet(*it);
458 // TODO verify if slot exist !
459 connect(job, &KIO::Job::result, this, &IncidenceAttachment::downloadComplete);
460 }
461 } else { // we take anything
462 addDataAttachment(data, mimeType, label);
463 }
464 }
465}
466
467void IncidenceAttachment::downloadComplete(KJob *)
468{
469 // TODO
470}
471
472void IncidenceAttachment::setupActions()
473{
474 auto ac = new KActionCollection(this);
475 // ac->addAssociatedWidget( this );
476
477 mOpenAction = new QAction(QIcon::fromTheme(QStringLiteral("document-open")), i18nc("@action:inmenu open the attachment in a viewer", "&Open"), this);
478 connect(mOpenAction, &QAction::triggered, this, &IncidenceAttachment::showSelectedAttachments);
479 ac->addAction(QStringLiteral("view"), mOpenAction);
480 mPopupMenu->addAction(mOpenAction);
481
482 mSaveAsAction =
483 new QAction(QIcon::fromTheme(QStringLiteral("document-save-as")), i18nc("@action:inmenu save the attachment to a file", "Save As..."), this);
484 connect(mSaveAsAction, &QAction::triggered, this, &IncidenceAttachment::saveSelectedAttachments);
485 mPopupMenu->addAction(mSaveAsAction);
486 mPopupMenu->addSeparator();
487
488#ifndef QT_NO_CLIPBOARD
489 mCopyAction = KStandardAction::copy(this, &IncidenceAttachment::copyToClipboard, ac);
490 mPopupMenu->addAction(mCopyAction);
491
492 mCutAction = KStandardAction::cut(this, &IncidenceAttachment::cutToClipboard, ac);
493 mPopupMenu->addAction(mCutAction);
494
495 QAction *action = KStandardAction::paste(this, &IncidenceAttachment::pasteFromClipboard, ac);
496 mPopupMenu->addAction(action);
497 mPopupMenu->addSeparator();
498#endif
499
500 mDeleteAction = new QAction(QIcon::fromTheme(QStringLiteral("list-remove")), i18nc("@action:inmenu remove the attachment", "&Remove"), this);
501 connect(mDeleteAction, &QAction::triggered, this, &IncidenceAttachment::removeSelectedAttachments);
502 ac->addAction(QStringLiteral("remove"), mDeleteAction);
503 mDeleteAction->setShortcut(Qt::Key_Delete);
504 mPopupMenu->addAction(mDeleteAction);
505 mPopupMenu->addSeparator();
506
507 mEditAction = new QAction(QIcon::fromTheme(QStringLiteral("document-properties")),
508 i18nc("@action:inmenu show a dialog used to edit the attachment", "&Properties..."),
509 this);
510 connect(mEditAction, &QAction::triggered, this, &IncidenceAttachment::editSelectedAttachments);
511 ac->addAction(QStringLiteral("edit"), mEditAction);
512 mPopupMenu->addAction(mEditAction);
513}
514
515void IncidenceAttachment::setupAttachmentIconView()
516{
517 mAttachmentView = new AttachmentIconView;
518 mAttachmentView->setWhatsThis(i18nc("@info:whatsthis",
519 "Displays items (files, mail, etc.) that "
520 "have been associated with this event or to-do."));
521
522 connect(mAttachmentView, &AttachmentIconView::itemDoubleClicked, this, &IncidenceAttachment::showAttachment);
523 connect(mAttachmentView, &AttachmentIconView::itemChanged, this, &IncidenceAttachment::slotItemRenamed);
524 connect(mAttachmentView, &AttachmentIconView::itemSelectionChanged, this, &IncidenceAttachment::slotSelectionChanged);
525 connect(mAttachmentView, &AttachmentIconView::customContextMenuRequested, this, &IncidenceAttachment::showContextMenu);
526
527 auto layout = new QGridLayout(mUi->mAttachmentViewPlaceHolder);
528 layout->setContentsMargins(0, 0, 0, 0);
529 layout->addWidget(mAttachmentView);
530 QWidget::setTabOrder(mUi->mAddButton, mAttachmentView);
531}
532
533// void IncidenceAttachmentEditor::addAttachment( KCalendarCore::Attachment *attachment )
534// {
535// new AttachmentIconItem( attachment, mAttachmentView );
536// }
537
538void IncidenceAttachment::addDataAttachment(const QByteArray &data, const QString &mimeType, const QString &label)
539{
540 auto item = new AttachmentIconItem(KCalendarCore::Attachment(), mAttachmentView);
541
543 if (mimeType == "message/rfc822"_L1) {
544 // mail message. try to set the label from the mail Subject:
545 KMime::Message msg;
546 msg.setContent(data);
547 msg.parse();
548 nlabel = msg.subject()->asUnicodeString();
549 }
550
551 item->setData(data);
552 item->setLabel(nlabel);
553 if (mimeType.isEmpty()) {
554 QMimeDatabase db;
555 item->setMimeType(db.mimeTypeForData(data).name());
556 } else {
557 item->setMimeType(mimeType);
558 }
559
561}
562
563void IncidenceAttachment::addUriAttachment(const QString &uri, const QString &mimeType, const QString &label, bool inLine)
564{
565 if (!inLine) {
566 auto item = new AttachmentIconItem(KCalendarCore::Attachment(), mAttachmentView);
567 item->setUri(uri);
568 item->setLabel(label);
569 if (mimeType.isEmpty()) {
570 if (uri.startsWith("uid:"_L1)) {
571 item->setMimeType(QStringLiteral("text/directory"));
572 } else if (uri.startsWith("kmail:"_L1)) {
573 item->setMimeType(QStringLiteral("message/rfc822"));
574 } else if (uri.startsWith("urn:x-ical"_L1)) {
575 item->setMimeType(QStringLiteral("text/calendar"));
576 } else if (uri.startsWith("news:"_L1)) {
577 item->setMimeType(QStringLiteral("message/news"));
578 } else {
579 QMimeDatabase db;
580 item->setMimeType(db.mimeTypeForUrl(QUrl(uri)).name());
581 }
582 }
583 } else {
584 auto job = KIO::storedGet(QUrl(uri));
585 KJobWidgets::setWindow(job, nullptr);
586 if (job->exec()) {
587 const QByteArray data = job->data();
588 addDataAttachment(data, mimeType, label);
589 }
590 }
591}
592
593#include "moc_incidenceattachment.cpp"
static bool process(const QString &uri)
KCal Incidences are complicated objects.
void checkDirtyStatus()
Checks if the dirty status has changed until last check and emits the dirtyStatusChanged signal if ne...
QSharedPointer< IncidenceT > incidence() const
Convenience method to get a pointer for a specific const Incidence Type.
AddresseeList List
void result(KJob *job)
void setContent(const QByteArray &s)
QString asUnicodeString() const override
KMime::Headers::Subject * subject(bool create=true)
static bool supportsReading(const QUrl &url)
QString xi18nc(const char *context, const char *text, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
KCALUTILS_EXPORT QString mimeType()
KCONTACTS_EXPORT bool canDecode(const QMimeData *md)
KCONTACTS_EXPORT bool fromMimeData(const QMimeData *md, KContacts::Addressee::List &contacts)
KIOCORE_EXPORT StoredTransferJob * storedGet(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
KIOCORE_EXPORT KJobUiDelegate * createDefaultJobUiDelegate()
KIOCORE_EXPORT FileCopyJob * file_copy(const QUrl &src, const QUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
void setWindow(QObject *job, QWidget *widget)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
ButtonCode questionTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Notify)
QAction * paste(const QObject *recvr, const char *slot, QObject *parent)
QAction * cut(const QObject *recvr, const char *slot, QObject *parent)
QAction * copy(const QObject *recvr, const char *slot, QObject *parent)
KGuiItem remove()
KGuiItem cancel()
const QList< QKeySequence > & next()
QString label(StandardShortcut id)
const QList< QKeySequence > & end()
QString name(StandardShortcut id)
void clicked(bool checked)
void update(const QModelIndex &index)
void setEnabled(bool)
void setShortcut(const QKeySequence &shortcut)
void triggered(bool checked)
char * data()
void setMimeData(QMimeData *src, Mode mode)
QPoint pos()
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
QClipboard * clipboard()
QIcon fromTheme(const QString &name)
typedef Iterator
void append(QList< T > &&value)
iterator begin()
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
iterator end()
T & first()
bool isEmpty() const const
void reserve(qsizetype size)
void clear()
QListWidgetItem * item(int row) const const
QListWidgetItem * itemAt(const QPoint &p) const const
void itemChanged(QListWidgetItem *item)
void itemDoubleClicked(QListWidgetItem *item)
void itemSelectionChanged()
int row(const QListWidgetItem *item) const const
bool isSelected() const const
virtual void setData(int role, const QVariant &value)
void setSelected(bool select)
QString text() const const
QAction * addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut)
QAction * addSeparator()
QAction * exec()
QByteArray data(const QString &mimeType) const const
virtual QStringList formats() const const
bool hasText() const const
bool hasUrls() const const
QString text() const const
QMimeType mimeTypeForData(QIODevice *device) const const
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
QMimeType mimeTypeForUrl(const QUrl &url) const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString join(QChar separator) const const
Key_Delete
SkipEmptyParts
WA_DeleteOnClose
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl fromLocalFile(const QString &localFile)
QString fromPercentEncoding(const QByteArray &input)
QString url(FormattingOptions options) const const
void customContextMenuRequested(const QPoint &pos)
QPoint mapToGlobal(const QPoint &pos) const const
void setTabOrder(QWidget *first, QWidget *second)
void setWhatsThis(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Apr 27 2024 22:14:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.