1 /***************************************************************************
2 * Copyright (C) 2005-2020 by the Quassel Project *
3 * devel@quassel-irc.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21 #include "coreaccountsettingspage.h"
22
23 #include "client.h"
24 #include "clientsettings.h"
25 #include "coreaccountmodel.h"
26 #include "icon.h"
27 #include "util.h"
28
CoreAccountSettingsPage(QWidget * parent)29 CoreAccountSettingsPage::CoreAccountSettingsPage(QWidget* parent)
30 : SettingsPage(tr("Remote Cores"), QString(), parent)
31 , _lastAccountId(0)
32 , _lastAutoConnectId(0)
33 {
34 ui.setupUi(this);
35 initAutoWidgets();
36 ui.addAccountButton->setIcon(icon::get("list-add"));
37 ui.editAccountButton->setIcon(icon::get("document-edit"));
38 ui.deleteAccountButton->setIcon(icon::get("edit-delete"));
39
40 _model = new CoreAccountModel(Client::coreAccountModel(), this);
41 _filteredModel = new FilteredCoreAccountModel(_model, this);
42
43 ui.accountView->setModel(filteredModel());
44 ui.autoConnectAccount->setModel(filteredModel());
45
46 connect(filteredModel(), &QAbstractItemModel::rowsAboutToBeRemoved, this, &CoreAccountSettingsPage::rowsAboutToBeRemoved);
47 connect(filteredModel(), &QAbstractItemModel::rowsInserted, this, &CoreAccountSettingsPage::rowsInserted);
48
49 connect(ui.accountView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &CoreAccountSettingsPage::setWidgetStates);
50 connect(ui.autoConnectAccount, selectOverload<int>(&QComboBox::currentIndexChanged), this, &CoreAccountSettingsPage::widgetHasChanged);
51 setWidgetStates();
52 }
53
setStandAlone(bool standalone)54 void CoreAccountSettingsPage::setStandAlone(bool standalone)
55 {
56 _standalone = standalone;
57 }
58
load()59 void CoreAccountSettingsPage::load()
60 {
61 model()->update(Client::coreAccountModel());
62 SettingsPage::load();
63
64 CoreAccountSettings s;
65
66 if (Quassel::runMode() != Quassel::Monolithic) {
67 // make sure we don't have selected the internal account as autoconnect account
68
69 if (s.autoConnectOnStartup() && s.autoConnectToFixedAccount()) {
70 CoreAccount acc = model()->account(s.autoConnectAccount());
71 if (acc.isInternal())
72 ui.autoConnectOnStartup->setChecked(false);
73 }
74 }
75 ui.accountView->setCurrentIndex(filteredModel()->index(0, 0));
76 ui.accountView->selectionModel()->select(filteredModel()->index(0, 0), QItemSelectionModel::Select);
77
78 QModelIndex idx = filteredModel()->mapFromSource(model()->accountIndex(s.autoConnectAccount()));
79 ui.autoConnectAccount->setCurrentIndex(idx.isValid() ? idx.row() : 0);
80 ui.autoConnectAccount->setProperty("storedValue", ui.autoConnectAccount->currentIndex());
81 setWidgetStates();
82 // Mark as no changes made, we just loaded settings
83 setChangedState(false);
84 }
85
save()86 void CoreAccountSettingsPage::save()
87 {
88 SettingsPage::save();
89 Client::coreAccountModel()->update(model());
90 Client::coreAccountModel()->save();
91 CoreAccountSettings s;
92 AccountId id = filteredModel()->index(ui.autoConnectAccount->currentIndex(), 0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
93 s.setAutoConnectAccount(id);
94 ui.autoConnectAccount->setProperty("storedValue", ui.autoConnectAccount->currentIndex());
95 }
96
97 // TODO: Qt 4.6 - replace by proper rowsMoved() semantics
98 // NOTE: This is the filtered model
rowsAboutToBeRemoved(const QModelIndex & index,int start,int end)99 void CoreAccountSettingsPage::rowsAboutToBeRemoved(const QModelIndex& index, int start, int end)
100 {
101 _lastAutoConnectId = _lastAccountId = 0;
102 if (index.isValid() || start != end)
103 return;
104
105 // the current index is removed, so remember it in case it's reinserted immediately afterwards
106 AccountId id = filteredModel()->index(start, 0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
107 if (start == ui.accountView->currentIndex().row())
108 _lastAccountId = id;
109 if (start == ui.autoConnectAccount->currentIndex())
110 _lastAutoConnectId = id;
111 }
112
rowsInserted(const QModelIndex & index,int start,int end)113 void CoreAccountSettingsPage::rowsInserted(const QModelIndex& index, int start, int end)
114 {
115 if (index.isValid() || start != end)
116 return;
117
118 // check if the inserted index was just removed and select it in that case
119 AccountId id = filteredModel()->index(start, 0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
120 if (id == _lastAccountId)
121 ui.accountView->setCurrentIndex(filteredModel()->index(start, 0));
122 if (id == _lastAutoConnectId)
123 ui.autoConnectAccount->setCurrentIndex(start);
124 _lastAccountId = _lastAutoConnectId = 0;
125 }
126
selectedAccount() const127 AccountId CoreAccountSettingsPage::selectedAccount() const
128 {
129 QModelIndex index = ui.accountView->currentIndex();
130 if (!index.isValid())
131 return 0;
132 return index.data(CoreAccountModel::AccountIdRole).value<AccountId>();
133 }
134
setSelectedAccount(AccountId accId)135 void CoreAccountSettingsPage::setSelectedAccount(AccountId accId)
136 {
137 QModelIndex index = filteredModel()->mapFromSource(model()->accountIndex(accId));
138 if (index.isValid())
139 ui.accountView->setCurrentIndex(index);
140 }
141
on_addAccountButton_clicked()142 void CoreAccountSettingsPage::on_addAccountButton_clicked()
143 {
144 CoreAccountEditDlg dlg(CoreAccount(), this);
145 if (dlg.exec() == QDialog::Accepted) {
146 AccountId id = model()->createOrUpdateAccount(dlg.account());
147 ui.accountView->setCurrentIndex(filteredModel()->mapFromSource(model()->accountIndex(id)));
148 widgetHasChanged();
149 }
150 }
151
on_editAccountButton_clicked()152 void CoreAccountSettingsPage::on_editAccountButton_clicked()
153 {
154 QModelIndex idx = ui.accountView->selectionModel()->currentIndex();
155 if (!idx.isValid())
156 return;
157
158 editAccount(idx);
159 }
160
editAccount(const QModelIndex & index)161 void CoreAccountSettingsPage::editAccount(const QModelIndex& index)
162 {
163 if (!index.isValid())
164 return;
165
166 CoreAccountEditDlg dlg(model()->account(filteredModel()->mapToSource(index)), this);
167 if (dlg.exec() == QDialog::Accepted) {
168 AccountId id = model()->createOrUpdateAccount(dlg.account());
169 ui.accountView->setCurrentIndex(filteredModel()->mapFromSource(model()->accountIndex(id)));
170 widgetHasChanged();
171 }
172 }
173
on_deleteAccountButton_clicked()174 void CoreAccountSettingsPage::on_deleteAccountButton_clicked()
175 {
176 if (!ui.accountView->selectionModel()->selectedIndexes().count())
177 return;
178
179 AccountId id = ui.accountView->selectionModel()->selectedIndexes().at(0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
180 if (id.isValid()) {
181 model()->removeAccount(id);
182 widgetHasChanged();
183 }
184 }
185
on_accountView_doubleClicked(const QModelIndex & index)186 void CoreAccountSettingsPage::on_accountView_doubleClicked(const QModelIndex& index)
187 {
188 if (!index.isValid())
189 return;
190
191 if (isStandAlone())
192 emit connectToCore(index.data(CoreAccountModel::AccountIdRole).value<AccountId>());
193 else
194 editAccount(index);
195 }
196
setWidgetStates()197 void CoreAccountSettingsPage::setWidgetStates()
198 {
199 AccountId accId = selectedAccount();
200 bool editable = accId.isValid() && accId != model()->internalAccount();
201
202 ui.editAccountButton->setEnabled(editable);
203 ui.deleteAccountButton->setEnabled(editable);
204 }
205
widgetHasChanged()206 void CoreAccountSettingsPage::widgetHasChanged()
207 {
208 setChangedState(testHasChanged());
209 setWidgetStates();
210 }
211
testHasChanged()212 bool CoreAccountSettingsPage::testHasChanged()
213 {
214 if (ui.autoConnectAccount->currentIndex() != ui.autoConnectAccount->property("storedValue").toInt()) {
215 return true;
216 }
217 if (*model() != *Client::coreAccountModel()) {
218 return true;
219 }
220
221 return false;
222 }
223
224 /*****************************************************************************************
225 * CoreAccountEditDlg
226 *****************************************************************************************/
CoreAccountEditDlg(const CoreAccount & acct,QWidget * parent)227 CoreAccountEditDlg::CoreAccountEditDlg(const CoreAccount& acct, QWidget* parent)
228 : QDialog(parent)
229 {
230 ui.setupUi(this);
231
232 _account = acct;
233
234 ui.hostName->setText(acct.hostName());
235 ui.port->setValue(acct.port());
236 ui.accountName->setText(acct.accountName());
237 ui.user->setText(acct.user());
238 ui.password->setText(acct.password());
239 ui.rememberPassword->setChecked(acct.storePassword());
240
241 ui.buttonGroupProxyType->setId(ui.radioButtonNoProxy, 0);
242 ui.buttonGroupProxyType->setId(ui.radioButtonSystemProxy, 1);
243 ui.buttonGroupProxyType->setId(ui.radioButtonManualProxy, 2);
244
245 bool manualProxy = false;
246 switch (acct.proxyType()) {
247 case QNetworkProxy::NoProxy:
248 ui.buttonGroupProxyType->button(0)->setChecked(true);
249 break;
250 case QNetworkProxy::DefaultProxy:
251 ui.buttonGroupProxyType->button(1)->setChecked(true);
252 break;
253 case QNetworkProxy::Socks5Proxy:
254 ui.buttonGroupProxyType->button(2)->setChecked(true);
255 ui.proxyType->setCurrentIndex(0);
256 manualProxy = true;
257 break;
258 case QNetworkProxy::HttpProxy:
259 ui.buttonGroupProxyType->button(2)->setChecked(true);
260 ui.proxyType->setCurrentIndex(1);
261 manualProxy = true;
262 break;
263 default:
264 break;
265 }
266
267 if (manualProxy) {
268 ui.proxyHostName->setText(acct.proxyHostName());
269 ui.proxyPort->setValue(acct.proxyPort());
270 ui.proxyType->setEnabled(true);
271 ui.proxyUser->setText(acct.proxyUser());
272 ui.proxyPassword->setText(acct.proxyPassword());
273 }
274
275 if (acct.accountId().isValid())
276 setWindowTitle(tr("Edit Core Account"));
277 else
278 setWindowTitle(tr("Add Core Account"));
279 }
280
account()281 CoreAccount CoreAccountEditDlg::account()
282 {
283 _account.setAccountName(ui.accountName->text().trimmed());
284 _account.setHostName(ui.hostName->text().trimmed());
285 _account.setPort(ui.port->value());
286 _account.setUser(ui.user->text().trimmed());
287 _account.setPassword(ui.password->text());
288 _account.setStorePassword(ui.rememberPassword->isChecked());
289
290 QNetworkProxy::ProxyType proxyType = QNetworkProxy::NoProxy;
291 int checkedId = ui.buttonGroupProxyType->checkedId();
292
293 switch (checkedId) {
294 case NoProxy: // QNetworkProxy::NoProxy
295 QNetworkProxyFactory::setUseSystemConfiguration(false);
296 _account.setProxyType(proxyType);
297 break;
298 case SystemProxy: // QNetworkProxy::DefaultProxy:
299 QNetworkProxyFactory::setUseSystemConfiguration(true);
300 _account.setProxyType(QNetworkProxy::DefaultProxy);
301 break;
302 case ManualProxy: // QNetworkProxy::Socks5Proxy || QNetworkProxy::HttpProxy
303 proxyType = ui.proxyType->currentIndex() == 0 ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy;
304 QNetworkProxyFactory::setUseSystemConfiguration(false);
305 _account.setProxyHostName(ui.proxyHostName->text().trimmed());
306 _account.setProxyPort(ui.proxyPort->value());
307 _account.setProxyType(proxyType);
308 _account.setProxyUser(ui.proxyUser->text().trimmed());
309 _account.setProxyPassword(ui.proxyPassword->text());
310 break;
311 default:
312 break;
313 }
314 return _account;
315 }
316
setWidgetStates()317 void CoreAccountEditDlg::setWidgetStates()
318 {
319 bool ok = !ui.accountName->text().trimmed().isEmpty() && !ui.user->text().trimmed().isEmpty() && !ui.hostName->text().isEmpty();
320 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
321 }
322
on_hostName_textChanged(const QString & text)323 void CoreAccountEditDlg::on_hostName_textChanged(const QString& text)
324 {
325 Q_UNUSED(text);
326 setWidgetStates();
327 }
328
on_accountName_textChanged(const QString & text)329 void CoreAccountEditDlg::on_accountName_textChanged(const QString& text)
330 {
331 Q_UNUSED(text);
332 setWidgetStates();
333 }
334
on_user_textChanged(const QString & text)335 void CoreAccountEditDlg::on_user_textChanged(const QString& text)
336 {
337 Q_UNUSED(text)
338 setWidgetStates();
339 }
340
on_radioButtonManualProxy_toggled(bool checked)341 void CoreAccountEditDlg::on_radioButtonManualProxy_toggled(bool checked)
342 {
343 ui.proxyType->setEnabled(checked);
344 ui.proxyHostName->setEnabled(checked);
345 ui.proxyPort->setEnabled(checked);
346 ui.proxyUser->setEnabled(checked);
347 ui.proxyPassword->setEnabled(checked);
348 }
349
350 /*****************************************************************************************
351 * FilteredCoreAccountModel
352 *****************************************************************************************/
353
FilteredCoreAccountModel(CoreAccountModel * model,QObject * parent)354 FilteredCoreAccountModel::FilteredCoreAccountModel(CoreAccountModel* model, QObject* parent)
355 : QSortFilterProxyModel(parent)
356 {
357 _internalAccount = model->internalAccount();
358 setSourceModel(model);
359 }
360
filterAcceptsRow(int source_row,const QModelIndex & source_parent) const361 bool FilteredCoreAccountModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
362 {
363 if (Quassel::runMode() == Quassel::Monolithic)
364 return true;
365
366 if (!_internalAccount.isValid())
367 return true;
368
369 return _internalAccount != sourceModel()->index(source_row, 0, source_parent).data(CoreAccountModel::AccountIdRole).value<AccountId>();
370 }
371