CalendarSupport

incidenceviewer.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
3 SPDX-FileContributor: Tobias Koenig <tokoe@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "incidenceviewer.h"
9#include "attachmenthandler.h"
10#include "incidenceviewer_p.h"
11#include "urihandler.h"
12#include "utils.h"
13
14#include "incidenceattachmentmodel.h"
15
16#include <Akonadi/CalendarBase>
17#include <Akonadi/CalendarUtils>
18#include <Akonadi/CollectionFetchJob>
19#include <Akonadi/ETMCalendar>
20#include <Akonadi/ItemFetchScope>
21
22#include <KCalUtils/IncidenceFormatter>
23
24#include <KJob>
25#include <QRegularExpression>
26#include <QTextBrowser>
27
28#include <QVBoxLayout>
29
30using namespace CalendarSupport;
31
32TextBrowser::TextBrowser(QWidget *parent)
33 : QTextBrowser(parent)
34{
35 setFrameStyle(QFrame::NoFrame);
36}
37
38void TextBrowser::doSetSource(const QUrl &name, QTextDocument::ResourceType type)
39{
40 Q_UNUSED(type);
41 QString uri = name.toString();
42 // QTextBrowser for some reason insists on putting // or / in links,
43 // this is a crude workaround
44 if (uri.startsWith(QLatin1StringView("uid:")) || uri.startsWith(QLatin1StringView("kmail:"))
45 || uri.startsWith(QStringLiteral("urn:x-ical").section(QLatin1Char(':'), 0, 0)) || uri.startsWith(QLatin1StringView("news:"))
46 || uri.startsWith(QLatin1StringView("mailto:"))) {
47 uri.replace(QRegularExpression(QLatin1StringView("^([^:]+:)/+")), QStringLiteral("\\1"));
48 }
49
50 if (uri.startsWith(QLatin1StringView("ATTACH:"))) {
51 Q_EMIT attachmentUrlClicked(uri);
52 } else {
54 }
55}
56
57class CalendarSupport::IncidenceViewerPrivate
58{
59public:
60 explicit IncidenceViewerPrivate(IncidenceViewer *parent)
61 : mParent(parent)
62 {
63 mAttachmentHandler = new AttachmentHandler(parent);
64 mBrowser = new TextBrowser;
65 parent->connect(mBrowser, &TextBrowser::attachmentUrlClicked, parent, [this](const QString &str) {
66 slotAttachmentUrlClicked(str);
67 });
68 }
69
70 void updateView()
71 {
72 QString text;
73
74 if (mCurrentItem.isValid()) {
77 mDate);
78 text.prepend(mHeaderText);
79 mBrowser->setHtml(text);
80 } else {
81 text = mDefaultText;
82 if (!mDelayedClear) {
83 mBrowser->setHtml(text);
84 }
85 }
86 }
87
88 void slotParentCollectionFetched(KJob *job)
89 {
90 mParentCollectionFetchJob = nullptr;
91 mParentCollection = Akonadi::Collection();
92
93 if (!job->error()) {
94 auto fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
95 if (!fetchJob->collections().isEmpty()) {
96 mParentCollection = fetchJob->collections().at(0);
97 }
98 }
99
100 updateView();
101 }
102
103 void slotAttachmentUrlClicked(const QString &uri)
104 {
105 const QString attachmentName = QString::fromUtf8(QByteArray::fromBase64(uri.mid(7).toUtf8()));
106 mAttachmentHandler->view(attachmentName, Akonadi::CalendarUtils::incidence(mCurrentItem));
107 }
108
109 Akonadi::EntityTreeModel *mETM = nullptr;
110 IncidenceViewer *const mParent;
111 TextBrowser *mBrowser = nullptr;
112 Akonadi::Item mCurrentItem;
113 QString mHeaderText;
114 QString mDefaultText;
115 Akonadi::Collection mParentCollection;
116 Akonadi::CollectionFetchJob *mParentCollectionFetchJob = nullptr;
117 IncidenceAttachmentModel *mAttachmentModel = nullptr;
118 AttachmentHandler *mAttachmentHandler = nullptr;
119 QDate mDate;
120 bool mDelayedClear = false;
121};
122
124 : QWidget(parent)
125 , d(new IncidenceViewerPrivate(this))
126{
127 d->mETM = calendar->entityTreeModel();
128 init();
129}
130
132 : QWidget(parent)
133 , d(new IncidenceViewerPrivate(this))
134{
135 d->mETM = etm;
136 init();
137}
138
140 : QWidget(parent)
141 , d(new IncidenceViewerPrivate(this))
142{
143 init();
144}
145
147{
148 auto layout = new QVBoxLayout(this);
149 layout->setContentsMargins(0, 0, 0, 0);
150
151 d->mBrowser->setOpenLinks(true);
152 d->mBrowser->setMinimumHeight(1);
153
154 layout->addWidget(d->mBrowser);
155
156 // always fetch full payload for incidences
159
160 d->updateView();
161}
162
164
166{
167 d->mETM = calendar->entityTreeModel();
168}
169
171{
172 d->mETM = model;
173}
174
176{
177 return ItemMonitor::item();
178}
179
181{
182 return d->mDate;
183}
184
186{
187 if (!d->mAttachmentModel) {
188 d->mAttachmentModel = new IncidenceAttachmentModel(const_cast<IncidenceViewer *>(this));
189 }
190 return d->mAttachmentModel;
191}
192
194{
195 d->mDelayedClear = delayed;
196}
197
199{
200 d->mDefaultText = message;
201}
202
204{
205 d->mHeaderText = text;
206}
207
209{
210 d->mDate = date;
211 ItemMonitor::setItem(incidence);
212
213 d->updateView();
214}
215
216void IncidenceViewer::itemChanged(const Akonadi::Item &item)
217{
219 d->mBrowser->clear();
220 return;
221 }
222
223 d->mCurrentItem = item;
224
225 if (d->mAttachmentModel) {
226 d->mAttachmentModel->setItem(d->mCurrentItem);
227 }
228
229 if (d->mParentCollectionFetchJob) {
230 disconnect(d->mParentCollectionFetchJob, SIGNAL(result(KJob *)), this, SLOT(slotParentCollectionFetched(KJob *)));
231 delete d->mParentCollectionFetchJob;
232 }
233
234 d->mParentCollectionFetchJob = new Akonadi::CollectionFetchJob(d->mCurrentItem.parentCollection(), Akonadi::CollectionFetchJob::Base, this);
235
236 connect(d->mParentCollectionFetchJob, SIGNAL(result(KJob *)), this, SLOT(slotParentCollectionFetched(KJob *)));
237}
238
239void IncidenceViewer::itemRemoved()
240{
241 d->mCurrentItem = Akonadi::Item();
242 d->mBrowser->clear();
243}
244
245#include "moc_incidenceviewer.cpp"
246#include "moc_incidenceviewer_p.cpp"
This file is part of the API for handling calendar data and provides static functions for dealing wit...
Akonadi::EntityTreeModel * entityTreeModel() const
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
void fetchFullPayload(bool fetch=true)
ItemFetchScope & fetchScope()
bool hasPayload() const
bool isValid() const
Provides methods to handle incidence attachments.
bool view(const KCalendarCore::Attachment &attachment)
Launches a viewer on the specified attachment.
A viewer component for incidences in Akonadi.
Akonadi::Item incidence() const
Returns the incidence that is currently displayed.
QDate activeDate() const
Returns the active date used for the currently displayed incidence.
void setCalendar(Akonadi::ETMCalendar *calendar)
Sets the Calendar for this viewer.
void setIncidence(const Akonadi::Item &incidence, QDate activeDate=QDate())
Sets the incidence that shall be displayed in the viewer.
IncidenceViewer(Akonadi::ETMCalendar *calendar, QWidget *parent=nullptr)
Creates a new incidence viewer.
void setHeaderText(const QString &text)
Sets an additional text that is shown above the incidence.
void setModel(Akonadi::EntityTreeModel *etm)
Sets the model for this viewer.
~IncidenceViewer() override
Destroys the incidence viewer.
void setDefaultMessage(const QString &message)
Sets the default message that shall be shown if no incidence is set.
void setDelayedClear(bool delayed)
Sets whether the view shall be cleared as soon as an empty incidence is set (default) or delayed when...
void init()
Initialize the widget settings.
QAbstractItemModel * attachmentModel() const
Returns the attachment model for the currently displayed incidence.
static bool process(const QString &uri)
Process URI (e.g.
int error() const
AKONADI_CALENDAR_EXPORT KCalendarCore::Incidence::Ptr incidence(const Akonadi::Item &item)
AKONADI_CALENDAR_EXPORT QString displayName(Akonadi::ETMCalendar *calendar, const Akonadi::Collection &collection)
KCALUTILS_EXPORT QString extensiveDisplayStr(const KCalendarCore::Calendar::Ptr &calendar, const KCalendarCore::IncidenceBase::Ptr &incidence, QDate date=QDate())
QString name(StandardShortcut id)
QByteArray fromBase64(const QByteArray &base64, Base64Options options)
void addWidget(QWidget *w)
void setContentsMargins(const QMargins &margins)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
T qobject_cast(QObject *object)
QString fromUtf8(QByteArrayView str)
QString mid(qsizetype position, qsizetype n) const const
QString & prepend(QChar ch)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QByteArray toUtf8() const const
QLayout * layout() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:16:32 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.