Libksieve

selectheadertypecombobox.cpp
1/*
2 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6#include "selectheadertypecombobox.h"
7#include "autocreatescripts/autocreatescriptutil_p.h"
8#include <KLineEditEventHandler>
9#include <KLocalizedString>
10#include <QIcon>
11#include <QLineEdit>
12#include <QPointer>
13#include <QPushButton>
14
15#include <KConfigGroup>
16#include <KLazyLocalizedString>
17#include <KSharedConfig>
18#include <KWindowConfig>
19#include <QDialogButtonBox>
20#include <QHBoxLayout>
21#include <QLabel>
22#include <QVBoxLayout>
23#include <QWindow>
24using namespace KSieveUi;
25namespace
26{
27static const char mySelectFlagsListDialogGroupName[] = "SelectHeadersDialog";
28}
29const KLazyLocalizedString selectMultipleHeaders = kli18n("Select multiple headers…");
30SelectHeadersDialog::SelectHeadersDialog(QWidget *parent)
31 : QDialog(parent)
32 , mListWidget(new SelectHeadersWidget(this))
33 , mNewHeader(new QLineEdit(this))
34 , mAddNewHeader(new QPushButton(this))
35{
36 setWindowTitle(i18nc("@title:window", "Headers"));
37
39 buttonBox->setObjectName(QLatin1StringView("buttonbox"));
40 auto mainLayout = new QVBoxLayout(this);
41 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
42 okButton->setDefault(true);
44 connect(buttonBox, &QDialogButtonBox::accepted, this, &SelectHeadersDialog::accept);
45 connect(buttonBox, &QDialogButtonBox::rejected, this, &SelectHeadersDialog::reject);
46 okButton->setFocus();
47
48 auto lay = new QVBoxLayout;
49 lay->setObjectName(QLatin1StringView("widgetlayout"));
50 lay->setContentsMargins({});
51 mainLayout->addLayout(lay);
52 mListWidget->setObjectName(QLatin1StringView("listwidget"));
53 lay->addWidget(mListWidget);
54
55 auto lab = new QLabel(i18nc("@label:textbox", "Add new header:"), this);
56 lab->setObjectName(QLatin1StringView("label"));
57 lay->addWidget(lab);
58
59 auto hbox = new QHBoxLayout;
60
62 mNewHeader->setObjectName(QLatin1StringView("newheader"));
63 mNewHeader->setClearButtonEnabled(true);
64 // mNewHeader->setTrapReturnKey(true);
65 connect(mNewHeader, &QLineEdit::returnPressed, this, &SelectHeadersDialog::slotAddNewHeader);
66 mNewHeader->setClearButtonEnabled(true);
67
68 mAddNewHeader->setObjectName(QLatin1StringView("addnewheader"));
69 mAddNewHeader->setEnabled(false);
70 mAddNewHeader->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
71 mAddNewHeader->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
72 connect(mAddNewHeader, &QPushButton::clicked, this, &SelectHeadersDialog::slotAddNewHeader);
73 connect(mNewHeader, &QLineEdit::textChanged, this, &SelectHeadersDialog::slotNewHeaderTextChanged);
74 hbox->addWidget(mNewHeader);
75 hbox->addWidget(mAddNewHeader);
76
77 lay->addLayout(hbox);
78
79 mainLayout->addWidget(buttonBox);
80
81 readConfig();
82}
83
84SelectHeadersDialog::~SelectHeadersDialog()
85{
86 writeConfig();
87}
88
89void SelectHeadersDialog::readConfig()
90{
91 create(); // ensure a window is created
92 windowHandle()->resize(QSize(400, 300));
93 KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(mySelectFlagsListDialogGroupName));
95 resize(windowHandle()->size()); // workaround for QTBUG-40584
96}
97
98void SelectHeadersDialog::writeConfig()
99{
100 KConfigGroup group(KSharedConfig::openStateConfig(), QLatin1StringView(mySelectFlagsListDialogGroupName));
102 group.sync();
103}
104
105void SelectHeadersDialog::slotNewHeaderTextChanged(const QString &text)
106{
107 mAddNewHeader->setEnabled(!text.trimmed().isEmpty());
108}
109
110void SelectHeadersDialog::slotAddNewHeader()
111{
112 const QString headerText = mNewHeader->text().trimmed();
113 if (!headerText.isEmpty()) {
114 mListWidget->addNewHeader(headerText);
115 mNewHeader->clear();
116 }
117}
118
119void SelectHeadersDialog::setListHeaders(const QMap<QString, QString> &lst, const QStringList &selectedHeaders)
120{
121 mListWidget->setListHeaders(lst, selectedHeaders);
122}
123
124QString SelectHeadersDialog::headers() const
125{
126 return mListWidget->headers();
127}
128
129SelectHeadersWidget::SelectHeadersWidget(QWidget *parent)
130 : QListWidget(parent)
131{
132}
133
134SelectHeadersWidget::~SelectHeadersWidget() = default;
135
136void SelectHeadersWidget::addNewHeader(const QString &header)
137{
138 const int numberOfItem = count();
139 for (int i = 0; i < numberOfItem; ++i) {
140 QListWidgetItem *it = item(i);
141 if ((it->data(HeaderId).toString()) == header || (it->text() == header)) {
142 return;
143 }
144 }
145
146 auto item = new QListWidgetItem(header, this);
147 item->setData(HeaderId, header);
150}
151
152void SelectHeadersWidget::setListHeaders(const QMap<QString, QString> &lst, const QStringList &selectedHeaders)
153{
155 while (i.hasNext()) {
156 i.next();
157 if (!i.value().isEmpty()) {
158 auto item = new QListWidgetItem(i.value(), this);
159 item->setData(HeaderId, i.key());
160 if (selectedHeaders.contains(i.key())) {
162 } else {
164 }
165 }
166 }
167 for (const QString &header : selectedHeaders) {
168 if (!lst.contains(header)) {
169 auto item = new QListWidgetItem(header, this);
170 item->setData(HeaderId, header);
172 }
173 }
174}
175
176QString SelectHeadersWidget::headers() const
177{
178 QString result;
179 bool selected = false;
180 const int numberOfItem = count();
181 for (int i = 0; i < numberOfItem; ++i) {
182 QListWidgetItem *it = item(i);
183 if (it->checkState() == Qt::Checked) {
184 if (selected) {
185 result += QLatin1StringView(", ");
186 }
187 selected = true;
188 result += QLatin1StringView("\"") + it->data(HeaderId).toString() + QLatin1StringView("\"");
189 }
190 }
191 if (!result.isEmpty()) {
192 result = QLatin1StringView("[ ") + result + QLatin1StringView(" ]");
193 }
194 return result;
195}
196
197SelectHeaderTypeComboBox::SelectHeaderTypeComboBox(bool onlyEnvelopType, QWidget *parent)
198 : QComboBox(parent)
199{
200 setEditable(true);
201 lineEdit()->setClearButtonEnabled(true);
202 // TODO add completion
203 initialize(onlyEnvelopType);
204 connect(this, &SelectHeaderTypeComboBox::textActivated, this, &SelectHeaderTypeComboBox::slotSelectItem);
205 connect(this, &SelectHeaderTypeComboBox::editTextChanged, this, &SelectHeaderTypeComboBox::valueChanged);
206 connect(this, &SelectHeaderTypeComboBox::activated, this, &SelectHeaderTypeComboBox::valueChanged);
207}
208
209SelectHeaderTypeComboBox::~SelectHeaderTypeComboBox() = default;
210
211void SelectHeaderTypeComboBox::changeReadOnlyStatus()
212{
213 const bool readOnly = (currentIndex() > 0);
214 lineEdit()->setReadOnly(readOnly);
215 lineEdit()->setClearButtonEnabled(!readOnly);
216}
217
218const QString SelectHeaderTypeComboBox::getSelectMultipleHeadersTranslated() const
219{
220 return selectMultipleHeaders.toString();
221}
222
223void SelectHeaderTypeComboBox::slotSelectItem(const QString &str)
224{
225 changeReadOnlyStatus();
226 if (str == getSelectMultipleHeadersTranslated()) {
227 QPointer<SelectHeadersDialog> dlg = new SelectHeadersDialog(this);
228 dlg->setListHeaders(mHeaderMap, AutoCreateScriptUtil::createListFromString(mCode));
229 if (dlg->exec()) {
230 mCode = dlg->headers();
231 lineEdit()->setText(dlg->headers());
232 Q_EMIT valueChanged();
233 } else {
234 lineEdit()->setText(mCode);
235 }
236 delete dlg;
237 } else {
238 mCode = str;
239 }
240}
241
242void SelectHeaderTypeComboBox::headerMap(bool onlyEnvelopType)
243{
244 mHeaderMap.insert(QString(), QString());
245 mHeaderMap.insert(QStringLiteral("from"), i18n("From"));
246 mHeaderMap.insert(QStringLiteral("to"), i18n("To"));
247 mHeaderMap.insert(QStringLiteral("Reply-To"), i18n("Reply To"));
248 mHeaderMap.insert(QStringLiteral("cc"), i18n("Cc"));
249 mHeaderMap.insert(QStringLiteral("bcc"), i18n("Bcc"));
250 mHeaderMap.insert(QStringLiteral("Resent-From"), i18n("Resent From"));
251 mHeaderMap.insert(QStringLiteral("Resent-To"), i18n("Resent To"));
252 mHeaderMap.insert(QStringLiteral("sender"), i18n("Sender"));
253 if (!onlyEnvelopType) {
254 mHeaderMap.insert(QStringLiteral("subject"), i18n("Subject"));
255 mHeaderMap.insert(QStringLiteral("Date"), i18n("Date"));
256 mHeaderMap.insert(QStringLiteral("Message-ID"), i18n("Message Id"));
257 mHeaderMap.insert(QStringLiteral("Content-Type"), i18n("Content type"));
258 }
259}
260
261void SelectHeaderTypeComboBox::initialize(bool onlyEnvelopType)
262{
263 headerMap(onlyEnvelopType);
264 QMapIterator<QString, QString> i(mHeaderMap);
265 while (i.hasNext()) {
266 i.next();
267 addItem(i.value(), i.key());
268 }
269 addItem(getSelectMultipleHeadersTranslated());
270}
271
272QString SelectHeaderTypeComboBox::code() const
273{
274 QString str = (currentIndex() > -1) ? itemData(currentIndex()).toString() : QString();
275 if (str.isEmpty()) {
276 str = currentText();
277 if (str == getSelectMultipleHeadersTranslated()) {
278 str = QString(); // return QString();
279 }
280 }
281 if (!str.isEmpty() && !str.startsWith(QLatin1Char('['))) {
282 str = QLatin1StringView("\"") + str + QLatin1StringView("\"");
283 }
284 return str;
285}
286
287void SelectHeaderTypeComboBox::setCode(const QString &code)
288{
289 QMapIterator<QString, QString> i(mHeaderMap);
290 bool foundHeaders = false;
291 while (i.hasNext()) {
292 i.next();
293 if (i.key() == code) {
294 const int index = findData(i.key());
295 setCurrentIndex(index);
296 lineEdit()->setText(i.value());
297 foundHeaders = true;
298 break;
299 }
300 }
301 // If not found select last combobox item
302 if (!foundHeaders) {
303 if (code.startsWith(QLatin1Char('['))) {
304 setCurrentIndex(count() - 1);
305 } else {
307 }
308 lineEdit()->setText(code);
309 }
310 mCode = code;
311 changeReadOnlyStatus();
312}
313
314#include "moc_selectheadertypecombobox.cpp"
QString toString() const
static KSharedConfig::Ptr openStateConfig(const QString &fileName=QString())
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void catchReturnKey(QObject *lineEdit)
void initialize(StandardShortcut id)
KCONFIGGUI_EXPORT void saveWindowSize(const QWindow *window, KConfigGroup &config, KConfigGroup::WriteConfigFlags options=KConfigGroup::Normal)
KCONFIGGUI_EXPORT void restoreWindowSize(QWindow *window, const KConfigGroup &config)
void clicked(bool checked)
void setShortcut(const QKeySequence &key)
void addItem(const QIcon &icon, const QString &text, const QVariant &userData)
int findData(const QVariant &data, int role, Qt::MatchFlags flags) const const
QVariant itemData(int index, int role) const const
QLineEdit * lineEdit() const const
QIcon fromTheme(const QString &name)
void clear()
void setClearButtonEnabled(bool enable)
void setReadOnly(bool)
void returnPressed()
void textChanged(const QString &text)
QListWidgetItem * item(int row) const const
void scrollToItem(const QListWidgetItem *item, QAbstractItemView::ScrollHint hint)
Qt::CheckState checkState() const const
virtual QVariant data(int role) const const
void setCheckState(Qt::CheckState state)
virtual void setData(int role, const QVariant &value)
QString text() const const
bool contains(const Key &key) const const
iterator insert(const Key &key, const T &value)
Q_EMITQ_EMIT
void setObjectName(QAnyStringView name)
void setDefault(bool)
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString trimmed() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
Key_Return
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString() const const
void create(WId window, bool initializeWindow, bool destroyOldWindow)
void setEnabled(bool)
void setFocus()
void resize(const QSize &)
QWindow * windowHandle() const const
void resize(const QSize &newSize)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:14:30 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.