ctkXnatLoginDialog.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*=============================================================================
  2. Library: CTK
  3. Copyright (c) University College London,
  4. Centre for Medical Image Computing
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. =============================================================================*/
  15. #include "ctkXnatLoginDialog.h"
  16. #include <QListView>
  17. #include <QMap>
  18. #include <QMessageBox>
  19. #include <QStringListModel>
  20. #include <QTimer>
  21. #include <ctkXnatConnection.h>
  22. #include <ctkXnatConnectionFactory.h>
  23. #include <ctkXnatException.h>
  24. #include "ctkXnatLoginProfile.h"
  25. #include "ctkXnatSettings.h"
  26. class ctkXnatLoginDialogPrivate
  27. {
  28. public:
  29. ctkXnatLoginDialogPrivate(ctkXnatConnectionFactory* f)
  30. : Factory(f)
  31. {
  32. }
  33. ctkXnatSettings* Settings;
  34. ctkXnatConnectionFactory* Factory;
  35. ctkXnatConnection* Connection;
  36. QMap<QString, ctkXnatLoginProfile*> Profiles;
  37. QStringListModel Model;
  38. QStringList ProfileNames;
  39. bool Dirty;
  40. };
  41. ctkXnatLoginDialog::ctkXnatLoginDialog(ctkXnatConnectionFactory* f, QWidget* parent, Qt::WindowFlags flags)
  42. : QDialog(parent, flags)
  43. , ui(0)
  44. , d_ptr(new ctkXnatLoginDialogPrivate(f))
  45. {
  46. Q_D(ctkXnatLoginDialog);
  47. // initialize data members
  48. d->Settings = 0;
  49. d->Connection = 0;
  50. d->Dirty = false;
  51. if (!ui)
  52. {
  53. // Create UI
  54. ui = new Ui::ctkXnatLoginDialog();
  55. ui->setupUi(this);
  56. QItemSelectionModel* oldSelectionModel = ui->lstProfiles->selectionModel();
  57. ui->lstProfiles->setModel(&d->Model);
  58. delete oldSelectionModel;
  59. ui->lstProfiles->setSelectionMode(QAbstractItemView::SingleSelection);
  60. ui->lstProfiles->setSelectionRectVisible(false);
  61. ui->lstProfiles->setEditTriggers(QAbstractItemView::NoEditTriggers);
  62. ui->btnSave->setEnabled(false);
  63. // Create connections after setting defaults, so you don't trigger stuff when setting defaults.
  64. this->createConnections();
  65. }
  66. }
  67. ctkXnatLoginDialog::~ctkXnatLoginDialog()
  68. {
  69. Q_D(ctkXnatLoginDialog);
  70. foreach (ctkXnatLoginProfile* profile, d->Profiles)
  71. {
  72. delete profile;
  73. }
  74. if (ui)
  75. {
  76. delete ui;
  77. }
  78. }
  79. void ctkXnatLoginDialog::createConnections()
  80. {
  81. connect(ui->edtProfileName, SIGNAL(textChanged(const QString&)), this, SLOT(onFieldChanged()));
  82. connect(ui->edtServerUri, SIGNAL(textChanged(const QString&)), this, SLOT(onFieldChanged()));
  83. connect(ui->edtUserName, SIGNAL(textChanged(const QString&)), this, SLOT(onFieldChanged()));
  84. // Password change is not listened to.
  85. // connect(ui->edtPassword, SIGNAL(textChanged(const QString&)), this, SLOT(onFieldChanged()));
  86. connect(ui->cbxDefaultProfile, SIGNAL(toggled(bool)), this, SLOT(onFieldChanged()));
  87. connect(ui->lstProfiles->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
  88. this, SLOT(onCurrentProfileChanged(const QModelIndex&)));
  89. }
  90. ctkXnatSettings* ctkXnatLoginDialog::settings() const
  91. {
  92. Q_D(const ctkXnatLoginDialog);
  93. return d->Settings;
  94. }
  95. void ctkXnatLoginDialog::setSettings(ctkXnatSettings* settings)
  96. {
  97. Q_D(ctkXnatLoginDialog);
  98. d->Settings = settings;
  99. if (!settings)
  100. {
  101. return;
  102. }
  103. d->Profiles = d->Settings->getLoginProfiles();
  104. d->ProfileNames = d->Profiles.keys();
  105. d->ProfileNames.sort();
  106. d->Model.setStringList(d->ProfileNames);
  107. ctkXnatLoginProfile* defaultProfile = d->Settings->getDefaultLoginProfile();
  108. if (defaultProfile)
  109. {
  110. int profileNumber = d->ProfileNames.indexOf(defaultProfile->name());
  111. QModelIndex index = d->Model.index(profileNumber);
  112. if (index.isValid())
  113. {
  114. ui->lstProfiles->setCurrentIndex(index);
  115. }
  116. ui->edtPassword->setFocus();
  117. }
  118. }
  119. ctkXnatConnection* ctkXnatLoginDialog::getConnection()
  120. {
  121. Q_D(ctkXnatLoginDialog);
  122. return d->Connection;
  123. }
  124. void ctkXnatLoginDialog::accept()
  125. {
  126. Q_D(ctkXnatLoginDialog);
  127. QString url = ui->edtServerUri->text();
  128. if ( url.isEmpty() )
  129. {
  130. QMessageBox::warning(this, tr("Missing XNAT server URI"), tr("Please enter XNAT server URI."));
  131. ui->edtServerUri->selectAll();
  132. ui->edtServerUri->setFocus();
  133. return;
  134. }
  135. QString userName = ui->edtUserName->text();
  136. if ( userName.isEmpty() )
  137. {
  138. QMessageBox::warning(this, tr("Missing user name"), tr("Please enter user name."));
  139. ui->edtUserName->selectAll();
  140. ui->edtUserName->setFocus();
  141. return;
  142. }
  143. if (d->Dirty)
  144. {
  145. const QString& profileName = ui->edtProfileName->text();
  146. if (this->askToSaveProfile(profileName))
  147. {
  148. this->saveProfile(profileName);
  149. }
  150. }
  151. QString password = ui->edtPassword->text();
  152. // create XNAT connection
  153. try
  154. {
  155. d->Connection = d->Factory->makeConnection(url.toAscii().constData(), userName.toAscii().constData(),
  156. password.toAscii().constData());
  157. d->Connection->setProfileName(ui->edtProfileName->text());
  158. }
  159. catch (ctkXnatException& e)
  160. {
  161. QMessageBox::warning(this, tr("Invalid Login Error"), tr(e.what()));
  162. ui->edtServerUri->selectAll();
  163. ui->edtServerUri->setFocus();
  164. return;
  165. }
  166. QDialog::accept();
  167. }
  168. void ctkXnatLoginDialog::onCurrentProfileChanged(const QModelIndex& currentIndex)
  169. {
  170. Q_D(ctkXnatLoginDialog);
  171. if (!currentIndex.isValid())
  172. {
  173. this->loadProfile();
  174. return;
  175. }
  176. int originalIndexRow = currentIndex.row();
  177. QString newProfileName = d->ProfileNames[currentIndex.row()];
  178. ctkXnatLoginProfile* profile = d->Profiles[newProfileName];
  179. bool newProfileSaved = false;
  180. if (d->Dirty)
  181. {
  182. QString profileName = ui->edtProfileName->text();
  183. if (this->askToSaveProfile(profileName))
  184. {
  185. this->saveProfile(profileName);
  186. newProfileSaved = true;
  187. }
  188. }
  189. this->loadProfile(*profile);
  190. d->Dirty = false;
  191. ui->btnSave->setEnabled(false);
  192. ui->btnDelete->setEnabled(true);
  193. // Ugly hack. If the current index has changed because of saving the edited element
  194. // then we have to select it again, but a bit later. If we select it right here then
  195. // both the original index and the new index are selected. (Even if single selection
  196. // is set.)
  197. if (newProfileSaved && originalIndexRow != currentIndex.row())
  198. {
  199. QTimer::singleShot(0, this, SLOT(resetLstProfilesCurrentIndex()));
  200. }
  201. }
  202. void ctkXnatLoginDialog::resetLstProfilesCurrentIndex()
  203. {
  204. // Yes, this is really needed. See the comment above.
  205. ui->lstProfiles->setCurrentIndex(ui->lstProfiles->currentIndex());
  206. }
  207. bool ctkXnatLoginDialog::askToSaveProfile(const QString& profileName)
  208. {
  209. QString question = QString(
  210. "You have not saved the changes of the %1 profile.\n"
  211. "Do you want to save them now?").arg(profileName);
  212. QMessageBox::StandardButton answer = QMessageBox::question(this, "", question, QMessageBox::Yes | QMessageBox::No,
  213. QMessageBox::Yes);
  214. return answer == QMessageBox::Yes;
  215. }
  216. void ctkXnatLoginDialog::saveProfile(const QString& profileName)
  217. {
  218. Q_D(ctkXnatLoginDialog);
  219. ctkXnatLoginProfile* profile = d->Profiles[profileName];
  220. bool oldProfileWasDefault = profile && profile->isDefault();
  221. if (!profile)
  222. {
  223. profile = new ctkXnatLoginProfile();
  224. d->Profiles[profileName] = profile;
  225. int profileNumber = d->ProfileNames.size();
  226. // Insertion into the profile name list and the listView (ascending order)
  227. int idx = 0;
  228. while (idx < profileNumber && QString::localeAwareCompare(profileName, d->ProfileNames[idx]) > 0)
  229. {
  230. ++idx;
  231. }
  232. d->ProfileNames.insert(idx, profileName);
  233. d->Model.insertRow(idx);
  234. d->Model.setData(d->Model.index(idx), profileName);
  235. }
  236. this->storeProfile(*profile);
  237. // If the profile is to be default then remove the default flag from the other profiles.
  238. // This code assumes that the newly created profiles are not default.
  239. if (profile->isDefault() && !oldProfileWasDefault)
  240. {
  241. foreach (ctkXnatLoginProfile* otherProfile, d->Profiles.values())
  242. {
  243. const QString& otherProfileName = otherProfile->name();
  244. if (otherProfileName != profileName && otherProfile->isDefault())
  245. {
  246. otherProfile->setDefault(false);
  247. if (d->Settings)
  248. {
  249. d->Settings->setLoginProfile(otherProfileName, otherProfile);
  250. }
  251. }
  252. }
  253. }
  254. if (d->Settings)
  255. {
  256. d->Settings->setLoginProfile(profileName, profile);
  257. }
  258. d->Dirty = false;
  259. ui->btnSave->setEnabled(false);
  260. }
  261. void ctkXnatLoginDialog::on_btnSave_clicked()
  262. {
  263. Q_D(ctkXnatLoginDialog);
  264. QString editedProfileName = ui->edtProfileName->text();
  265. bool selectSavedProfile = true;
  266. QModelIndex currentIndex = ui->lstProfiles->currentIndex();
  267. if (currentIndex.isValid())
  268. {
  269. QString selectedProfileName = d->ProfileNames[currentIndex.row()];
  270. if (editedProfileName == selectedProfileName)
  271. {
  272. selectSavedProfile = false;
  273. }
  274. }
  275. this->saveProfile(editedProfileName);
  276. if (selectSavedProfile)
  277. {
  278. int editedProfileNumber = d->ProfileNames.indexOf(editedProfileName);
  279. QModelIndex editedProfileIndex = d->Model.index(editedProfileNumber, 0);
  280. ui->lstProfiles->setCurrentIndex(editedProfileIndex);
  281. }
  282. }
  283. void ctkXnatLoginDialog::blockSignalsOfFields(bool value)
  284. {
  285. ui->edtProfileName->blockSignals(value);
  286. ui->edtServerUri->blockSignals(value);
  287. ui->edtUserName->blockSignals(value);
  288. ui->edtPassword->blockSignals(value);
  289. ui->cbxDefaultProfile->blockSignals(value);
  290. }
  291. void ctkXnatLoginDialog::loadProfile(const ctkXnatLoginProfile& profile)
  292. {
  293. this->blockSignalsOfFields(true);
  294. ui->edtProfileName->setText(profile.name());
  295. ui->edtServerUri->setText(profile.serverUri());
  296. ui->edtUserName->setText(profile.userName());
  297. ui->edtPassword->setText(profile.password());
  298. ui->cbxDefaultProfile->setChecked(profile.isDefault());
  299. this->blockSignalsOfFields(false);
  300. }
  301. void ctkXnatLoginDialog::storeProfile(ctkXnatLoginProfile& profile)
  302. {
  303. profile.setName(ui->edtProfileName->text());
  304. profile.setServerUri(ui->edtServerUri->text());
  305. profile.setUserName(ui->edtUserName->text());
  306. profile.setPassword(ui->edtPassword->text());
  307. profile.setDefault(ui->cbxDefaultProfile->isChecked());
  308. }
  309. void ctkXnatLoginDialog::on_btnDelete_clicked()
  310. {
  311. Q_D(ctkXnatLoginDialog);
  312. QString profileName = ui->edtProfileName->text();
  313. int idx = d->ProfileNames.indexOf(profileName);
  314. d->Model.removeRow(idx);
  315. d->ProfileNames.removeAt(idx);
  316. delete d->Profiles.take(profileName);
  317. if (d->Profiles.empty())
  318. {
  319. ui->btnDelete->setEnabled(false);
  320. ui->edtProfileName->setFocus();
  321. }
  322. if (d->Settings)
  323. {
  324. d->Settings->removeLoginProfile(profileName);
  325. }
  326. }
  327. void ctkXnatLoginDialog::on_edtProfileName_textChanged(const QString& /*text*/)
  328. {
  329. ui->lstProfiles->clearSelection();
  330. ui->btnDelete->setEnabled(false);
  331. }
  332. void ctkXnatLoginDialog::onFieldChanged()
  333. {
  334. Q_D(ctkXnatLoginDialog);
  335. d->Dirty = true;
  336. ui->btnSave->setEnabled(true);
  337. }