Quassel IRC  Pre-Release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
identitiessettingspage.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2015 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 "identitiessettingspage.h"
22 
23 #include <QIcon>
24 #include <QInputDialog>
25 #include <QMessageBox>
26 
27 #include "client.h"
28 #include "signalproxy.h"
29 
31  : SettingsPage(tr("IRC"), tr("Identities"), parent),
32  _editSsl(false)
33 {
34  ui.setupUi(this);
35  ui.renameIdentity->setIcon(QIcon::fromTheme("edit-rename"));
36  ui.addIdentity->setIcon(QIcon::fromTheme("list-add-user"));
37  ui.deleteIdentity->setIcon(QIcon::fromTheme("list-remove-user"));
38 
39  coreConnectionStateChanged(Client::isConnected()); // need a core connection!
40  connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
41 
42  connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientIdentityCreated(IdentityId)));
43  connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientIdentityRemoved(IdentityId)));
44 
45  connect(ui.identityEditor, SIGNAL(widgetHasChanged()), this, SLOT(widgetHasChanged()));
46 #ifdef HAVE_SSL
47  connect(ui.identityEditor, SIGNAL(requestEditSsl()), this, SLOT(continueUnsecured()));
48 #endif
49 
50  currentId = 0;
51 
52  //connect(ui.identityList, SIGNAL(editTextChanged(const QString &)), this, SLOT(widgetHasChanged()));
53 }
54 
55 
57 {
58  setEnabled(connected);
59  if (connected) {
60 #ifdef HAVE_SSL
61  if (Client::signalProxy()->isSecure()) {
62  ui.identityEditor->setSslState(IdentityEditWidget::AllowSsl);
63  _editSsl = true;
64  }
65  else {
66  ui.identityEditor->setSslState(IdentityEditWidget::UnsecureSsl);
67  _editSsl = false;
68  }
69 #else
70  ui.identityEditor->setSslState(IdentityEditWidget::NoSsl);
71 #endif
72  load();
73  }
74  else {
75  // reset
76  currentId = 0;
77  }
78 }
79 
80 
81 #ifdef HAVE_SSL
82 void IdentitiesSettingsPage::continueUnsecured()
83 {
84  _editSsl = true;
85 
86  QHash<IdentityId, CertIdentity *>::iterator idIter;
87  for (idIter = identities.begin(); idIter != identities.end(); idIter++) {
88  idIter.value()->enableEditSsl();
89  }
90 
91  ui.identityEditor->setSslState(IdentityEditWidget::AllowSsl);
92 }
93 
94 
95 #endif
96 
98 {
99  setEnabled(false);
100  QList<CertIdentity *> toCreate, toUpdate;
101  // we need to remove our temporarily created identities.
102  // these are going to be re-added after the core has propagated them back...
103  QHash<IdentityId, CertIdentity *>::iterator i = identities.begin();
104  while (i != identities.end()) {
105  if ((*i)->id() < 0) {
106  CertIdentity *temp = *i;
107  i = identities.erase(i);
108  toCreate.append(temp);
109  ui.identityList->removeItem(ui.identityList->findData(temp->id().toInt()));
110  }
111  else {
112  if (**i != *Client::identity((*i)->id()) || (*i)->isDirty()) {
113  toUpdate.append(*i);
114  }
115  ++i;
116  }
117  }
118  SaveIdentitiesDlg dlg(toCreate, toUpdate, deletedIdentities, this);
119  int ret = dlg.exec();
120  if (ret == QDialog::Rejected) {
121  // canceled -> reload everything to be safe
122  load();
123  }
124  foreach(Identity *id, toCreate) {
125  id->deleteLater();
126  }
127  changedIdentities.clear();
128  deletedIdentities.clear();
129  setChangedState(false);
130  setEnabled(true);
131 }
132 
133 
135 {
136  currentId = 0;
137  foreach(Identity *identity, identities.values()) {
138  identity->deleteLater();
139  }
140  identities.clear();
141  deletedIdentities.clear();
142  changedIdentities.clear();
143  ui.identityList->clear();
144  setWidgetStates();
145  foreach(IdentityId id, Client::identityIds()) {
147  }
148  setChangedState(false);
149 }
150 
151 
153 {
154  bool changed = testHasChanged();
155  if (changed != hasChanged()) setChangedState(changed);
156 }
157 
158 
160 {
161  bool enabled = (ui.identityList->count() > 0);
162  ui.identityEditor->setEnabled(enabled);
163  ui.renameIdentity->setEnabled(enabled);
164  ui.deleteIdentity->setEnabled(ui.identityList->count() > 1);
165 }
166 
167 
169 {
170  if (deletedIdentities.count()) return true;
171  if (currentId < 0) {
172  return true; // new identity
173  }
174  else {
175  if (currentId != 0) {
176  changedIdentities.removeAll(currentId);
177  CertIdentity temp(currentId, this);
178 #ifdef HAVE_SSL
179  // we need to set the cert and key manually, as they aren't synced
181  temp.setSslKey(old->sslKey());
182  temp.setSslCert(old->sslCert());
183 #endif
184  ui.identityEditor->saveToIdentity(&temp);
185  temp.setIdentityName(identities[currentId]->identityName());
186  if (temp != *Client::identity(currentId) || temp.isDirty())
188  }
189  return changedIdentities.count();
190  }
191 }
192 
193 
195 {
196  ui.identityEditor->saveToIdentity(identities[currentId]);
197  QList<int> errors;
198  foreach(Identity *id, identities.values()) {
199  if (id->identityName().isEmpty()) errors.append(1);
200  if (!id->nicks().count()) errors.append(2);
201  if (id->realName().isEmpty()) errors.append(3);
202  if (id->ident().isEmpty()) errors.append(4);
203  }
204  if (!errors.count()) return true;
205  QString error(tr("<b>The following problems need to be corrected before your changes can be applied:</b><ul>"));
206  if (errors.contains(1)) error += tr("<li>All identities need an identity name set</li>");
207  if (errors.contains(2)) error += tr("<li>Every identity needs at least one nickname defined</li>");
208  if (errors.contains(3)) error += tr("<li>You need to specify a real name for every identity</li>");
209  if (errors.contains(4)) error += tr("<li>You need to specify an ident for every identity</li>");
210  error += tr("</ul>");
211  QMessageBox::warning(this, tr("One or more identities are invalid"), error);
212  return false;
213 }
214 
215 
217 {
218  CertIdentity *identity = new CertIdentity(*Client::identity(id), this);
219 #ifdef HAVE_SSL
220  identity->enableEditSsl(_editSsl);
221 #endif
222  insertIdentity(identity);
223 #ifdef HAVE_SSL
224  connect(identity, SIGNAL(sslSettingsUpdated()), this, SLOT(clientIdentityUpdated()));
225 #endif
226  connect(Client::identity(id), SIGNAL(updatedRemotely()), this, SLOT(clientIdentityUpdated()));
227 }
228 
229 
231 {
232  const Identity *clientIdentity = qobject_cast<Identity *>(sender());
233  if (!clientIdentity) {
234  qWarning() << "Invalid identity to update!";
235  return;
236  }
237  if (!identities.contains(clientIdentity->id())) {
238  qWarning() << "Unknown identity to update:" << clientIdentity->identityName();
239  return;
240  }
241 
242  CertIdentity *identity = identities[clientIdentity->id()];
243 
244  if (identity->identityName() != clientIdentity->identityName())
245  renameIdentity(identity->id(), clientIdentity->identityName());
246 
247  identity->copyFrom(*clientIdentity);
248 
249  if (identity->id() == currentId)
250  ui.identityEditor->displayIdentity(identity);
251 }
252 
253 
255 {
256  if (identities.contains(id)) {
258  changedIdentities.removeAll(id);
259  deletedIdentities.removeAll(id);
260  }
261 }
262 
263 
265 {
266  IdentityId id = identity->id();
267  identities[id] = identity;
268 
269  QString name = identity->identityName();
270  for (int j = 0; j < ui.identityList->count(); j++) {
271  if ((j > 0 || ui.identityList->itemData(0).toInt() != 1) && name.localeAwareCompare(ui.identityList->itemText(j)) < 0) {
272  ui.identityList->insertItem(j, name, id.toInt());
274  return;
275  }
276  }
277  // append
278  ui.identityList->insertItem(ui.identityList->count(), name, id.toInt());
279  setWidgetStates();
281 }
282 
283 
284 void IdentitiesSettingsPage::renameIdentity(IdentityId id, const QString &newName)
285 {
286  Identity *identity = identities[id];
287  ui.identityList->setItemText(ui.identityList->findData(identity->id().toInt()), newName);
288  identity->setIdentityName(newName);
289 }
290 
291 
293 {
294  identities.remove(id->id());
295  ui.identityList->removeItem(ui.identityList->findData(id->id().toInt()));
296  changedIdentities.removeAll(id->id());
297  if (currentId == id->id()) currentId = 0;
298  id->deleteLater();
299  setWidgetStates();
301 }
302 
303 
305 {
306  CertIdentity *previousIdentity = 0;
307  if (currentId != 0 && identities.contains(currentId))
308  previousIdentity = identities[currentId];
309 
310  if (index < 0) {
311  //ui.identityList->setEditable(false);
312  ui.identityEditor->displayIdentity(0, previousIdentity);
313  currentId = 0;
314  }
315  else {
316  IdentityId id = ui.identityList->itemData(index).toInt();
317  if (identities.contains(id)) {
318  ui.identityEditor->displayIdentity(identities[id], previousIdentity);
319  currentId = id;
320  }
321  }
322 }
323 
324 
326 {
327  CreateIdentityDlg dlg(ui.identityList->model(), this);
328  if (dlg.exec() == QDialog::Accepted) {
329  // find a free (negative) ID
330  IdentityId id;
331  for (id = 1; id <= identities.count(); id++) {
332  if (!identities.keys().contains(-id.toInt())) break;
333  }
334  id = -id.toInt();
335  CertIdentity *newId = new CertIdentity(id, this);
336 #ifdef HAVE_SSL
337  newId->enableEditSsl(_editSsl);
338 #endif
339  if (dlg.duplicateId() != 0) {
340  // duplicate
341  newId->copyFrom(*identities[dlg.duplicateId()]);
342  newId->setId(id);
343  }
344  newId->setIdentityName(dlg.identityName());
345  identities[id] = newId;
346  insertIdentity(newId);
347  ui.identityList->setCurrentIndex(ui.identityList->findData(id.toInt()));
349  }
350 }
351 
352 
354 {
356  int ret = QMessageBox::question(this, tr("Delete Identity?"),
357  tr("Do you really want to delete identity \"%1\"?").arg(id->identityName()),
358  QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
359  if (ret != QMessageBox::Yes) return;
360  if (id->id() > 0) deletedIdentities.append(id->id());
361  currentId = 0;
362  removeIdentity(id);
363 }
364 
365 
367 {
368  QString oldName = identities[currentId]->identityName();
369  bool ok = false;
370  QString name = QInputDialog::getText(this, tr("Rename Identity"),
371  tr("Please enter a new name for the identity \"%1\"!").arg(oldName),
372  QLineEdit::Normal, oldName, &ok);
373  if (ok && !name.isEmpty()) {
374  renameIdentity(currentId, name);
376  }
377 }
378 
379 
380 /*****************************************************************************************/
381 
382 CreateIdentityDlg::CreateIdentityDlg(QAbstractItemModel *model, QWidget *parent)
383  : QDialog(parent)
384 {
385  ui.setupUi(this);
386 
387  ui.identityList->setModel(model); // now we use the identity list of the main page... Trolltech <3
388  on_identityName_textChanged(""); // disable ok button :)
389 }
390 
391 
393 {
394  return ui.identityName->text();
395 }
396 
397 
399 {
400  if (!ui.duplicateIdentity->isChecked()) return 0;
401  if (ui.identityList->currentIndex() >= 0) {
402  return ui.identityList->itemData(ui.identityList->currentIndex()).toInt();
403  }
404  return 0;
405 }
406 
407 
409 {
410  ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(text.count());
411 }
412 
413 
414 /*********************************************************************************************/
415 
416 SaveIdentitiesDlg::SaveIdentitiesDlg(const QList<CertIdentity *> &toCreate, const QList<CertIdentity *> &toUpdate, const QList<IdentityId> &toRemove, QWidget *parent)
417  : QDialog(parent)
418 {
419  ui.setupUi(this);
420  ui.abort->setIcon(QIcon::fromTheme("dialog-cancel"));
421 
422  numevents = toCreate.count() + toUpdate.count() + toRemove.count();
423  rcvevents = 0;
424  if (numevents) {
425  ui.progressBar->setMaximum(numevents);
426  ui.progressBar->setValue(0);
427 
428  connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientEvent()));
429  connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientEvent()));
430 
431  foreach(CertIdentity *id, toCreate) {
433  }
434  foreach(CertIdentity *id, toUpdate) {
435  const Identity *cid = Client::identity(id->id());
436  if (!cid) {
437  qWarning() << "Invalid client identity!";
438  numevents--;
439  continue;
440  }
441  connect(cid, SIGNAL(updatedRemotely()), this, SLOT(clientEvent()));
442  Client::updateIdentity(id->id(), id->toVariantMap());
443 #ifdef HAVE_SSL
444  id->requestUpdateSslSettings();
445 #endif
446  }
447  foreach(IdentityId id, toRemove) {
449  }
450  }
451  else {
452  qWarning() << "Sync dialog called without stuff to change!";
453  accept();
454  }
455 }
456 
457 
459 {
460  ui.progressBar->setValue(++rcvevents);
461  if (rcvevents >= numevents) accept();
462 }
463 
464 
465 /*************************************************************************************************/
466 
467 NickEditDlg::NickEditDlg(const QString &old, const QStringList &exist, QWidget *parent)
468  : QDialog(parent), oldNick(old), existing(exist)
469 {
470  ui.setupUi(this);
471 
472  // define a regexp for valid nicknames
473  // TODO: add max nicklength according to ISUPPORT
474  QString letter = "A-Za-z";
475  QString special = "\x5b-\x60\x7b-\x7d";
476  QRegExp rx(QString("[%1%2][%1%2\\d-]*").arg(letter, special));
477  ui.nickEdit->setValidator(new QRegExpValidator(rx, ui.nickEdit));
478  if (old.isEmpty()) {
479  // new nick
480  setWindowTitle(tr("Add Nickname"));
481  on_nickEdit_textChanged(""); // disable ok button
482  }
483  else ui.nickEdit->setText(old);
484 }
485 
486 
487 QString NickEditDlg::nick() const
488 {
489  return ui.nickEdit->text();
490 }
491 
492 
493 void NickEditDlg::on_nickEdit_textChanged(const QString &text)
494 {
495  ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text));
496 }