1 /*
2 SPDX-FileCopyrightText: 2012-2021 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "accountconfigorderdialog.h"
8 #include "mailcommon_debug.h"
9 #include "mailcommonsettings_base.h"
10 #include "util/mailutil.h"
11 #include <KLocalizedString>
12 #include <PimCommon/PimUtil>
13 #include <QIcon>
14 #include <QPushButton>
15 #include <QVBoxLayout>
16
17 #include <Akonadi/AgentInstance>
18 #include <Akonadi/AgentManager>
19
20 #include <KMime/KMimeMessage>
21
22 #include <KConfigGroup>
23 #include <QCheckBox>
24 #include <QDialogButtonBox>
25 #include <QHBoxLayout>
26 #include <QListWidget>
27
28 using namespace MailCommon;
29
30 struct InstanceStruct {
31 QString name;
32 QIcon icon;
isValidInstanceStruct33 Q_REQUIRED_RESULT bool isValid() const
34 {
35 return !name.isEmpty();
36 }
37 };
38
39 class MailCommon::AccountConfigOrderDialogPrivate
40 {
41 public:
42 QListWidget *mListAccount = nullptr;
43 QPushButton *mUpButton = nullptr;
44 QPushButton *mDownButton = nullptr;
45 QCheckBox *mEnableAccountOrder = nullptr;
46 MailCommon::MailCommonSettings *mSettings = nullptr;
47 };
48
AccountConfigOrderDialog(MailCommon::MailCommonSettings * settings,QWidget * parent)49 AccountConfigOrderDialog::AccountConfigOrderDialog(MailCommon::MailCommonSettings *settings, QWidget *parent)
50 : QDialog(parent)
51 , d(new MailCommon::AccountConfigOrderDialogPrivate)
52 {
53 d->mSettings = settings;
54 setWindowTitle(i18nc("@title:window", "Edit Accounts Order"));
55 auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
56 auto mainLayout = new QVBoxLayout(this);
57
58 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
59 okButton->setDefault(true);
60 okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
61 connect(buttonBox, &QDialogButtonBox::rejected, this, &AccountConfigOrderDialog::reject);
62
63 auto page = new QWidget(this);
64 mainLayout->addWidget(page);
65 mainLayout->addWidget(buttonBox);
66
67 auto vbox = new QVBoxLayout;
68 vbox->setContentsMargins({});
69 page->setLayout(vbox);
70
71 d->mEnableAccountOrder = new QCheckBox(i18n("Use custom order"), this);
72 connect(d->mEnableAccountOrder, &QCheckBox::clicked, this, &AccountConfigOrderDialog::slotEnableAccountOrder);
73 vbox->addWidget(d->mEnableAccountOrder);
74
75 auto vlay = new QHBoxLayout;
76 vbox->addLayout(vlay);
77
78 d->mListAccount = new QListWidget(this);
79 d->mListAccount->setDragDropMode(QAbstractItemView::InternalMove);
80 vlay->addWidget(d->mListAccount);
81
82 auto upDownBox = new QWidget(page);
83 auto upDownBoxVBoxLayout = new QVBoxLayout(upDownBox);
84 upDownBoxVBoxLayout->setContentsMargins({});
85 d->mUpButton = new QPushButton(upDownBox);
86 upDownBoxVBoxLayout->addWidget(d->mUpButton);
87 d->mUpButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up")));
88 d->mUpButton->setToolTip(i18nc("Move selected account up.", "Up"));
89 d->mUpButton->setEnabled(false); // b/c no item is selected yet
90 d->mUpButton->setFocusPolicy(Qt::StrongFocus);
91 d->mUpButton->setAutoRepeat(true);
92
93 d->mDownButton = new QPushButton(upDownBox);
94 upDownBoxVBoxLayout->addWidget(d->mDownButton);
95 d->mDownButton->setIcon(QIcon::fromTheme(QStringLiteral("go-down")));
96 d->mDownButton->setToolTip(i18nc("Move selected account down.", "Down"));
97 d->mDownButton->setEnabled(false); // b/c no item is selected yet
98 d->mDownButton->setFocusPolicy(Qt::StrongFocus);
99 d->mDownButton->setAutoRepeat(true);
100
101 auto spacer = new QWidget(upDownBox);
102 upDownBoxVBoxLayout->addWidget(spacer);
103 upDownBoxVBoxLayout->setStretchFactor(spacer, 100);
104 vlay->addWidget(upDownBox);
105
106 connect(d->mUpButton, &QPushButton::clicked, this, &AccountConfigOrderDialog::slotMoveUp);
107 connect(d->mDownButton, &QPushButton::clicked, this, &AccountConfigOrderDialog::slotMoveDown);
108 connect(d->mListAccount, &QListWidget::itemSelectionChanged, this, &AccountConfigOrderDialog::slotEnableControls);
109 connect(d->mListAccount->model(), &QAbstractItemModel::rowsMoved, this, &AccountConfigOrderDialog::slotEnableControls);
110
111 connect(okButton, &QPushButton::clicked, this, &AccountConfigOrderDialog::slotOk);
112 readConfig();
113 init();
114 }
115
~AccountConfigOrderDialog()116 AccountConfigOrderDialog::~AccountConfigOrderDialog()
117 {
118 writeConfig();
119 }
120
slotEnableAccountOrder(bool state)121 void AccountConfigOrderDialog::slotEnableAccountOrder(bool state)
122 {
123 d->mListAccount->setEnabled(state);
124 d->mUpButton->setEnabled(state);
125 d->mDownButton->setEnabled(state);
126 if (state) {
127 slotEnableControls();
128 }
129 }
130
slotMoveUp()131 void AccountConfigOrderDialog::slotMoveUp()
132 {
133 if (!d->mListAccount->currentItem()) {
134 return;
135 }
136 const int pos = d->mListAccount->row(d->mListAccount->currentItem());
137 d->mListAccount->blockSignals(true);
138 QListWidgetItem *item = d->mListAccount->takeItem(pos);
139 // now selected item is at idx(idx-1), so
140 // insert the other item at idx, ie. above(below).
141 d->mListAccount->insertItem(pos - 1, item);
142 d->mListAccount->blockSignals(false);
143 d->mListAccount->setCurrentRow(pos - 1);
144 }
145
slotMoveDown()146 void AccountConfigOrderDialog::slotMoveDown()
147 {
148 if (!d->mListAccount->currentItem()) {
149 return;
150 }
151 const int pos = d->mListAccount->row(d->mListAccount->currentItem());
152 d->mListAccount->blockSignals(true);
153 QListWidgetItem *item = d->mListAccount->takeItem(pos);
154 // now selected item is at idx(idx-1), so
155 // insert the other item at idx, ie. above(below).
156 d->mListAccount->insertItem(pos + 1, item);
157 d->mListAccount->blockSignals(false);
158 d->mListAccount->setCurrentRow(pos + 1);
159 }
160
slotEnableControls()161 void AccountConfigOrderDialog::slotEnableControls()
162 {
163 QListWidgetItem *item = d->mListAccount->currentItem();
164
165 d->mUpButton->setEnabled(item && d->mListAccount->currentRow() != 0);
166 d->mDownButton->setEnabled(item && d->mListAccount->currentRow() != d->mListAccount->count() - 1);
167 }
168
init()169 void AccountConfigOrderDialog::init()
170 {
171 const QStringList listOrderAccount = d->mSettings->order();
172 QStringList instanceList;
173
174 QMap<QString, InstanceStruct> mapInstance;
175 const Akonadi::AgentInstance::List lstInstances = Akonadi::AgentManager::self()->instances();
176 for (const Akonadi::AgentInstance &instance : lstInstances) {
177 const QString identifier = instance.identifier();
178 if (!MailCommon::Util::isMailAgent(instance) || identifier.contains(POP3_RESOURCE_IDENTIFIER)) {
179 continue;
180 }
181 instanceList << instance.identifier();
182 InstanceStruct instanceStruct;
183 instanceStruct.name = instance.name();
184 if (PimCommon::Util::isImapResource(identifier)) {
185 instanceStruct.name += QLatin1String(" (IMAP)");
186 } else if (identifier.startsWith(QLatin1String("akonadi_maildir_resource"))) {
187 instanceStruct.name += QLatin1String(" (Maildir)");
188 } else if (identifier.startsWith(QLatin1String("akonadi_mailbox_resource"))) {
189 instanceStruct.name += QLatin1String(" (Mailbox)");
190 } else if (identifier.startsWith(QLatin1String("akonadi_mixedmaildir_resource"))) {
191 instanceStruct.name += QLatin1String(" (Mixedmaildir)");
192 } else {
193 qCDebug(MAILCOMMON_LOG) << " Unknown resource type " << identifier;
194 }
195 instanceStruct.icon = instance.type().icon();
196 mapInstance.insert(instance.identifier(), instanceStruct);
197 }
198 instanceList.sort(Qt::CaseInsensitive);
199 const int numberOfList(listOrderAccount.count());
200 for (int i = 0; i < numberOfList; ++i) {
201 instanceList.removeOne(listOrderAccount.at(i));
202 }
203
204 QStringList finalList(listOrderAccount);
205 finalList += instanceList;
206
207 const int numberOfElement(finalList.count());
208 for (int i = 0; i < numberOfElement; ++i) {
209 const QString identifier(finalList.at(i));
210 const InstanceStruct tmp = mapInstance.value(identifier);
211 if (tmp.isValid()) {
212 auto item = new QListWidgetItem(tmp.icon, tmp.name, d->mListAccount);
213 item->setData(AccountConfigOrderDialog::IdentifierAccount, identifier);
214 d->mListAccount->addItem(item);
215 }
216 }
217 const bool enabled = d->mSettings->enableAccountOrder();
218 d->mEnableAccountOrder->setChecked(enabled);
219 slotEnableAccountOrder(enabled);
220 }
221
slotOk()222 void AccountConfigOrderDialog::slotOk()
223 {
224 QStringList order;
225 const int numberOfItems(d->mListAccount->count());
226 order.reserve(numberOfItems);
227 for (int i = 0; i < numberOfItems; ++i) {
228 order << d->mListAccount->item(i)->data(AccountConfigOrderDialog::IdentifierAccount).toString();
229 }
230
231 d->mSettings->setOrder(order);
232 d->mSettings->setEnableAccountOrder(d->mEnableAccountOrder->isChecked());
233 d->mSettings->save();
234 QDialog::accept();
235 }
236
readConfig()237 void AccountConfigOrderDialog::readConfig()
238 {
239 KConfigGroup accountConfigDialog(d->mSettings->config(), "AccountConfigOrderDialog");
240 const QSize size = accountConfigDialog.readEntry("Size", QSize(600, 400));
241 if (size.isValid()) {
242 resize(size);
243 }
244 }
245
writeConfig()246 void AccountConfigOrderDialog::writeConfig()
247 {
248 KConfigGroup accountConfigDialog(d->mSettings->config(), "AccountConfigOrderDialog");
249 accountConfigDialog.writeEntry("Size", size());
250 accountConfigDialog.sync();
251 }
252