Akonadi Contacts

textbrowser.cpp
1/*
2 SPDX-FileCopyrightText: 2012-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5
6*/
7
8#include "textbrowser_p.h"
9#include <KCodecs>
10#include <KLocalizedString>
11#include <KStandardAction>
12#include <QAction>
13#include <QUrl>
14
15#include <QApplication>
16#include <QClipboard>
17#include <QContextMenuEvent>
18#include <QMenu>
19#include <QRegularExpression>
20#include <QTextBlock>
21
22using namespace Akonadi;
23
24TextBrowser::TextBrowser(QWidget *parent)
25 : QTextBrowser(parent)
26{
27 setOpenLinks(false);
28}
29
30void TextBrowser::slotCopyData()
31{
32#ifndef QT_NO_CLIPBOARD
34 // put the data into the mouse selection and the clipboard
35 if (mDataToCopy.userType() == QMetaType::QPixmap) {
36 clip->setPixmap(mDataToCopy.value<QPixmap>(), QClipboard::Clipboard);
37 clip->setPixmap(mDataToCopy.value<QPixmap>(), QClipboard::Selection);
38 } else {
39 clip->setText(mDataToCopy.toString(), QClipboard::Clipboard);
40 clip->setText(mDataToCopy.toString(), QClipboard::Selection);
41 }
42#endif
43}
44
45#ifndef QT_NO_CONTEXTMENU
46void TextBrowser::contextMenuEvent(QContextMenuEvent *event)
47{
48#ifndef QT_NO_CLIPBOARD
49 QMenu popup;
50
51 QAction *act = KStandardAction::copy(this, &TextBrowser::copy, this);
52 act->setEnabled(!textCursor().selectedText().isEmpty());
54 popup.addAction(act);
55
56 // Create a new action to correspond with what is under the click
57 act = new QAction(i18nc("@action:inmenu Copy the text of a general item", "Copy Item"), this);
58
59 mDataToCopy.clear(); // nothing found to copy yet
60
61 QString link = anchorAt(event->pos());
62 if (!link.isEmpty()) {
63 if (link.startsWith(QLatin1StringView("mailto:"))) {
64 mDataToCopy = KCodecs::decodeRFC2047String(QUrl(link).path());
65 // Action text matches that used in KMail
66 act->setText(i18nc("@action:inmenu Copy a displayed email address", "Copy Email Address"));
67 } else {
68 // A link, but it could be one of our internal ones. There is
69 // no point in copying these. Internal links are always in the
70 // form "protocol:?argument", whereas valid external links should
71 // be in the form starting with "protocol://".
72 if (!link.contains(QRegularExpression(QStringLiteral("^\\w+:\\?")))) {
73 mDataToCopy = link;
74 // Action text matches that used in Konqueror
75 act->setText(i18nc("@action:inmenu Copy a link URL", "Copy Link URL"));
76 }
77 }
78 }
79
80 if (!mDataToCopy.isValid()) { // no link was found above
81 QTextCursor curs = cursorForPosition(event->pos());
82 QString text = curs.block().text(); // try the text under cursor
83
84 if (!text.isEmpty()) {
85 // curs().block().text() over an image (contact photo or QR code)
86 // returns a string starting with the character 0xFFFC (Unicode
87 // object replacement character). See the documentation for
88 // QTextImageFormat.
89 if (text.startsWith(QChar(0xFFFC))) {
90 QTextCharFormat charFormat = curs.charFormat();
91 if (charFormat.isImageFormat()) {
92 const QTextImageFormat imageFormat = charFormat.toImageFormat();
93 const QString imageName = imageFormat.name();
94 const QVariant imageResource = document()->resource(QTextDocument::ImageResource, QUrl(imageName));
95
96 const auto pix = imageResource.value<QPixmap>();
97 if (!pix.isNull()) {
98 // There may be other images (e.g. contact type icons) that
99 // there is no point in copying.
100 if (imageName == QLatin1StringView("contact_photo")) {
101 mDataToCopy = pix;
102 act->setText(i18nc("@action:inmenu Copy a contact photo", "Copy Photo"));
103 } else if (imageName == QLatin1StringView("qrcode")) {
104 mDataToCopy = pix;
105 act->setText(i18nc("@action:inmenu Copy a QR code image", "Copy Code"));
106 }
107 }
108 }
109 } else {
110 // Added by our formatter (but not I18N'ed) for a mobile
111 // telephone number. See
112 // kdepim/kaddressbook/grantlee/grantleecontactformatter.cpp and
113 // kdepimlibs/akonadi/contact/standardcontactformatter.cpp
114 text.remove(QRegularExpression(QStringLiteral("\\s*\\(SMS\\)$")));
115
116 // For an item which was formatted with line breaks (as <br>
117 // in HTML), the returned text contains the character 0x2028
118 // (Unicode line separator). Convert any of these back to newlines.
119 text.replace(QChar(0x2028), QLatin1Char('\n'));
120
121 mDataToCopy = text;
122 }
123 }
124 }
125
126 if (mDataToCopy.isValid()) {
127 connect(act, &QAction::triggered, this, &TextBrowser::slotCopyData);
128 } else {
129 act->setEnabled(false);
130 }
131
132 popup.addAction(act);
133 popup.exec(event->globalPos());
134#endif
135}
136
137#endif
138
139#include "moc_textbrowser_p.cpp"
QString i18nc(const char *context, const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
A widget for editing the display name of a contact.
KCODECS_EXPORT QString decodeRFC2047String(QByteArrayView src, QByteArray *usedCS, const QByteArray &defaultCS=QByteArray(), CharsetOption option=NoOption)
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
QString path(const QString &relativePath)
QAction * copy(const QObject *recvr, const char *slot, QObject *parent)
void setEnabled(bool)
void setShortcut(const QKeySequence &shortcut)
void setText(const QString &text)
void triggered(bool checked)
void setPixmap(const QPixmap &pixmap, Mode mode)
void setText(const QString &text, Mode mode)
QClipboard * clipboard()
QAction * addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut)
QAction * exec()
bool isEmpty() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString text() const const
QTextBlock block() const const
QTextCharFormat charFormat() const const
bool isImageFormat() const const
QTextImageFormat toImageFormat() const const
QString name() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
T value() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:20 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.