client: Fix Remote Cores marked unsaved on load
[quassel.git] / src / qtui / settingspages / coreaccountsettingspage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 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
28 CoreAccountSettingsPage::CoreAccountSettingsPage(QWidget *parent)
29     : SettingsPage(tr("Remote Cores"), QString(), parent),
30     _lastAccountId(0),
31     _lastAutoConnectId(0),
32     _standalone(false)
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(), SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), SLOT(rowsAboutToBeRemoved(QModelIndex, int, int)));
47     connect(filteredModel(), SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(rowsInserted(QModelIndex, int, int)));
48
49     connect(ui.accountView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(setWidgetStates()));
50     connect(ui.autoConnectAccount, SIGNAL(currentIndexChanged(int)), SLOT(widgetHasChanged()));
51     setWidgetStates();
52 }
53
54
55 void CoreAccountSettingsPage::setStandAlone(bool standalone)
56 {
57     _standalone = standalone;
58 }
59
60
61 void CoreAccountSettingsPage::load()
62 {
63     model()->update(Client::coreAccountModel());
64     SettingsPage::load();
65
66     CoreAccountSettings s;
67
68     if (Quassel::runMode() != Quassel::Monolithic) {
69         // make sure we don't have selected the internal account as autoconnect account
70
71         if (s.autoConnectOnStartup() && s.autoConnectToFixedAccount()) {
72             CoreAccount acc = model()->account(s.autoConnectAccount());
73             if (acc.isInternal())
74                 ui.autoConnectOnStartup->setChecked(false);
75         }
76     }
77     ui.accountView->setCurrentIndex(filteredModel()->index(0, 0));
78     ui.accountView->selectionModel()->select(filteredModel()->index(0, 0), QItemSelectionModel::Select);
79
80     QModelIndex idx = filteredModel()->mapFromSource(model()->accountIndex(s.autoConnectAccount()));
81     ui.autoConnectAccount->setCurrentIndex(idx.isValid() ? idx.row() : 0);
82     ui.autoConnectAccount->setProperty("storedValue", ui.autoConnectAccount->currentIndex());
83     setWidgetStates();
84     // Mark as no changes made, we just loaded settings
85     setChangedState(false);
86 }
87
88
89 void CoreAccountSettingsPage::save()
90 {
91     SettingsPage::save();
92     Client::coreAccountModel()->update(model());
93     Client::coreAccountModel()->save();
94     CoreAccountSettings s;
95     AccountId id = filteredModel()->index(ui.autoConnectAccount->currentIndex(), 0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
96     s.setAutoConnectAccount(id);
97     ui.autoConnectAccount->setProperty("storedValue", ui.autoConnectAccount->currentIndex());
98 }
99
100
101 // TODO: Qt 4.6 - replace by proper rowsMoved() semantics
102 // NOTE: This is the filtered model
103 void CoreAccountSettingsPage::rowsAboutToBeRemoved(const QModelIndex &index, int start, int end)
104 {
105     _lastAutoConnectId = _lastAccountId = 0;
106     if (index.isValid() || start != end)
107         return;
108
109     // the current index is removed, so remember it in case it's reinserted immediately afterwards
110     AccountId id = filteredModel()->index(start, 0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
111     if (start == ui.accountView->currentIndex().row())
112         _lastAccountId = id;
113     if (start == ui.autoConnectAccount->currentIndex())
114         _lastAutoConnectId = id;
115 }
116
117
118 void CoreAccountSettingsPage::rowsInserted(const QModelIndex &index, int start, int end)
119 {
120     if (index.isValid() || start != end)
121         return;
122
123     // check if the inserted index was just removed and select it in that case
124     AccountId id = filteredModel()->index(start, 0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
125     if (id == _lastAccountId)
126         ui.accountView->setCurrentIndex(filteredModel()->index(start, 0));
127     if (id == _lastAutoConnectId)
128         ui.autoConnectAccount->setCurrentIndex(start);
129     _lastAccountId = _lastAutoConnectId = 0;
130 }
131
132
133 AccountId CoreAccountSettingsPage::selectedAccount() const
134 {
135     QModelIndex index = ui.accountView->currentIndex();
136     if (!index.isValid())
137         return 0;
138     return index.data(CoreAccountModel::AccountIdRole).value<AccountId>();
139 }
140
141
142 void CoreAccountSettingsPage::setSelectedAccount(AccountId accId)
143 {
144     QModelIndex index = filteredModel()->mapFromSource(model()->accountIndex(accId));
145     if (index.isValid())
146         ui.accountView->setCurrentIndex(index);
147 }
148
149
150 void CoreAccountSettingsPage::on_addAccountButton_clicked()
151 {
152     CoreAccountEditDlg dlg(CoreAccount(), this);
153     if (dlg.exec() == QDialog::Accepted) {
154         AccountId id = model()->createOrUpdateAccount(dlg.account());
155         ui.accountView->setCurrentIndex(filteredModel()->mapFromSource(model()->accountIndex(id)));
156         widgetHasChanged();
157     }
158 }
159
160
161 void CoreAccountSettingsPage::on_editAccountButton_clicked()
162 {
163     QModelIndex idx = ui.accountView->selectionModel()->currentIndex();
164     if (!idx.isValid())
165         return;
166
167     editAccount(idx);
168 }
169
170
171 void CoreAccountSettingsPage::editAccount(const QModelIndex &index)
172 {
173     if (!index.isValid())
174         return;
175
176     CoreAccountEditDlg dlg(model()->account(filteredModel()->mapToSource(index)), this);
177     if (dlg.exec() == QDialog::Accepted) {
178         AccountId id = model()->createOrUpdateAccount(dlg.account());
179         ui.accountView->setCurrentIndex(filteredModel()->mapFromSource(model()->accountIndex(id)));
180         widgetHasChanged();
181     }
182 }
183
184
185 void CoreAccountSettingsPage::on_deleteAccountButton_clicked()
186 {
187     if (!ui.accountView->selectionModel()->selectedIndexes().count())
188         return;
189
190     AccountId id = ui.accountView->selectionModel()->selectedIndexes().at(0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
191     if (id.isValid()) {
192         model()->removeAccount(id);
193         widgetHasChanged();
194     }
195 }
196
197
198 void CoreAccountSettingsPage::on_accountView_doubleClicked(const QModelIndex &index)
199 {
200     if (!index.isValid())
201         return;
202
203     if (isStandAlone())
204         emit connectToCore(index.data(CoreAccountModel::AccountIdRole).value<AccountId>());
205     else
206         editAccount(index);
207 }
208
209
210 void CoreAccountSettingsPage::setWidgetStates()
211 {
212     AccountId accId = selectedAccount();
213     bool editable = accId.isValid() && accId != model()->internalAccount();
214
215     ui.editAccountButton->setEnabled(editable);
216     ui.deleteAccountButton->setEnabled(editable);
217 }
218
219
220 void CoreAccountSettingsPage::widgetHasChanged()
221 {
222     setChangedState(testHasChanged());
223     setWidgetStates();
224 }
225
226
227 bool CoreAccountSettingsPage::testHasChanged()
228 {
229     if (ui.autoConnectAccount->currentIndex() !=
230             ui.autoConnectAccount->property("storedValue").toInt()) {
231         return true;
232     }
233     if (*model() != *Client::coreAccountModel()) {
234         return true;
235     }
236
237     return false;
238 }
239
240
241 /*****************************************************************************************
242  * CoreAccountEditDlg
243  *****************************************************************************************/
244 CoreAccountEditDlg::CoreAccountEditDlg(const CoreAccount &acct, QWidget *parent)
245     : QDialog(parent)
246 {
247     ui.setupUi(this);
248
249     _account = acct;
250
251     ui.hostName->setText(acct.hostName());
252     ui.port->setValue(acct.port());
253     ui.accountName->setText(acct.accountName());
254     ui.user->setText(acct.user());
255     ui.password->setText(acct.password());
256     ui.rememberPassword->setChecked(acct.storePassword());
257
258     ui.buttonGroupProxyType->setId(ui.radioButtonNoProxy, 0);
259     ui.buttonGroupProxyType->setId(ui.radioButtonSystemProxy, 1);
260     ui.buttonGroupProxyType->setId(ui.radioButtonManualProxy, 2);
261
262     bool manualProxy = false;
263     switch (acct.proxyType()) {
264     case QNetworkProxy::NoProxy:
265         ui.buttonGroupProxyType->button(0)->setChecked(true);
266         break;
267     case QNetworkProxy::DefaultProxy:
268         ui.buttonGroupProxyType->button(1)->setChecked(true);
269         break;
270     case QNetworkProxy::Socks5Proxy:
271         ui.buttonGroupProxyType->button(2)->setChecked(true);
272         ui.proxyType->setCurrentIndex(0);
273         manualProxy = true;
274         break;
275     case QNetworkProxy::HttpProxy:
276         ui.buttonGroupProxyType->button(2)->setChecked(true);
277         ui.proxyType->setCurrentIndex(1);
278         manualProxy = true;
279         break;
280     default:
281         break;
282     }
283
284     if (manualProxy) {
285         ui.proxyHostName->setText(acct.proxyHostName());
286         ui.proxyPort->setValue(acct.proxyPort());
287         ui.proxyType->setEnabled(true);
288         ui.proxyUser->setText(acct.proxyUser());
289         ui.proxyPassword->setText(acct.proxyPassword());
290     }
291
292     if (acct.accountId().isValid())
293         setWindowTitle(tr("Edit Core Account"));
294     else
295         setWindowTitle(tr("Add Core Account"));
296 }
297
298
299 CoreAccount CoreAccountEditDlg::account()
300 {
301     _account.setAccountName(ui.accountName->text().trimmed());
302     _account.setHostName(ui.hostName->text().trimmed());
303     _account.setPort(ui.port->value());
304     _account.setUser(ui.user->text().trimmed());
305     _account.setPassword(ui.password->text());
306     _account.setStorePassword(ui.rememberPassword->isChecked());
307
308     QNetworkProxy::ProxyType proxyType = QNetworkProxy::NoProxy;
309     int checkedId = ui.buttonGroupProxyType->checkedId();
310
311     switch (checkedId) {
312     case NoProxy: // QNetworkProxy::NoProxy
313         QNetworkProxyFactory::setUseSystemConfiguration(false);
314         _account.setProxyType(proxyType);
315         break;
316     case SystemProxy: // QNetworkProxy::DefaultProxy:
317         QNetworkProxyFactory::setUseSystemConfiguration(true);
318         _account.setProxyType(QNetworkProxy::DefaultProxy);
319         break;
320     case ManualProxy: // QNetworkProxy::Socks5Proxy || QNetworkProxy::HttpProxy
321         proxyType = ui.proxyType->currentIndex() == 0 ?
322                     QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy;
323         QNetworkProxyFactory::setUseSystemConfiguration(false);
324         _account.setProxyHostName(ui.proxyHostName->text().trimmed());
325         _account.setProxyPort(ui.proxyPort->value());
326         _account.setProxyType(proxyType);
327         _account.setProxyUser(ui.proxyUser->text().trimmed());
328         _account.setProxyPassword(ui.proxyPassword->text());
329         break;
330     default:
331         break;
332     }
333     return _account;
334 }
335
336
337 void CoreAccountEditDlg::setWidgetStates()
338 {
339     bool ok = !ui.accountName->text().trimmed().isEmpty()
340               && !ui.user->text().trimmed().isEmpty()
341               && !ui.hostName->text().isEmpty();
342     ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
343 }
344
345
346 void CoreAccountEditDlg::on_hostName_textChanged(const QString &text)
347 {
348     Q_UNUSED(text);
349     setWidgetStates();
350 }
351
352
353 void CoreAccountEditDlg::on_accountName_textChanged(const QString &text)
354 {
355     Q_UNUSED(text);
356     setWidgetStates();
357 }
358
359
360 void CoreAccountEditDlg::on_user_textChanged(const QString &text)
361 {
362     Q_UNUSED(text)
363     setWidgetStates();
364 }
365
366 void CoreAccountEditDlg::on_radioButtonManualProxy_toggled(bool checked)
367 {
368     ui.proxyType->setEnabled(checked);
369     ui.proxyHostName->setEnabled(checked);
370     ui.proxyPort->setEnabled(checked);
371     ui.proxyUser->setEnabled(checked);
372     ui.proxyPassword->setEnabled(checked);
373 }
374
375
376 /*****************************************************************************************
377  * FilteredCoreAccountModel
378  *****************************************************************************************/
379
380 FilteredCoreAccountModel::FilteredCoreAccountModel(CoreAccountModel *model, QObject *parent) : QSortFilterProxyModel(parent)
381 {
382     _internalAccount = model->internalAccount();
383     setSourceModel(model);
384 }
385
386
387 bool FilteredCoreAccountModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
388 {
389     if (Quassel::runMode() == Quassel::Monolithic)
390         return true;
391
392     if (!_internalAccount.isValid())
393         return true;
394
395     return _internalAccount != sourceModel()->index(source_row, 0, source_parent).data(CoreAccountModel::AccountIdRole).value<AccountId>();
396 }