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