BibleTime
cswordsetupinstallsourcesdialog.cpp
Go to the documentation of this file.
1 /*********
2 *
3 * In the name of the Father, and of the Son, and of the Holy Spirit.
4 *
5 * This file is part of BibleTime's source code, https://bibletime.info/
6 *
7 * Copyright 1999-2021 by the BibleTime developers.
8 * The BibleTime source code is licensed under the GNU General Public License
9 * version 2.0.
10 *
11 **********/
12 
14 
15 #include <QByteArray>
16 #include <QComboBox>
17 #include <QDebug>
18 #include <QDir>
19 #include <QFileInfo>
20 #include <QFileDialog>
21 #include <QGridLayout>
22 #include <QHBoxLayout>
23 #include <QLabel>
24 #include <QLineEdit>
25 #include <QMessageBox>
26 #include <QNonConstOverload>
27 #include <QPushButton>
28 #include <Qt>
29 #include <QVBoxLayout>
30 #include <QDialogButtonBox>
31 #include <QProgressDialog>
32 #include <QApplication>
33 #include "../../backend/btinstallbackend.h"
34 #include "../../backend/btinstallmgr.h"
35 #include "../../util/btconnect.h"
36 #include "../messagedialog.h"
37 
38 // Sword includes:
39 #include <installmgr.h>
40 #include <swbuf.h>
41 
42 
43 namespace {
44 
45 enum class SourceProtocol : int { Local, FTP, SFTP, HTTP, HTTPS };
46 
47 } // anonymous namespace
48 
50  : QDialog(),
51  m_remoteListAdded(false) {
52  setWindowTitle(tr("New Installation Source"));
53 
54  QVBoxLayout* mainLayout = new QVBoxLayout( this );
55  mainLayout->setContentsMargins(10, 10, 10, 10);
56  mainLayout->setSpacing( 5 );
57 
58  QHBoxLayout *captionLayout = new QHBoxLayout;
59  mainLayout->addLayout(captionLayout);
60  QLabel *label = new QLabel( tr("Caption"), this );
61  captionLayout->addWidget( label );
62 
63  m_captionEdit = new QLineEdit( this );
64  m_captionEdit->setText(QStringLiteral("CrossWire Bible Society"));
65  captionLayout->addWidget( m_captionEdit );
66 
67  mainLayout->addSpacing( 10 );
68 
69  QGridLayout* layout = new QGridLayout;
70  layout->setSpacing(3);
71  layout->setContentsMargins(3, 3, 3, 3);
72  mainLayout->addLayout(layout);
73  layout->setSpacing( 5 );
74 
75  label = new QLabel(tr("Type"), this);
76  layout->addWidget( label, 0, 0);
77 
78  m_serverLabel = new QLabel(tr("Server"), this);
79  layout->addWidget( m_serverLabel, 0, 1);
80 
81  label = new QLabel(tr("Path"), this);
82  layout->addWidget( label, 0, 2 );
83 
84  m_protocolCombo = new QComboBox( this );
85  layout->addWidget(m_protocolCombo, 1, 0);
86  m_protocolCombo->addItem(tr("Remote FTP"), int(SourceProtocol::FTP));
87  m_protocolCombo->addItem(tr("Remote SFTP"), int(SourceProtocol::SFTP));
88  m_protocolCombo->addItem(tr("Remote HTTP"), int(SourceProtocol::HTTP));
89  m_protocolCombo->addItem(tr("Remote HTTPS"), int(SourceProtocol::HTTPS));
90  m_protocolCombo->addItem(tr("Local"), int(SourceProtocol::Local));
91 
92  m_serverEdit = new QLineEdit( this );
93  layout->addWidget( m_serverEdit, 1, 1 );
94  m_serverEdit->setText(QStringLiteral("ftp.crosswire.org"));
95 
96  m_pathEdit = new QLineEdit( this );
97  layout->addWidget( m_pathEdit, 1, 2 );
98  m_pathEdit->setText(QStringLiteral("/pub/sword/raw"));
99 
100  mainLayout->addSpacing( 10 );
101 
102  QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Save, Qt::Horizontal, this);
103  message::prepareDialogBox(buttonBox);
104  QPushButton* getListButton = new QPushButton(tr("Get list..."), this);
105  getListButton->setToolTip(tr("Download a list of sources from CrossWire server and add sources"));
106  buttonBox->addButton(getListButton, QDialogButtonBox::ActionRole);
107  BT_CONNECT(getListButton, &QPushButton::clicked,
108  [this]{
110  this,
111  tr("Get source list from remote server?"),
112  tr("List of sources will be downloaded from a "
113  "remote server. Sources will be added to the "
114  "current list. New source will replace an "
115  "old one if it has the same label. You can "
116  "later remove the sources you don't want to "
117  "keep.\n\nDo you want to continue?"),
118  QMessageBox::Yes | QMessageBox::No,
119  QMessageBox::Yes) == QMessageBox::No)
120  return;
121 
122  BtInstallMgr iMgr;
123 
124  QProgressDialog progressDialog(tr("Connecting..."),
125  tr("Cancel"),
126  0,
127  100,
128  this);
129  progressDialog.setValue(0);
130  progressDialog.setWindowTitle(tr("Downloading List"));
131  progressDialog.setMinimumDuration(0);
132  BT_CONNECT(&progressDialog, &QProgressDialog::canceled,
133  [&iMgr]{
134  iMgr.terminate();
135  qApp->processEvents();
136  });
137  /** \todo connect this directly to the dialog setValue(int)
138  if possible: */
140  [&progressDialog](const int, const int current) {
141  progressDialog.setLabelText(
142  tr("Refreshing..."));
143  progressDialog.setValue(current);
144  qApp->processEvents();
145  });
146 
147  progressDialog.show();
148  qApp->processEvents();
149 
150  if (!iMgr.refreshRemoteSourceConfiguration()) {
151  // make sure the dialog closes with autoClose:
152  progressDialog.setValue(100);
153  m_remoteListAdded = true;
154  accept();
155  } else {
156  qWarning("InstallMgr: getting remote list returned an "
157  "error.");
158  }
159  });
160  mainLayout->addWidget(buttonBox);
161  BT_CONNECT(buttonBox, &QDialogButtonBox::accepted,
162  [this]{
163  struct Error { QString msg; };
164  try {
165  if (m_captionEdit->text().trimmed().isEmpty())
166  throw Error{tr("Please provide a caption.")};
167 
168  auto is(BtInstallBackend::source(m_captionEdit->text()));
169  if (is.caption.c_str() == m_captionEdit->text())
170  throw Error{tr("A source with this caption already "
171  "exists. Please provide a different "
172  "caption.")};
173 
174  if (m_protocolCombo->currentData().toInt()
175  != int(SourceProtocol::Local)
176  && m_serverEdit->text().trimmed().isEmpty())
177  throw Error{tr("Please provide a server name.")};
178 
179  if (m_protocolCombo->currentData().toInt()
180  == int(SourceProtocol::Local))
181  {
182  if (m_pathEdit->text().isEmpty())
183  throw Error{tr("Please provide a path.")};
184 
185  QFileInfo const fi(m_pathEdit->text());
186  if (!fi.exists() || !fi.isReadable())
187  throw Error{tr("Please provide a valid, "
188  "readable path.")};
189  }
190  } catch (Error const & e) {
191  message::showCritical(this, tr("Error"), e.msg);
192  return;
193  }
194  accept();
195  });
196  BT_CONNECT(buttonBox, &QDialogButtonBox::rejected,
197  this, &CSwordSetupInstallSourcesDialog::reject);
198  BT_CONNECT(m_protocolCombo, qOverload<int>(&QComboBox::activated),
199  [this]{
200  if (m_protocolCombo->currentData().toInt()
201  != int(SourceProtocol::Local))
202  {
203  m_serverLabel->setEnabled(true);
204  m_serverEdit->setEnabled(true);
205  } else { // LOCAL, no server needed
206  m_serverLabel->setEnabled(false);
207  m_serverEdit->setEnabled(false);
208 
209  QString dirname = QFileDialog::getExistingDirectory(this);
210  if (dirname.isEmpty()) {
211  return; // user cancelled
212  }
213  QDir dir(dirname);
214  if (dir.exists()) {
215  m_pathEdit->setText( dir.canonicalPath() );
216  }
217  }
218 
219  });
220 }
221 
223  sword::InstallSource newSource(""); //empty, invalid Source
224  auto const protocol =
225  static_cast<SourceProtocol>(m_protocolCombo->currentData().toInt());
226  if (protocol != SourceProtocol::Local) {
227  if (protocol == SourceProtocol::FTP) {
228  newSource.type = "FTP";
229  } else if (protocol == SourceProtocol::SFTP) {
230  newSource.type = "SFTP";
231  } else if (protocol == SourceProtocol::HTTP) {
232  newSource.type = "HTTP";
233  } else if (protocol == SourceProtocol::HTTPS) {
234  newSource.type = "HTTPS";
235  }
236  /// \todo Add validator for server
237  // a message to the user would be nice, but we're in message freeze right now (1.5.1)
238  auto server = m_serverEdit->text();
239  while (server.endsWith('/'))
240  server.chop(1);
241  newSource.source = server.toUtf8();
242  }
243  else {
244  newSource.type = "DIR";
245  newSource.source = "local";
246  }
247  newSource.caption = m_captionEdit->text().toUtf8();
248  newSource.directory = m_pathEdit->text().toUtf8();
249  newSource.uid = newSource.source;
250 
251  return newSource;
252 }
#define BT_CONNECT(...)
Definition: btconnect.h:20
void percentCompleted(const int total, const int file)
if(plainSearchedText)
sword::InstallSource source(const QString &name)
void prepareDialogBox(QDialogButtonBox *box)
QMessageBox::StandardButton showQuestion(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
QMessageBox::StandardButton showCritical(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)