1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2021 Julius Künzel <jk.kdedev@smartlab.uber.space>
4
5 SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
8#include "kaboutapplicationcomponentlistdelegate_p.h"
9
10#include "kaboutapplicationcomponentmodel_p.h"
11#include "kaboutapplicationlistview_p.h"
12#include "klicensedialog_p.h"
13#include "ktoolbar.h"
14
15#include <KLocalizedString>
16
17#include <QAction>
18#include <QApplication>
19#include <QDesktopServices>
20#include <QLabel>
21#include <QPainter>
22#include <QStandardPaths>
23#include <QUrl>
24
25namespace KDEPrivate
26{
27
28KAboutApplicationComponentListDelegate::KAboutApplicationComponentListDelegate(QAbstractItemView *itemView, QObject *parent)
29 : KWidgetItemDelegate(itemView, parent)
30{
31}
32
33QList<QWidget *> KAboutApplicationComponentListDelegate::createItemWidgets(const QModelIndex &index) const
34{
35 Q_UNUSED(index);
36 QList<QWidget *> list;
37
38 QLabel *textLabel = new QLabel(itemView());
39 list.append(t: textLabel);
40
41 KAboutApplicationComponentProfile profile = index.data().value<KAboutApplicationComponentProfile>();
42 textLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
43 QObject::connect(sender: textLabel, signal: &QLabel::linkActivated, context: itemView(), slot: [this, profile]() {
44 auto *dialog = new KLicenseDialog(profile.license(), itemView());
45 dialog->show();
46 });
47
48 KToolBar *mainLinks = new KToolBar(itemView(), false, false);
49
50 QAction *homepageAction = new QAction(QIcon::fromTheme(QStringLiteral("internet-services")), //
51 i18n("Visit component's homepage"),
52 mainLinks);
53 homepageAction->setVisible(false);
54 mainLinks->addAction(action: homepageAction);
55 QAction *visitProfileAction = new QAction(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")), QString(), mainLinks);
56 visitProfileAction->setVisible(false);
57 mainLinks->addAction(action: visitProfileAction);
58
59 list.append(t: mainLinks);
60
61 connect(sender: mainLinks, signal: &QToolBar::actionTriggered, context: this, slot: &KAboutApplicationComponentListDelegate::launchUrl);
62
63 return list;
64}
65
66void KAboutApplicationComponentListDelegate::updateItemWidgets(const QList<QWidget *> &widgets,
67 const QStyleOptionViewItem &option,
68 const QPersistentModelIndex &index) const
69{
70 const int margin = option.fontMetrics.height() / 2;
71
72 KAboutApplicationComponentProfile profile = index.data().value<KAboutApplicationComponentProfile>();
73
74 QRect wRect = widgetsRect(option, index);
75
76 // Let's fill in the text first...
77 QLabel *label = qobject_cast<QLabel *>(object: widgets.at(i: TextLabel));
78 label->setSizePolicy(hor: QSizePolicy::Fixed, ver: QSizePolicy::Fixed);
79
80 QString text = buildTextForProfile(profile);
81
82 label->move(ax: wRect.left(), ay: wRect.top());
83 label->resize(w: wRect.width(), h: heightForString(string: text, lineWidth: wRect.width() - margin, option) + margin);
84 label->setWordWrap(true);
85 label->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
86 label->setAlignment(Qt::AlignBottom | Qt::AlignLeft);
87 label->setForegroundRole(QPalette::WindowText);
88
89 label->setText(text);
90
91 // And now we fill in the main links (email + homepage + OCS profile)...
92 KToolBar *mainLinks = qobject_cast<KToolBar *>(object: widgets.at(i: MainLinks));
93 mainLinks->setIconSize(QSize(22, 22));
94 mainLinks->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
95 mainLinks->setSizePolicy(hor: QSizePolicy::Fixed, ver: QSizePolicy::Fixed);
96 QAction *action;
97 if (!profile.webAdress().isEmpty()) {
98 action = mainLinks->actions().at(i: HomepageAction);
99 action->setToolTip(i18nc("@info:tooltip", "Visit components's homepage\n%1", profile.webAdress()));
100 action->setData(profile.webAdress());
101 action->setVisible(true);
102 }
103 mainLinks->resize(QSize(mainLinks->sizeHint().width(), LINK_HEIGHT));
104 mainLinks->move(ax: wRect.left(), ay: wRect.top() + label->height());
105 itemView()->reset();
106}
107
108QSize KAboutApplicationComponentListDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
109{
110 int height = widgetsRect(option, index).height();
111
112 QSize metrics(option.fontMetrics.height() * 7, height);
113 return metrics;
114}
115
116void KAboutApplicationComponentListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &) const
117{
118 QStyle *style = QApplication::style();
119 style->drawPrimitive(pe: QStyle::PE_Widget, opt: &option, p: painter, w: nullptr);
120}
121
122void KAboutApplicationComponentListDelegate::launchUrl(QAction *action) const
123{
124 QString url = action->data().toString();
125 if (!url.isEmpty()) {
126 QDesktopServices::openUrl(url: QUrl(url));
127 }
128}
129
130int KAboutApplicationComponentListDelegate::heightForString(const QString &string, int lineWidth, const QStyleOptionViewItem &option) const
131{
132 QFontMetrics fm = option.fontMetrics;
133 constexpr auto opts = Qt::AlignLeft | Qt::AlignBottom | Qt::TextWordWrap;
134 QRect boundingRect = fm.boundingRect(x: 0, y: 0, w: lineWidth, h: 9999, flags: opts, text: string);
135 return boundingRect.height();
136}
137
138QString KAboutApplicationComponentListDelegate::buildTextForProfile(const KAboutApplicationComponentProfile &profile) const
139{
140 QString text = QLatin1String("<b>") + i18nc("@item Component name in about dialog.", "%1", profile.name()) + QLatin1String("</b>");
141
142 if (!profile.version().isEmpty()) {
143 text += QStringLiteral("\n<br><i>%1</i>").arg(i18n("Version %1", profile.version()));
144 }
145
146 if (!profile.description().isEmpty()) {
147 text += QLatin1String("\n<br>") + profile.description();
148 }
149
150 if (profile.license().key() != KAboutLicense::Unknown) {
151 text += QLatin1String("\n<br>");
152 text += QStringLiteral("<a href=\"#\">%2</a>").arg(i18n("License: %1", profile.license().name(KAboutLicense::FullName)));
153 }
154
155 return text;
156}
157
158QRect KAboutApplicationComponentListDelegate::widgetsRect(const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const
159{
160 KAboutApplicationComponentProfile profile = index.data().value<KAboutApplicationComponentProfile>();
161 int margin = option.fontMetrics.height() / 2;
162
163 QRect widgetsRect = QRect(option.rect.left() + margin, //
164 margin / 2, //
165 option.rect.width() - 2 * margin, //
166 0);
167
168 int textHeight = heightForString(string: buildTextForProfile(profile), lineWidth: widgetsRect.width() - margin, option);
169 widgetsRect.setHeight(textHeight + LINK_HEIGHT + 1.5 * margin);
170
171 return widgetsRect;
172}
173
174} // namespace KDEPrivate
175
176#include "moc_kaboutapplicationcomponentlistdelegate_p.cpp"
177

source code of kxmlgui/src/kaboutapplicationcomponentlistdelegate_p.cpp