1 #include "transfer_dialog.h"
2 #include "list_of_job_options.h"
3 #include "utils.h"
4
TransferDialog(bool isDownload,bool isDrop,const QString & remote,const QDir & path,bool isFolder,QWidget * parent,JobOptions * task,bool editMode)5 TransferDialog::TransferDialog(bool isDownload, bool isDrop,
6 const QString &remote, const QDir &path,
7 bool isFolder, QWidget *parent, JobOptions *task,
8 bool editMode)
9 : QDialog(parent), mIsDownload(isDownload), mIsFolder(isFolder),
10 mIsEditMode(editMode), mJobOptions(task) {
11 ui.setupUi(this);
12 resize(0, 0);
13 setWindowTitle(isDownload ? "Download" : "Upload");
14
15 QStyle *style = qApp->style();
16 ui.buttonSourceFile->setIcon(style->standardIcon(QStyle::SP_FileIcon));
17 ui.buttonSourceFolder->setIcon(style->standardIcon(QStyle::SP_DirIcon));
18 ui.buttonDest->setIcon(style->standardIcon(QStyle::SP_DirIcon));
19
20 ui.buttonDefaultSource->setIcon(style->standardIcon(QStyle::SP_DirHomeIcon));
21 ui.buttonDefaultDest->setIcon(style->standardIcon(QStyle::SP_DirHomeIcon));
22
23 if (!mIsEditMode) {
24 QPushButton *dryRun =
25 ui.buttonBox->addButton("&Dry run", QDialogButtonBox::AcceptRole);
26 ui.buttonBox->addButton("&Run", QDialogButtonBox::AcceptRole);
27 QObject::connect(dryRun, &QPushButton::clicked, this,
28 [=]() { mDryRun = true; });
29 }
30
31 QPushButton *saveTask = ui.buttonBox->addButton(
32 "&Save task", QDialogButtonBox::ButtonRole::ActionRole);
33
34 QObject::connect(
35 ui.buttonBox->button(QDialogButtonBox::RestoreDefaults),
36 &QPushButton::clicked, this, [=]() {
37 ui.cbSyncDelete->setCurrentIndex(0);
38 // set combobox tooltips
39 ui.cbSyncDelete->setItemData(0, "--delete-during", Qt::ToolTipRole);
40 ui.cbSyncDelete->setItemData(1, "--delete-after", Qt::ToolTipRole);
41 ui.cbSyncDelete->setItemData(2, "--delete-before", Qt::ToolTipRole);
42 ui.checkSkipNewer->setChecked(false);
43 ui.checkSkipNewer->setChecked(false);
44 ui.checkSkipExisting->setChecked(false);
45 ui.checkCompare->setChecked(true);
46 ui.cbCompare->setCurrentIndex(0);
47 // set combobox tooltips
48 ui.cbCompare->setItemData(0, "default", Qt::ToolTipRole);
49 ui.cbCompare->setItemData(1, "--checksum", Qt::ToolTipRole);
50 ui.cbCompare->setItemData(2, "--ignore-size", Qt::ToolTipRole);
51 ui.cbCompare->setItemData(3, "--size-only", Qt::ToolTipRole);
52 ui.cbCompare->setItemData(4, "--checksum --ignore-size",
53 Qt::ToolTipRole);
54 // ui.checkVerbose->setChecked(false);
55 ui.checkSameFilesystem->setChecked(false);
56 ui.checkDontUpdateModified->setChecked(false);
57 ui.spinTransfers->setValue(4);
58 ui.spinCheckers->setValue(8);
59 ui.textBandwidth->clear();
60 ui.textMinSize->clear();
61 ui.textMinAge->clear();
62 ui.textMaxAge->clear();
63 ui.spinMaxDepth->setValue(0);
64 ui.spinConnectTimeout->setValue(60);
65 ui.spinIdleTimeout->setValue(300);
66 ui.spinRetries->setValue(3);
67 ui.spinLowLevelRetries->setValue(10);
68 ui.checkDeleteExcluded->setChecked(false);
69 ui.textExclude->clear();
70 auto settings = GetSettings();
71 if (isDownload) {
72 // download
73 ui.textExtra->setText(
74 settings->value("Settings/defaultDownloadOptions").toString());
75 } else {
76 // upload
77 ui.textExtra->setText(
78 settings->value("Settings/defaultUploadOptions").toString());
79 }
80 });
81
82 ui.buttonBox->button(QDialogButtonBox::RestoreDefaults)->click();
83
84 QObject::connect(saveTask, &QPushButton::clicked, this, [=]() {
85 // validate before saving task...
86 if (ui.textDescription->text().isEmpty()) {
87 QMessageBox::warning(this, "Warning",
88 "Please enter task description to Save!");
89 ui.textDescription->setFocus(Qt::FocusReason::OtherFocusReason);
90 return;
91 }
92 // even though the below does not match the condition on the Run buttons
93 // it SEEMS like blanking either one would be a problem, right?
94 if (ui.textDest->text().isEmpty() || ui.textSource->text().isEmpty()) {
95 QMessageBox::warning(this, "Error",
96 "Invalid Task, source and destination required!");
97 return;
98 }
99 JobOptions *jobo = getJobOptions();
100 ListOfJobOptions::getInstance()->Persist(jobo);
101 // always close on save
102 // if (mIsEditMode)
103 this->close();
104 });
105
106 QObject::connect(ui.buttonBox, &QDialogButtonBox::accepted, this,
107 &QDialog::accept);
108 QObject::connect(ui.buttonBox, &QDialogButtonBox::rejected, this,
109 &QDialog::reject);
110
111 QObject::connect(ui.buttonSourceFile, &QToolButton::clicked, this, [=]() {
112 QString file = QFileDialog::getOpenFileName(this, "Choose file to upload");
113 if (!file.isEmpty()) {
114 ui.textSource->setText(QDir::toNativeSeparators(file));
115 ui.textDest->setText(remote + ":" + path.path());
116 }
117 });
118
119 QObject::connect(ui.buttonSourceFolder, &QToolButton::clicked, this, [=]() {
120 auto settings = GetSettings();
121 QString last_used_source_folder =
122 (settings->value("Settings/lastUsedSourceFolder").toString());
123 QString folder = QFileDialog::getExistingDirectory(
124 this, "Choose folder to upload", last_used_source_folder,
125 QFileDialog::ShowDirsOnly);
126 if (!folder.isEmpty()) {
127 // store new folder in lastUsedSourceFolder
128 settings->setValue("Settings/lastUsedSourceFolder", folder);
129 ui.textSource->setText(QDir::toNativeSeparators(folder));
130 ui.textDest->setText(remote + ":" +
131 path.filePath(QFileInfo(folder).fileName()));
132 }
133 });
134
135 QObject::connect(ui.buttonDefaultSource, &QToolButton::clicked, this, [=]() {
136 auto settings = GetSettings();
137 QString default_folder =
138 (settings->value("Settings/defaultUploadDir").toString());
139 // store default folder in lastUsedSourceFolder
140 settings->setValue("Settings/lastUsedSourceFolder", default_folder);
141 ui.textSource->setText(QDir::toNativeSeparators(default_folder));
142 if (!default_folder.isEmpty()) {
143 ui.textDest->setText(remote + ":" +
144 path.filePath(QFileInfo(default_folder).fileName()));
145 } else {
146 ui.textDest->setText(remote + ":" + path.path());
147 };
148 });
149
150 QObject::connect(ui.buttonDest, &QToolButton::clicked, this, [=]() {
151 auto settings = GetSettings();
152 QString last_used_dest_folder =
153 (settings->value("Settings/lastUsedDestFolder").toString());
154 QString folder = QFileDialog::getExistingDirectory(
155 this, "Choose destination folder", last_used_dest_folder,
156 QFileDialog::ShowDirsOnly);
157 if (!folder.isEmpty()) {
158 // store new folder in lastUsedDestFolder
159 settings->setValue("Settings/lastUsedDestFolder", folder);
160 if (isFolder) {
161 ui.textDest->setText(
162 QDir::toNativeSeparators(folder + "/" + path.dirName()));
163 } else {
164 ui.textDest->setText(QDir::toNativeSeparators(folder));
165 }
166 }
167 });
168
169 QObject::connect(ui.buttonDefaultDest, &QToolButton::clicked, this, [=]() {
170 auto settings = GetSettings();
171 QString default_folder =
172 (settings->value("Settings/defaultDownloadDir").toString());
173 // store default_folder in lastUsedDestFolder
174 settings->setValue("Settings/lastUsedDestFolder", default_folder);
175 if (!default_folder.isEmpty()) {
176 if (isFolder) {
177 ui.textDest->setText(
178 QDir::toNativeSeparators(default_folder + "/" + path.dirName()));
179 } else {
180 ui.textDest->setText(QDir::toNativeSeparators(default_folder));
181 }
182 } else {
183 ui.textDest->setText("");
184 };
185 });
186
187 auto settings = GetSettings();
188 settings->beginGroup("Transfer");
189 ReadSettings(settings.get(), this);
190 settings->endGroup();
191
192 ui.buttonSourceFile->setVisible(!isDownload);
193 ui.buttonSourceFolder->setVisible(!isDownload);
194 ui.buttonDefaultSource->setVisible(!isDownload);
195
196 ui.buttonDest->setVisible(isDownload);
197 ui.buttonDefaultDest->setVisible(isDownload);
198
199 // Info only - should not be edited
200 // would be nice to display it only for Google Drive - todo
201 ui.checkisDriveSharedWithMe->setDisabled(true);
202
203 ui.checkisDriveSharedWithMe->setChecked(
204 settings->value("Settings/driveShared", false).toBool());
205 // always clear for new jobs
206 ui.textDescription->clear();
207
208 if (mIsEditMode && mJobOptions != nullptr) {
209 // it's not really valid for only one of these things to be true.
210 // when operating on an existing instance i.e. a saved task,
211 // changing the dest or src seems to have problems so we
212 // will not allow it. simple enough, and better, to make a
213 // new task for different pairings anyway. that will make
214 // a lot more sense when/if scheduling and history are added...
215 ui.buttonSourceFile->setVisible(false);
216 ui.buttonSourceFolder->setVisible(false);
217 ui.buttonDefaultSource->setVisible(false);
218
219 ui.buttonDest->setVisible(false);
220 ui.buttonDefaultDest->setVisible(false);
221
222 ui.textDest->setDisabled(true);
223 ui.textSource->setDisabled(true);
224 putJobOptions();
225 } else {
226
227 // set source and destination using defaults
228 if (isDownload) {
229 // download
230 ui.textExtra->setText(
231 settings->value("Settings/defaultDownloadOptions").toString());
232 ui.textSource->setText(remote + ":" + path.path());
233 QString folder;
234 QString default_folder =
235 (settings->value("Settings/defaultDownloadDir").toString());
236 QString last_used_dest_folder =
237 (settings->value("Settings/lastUsedDestFolder").toString());
238
239 if (last_used_dest_folder.isEmpty()) {
240 folder = default_folder;
241 } else {
242 folder = last_used_dest_folder;
243 };
244
245 if (!folder.isEmpty()) {
246 if (isFolder) {
247 ui.textDest->setText(
248 QDir::toNativeSeparators(folder + "/" + path.dirName()));
249 } else {
250 ui.textDest->setText(QDir::toNativeSeparators(folder));
251 }
252 }
253
254 } else {
255 // upload
256 ui.textExtra->setText(
257 settings->value("Settings/defaultUploadOptions").toString());
258 QString folder;
259 QString default_folder =
260 (settings->value("Settings/defaultUploadDir").toString());
261 QString last_used_source_folder =
262 (settings->value("Settings/lastUsedSourceFolder").toString());
263
264 if (last_used_source_folder.isEmpty()) {
265 folder = default_folder;
266 } else {
267 folder = last_used_source_folder;
268 };
269
270 // if upload initiated from drag and drop we dont use default upload
271 // folder
272 if (!isDrop) {
273 ui.textSource->setText(QDir::toNativeSeparators(folder));
274 if (!folder.isEmpty()) {
275 ui.textDest->setText(remote + ":" +
276 path.filePath(QFileInfo(folder).fileName()));
277 } else {
278 ui.textDest->setText(remote + ":" + path.path());
279 }
280 } else {
281 // when dropping to root folder
282 if (path.path() == ".") {
283 ui.textDest->setText(remote + ":");
284 } else {
285 ui.textDest->setText(remote + ":" + path.path());
286 }
287 };
288 };
289 }
290 }
291
~TransferDialog()292 TransferDialog::~TransferDialog() {
293 if (result() == QDialog::Accepted) {
294 auto settings = GetSettings();
295 settings->beginGroup("Transfer");
296 WriteSettings(settings.get(), this);
297 settings->remove("textSource");
298 settings->remove("textDest");
299 settings->endGroup();
300 }
301 }
302
setSource(const QString & path)303 void TransferDialog::setSource(const QString &path) {
304 ui.textSource->setText(QDir::toNativeSeparators(path));
305 }
306
getMode() const307 QString TransferDialog::getMode() const {
308 if (ui.rbCopy->isChecked()) {
309 return "Copy";
310 } else if (ui.rbMove->isChecked()) {
311 return "Move";
312 } else if (ui.rbSync->isChecked()) {
313 return "Sync";
314 }
315
316 return QString();
317 }
318
getSource() const319 QString TransferDialog::getSource() const { return ui.textSource->text(); }
320
getDest() const321 QString TransferDialog::getDest() const { return ui.textDest->text(); }
322
getOptions()323 QStringList TransferDialog::getOptions() {
324 JobOptions *jobo = getJobOptions();
325 QStringList newWay = jobo->getOptions();
326 return newWay;
327 }
328
329 /*
330 * Apply the displayed/edited values on the UI to the
331 * JobOptions object.
332 *
333 * This needs to be edited whenever options are added or changed.
334 */
getJobOptions()335 JobOptions *TransferDialog::getJobOptions() {
336 if (mJobOptions == nullptr)
337 mJobOptions = new JobOptions(mIsDownload);
338
339 if (ui.rbCopy->isChecked()) {
340 mJobOptions->operation = JobOptions::Copy;
341 mJobOptions->sync = false;
342 } else if (ui.rbMove->isChecked()) {
343 mJobOptions->operation = JobOptions::Move;
344 mJobOptions->sync = false;
345 } else if (ui.rbSync->isChecked()) {
346 mJobOptions->operation = JobOptions::Sync;
347 }
348
349 mJobOptions->dryRun = mDryRun;
350 ;
351
352 if (ui.rbSync->isChecked()) {
353 mJobOptions->sync = true;
354 switch (ui.cbSyncDelete->currentIndex()) {
355 case 0:
356 mJobOptions->syncTiming = JobOptions::During;
357 break;
358 case 1:
359 mJobOptions->syncTiming = JobOptions::After;
360 break;
361 case 2:
362 mJobOptions->syncTiming = JobOptions::Before;
363 break;
364 }
365 }
366
367 mJobOptions->skipNewer = ui.checkSkipNewer->isChecked();
368 mJobOptions->skipExisting = ui.checkSkipExisting->isChecked();
369
370 if (ui.checkCompare->isChecked()) {
371 mJobOptions->compare = true;
372 switch (ui.cbCompare->currentIndex()) {
373 case 0:
374 mJobOptions->compareOption = JobOptions::SizeAndModTime;
375 break;
376 case 1:
377 mJobOptions->compareOption = JobOptions::Checksum;
378 break;
379 case 2:
380 mJobOptions->compareOption = JobOptions::IgnoreSize;
381 break;
382 case 3:
383 mJobOptions->compareOption = JobOptions::SizeOnly;
384 break;
385 case 4:
386 mJobOptions->compareOption = JobOptions::ChecksumIgnoreSize;
387 break;
388 }
389 } else {
390 mJobOptions->compare = false;
391 };
392
393 // mJobOptions->verbose = ui.checkVerbose->isChecked();
394 mJobOptions->sameFilesystem = ui.checkSameFilesystem->isChecked();
395 mJobOptions->dontUpdateModified = ui.checkDontUpdateModified->isChecked();
396
397 mJobOptions->transfers = ui.spinTransfers->text();
398 mJobOptions->checkers = ui.spinCheckers->text();
399 mJobOptions->bandwidth = ui.textBandwidth->text();
400 mJobOptions->minSize = ui.textMinSize->text();
401 mJobOptions->minAge = ui.textMinAge->text();
402 mJobOptions->maxAge = ui.textMaxAge->text();
403 mJobOptions->maxDepth = ui.spinMaxDepth->value();
404
405 mJobOptions->connectTimeout = ui.spinConnectTimeout->text();
406 mJobOptions->idleTimeout = ui.spinIdleTimeout->text();
407 mJobOptions->retries = ui.spinRetries->text();
408 mJobOptions->lowLevelRetries = ui.spinLowLevelRetries->text();
409 mJobOptions->deleteExcluded = ui.checkDeleteExcluded->isChecked();
410
411 mJobOptions->excluded = ui.textExclude->toPlainText().trimmed();
412 mJobOptions->extra = ui.textExtra->text().trimmed();
413
414 mJobOptions->source = ui.textSource->text();
415 mJobOptions->dest = ui.textDest->text();
416 mJobOptions->isFolder = mIsFolder;
417
418 mJobOptions->description = ui.textDescription->text();
419 // auto settings = GetSettings();
420 // mJobOptions->DriveSharedWithMe = settings->value("Settings/driveShared",
421 // false).toBool();
422
423 if (mIsEditMode)
424 mJobOptions->DriveSharedWithMe = ui.checkisDriveSharedWithMe->isChecked();
425 else {
426 auto settings = GetSettings();
427 mJobOptions->DriveSharedWithMe =
428 settings->value("Settings/driveShared", false).toBool();
429 };
430
431 return mJobOptions;
432 }
433
434 /*
435 * Apply the JobOptions object to the displayed widget values.
436 *
437 * It could be "better" to use a two-way binding mechanism, but
438 * if used that should be global to the app; and anyway doing
439 * it this old primitive way makes it easier when the user wants
440 * to not save changes...
441 */
putJobOptions()442 void TransferDialog::putJobOptions() {
443 ui.rbCopy->setChecked(mJobOptions->operation == JobOptions::Copy);
444 ui.rbMove->setChecked(mJobOptions->operation == JobOptions::Move);
445 ui.rbSync->setChecked(mJobOptions->operation == JobOptions::Sync);
446
447 mDryRun = mJobOptions->dryRun;
448 ui.rbSync->setChecked(mJobOptions->sync);
449
450 ui.cbSyncDelete->setCurrentIndex((int)mJobOptions->syncTiming);
451 // set combobox tooltips
452 ui.cbSyncDelete->setItemData(0, "--delete-during", Qt::ToolTipRole);
453 ui.cbSyncDelete->setItemData(1, "--delete-after", Qt::ToolTipRole);
454 ui.cbSyncDelete->setItemData(2, "--delete-before", Qt::ToolTipRole);
455
456 ui.checkSkipNewer->setChecked(mJobOptions->skipNewer);
457 ui.checkSkipExisting->setChecked(mJobOptions->skipExisting);
458
459 ui.checkCompare->setChecked(mJobOptions->compare);
460
461 ui.cbCompare->setCurrentIndex(mJobOptions->compareOption);
462 // set combobox tooltips
463 ui.cbCompare->setItemData(0, "default", Qt::ToolTipRole);
464 ui.cbCompare->setItemData(1, "--checksum", Qt::ToolTipRole);
465 ui.cbCompare->setItemData(2, "--ignore-size", Qt::ToolTipRole);
466 ui.cbCompare->setItemData(3, "--size-only", Qt::ToolTipRole);
467 ui.cbCompare->setItemData(4, "--checksum --ignore-size", Qt::ToolTipRole);
468 // ui.checkVerbose->setChecked(mJobOptions->verbose);
469 ui.checkSameFilesystem->setChecked(mJobOptions->sameFilesystem);
470 ui.checkDontUpdateModified->setChecked(mJobOptions->dontUpdateModified);
471
472 ui.spinTransfers->setValue(mJobOptions->transfers.toInt());
473 ui.spinCheckers->setValue(mJobOptions->checkers.toInt());
474 ui.textBandwidth->setText(mJobOptions->bandwidth);
475 ui.textMinSize->setText(mJobOptions->minSize);
476 ui.textMinAge->setText(mJobOptions->minAge);
477 ui.textMaxAge->setText(mJobOptions->maxAge);
478 ui.spinMaxDepth->setValue(mJobOptions->maxDepth);
479
480 ui.spinConnectTimeout->setValue(mJobOptions->connectTimeout.toInt());
481 ui.spinIdleTimeout->setValue(mJobOptions->idleTimeout.toInt());
482 ui.spinRetries->setValue(mJobOptions->retries.toInt());
483 ui.spinLowLevelRetries->setValue(mJobOptions->lowLevelRetries.toInt());
484 ui.checkDeleteExcluded->setChecked(mJobOptions->deleteExcluded);
485
486 ui.textExclude->setPlainText(mJobOptions->excluded);
487 ui.textExtra->setText(mJobOptions->extra);
488
489 ui.textSource->setText(mJobOptions->source);
490 ui.textDest->setText(mJobOptions->dest);
491 ui.textDescription->setText(mJobOptions->description);
492 // DDBB
493 ui.checkisDriveSharedWithMe->setChecked(mJobOptions->DriveSharedWithMe);
494 }
495
done(int r)496 void TransferDialog::done(int r) {
497 if (r == QDialog::Accepted) {
498 if (mIsDownload) {
499 if (ui.textDest->text().isEmpty()) {
500 QMessageBox::warning(this, "Warning", "Please enter destination!");
501 return;
502 }
503 } else {
504 if (ui.textSource->text().isEmpty()) {
505 QMessageBox::warning(this, "Warning", "Please enter source!");
506 return;
507 }
508 }
509 }
510 QDialog::done(r);
511 }
512