| 1 | /* |
| 2 | This file is part of the KDE libraries |
| 3 | SPDX-FileCopyrightText: 2005 Olivier Goffart <ogoffart at kde.org> |
| 4 | |
| 5 | SPDX-License-Identifier: LGPL-2.0-only |
| 6 | */ |
| 7 | |
| 8 | #include "knotifyeventlist.h" |
| 9 | |
| 10 | #include <knotifyconfig_debug.h> |
| 11 | |
| 12 | #include <KConfig> |
| 13 | #include <KConfigGroup> |
| 14 | #include <KLocalizedString> |
| 15 | |
| 16 | #include <QHeaderView> |
| 17 | #include <QPainter> |
| 18 | #include <QRegularExpression> |
| 19 | #include <QStandardPaths> |
| 20 | #include <QStyledItemDelegate> |
| 21 | |
| 22 | // BEGIN KNotifyEventListDelegate |
| 23 | |
| 24 | class KNotifyEventList::KNotifyEventListDelegate : public QStyledItemDelegate |
| 25 | { |
| 26 | public: |
| 27 | explicit KNotifyEventListDelegate(QObject *parent = nullptr); |
| 28 | |
| 29 | void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; |
| 30 | |
| 31 | private: |
| 32 | }; |
| 33 | |
| 34 | KNotifyEventList::KNotifyEventListDelegate::KNotifyEventListDelegate(QObject *parent) |
| 35 | : QStyledItemDelegate(parent) |
| 36 | { |
| 37 | } |
| 38 | |
| 39 | void KNotifyEventList::KNotifyEventListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const |
| 40 | { |
| 41 | if (index.column() != 0) { |
| 42 | return QStyledItemDelegate::paint(painter, option, index); |
| 43 | } |
| 44 | |
| 45 | QVariant displayData = index.data(arole: Qt::UserRole); |
| 46 | QString prstring = displayData.toString(); |
| 47 | |
| 48 | QStyledItemDelegate::paint(painter, option, index); |
| 49 | |
| 50 | // qDebug() << prstring; |
| 51 | |
| 52 | QRect rect = option.rect; |
| 53 | |
| 54 | QStringList optionsList = prstring.split(sep: QLatin1Char('|')); |
| 55 | QList<QIcon> iconList; |
| 56 | iconList << (optionsList.contains(QStringLiteral("Sound" )) ? QIcon::fromTheme(QStringLiteral("media-playback-start" )) : QIcon()); |
| 57 | iconList << (optionsList.contains(QStringLiteral("Popup" )) ? QIcon::fromTheme(QStringLiteral("dialog-information" )) : QIcon()); |
| 58 | |
| 59 | int mc_x = 0; |
| 60 | |
| 61 | int iconWidth = option.decorationSize.width(); |
| 62 | int iconHeight = option.decorationSize.height(); |
| 63 | for (const QIcon &icon : std::as_const(t&: iconList)) { |
| 64 | icon.paint(painter, x: rect.left() + mc_x + 4, y: rect.top() + (rect.height() - iconHeight) / 2, w: iconWidth, h: iconHeight); |
| 65 | mc_x += iconWidth + 4; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | // END KNotifyEventListDelegate |
| 70 | |
| 71 | KNotifyEventList::KNotifyEventList(QWidget *parent) |
| 72 | : QTreeWidget(parent) |
| 73 | , config(nullptr) |
| 74 | { |
| 75 | QStringList ; |
| 76 | headerLabels << i18nc("State of the notified event" , "State" ) << i18nc("Title of the notified event" , "Title" ) |
| 77 | << i18nc("Description of the notified event" , "Description" ); |
| 78 | setHeaderLabels(headerLabels); |
| 79 | |
| 80 | setItemDelegate(new KNotifyEventListDelegate(this)); |
| 81 | setRootIsDecorated(false); |
| 82 | setAlternatingRowColors(true); |
| 83 | |
| 84 | // Extract icon size as the font height (as h=w on icons) |
| 85 | QStyleOptionViewItem iconOption; |
| 86 | iconOption.initFrom(w: this); |
| 87 | int iconWidth = iconOption.fontMetrics.height() - 2; // 1px margin top & bottom |
| 88 | setIconSize(QSize(iconWidth, iconWidth)); |
| 89 | |
| 90 | header()->setSectionResizeMode(logicalIndex: 0, mode: QHeaderView::Fixed); |
| 91 | header()->setSectionResizeMode(logicalIndex: 1, mode: QHeaderView::ResizeToContents); |
| 92 | |
| 93 | connect(sender: this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), receiver: this, SLOT(slotSelectionChanged(QTreeWidgetItem *, QTreeWidgetItem *))); |
| 94 | } |
| 95 | |
| 96 | KNotifyEventList::~KNotifyEventList() |
| 97 | { |
| 98 | delete config; |
| 99 | } |
| 100 | |
| 101 | void KNotifyEventList::fill(const QString &appname, bool loadDefaults) |
| 102 | { |
| 103 | m_elements.clear(); |
| 104 | clear(); |
| 105 | delete config; |
| 106 | config = new KConfig(appname + QStringLiteral(".notifyrc" ), KConfig::NoGlobals); |
| 107 | auto configSources = |
| 108 | QStandardPaths::locateAll(type: QStandardPaths::GenericDataLocation, QStringLiteral("knotifications6/" ) + appname + QStringLiteral(".notifyrc" )); |
| 109 | // `QStandardPaths` follows the order of precedence given by `$XDG_DATA_DIRS |
| 110 | // (more priority goest first), but for `addConfigSources() it is the opposite |
| 111 | std::reverse(first: configSources.begin(), last: configSources.end()); |
| 112 | config->addConfigSources(sources: configSources); |
| 113 | |
| 114 | QStringList conflist = config->groupList(); |
| 115 | QRegularExpression rx(QStringLiteral("^Event/([^/]*)$" )); |
| 116 | conflist = conflist.filter(re: rx); |
| 117 | |
| 118 | for (const QString &group : std::as_const(t&: conflist)) { |
| 119 | KConfigGroup cg(config, group); |
| 120 | QString id = rx.match(subject: group).captured(nth: 1); |
| 121 | QString name = cg.readEntry(key: "Name" ); |
| 122 | QString description = cg.readEntry(key: "Comment" ); |
| 123 | |
| 124 | if (loadDefaults) { |
| 125 | KConfigGroup g(config, QStringLiteral("Event/" ) + id); |
| 126 | const auto keyList = g.keyList(); |
| 127 | for (const QString &entry : keyList) { |
| 128 | g.revertToDefault(key: entry); |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | m_elements << new KNotifyEventListItem(this, id, name, description, config); |
| 133 | } |
| 134 | |
| 135 | resizeColumnToContents(column: 2); |
| 136 | } |
| 137 | |
| 138 | void KNotifyEventList::save() |
| 139 | { |
| 140 | for (KNotifyEventListItem *it : std::as_const(t&: m_elements)) { |
| 141 | it->save(); |
| 142 | } |
| 143 | config->sync(); |
| 144 | } |
| 145 | |
| 146 | bool KNotifyEventList::disableAllSounds() |
| 147 | { |
| 148 | bool changed = false; |
| 149 | for (KNotifyEventListItem *it : std::as_const(t&: m_elements)) { |
| 150 | QStringList actions = it->configElement()->readEntry(QStringLiteral("Action" )).split(sep: QLatin1Char('|')); |
| 151 | if (actions.removeAll(QStringLiteral("Sound" ))) { |
| 152 | it->configElement()->writeEntry(QStringLiteral("Action" ), data: actions.join(sep: QLatin1Char('|'))); |
| 153 | changed = true; |
| 154 | } |
| 155 | } |
| 156 | return changed; |
| 157 | } |
| 158 | |
| 159 | void KNotifyEventList::slotSelectionChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) |
| 160 | { |
| 161 | Q_UNUSED(current); |
| 162 | |
| 163 | KNotifyEventListItem *it = dynamic_cast<KNotifyEventListItem *>(currentItem()); |
| 164 | if (it) { |
| 165 | Q_EMIT eventSelected(it->configElement()); |
| 166 | } else { |
| 167 | Q_EMIT eventSelected(nullptr); |
| 168 | } |
| 169 | |
| 170 | it = dynamic_cast<KNotifyEventListItem *>(previous); |
| 171 | if (it) { |
| 172 | it->update(); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | void KNotifyEventList::updateCurrentItem() |
| 177 | { |
| 178 | KNotifyEventListItem *it = dynamic_cast<KNotifyEventListItem *>(currentItem()); |
| 179 | if (it) { |
| 180 | it->update(); |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | void KNotifyEventList::updateAllItems() |
| 185 | { |
| 186 | for (KNotifyEventListItem *it : std::as_const(t&: m_elements)) { |
| 187 | it->update(); |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | void KNotifyEventList::selectEvent(const QString &eventId) |
| 192 | { |
| 193 | auto it = std::find_if(first: m_elements.constBegin(), last: m_elements.constEnd(), pred: [&eventId](KNotifyEventListItem *item) { |
| 194 | return item->configElement()->eventId() == eventId; |
| 195 | }); |
| 196 | |
| 197 | if (it != m_elements.constEnd()) { |
| 198 | setCurrentItem(*it); |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | QSize KNotifyEventList::sizeHint() const |
| 203 | { |
| 204 | int fontSize = fontMetrics().height(); |
| 205 | return QSize(48 * fontSize, 12 * fontSize); |
| 206 | } |
| 207 | |
| 208 | KNotifyEventListItem::KNotifyEventListItem(QTreeWidget *parent, const QString &eventName, const QString &name, const QString &description, KConfig *config) |
| 209 | : QTreeWidgetItem(parent) |
| 210 | , m_config(eventName, config) |
| 211 | { |
| 212 | setText(column: 1, atext: name); |
| 213 | setToolTip(column: 1, atoolTip: description); |
| 214 | setText(column: 2, atext: description); |
| 215 | setToolTip(column: 2, atoolTip: description); |
| 216 | update(); |
| 217 | } |
| 218 | |
| 219 | KNotifyEventListItem::~KNotifyEventListItem() |
| 220 | { |
| 221 | } |
| 222 | |
| 223 | void KNotifyEventListItem::save() |
| 224 | { |
| 225 | m_config.save(); |
| 226 | } |
| 227 | |
| 228 | void KNotifyEventListItem::update() |
| 229 | { |
| 230 | setData(column: 0, role: Qt::UserRole, value: m_config.readEntry(QStringLiteral("Action" ))); |
| 231 | } |
| 232 | |
| 233 | #include "moc_knotifyeventlist.cpp" |
| 234 | |