Fix changed state detection in CoreAccountSettingsPage
[quassel.git] / src / qtui / settingspages / coreaccountsettingspage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2009 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  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "coreaccountsettingspage.h"
22
23 #include "client.h"
24 #include "clientsettings.h"
25 #include "coreaccountmodel.h"
26 #include "iconloader.h"
27
28 CoreAccountSettingsPage::CoreAccountSettingsPage(QWidget *parent)
29 : SettingsPage(tr("Misc"), tr("Core Accounts"), parent),
30 _lastAccountId(0),
31 _lastAutoConnectId(0),
32 _standalone(false)
33 {
34   ui.setupUi(this);
35   initAutoWidgets();
36   ui.addAccountButton->setIcon(SmallIcon("list-add"));
37   ui.editAccountButton->setIcon(SmallIcon("document-edit"));
38   ui.deleteAccountButton->setIcon(SmallIcon("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 void CoreAccountSettingsPage::setStandAlone(bool standalone) {
55   _standalone = standalone;
56 }
57
58 void CoreAccountSettingsPage::load() {
59   model()->update(Client::coreAccountModel());
60   SettingsPage::load();
61
62   CoreAccountSettings s;
63
64   if(Quassel::runMode() != Quassel::Monolithic) {
65     // make sure we don't have selected the internal account as autoconnect account
66
67     if(s.autoConnectOnStartup() && s.autoConnectToFixedAccount()) {
68       CoreAccount acc = model()->account(s.autoConnectAccount());
69       if(acc.isInternal())
70         ui.autoConnectOnStartup->setChecked(false);
71     }
72   }
73   ui.accountView->setCurrentIndex(filteredModel()->index(0, 0));
74   ui.accountView->selectionModel()->select(filteredModel()->index(0, 0), QItemSelectionModel::Select);
75
76   QModelIndex idx = filteredModel()->mapFromSource(model()->accountIndex(s.autoConnectAccount()));
77   ui.autoConnectAccount->setCurrentIndex(idx.isValid() ? idx.row() : 0);
78   ui.autoConnectAccount->setProperty("storedValue", ui.autoConnectAccount->currentIndex());
79   setWidgetStates();
80 }
81
82 void CoreAccountSettingsPage::save() {
83   SettingsPage::save();
84   Client::coreAccountModel()->update(model());
85   Client::coreAccountModel()->save();
86   CoreAccountSettings s;
87   AccountId id = filteredModel()->index(ui.autoConnectAccount->currentIndex(), 0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
88   s.setAutoConnectAccount(id);
89   ui.autoConnectAccount->setProperty("storedValue", ui.autoConnectAccount->currentIndex());
90 }
91
92 // TODO: Qt 4.6 - replace by proper rowsMoved() semantics
93 // NOTE: This is the filtered model
94 void CoreAccountSettingsPage::rowsAboutToBeRemoved(const QModelIndex &index, int start, int end) {
95   _lastAutoConnectId = _lastAccountId = 0;
96   if(index.isValid() || start != end)
97     return;
98
99   // the current index is removed, so remember it in case it's reinserted immediately afterwards
100   AccountId id = filteredModel()->index(start, 0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
101   if(start == ui.accountView->currentIndex().row())
102     _lastAccountId = id;
103   if(start == ui.autoConnectAccount->currentIndex())
104     _lastAutoConnectId = id;
105 }
106
107 void CoreAccountSettingsPage::rowsInserted(const QModelIndex &index, int start, int end) {
108   if(index.isValid() || start != end)
109     return;
110
111   // check if the inserted index was just removed and select it in that case
112   AccountId id = filteredModel()->index(start, 0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
113   if(id == _lastAccountId)
114     ui.accountView->setCurrentIndex(filteredModel()->index(start, 0));
115   if(id == _lastAutoConnectId)
116     ui.autoConnectAccount->setCurrentIndex(start);
117   _lastAccountId = _lastAutoConnectId = 0;
118 }
119
120 AccountId CoreAccountSettingsPage::selectedAccount() const {
121   QModelIndex index = ui.accountView->currentIndex();
122   if(!index.isValid())
123     return 0;
124   return index.data(CoreAccountModel::AccountIdRole).value<AccountId>();
125 }
126
127 void CoreAccountSettingsPage::setSelectedAccount(AccountId accId) {
128   QModelIndex index = filteredModel()->mapFromSource(model()->accountIndex(accId));
129   if(index.isValid())
130     ui.accountView->setCurrentIndex(index);
131 }
132
133 void CoreAccountSettingsPage::on_addAccountButton_clicked() {
134   CoreAccountEditDlg dlg(CoreAccount(), this);
135   if(dlg.exec() == QDialog::Accepted) {
136     AccountId id =model()->createOrUpdateAccount(dlg.account());
137     ui.accountView->setCurrentIndex(filteredModel()->mapFromSource(model()->accountIndex(id)));
138     widgetHasChanged();
139   }
140 }
141
142 void CoreAccountSettingsPage::on_editAccountButton_clicked() {
143   QModelIndex idx = ui.accountView->selectionModel()->currentIndex();
144   if(!idx.isValid())
145     return;
146
147   editAccount(idx);
148 }
149
150 void CoreAccountSettingsPage::editAccount(const QModelIndex &index) {
151   if(!index.isValid())
152     return;
153
154   CoreAccountEditDlg dlg(model()->account(filteredModel()->mapToSource(index)), this);
155   if(dlg.exec() == QDialog::Accepted) {
156     AccountId id = model()->createOrUpdateAccount(dlg.account());
157     ui.accountView->setCurrentIndex(filteredModel()->mapFromSource(model()->accountIndex(id)));
158     widgetHasChanged();
159   }
160 }
161
162 void CoreAccountSettingsPage::on_deleteAccountButton_clicked() {
163   if(!ui.accountView->selectionModel()->selectedIndexes().count())
164     return;
165
166   AccountId id = ui.accountView->selectionModel()->selectedIndexes().at(0).data(CoreAccountModel::AccountIdRole).value<AccountId>();
167   if(id.isValid()) {
168     model()->removeAccount(id);
169     widgetHasChanged();
170   }
171 }
172
173 void CoreAccountSettingsPage::on_accountView_doubleClicked(const QModelIndex &index) {
174   if(!index.isValid())
175     return;
176
177   if(isStandAlone())
178     emit connectToCore(index.data(CoreAccountModel::AccountIdRole).value<AccountId>());
179   else
180     editAccount(index);
181 }
182
183 void CoreAccountSettingsPage::setWidgetStates() {
184   AccountId accId = selectedAccount();
185   bool editable = accId.isValid() && accId != model()->internalAccount();
186
187   ui.editAccountButton->setEnabled(editable);
188   ui.deleteAccountButton->setEnabled(editable);
189 }
190
191 void CoreAccountSettingsPage::widgetHasChanged() {
192   setChangedState(testHasChanged());
193   setWidgetStates();
194 }
195
196 bool CoreAccountSettingsPage::testHasChanged() {
197   if(ui.autoConnectAccount->currentIndex() != ui.autoConnectAccount->property("storedValue").toInt())
198     return true;
199   if(!(*model() == *Client::coreAccountModel()))
200     return true;
201
202   return false;
203 }
204
205 /*****************************************************************************************
206  * CoreAccountEditDlg
207  *****************************************************************************************/
208 CoreAccountEditDlg::CoreAccountEditDlg(const CoreAccount &acct, QWidget *parent)
209   : QDialog(parent)
210 {
211   ui.setupUi(this);
212
213   _account = acct;
214
215   ui.hostName->setText(acct.hostName());
216   ui.port->setValue(acct.port());
217   ui.accountName->setText(acct.accountName());
218   ui.user->setText(acct.user());
219   ui.password->setText(acct.password());
220   ui.rememberPassword->setChecked(acct.storePassword());
221   ui.useProxy->setChecked(acct.useProxy());
222   ui.proxyHostName->setText(acct.proxyHostName());
223   ui.proxyPort->setValue(acct.proxyPort());
224   ui.proxyType->setCurrentIndex(acct.proxyType() == QNetworkProxy::Socks5Proxy ? 0 : 1);
225   ui.proxyUser->setText(acct.proxyUser());
226   ui.proxyPassword->setText(acct.proxyPassword());
227
228   if(acct.accountId().isValid())
229     setWindowTitle(tr("Edit Core Account"));
230   else
231     setWindowTitle(tr("Add Core Account"));
232 }
233
234 CoreAccount CoreAccountEditDlg::account() {
235   _account.setAccountName(ui.accountName->text().trimmed());
236   _account.setHostName(ui.hostName->text().trimmed());
237   _account.setPort(ui.port->value());
238   _account.setUser(ui.user->text().trimmed());
239   _account.setPassword(ui.password->text());
240   _account.setStorePassword(ui.rememberPassword->isChecked());
241   _account.setUseProxy(ui.useProxy->isChecked());
242   _account.setProxyHostName(ui.proxyHostName->text().trimmed());
243   _account.setProxyPort(ui.proxyPort->value());
244   _account.setProxyType(ui.proxyType->currentIndex() == 0 ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy);
245   _account.setProxyUser(ui.proxyUser->text().trimmed());
246   _account.setProxyPassword(ui.proxyPassword->text());
247   return _account;
248 }
249
250 void CoreAccountEditDlg::setWidgetStates() {
251   bool ok = !ui.accountName->text().trimmed().isEmpty()
252             && !ui.user->text().trimmed().isEmpty()
253             && !ui.hostName->text().isEmpty();
254   ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
255 }
256
257 void CoreAccountEditDlg::on_hostName_textChanged(const QString &text) {
258   Q_UNUSED(text);
259   setWidgetStates();
260 }
261
262 void CoreAccountEditDlg::on_accountName_textChanged(const QString &text) {
263   Q_UNUSED(text);
264   setWidgetStates();
265 }
266
267 void CoreAccountEditDlg::on_user_textChanged(const QString &text) {
268   Q_UNUSED(text)
269   setWidgetStates();
270 }
271
272 /*****************************************************************************************
273  * FilteredCoreAccountModel
274  *****************************************************************************************/
275
276 FilteredCoreAccountModel::FilteredCoreAccountModel(CoreAccountModel *model, QObject *parent) : QSortFilterProxyModel(parent) {
277   _internalAccount = model->internalAccount();
278   setSourceModel(model);
279 }
280
281 bool FilteredCoreAccountModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const {
282   if(Quassel::runMode() == Quassel::Monolithic)
283     return true;
284
285   if(!_internalAccount.isValid())
286     return true;
287
288   return _internalAccount != sourceModel()->index(source_row, 0, source_parent).data(CoreAccountModel::AccountIdRole).value<AccountId>();
289 }