Libksieve

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

KDE's Doxygen guidelines are available online.