1288 lines
42 KiB
C++
1288 lines
42 KiB
C++
#include "mainwindow.h"
|
|
#include <QComboBox>
|
|
|
|
using namespace std;
|
|
|
|
bool display = false;
|
|
//extern QDialog Configuration;
|
|
extern Ui::Configuration config;
|
|
extern bool testRsyncReturn(QProcess *);
|
|
|
|
QMap<int, QString> rsyncErrorStrings {
|
|
{0, QTranslator::tr("Success. The rsync command completed successfully without any errors.")},
|
|
{1, QTranslator::tr("Syntax or usage error. There was a problem with the syntax of the rsync command or with the options specified.")},
|
|
{2, QTranslator::tr("Protocol incompatibility. There was a problem with the protocol version or negotiation between the rsync client and server.")},
|
|
{3, QTranslator::tr("Errors selecting input/output files, dirs. There was a problem with the source or destination file or directory specified in the rsync command.")},
|
|
{4, QTranslator::tr("Requested action not supported: An attempt was made to use an unsupported action or option.")},
|
|
{5, QTranslator::tr("Error starting client-server protocol. There was an error starting the client-server protocol.")},
|
|
{6, QTranslator::tr("Daemon unable to append to log-file. The rsync daemon was unable to write to its log file.")},
|
|
{10, QTranslator::tr("Error in socket I/O. There was an error with the socket input/output.")},
|
|
{11, QTranslator::tr("Error in file I/O. There was an error reading or writing to a file.")},
|
|
{12, QTranslator::tr("Error in rsync protocol data stream. There was an error in the rsync protocol data stream.")},
|
|
{13, QTranslator::tr("Errors with program diagnostics. There was an error generating program diagnostics.")},
|
|
{14, QTranslator::tr("Error in IPC code. There was an error in the inter-process communication (IPC) code.")},
|
|
{20, QTranslator::tr("Received SIGUSR1 or SIGINT. The rsync process was interrupted by a signal.")},
|
|
{21, QTranslator::tr("Some error returned by waitpid(). An error occurred while waiting for a child process to complete.")},
|
|
{22, QTranslator::tr("Error allocating core memory buffers. There was an error allocating memory buffers.")},
|
|
{23, QTranslator::tr("Partial transfer due to error. The rsync command completed with an error, but some files may have been transferred successfully.")},
|
|
{24, QTranslator::tr("Partial transfer due to vanished source files. Some source files disappeared before they could be transferred.")}
|
|
};
|
|
|
|
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
: QMainWindow(parent)
|
|
, ui(new Ui::MainWindow)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
QCoreApplication::setOrganizationName("RsyncUI");
|
|
QCoreApplication::setApplicationName("RsyncUI");
|
|
|
|
// context menu for treewidget (list of files)
|
|
ui->treeWidget->addAction(ui->actionDownload);
|
|
|
|
// init configuration window
|
|
config.setupUi(&Configuration);
|
|
|
|
// init about window
|
|
AboutW.setupUi(&aboutDialog);
|
|
|
|
//init login dialog
|
|
loginD.setupUi(&loginDialog);
|
|
loginD.loginEdit->setFocus();
|
|
|
|
// text of About
|
|
QString aboutText = tr("<h2>Client for rsync server</h2>") +
|
|
"<b>" + tr("Version") + ": " + this->about.version + "</b><br>" +
|
|
"<b>" + tr("Licence") + ": " + this->about.licence + "</b><br>" +
|
|
"<b>" + tr("Author") + ": " + this->about.author + "</b><br>" +
|
|
"<b>" + tr("EMail") + ": " + this->about.email + "</b><br>" +
|
|
"<b>" + tr("Source code") + ": " + this->about.git + "</b><br>" +
|
|
tr("You click on file to enqueue it, and RyncUI Download one file a time");
|
|
|
|
AboutW.TextAbout->setHtml(aboutText);
|
|
|
|
// connectors
|
|
connect(this, &MainWindow::fileName, ui->progressBar, &QProgressBar::setFormat);
|
|
connect(this, &MainWindow::progressSignal, ui->progressBar, &QProgressBar::setValue);
|
|
connect(this, &MainWindow::stopDownloading, this, &MainWindow::cancelled);
|
|
connect(config.buttonBox, SIGNAL(accepted()), this, SLOT(on_buttonBox_accepted()));
|
|
connect(config.comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::on_comboBox_currentIndexChanged);
|
|
connect(loginD.loginBox, SIGNAL(accepted()), this, SLOT(on_loginBox_accepted()));
|
|
|
|
loadSettings();
|
|
|
|
// init of widgets
|
|
ui->ktreewidgetsearchline->setTreeWidget(ui->treeWidget); // attach search widget to treewidget
|
|
ui->ktreewidgetsearchline->setCaseSensitivity(Qt::CaseInsensitive); // and set it case insensitive
|
|
ui->treeWidget->setHeaderLabels({tr("Path"), tr("Type"), tr("Size"), tr("Date"), "fullSize"} ); // set header of columns of tree widget
|
|
//ui->treeWidget->header()->setContextMenuPolicy();
|
|
// setting arrowcursor for treeWidget, listWidget and listDownload to arrow
|
|
ui->treeWidget->setCursor(Qt::ArrowCursor);
|
|
ui->listWidget->setCursor(Qt::ArrowCursor);
|
|
ui->listDownload->setCursor(Qt::ArrowCursor);
|
|
|
|
// Hiding progress bar
|
|
ui->progressBar->hide();
|
|
|
|
|
|
// if last server exists in settings
|
|
if (this->settings.contains("connexion/lastServer"))
|
|
{
|
|
// set window to precedent server/port configuration
|
|
ui->portEdit->setText(this->settings.value("connexion/port").toString());
|
|
ui->khistorycombobox->setCurrentText(this->settings.value("connexion/lastServer").toString());
|
|
}else
|
|
{
|
|
ui->portEdit->setText(QString::number(this->connexion.port));
|
|
ui->khistorycombobox->clear();
|
|
}
|
|
|
|
//setting configuration window
|
|
config.comboBox->setCurrentIndex(ui->toolBar->toolButtonStyle()); // setting combobox to saved settings
|
|
|
|
//setting unit of bandwidth limit
|
|
config.UnitCombobox->addItems({tr("KB/s"), tr("MB/s"), tr("GB/s"), tr("TB/s"), tr("PB/s")});
|
|
|
|
// hide fullsize column of treeview
|
|
ui->treeWidget->setColumnHidden(4, true);
|
|
|
|
initSystemTrayIcon();
|
|
}
|
|
|
|
void MainWindow::init()
|
|
{
|
|
QAbstractButton * reply;
|
|
QMessageBox msgBox;
|
|
|
|
//if exists list of donwloads in saved settings
|
|
if (this->settings.value("Downloads/rows").toInt() != 0)
|
|
{
|
|
// asking if we load the list and continue downloading
|
|
msgBox.setWindowTitle("RsyncUI");
|
|
msgBox.setInformativeText(tr("A list of interrupted downloads exists, do you want to continue downloading ? if not the list will be cleared" ));
|
|
|
|
QPushButton *yes = msgBox.addButton(QMessageBox::Yes);
|
|
msgBox.addButton(QMessageBox::No);
|
|
msgBox.setDefaultButton(QMessageBox::Yes);
|
|
|
|
msgBox.exec();
|
|
reply = msgBox.clickedButton();
|
|
|
|
// if response is yes then loading list
|
|
if(reply == yes)
|
|
{
|
|
loadDownloadList();
|
|
}
|
|
}
|
|
// load list of services
|
|
populateList();
|
|
}
|
|
|
|
void MainWindow::initSystemTrayIcon()
|
|
{
|
|
QMenu *trayIconMenu;
|
|
QAction * quitAction;
|
|
QIcon icon;
|
|
|
|
icon.addFile(this->icon);
|
|
this->trayIcon = new QSystemTrayIcon;
|
|
this->trayIcon->setIcon(icon);
|
|
|
|
quitAction = new QAction(tr("&Quit"), this);
|
|
connect(quitAction, &QAction::triggered, this, &MainWindow::quitApp);
|
|
|
|
trayIconMenu = new QMenu(this);
|
|
trayIconMenu->addAction(quitAction);
|
|
trayIcon->setContextMenu(trayIconMenu);
|
|
|
|
connect(this->trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(on_trayIcon_clicked(QSystemTrayIcon::ActivationReason)));
|
|
this->trayIcon->show();
|
|
}
|
|
|
|
void MainWindow::on_trayIcon_clicked(QSystemTrayIcon::ActivationReason reason)
|
|
{
|
|
if (reason == QSystemTrayIcon::Trigger)
|
|
{
|
|
if (this->isHidden())
|
|
{
|
|
this->show();
|
|
}else
|
|
{
|
|
this->hide();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::hideWindow()
|
|
{
|
|
this->hide();
|
|
}
|
|
|
|
void MainWindow::showWindow()
|
|
{
|
|
this->show();
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
delete ui;
|
|
QCoreApplication::quit();
|
|
}
|
|
|
|
void MainWindow::quitApp()
|
|
{
|
|
QMessageBox::StandardButton reply;
|
|
QMessageBox::StandardButtons param;
|
|
QString displayText;
|
|
|
|
// saving settings
|
|
saveSettings();
|
|
|
|
if (ui->listDownload->count() != 0) // some downloads waiting
|
|
{
|
|
// Asking for stopping or continuing
|
|
param = QMessageBox::Yes|QMessageBox::No;
|
|
if (config.autosaveCheckbox->checkState() != Qt::Checked)
|
|
{
|
|
param |= QMessageBox::Save;
|
|
displayText = tr("Clicking Save button, You can save the list of downloads\n");
|
|
}
|
|
|
|
reply = QMessageBox::question(
|
|
this,
|
|
"RsyncUI",
|
|
tr("Exiting will stop downloading, and will clear the download queue.\nDo you want to exit ?") + displayText,
|
|
param,
|
|
QMessageBox::No);
|
|
this->downloading.quit = true;
|
|
if(reply == QMessageBox::Yes)
|
|
{
|
|
if (this->downloading.process->state() != QProcess::NotRunning)
|
|
{
|
|
// emission of signal to downloading thread and stopping
|
|
emit (stopDownloading(this->downloading.process));
|
|
}
|
|
}else if (reply == QMessageBox::Save)
|
|
{
|
|
if (config.autosaveCheckbox->checkState() == Qt::Unchecked)
|
|
{
|
|
|
|
//saveDownloadList();
|
|
emit (stopDownloading(this->downloading.process));
|
|
}
|
|
}else if (reply == QMessageBox::No)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
QCoreApplication::quit();
|
|
}
|
|
|
|
// Close window has been clicked
|
|
void MainWindow::closeEvent (QCloseEvent *event)
|
|
{
|
|
QMessageBox msgBox;
|
|
QCheckBox *cb = new QCheckBox("Don't show this again ?");
|
|
|
|
if (!event->spontaneous() || !isVisible())
|
|
return;
|
|
if (trayIcon->isVisible() and this->settings.value("CloseCheckbox").toBool() == false)
|
|
{
|
|
msgBox.setWindowTitle("RsyncUI");
|
|
msgBox.setInformativeText(tr("The program will keep running in the "
|
|
"system tray. To terminate the program, "
|
|
"choose <b>Quit</b> in the context menu "
|
|
"of the system tray entry."));
|
|
|
|
msgBox.addButton(QMessageBox::Ok);
|
|
//msgBox.addButton(QMessageBox::No);
|
|
// msgBox.setDefaultButton(QMessageBox::Yes);
|
|
msgBox.setCheckBox(cb);
|
|
msgBox.exec();
|
|
msgBox.clickedButton();
|
|
|
|
// if response is yes then loading list
|
|
if (cb->isChecked())
|
|
{
|
|
this->settings.setValue("CloseCheckbox", true);
|
|
}
|
|
hide();
|
|
|
|
|
|
//event->accept();
|
|
event->ignore();
|
|
}
|
|
}
|
|
|
|
// Populate treeview with list of files
|
|
void MainWindow::populateTree()
|
|
{
|
|
QString path;
|
|
|
|
// Clear treewidget
|
|
ui->treeWidget->clear();
|
|
if (!this->connexion.server.isEmpty() and this->connexion.port > 0 and this->connexion.port < 65536)
|
|
{
|
|
// setting cursor to "Wait"
|
|
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
|
|
|
|
// validating server's address
|
|
if (validateServer(this->connexion.server))
|
|
{
|
|
// server is validated, scanning directory
|
|
path = this->connexion.service + "/";
|
|
scanDir(this->connexion.server, this->connexion.port, nullptr, path);
|
|
}
|
|
// Restoring cursor
|
|
QGuiApplication::restoreOverrideCursor();
|
|
}
|
|
}
|
|
|
|
// Populate Listview with list of services
|
|
void MainWindow::populateList()
|
|
{
|
|
QString server;
|
|
QStringList hidden;
|
|
int port;
|
|
int i;
|
|
|
|
server = ui->khistorycombobox->currentText();
|
|
port = ui->portEdit->text().toUInt();
|
|
if ((server != this->connexion.server) or (port != this->connexion.port))
|
|
{
|
|
// clearing listwidget
|
|
ui->listWidget->clear();
|
|
|
|
this->connexion.server = server;
|
|
this->connexion.port = port;
|
|
|
|
// setting cursor to "Wait"
|
|
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
|
|
|
|
// verify if server is in history
|
|
this->settings.beginGroup("connexion/server");
|
|
if (this->settings.contains(server) and this->connexion.comboboxChanged)
|
|
{
|
|
// server is in history => setting port value
|
|
port = this->settings.value(server).toUInt();
|
|
ui->portEdit->setText(QString::number(port));
|
|
this->connexion.port = port;
|
|
|
|
//display list of services
|
|
listServices();
|
|
}else
|
|
{
|
|
if (!server.isEmpty() and (port > 0 and port < 65536))
|
|
{
|
|
if (validateServer(server))
|
|
{
|
|
cout << server.toStdString() << endl;
|
|
|
|
// storing serverURL and port in settings
|
|
this->settings.setValue(server, port);
|
|
this->settings.sync();
|
|
this->downloading.server = server;
|
|
|
|
// storing in history of combobox
|
|
ui->khistorycombobox->addToHistory(server);
|
|
|
|
// load and display rsync services of the rsync server
|
|
listServices();
|
|
}
|
|
}
|
|
}
|
|
this->settings.endGroup();
|
|
this->settings.beginGroup("Hidden/");
|
|
hidden = this->settings.allKeys();
|
|
for (i = 0; i < hidden.size(); i++)
|
|
{
|
|
//TODO detect if service is already present
|
|
ui->listWidget->addItem(this->settings.value(hidden.at(i)).toString() + "\n\t");
|
|
}
|
|
QGuiApplication::restoreOverrideCursor(); //setting cursor to default
|
|
this->settings.endGroup();
|
|
}
|
|
}
|
|
|
|
//list services of the rsync server
|
|
void MainWindow::listServices()
|
|
{
|
|
QString cmd;
|
|
QStringList param;
|
|
QString line;
|
|
QString errorRsync;
|
|
QStringList v;
|
|
QString service;
|
|
QProcess *myProcess;
|
|
bool flag = false;
|
|
|
|
cmd = "/usr/bin/rsync";
|
|
param << "--contimeout=20" << "--port=" + QString::number(this->connexion.port) << this->connexion.server + "::";
|
|
myProcess = new QProcess(this);
|
|
myProcess->start(cmd, param);
|
|
|
|
// waiting for response of the server with a timeout of 10 seconds
|
|
while(myProcess->waitForReadyRead(10000))
|
|
{
|
|
while(!flag)
|
|
{
|
|
line = QString::fromUtf8(myProcess->readLine());
|
|
// line empty then buffer is empty so returning to wait new datas
|
|
if (line.isEmpty())
|
|
{
|
|
flag = true;
|
|
break;
|
|
}
|
|
// extracting name and comment of the service
|
|
v = line.split("\t");
|
|
v[0].replace(" ", "");
|
|
v[1].replace("\n", "");
|
|
service = v[0] + "\n\t" + v[1];
|
|
|
|
// adding to list of services
|
|
ui->listWidget->addItem(service);
|
|
}
|
|
// buffer empty go to waiting new datas
|
|
flag =false;
|
|
}
|
|
|
|
// verifying error code
|
|
testRsyncReturn(this, myProcess);
|
|
myProcess->close();
|
|
}
|
|
|
|
// connect to rsync server to get list of files
|
|
bool MainWindow::scanDir(QString server, int portN, QTreeWidgetItem *parent, QString path)
|
|
{
|
|
QString cmd;
|
|
QStringList param;
|
|
QStringList sizeA;
|
|
QString line;
|
|
QString size;
|
|
QString fullsize;
|
|
QString filename;
|
|
QString fileType;
|
|
QString date;
|
|
QProcess * myProcess;
|
|
bool isDir = false;
|
|
bool flag = false;
|
|
bool readOk = false;
|
|
int nChild = 0;
|
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
|
|
|
myProcess = new QProcess(this);
|
|
|
|
if (parent != nullptr)
|
|
{
|
|
nChild = parent->childCount();
|
|
}
|
|
if (nChild == 0)
|
|
{
|
|
if (!this->connexion.user.isEmpty())
|
|
{
|
|
server.prepend(this->connexion.user + "@");
|
|
env.insert("RSYNC_PASSWORD", this->connexion.password); // Add an environment variable
|
|
}else
|
|
{
|
|
server.prepend("anonymous@");
|
|
env.insert("RSYNC_PASSWORD", "anonymous"); // Add an environment variable
|
|
}
|
|
myProcess->setProcessEnvironment(env);
|
|
cmd = "rsync";
|
|
param << "--contimeout=20" << "--port=" + QString::number(portN) << server + "::" + path;
|
|
|
|
|
|
myProcess->start(cmd, param);
|
|
|
|
// waiting for response of the server with a timeout of 10 seconds
|
|
do
|
|
{
|
|
readOk = myProcess->waitForReadyRead(10000);
|
|
if (readOk)
|
|
{
|
|
while (!flag)
|
|
{
|
|
line = QString::fromUtf8(myProcess->readLine());
|
|
// line empty then buffer is empty so returning to wait new datas
|
|
if (line.isEmpty())
|
|
{
|
|
flag = true;
|
|
break;
|
|
}
|
|
// extracting name, size and if is dir/file
|
|
line = line.simplified();
|
|
filename = line.section(" ", 4);
|
|
if (filename != '.')
|
|
{
|
|
|
|
size = line.section(" ", 1, 1);
|
|
fullsize = size;
|
|
fullsize.remove(",");
|
|
sizeA = size.split(',');
|
|
if (sizeA.count() <= 1)
|
|
{
|
|
size = sizeA.at(0) + " " + UnitText[0] + " ";
|
|
}else
|
|
{
|
|
size = sizeA.at(0) + "," + sizeA.at(1).left(2) + " " + UnitText[sizeA.count()-1] + " ";
|
|
}
|
|
|
|
if (line[0] == "d")
|
|
{
|
|
isDir = true;
|
|
}else
|
|
{
|
|
isDir = false;
|
|
}
|
|
date = line.section(' ', 2, 2);
|
|
fileType = getFileType(filename);
|
|
addTreeItem(filename, size, fullsize, fileType, date, isDir, parent);
|
|
}
|
|
}
|
|
flag = false;
|
|
}else
|
|
{
|
|
if (myProcess->state() == QProcess::Running)
|
|
{
|
|
if (myProcess->waitForFinished(10000) == 0)
|
|
{
|
|
QMessageBox::warning(
|
|
this,
|
|
"RsyncUI",
|
|
tr("The processus does'nt respond: ") + myProcess->errorString());
|
|
}
|
|
}
|
|
}
|
|
}while(readOk);
|
|
// buffer empty go to waiting new datas
|
|
|
|
testRsyncReturn(this, myProcess);
|
|
myProcess->close();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Verify if server address is IP address
|
|
bool MainWindow::isIpAddress(QString server)
|
|
{
|
|
QStringList r;
|
|
int elementN;
|
|
bool ok;
|
|
|
|
r = server.split('.');
|
|
if (r.size() == 4)
|
|
{
|
|
for (auto element : r)
|
|
{
|
|
elementN = element.toInt(&ok);
|
|
if (elementN < 0 or elementN > 255 or ok == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// validate address server
|
|
bool MainWindow::validateServer(QString server)
|
|
{
|
|
QString cmd;
|
|
QStringList param;
|
|
QString line;
|
|
QProcess * myProcess;
|
|
bool flag = false;
|
|
bool bflag = false;
|
|
|
|
cmd = "dig";
|
|
param << server;
|
|
|
|
myProcess = new QProcess(this);
|
|
myProcess->start(cmd, param);
|
|
|
|
// maiking a dig on the server's address
|
|
while(myProcess->waitForReadyRead())
|
|
{
|
|
while (!bflag)
|
|
{
|
|
line = QString::fromUtf8(myProcess->readAllStandardOutput());
|
|
// line empty then buffer is empty so returning to wait new datas
|
|
if (line.isEmpty())
|
|
{
|
|
bflag = true;
|
|
break;
|
|
}else if (line.indexOf(";; ANSWER SECTION:") != -1)
|
|
{
|
|
flag = true;
|
|
}
|
|
}
|
|
bflag = false;
|
|
}
|
|
|
|
//testRsyncReturn(myProcess);
|
|
|
|
if ( flag == false)
|
|
{
|
|
//server's address is not valid testing if ip address is valid
|
|
flag = isIpAddress(server);
|
|
}
|
|
if ( flag == false)
|
|
{
|
|
// server-s address not valid
|
|
QMessageBox::warning(
|
|
this,
|
|
"RsyncUI",
|
|
tr("server does not exists" )
|
|
);
|
|
}
|
|
myProcess->close();
|
|
return flag;
|
|
}
|
|
|
|
// slot activated when combobox is changed
|
|
void MainWindow::on_khistorycombobox_currentIndexChanged(int i)
|
|
{
|
|
this->connexion.comboboxChanged = true;
|
|
populateList();
|
|
}
|
|
|
|
// slot activated when button connection is clicked
|
|
void MainWindow::on_connectButton_clicked()
|
|
{
|
|
populateList();
|
|
}
|
|
|
|
// add parent in treeview
|
|
void MainWindow::addTreeItem(QString name, QString fileSize, QString fullsize, QString type, QString date, bool isDir=false, QTreeWidgetItem *parent=nullptr)
|
|
{
|
|
QTreeWidgetItem *treeItem;
|
|
if (parent != nullptr)
|
|
{
|
|
treeItem = new QTreeWidgetItem();
|
|
}else
|
|
{
|
|
treeItem = new QTreeWidgetItem(ui->treeWidget);
|
|
}
|
|
if (isDir == true)
|
|
{
|
|
// item is a dir
|
|
treeItem->setText(1, tr("Dir"));
|
|
treeItem->setIcon(0, QIcon::fromTheme("folder"));
|
|
}else
|
|
{
|
|
// item is a file
|
|
treeItem->setText(1,type);
|
|
}
|
|
treeItem->setText(0, name);
|
|
treeItem->setText(2, fileSize);
|
|
treeItem->setText(3, date);
|
|
treeItem->setText(4, fullsize);
|
|
|
|
treeItem->setTextAlignment(2, Qt::AlignRight);
|
|
|
|
if (parent != nullptr)
|
|
{
|
|
// QTreeWidgetItem::addChild(QTreeWidgetItem * child)
|
|
parent->addChild(treeItem);
|
|
}
|
|
}
|
|
|
|
// Slot activated when a service in the list is clicked
|
|
void MainWindow::on_listWidget_clicked()
|
|
{
|
|
this->connexion.service = ui->listWidget->currentItem()->text().section("\n", 0 ,0);
|
|
preparePopulateTree();
|
|
}
|
|
|
|
void MainWindow::preparePopulateTree()
|
|
{
|
|
QString str;
|
|
QStringList logins;
|
|
|
|
this->rescan = true;
|
|
this->connexion.user = nullptr;
|
|
this->connexion.password = nullptr;
|
|
str = "Folder/" + this->connexion.server + "/" + this->connexion.service;
|
|
// if service exists in settings for this server
|
|
if (this->settings.contains(str))
|
|
{
|
|
// setting savePath from settings
|
|
this->downloading.savePath = this->settings.value(str).toString();
|
|
}
|
|
|
|
getUserPassword(false);
|
|
//this->settings.beginGroup("Passwords/" + this->connexion.server + "/" + this->connexion.service);
|
|
//logins = this->settings.allKeys();
|
|
//if (logins.count() != 0)
|
|
//{
|
|
// this->connexion.user = logins[0];
|
|
// this->connexion.password = this->settings.value(logins[0]).toString();
|
|
//}
|
|
this->settings.endGroup();
|
|
populateTree();
|
|
}
|
|
|
|
// get password and user login
|
|
// if object = false ==> searching from connexion object
|
|
// else searching from downloading object
|
|
bool MainWindow::getUserPassword(bool object = false)
|
|
{
|
|
QStringList logins;
|
|
QString login;
|
|
bool returnValue;
|
|
bool ok = false;
|
|
|
|
if (object == false)
|
|
{
|
|
this->settings.beginGroup("Passwords/" + this->connexion.server + "/" + this->connexion.service);
|
|
}else
|
|
{
|
|
this->settings.beginGroup("Passwords/" + this->downloading.server + "/" + this->downloading.service);
|
|
}
|
|
logins = this->settings.allKeys();
|
|
|
|
//TODO choose login in case of multiples logins
|
|
if (logins.count() != 0)
|
|
{
|
|
login = QInputDialog::getItem(this,
|
|
"RsincUI",
|
|
tr("There is many users for this service.\nSelect user you want to connect with."),
|
|
logins,
|
|
0,
|
|
true,
|
|
&ok,
|
|
Qt::Popup,
|
|
Qt::ImhNoPredictiveText
|
|
);
|
|
if (object == false)
|
|
{
|
|
this->connexion.user = logins[0];
|
|
this->connexion.password = this->settings.value(logins[0]).toString();
|
|
}else
|
|
{
|
|
this->downloading.user = logins[0];
|
|
this->downloading.password = this->settings.value(logins[0]).toString();
|
|
}
|
|
returnValue = true;
|
|
}else
|
|
{
|
|
this->downloading.user = nullptr;
|
|
this->downloading.password = nullptr;
|
|
returnValue = false;
|
|
}
|
|
this->settings.endGroup();
|
|
return returnValue;
|
|
}
|
|
|
|
//Slot activated when a file is clicked in the treeview
|
|
void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadDir)
|
|
{
|
|
QFuture<void> future;
|
|
QFileDialog dialog;
|
|
QTreeWidgetItem * itemR;
|
|
QString path;
|
|
QString str;
|
|
QMessageBox::StandardButton reply;
|
|
int sizeFromRsync;
|
|
|
|
itemR = item;
|
|
|
|
// assembling path from treewidget
|
|
path = item->text(0);
|
|
sizeFromRsync = item->text(4).toUInt();
|
|
|
|
while(itemR->parent() != NULL)
|
|
{
|
|
itemR = itemR->parent();
|
|
// concatening parent to path
|
|
path.prepend(itemR->text(0) + "/");
|
|
};
|
|
|
|
cout << item->text(1).toStdString() <<endl;
|
|
if (item->text(1) != tr("Dir") or downloadDir == true)
|
|
{
|
|
// exists saving path in settings ?
|
|
str = "Folder/" + this->connexion.server + "/" + this->connexion.service;
|
|
if(!this->settings.contains(str))
|
|
{
|
|
// saving path do not exists, asking for it
|
|
if(!on_DefaultSaveFolder_triggered())
|
|
{
|
|
cout << "no directory selectioned, ignoring download request";
|
|
return;
|
|
}
|
|
}else
|
|
{
|
|
this->downloading.savePath = this->settings.value(str).toString();
|
|
}
|
|
|
|
// Item is a file
|
|
// searching if file exists in savepath
|
|
if (QFile::exists(this->downloading.savePath + "/" + path))
|
|
{
|
|
|
|
QFileInfo info(this->downloading.savePath + "/" + path);
|
|
if (info.size() < sizeFromRsync)
|
|
{
|
|
reply = QMessageBox::question(
|
|
this,
|
|
"RsyncUI",
|
|
tr("File is partially downloaded. Do you want to resume download ? if no, the file will be deleted from destination directory"),
|
|
QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,
|
|
QMessageBox::Cancel);
|
|
|
|
if (reply == QMessageBox::Cancel)
|
|
{
|
|
return;
|
|
}else if(reply == QMessageBox::No)
|
|
{
|
|
QFile::remove(this->downloading.savePath + "/" + path);
|
|
return;
|
|
}
|
|
}else
|
|
{
|
|
reply = QMessageBox::question(
|
|
this,
|
|
"RsyncUI",
|
|
tr("File is already downloaded. Do you want to reload it ? The old file will be deleted"),
|
|
QMessageBox::Yes|QMessageBox::No,
|
|
QMessageBox::No);
|
|
|
|
if (reply == QMessageBox::No)
|
|
{
|
|
return;
|
|
}else
|
|
{
|
|
QFile::remove(this->downloading.savePath + "/" + path);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ui->listDownload->findItems(path, Qt::MatchStartsWith).empty())
|
|
{
|
|
// is there a downloading process ?
|
|
if (this->downloading.process == nullptr)
|
|
{
|
|
// no downloading process launching it
|
|
this->downloading.path = path;
|
|
this->downloading.server = this->connexion.server;
|
|
this->downloading.port = this->connexion.port;
|
|
this->downloading.service = this->connexion.service;
|
|
startDownloading();
|
|
// wait 1 second to process start
|
|
//sleep(1);
|
|
}
|
|
|
|
// Adding download in download list
|
|
str = path + " => " + this->connexion.server + "/" + this->connexion.service;
|
|
ui->listDownload->addItem(str);
|
|
}else
|
|
{
|
|
QMessageBox::warning(
|
|
this,
|
|
"RsyncUI",
|
|
tr("File is already downloading" )
|
|
);
|
|
}
|
|
}else
|
|
{
|
|
//Item is a Directory
|
|
scanDir(this->connexion.server, this->connexion.port, item, this->connexion.service + "/" + path +"/");
|
|
item->setExpanded(true);
|
|
}
|
|
if (config.autosaveCheckbox->checkState() == Qt::Checked)
|
|
{
|
|
saveDownloadList();
|
|
}
|
|
}
|
|
|
|
// Launch the thread which download the file
|
|
void MainWindow::startDownloading()
|
|
{
|
|
|
|
ui->progressBar->setValue(0);
|
|
ui->progressBar->show();
|
|
getUserPassword(false);
|
|
|
|
//QtConcurrent::run(&this->downloadO, &downloadFile::download, this);
|
|
this->download();
|
|
this->trayIcon->showMessage("RsyncUI", tr("Starting downloading\n") + this->downloading.path, QSystemTrayIcon::Information);
|
|
}
|
|
|
|
// Slot stopping download
|
|
void MainWindow::stoppingDownload()
|
|
{
|
|
emit (stopDownloading(this->downloading.process));
|
|
}
|
|
|
|
// when download is finished, launch download of next file in queue
|
|
void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
|
{
|
|
QString path;
|
|
QString str;
|
|
int pos;
|
|
QString aborted = tr("finished");
|
|
QMessageBox::StandardButton reply;
|
|
bool retry = false;
|
|
|
|
// test if process crashed
|
|
if (exitStatus == QProcess::CrashExit)
|
|
{
|
|
QMessageBox::warning(
|
|
NULL,
|
|
"RsyncUI",
|
|
tr("Rsync process crashed"));
|
|
}
|
|
//test result code of command (if 20 then command stopped by user)
|
|
if (exitCode != 0)
|
|
{
|
|
if (exitCode == 20)
|
|
{
|
|
aborted = tr("stopped by user");
|
|
}else if (exitCode == 5) // password asked
|
|
{
|
|
loginDialog.show();
|
|
retry = true;
|
|
}
|
|
|
|
// displaying warning with exit code
|
|
reply = QMessageBox::warning(
|
|
this,
|
|
"RsyncUI",
|
|
rsyncErrorStrings[exitCode] + tr("\nDo you want to retry?"),
|
|
QMessageBox::Yes|QMessageBox::No,
|
|
QMessageBox::Yes);
|
|
if (reply == QMessageBox::Yes)
|
|
{
|
|
retry = true;
|
|
}
|
|
}
|
|
|
|
this->trayIcon->showMessage("RsyncUI", tr("Download ") + aborted + "\n" + this->downloading.path, QSystemTrayIcon::Information);
|
|
|
|
// disconnecting signals to slots
|
|
disconnect(this->downloading.process, 0, 0, 0);
|
|
|
|
// reset variables and window
|
|
this->downloading.process->close();
|
|
ui->progressBar->hide();
|
|
|
|
if (retry == false)
|
|
{
|
|
delete ui->listDownload->takeItem(0);
|
|
}
|
|
this->downloading.clear();
|
|
|
|
// Some downloads staying in queue
|
|
if (ui->listDownload->count() != 0)
|
|
{
|
|
// initializing download
|
|
path = ui->listDownload->item(0)->text();
|
|
pos = path.lastIndexOf("/");
|
|
this->downloading.service = path.midRef(pos+1).toString();
|
|
path.resize(pos);
|
|
pos = path.lastIndexOf(" => ");
|
|
this->downloading.server = path.midRef(pos+4).toString();
|
|
path.resize(pos);
|
|
this->downloading.path = path;
|
|
getUserPassword(true);
|
|
|
|
// savepath exists in settings ?
|
|
str = "Folder/" + this->downloading.server + "/" + this->downloading.service;
|
|
if (this->settings.contains(str))
|
|
{
|
|
// setting savepath from saved settings
|
|
this->downloading.savePath = this->settings.value(str).toString();
|
|
startDownloading();
|
|
}else
|
|
{
|
|
// no save path
|
|
if(!on_DefaultSaveFolder_triggered())
|
|
{
|
|
cout << "Error no save path so deleting download";
|
|
//downloadFinished();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if(config.autosaveCheckbox->checkState() == Qt::Checked and this->downloading.quit == false)
|
|
{
|
|
saveDownloadList();
|
|
}
|
|
}
|
|
|
|
|
|
// Slot activated when a line is clicked in queue list
|
|
void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item)
|
|
{
|
|
QMessageBox::StandardButton reply;
|
|
|
|
if (item->listWidget()->row(item) == 0)
|
|
{
|
|
// first line clicked on download list
|
|
reply = QMessageBox::question(
|
|
this,
|
|
"RsyncUI",
|
|
tr("Do you want to stop downloading and delete this file from download queue ?"),
|
|
QMessageBox::Yes|QMessageBox::No,
|
|
QMessageBox::No);
|
|
if (reply == QMessageBox::Yes)
|
|
{
|
|
// stopping download
|
|
emit (stopDownloading(this->downloading.process));
|
|
}
|
|
}else
|
|
{
|
|
// not first line on download list
|
|
reply = QMessageBox::question(
|
|
this,
|
|
"RsyncUI",
|
|
tr("Do you want to delete this file from download queue ?"),
|
|
QMessageBox::Yes|QMessageBox::No,
|
|
QMessageBox::No);
|
|
if (reply == QMessageBox::Yes)
|
|
{
|
|
// removing line from download list
|
|
ui->listDownload->removeItemWidget(item);
|
|
delete item;
|
|
|
|
}
|
|
}
|
|
if (config.autosaveCheckbox->checkState() == Qt::Checked)
|
|
{
|
|
// autosave acivated,so saving download list
|
|
saveDownloadList();
|
|
}
|
|
}
|
|
|
|
// load settings
|
|
void MainWindow::loadSettings()
|
|
{
|
|
// restoring geometry and state of window and widgets
|
|
this->restoreGeometry(this->settings.value("window/geometry").toByteArray());
|
|
this->restoreState(this->settings.value("window/state").toByteArray());
|
|
ui->treeWidget->header()->restoreState(this->settings.value("treeWidget/state").toByteArray());
|
|
ui->splitter->restoreState(this->settings.value("splitter/state").toByteArray());
|
|
ui->splitter_2->restoreState(this->settings.value("splitter2/state").toByteArray());
|
|
ui->toolBar->setToolButtonStyle((Qt::ToolButtonStyle)this->settings.value("toolbar/state").toInt());
|
|
if (this->settings.value("Autosave").toInt() == Qt::Checked)
|
|
{
|
|
this->config.autosaveCheckbox->setChecked(true);
|
|
}
|
|
// loading connexion settings
|
|
// loading servers history
|
|
this->settings.beginGroup("connexion/server");
|
|
QStringList servers = this->settings.allKeys();
|
|
this->settings.endGroup();
|
|
for( const QString &server : servers )
|
|
{
|
|
ui->khistorycombobox->addToHistory(server);
|
|
}
|
|
|
|
// loading save path
|
|
this->downloading.savePath = this->settings.value("Folder").toString();
|
|
|
|
// loading bandwidth limit
|
|
this->connexion.bandwidthLimit = this->settings.value("bandwidthlimit").toUInt();
|
|
this->connexion.bandwidthLimitUnit = this->settings.value("bandwidthlimitunit").toInt();
|
|
}
|
|
|
|
// save settings
|
|
void MainWindow::saveSettings()
|
|
{
|
|
this->settings.setValue("window/geometry", saveGeometry());
|
|
this->settings.setValue("window/state", saveState());
|
|
this->settings.setValue("treeWidget/state", ui->treeWidget->header()->saveState());
|
|
this->settings.setValue("splitter/state", ui->splitter->saveState());
|
|
this->settings.setValue("splitter2/state", ui->splitter_2->saveState());
|
|
this->settings.setValue("connexion/lastServer", this->connexion.server);
|
|
this->settings.setValue("connexion/lastPort", QString::number(this->connexion.port));
|
|
this->settings.setValue("toolbar/state", ui->toolBar->toolButtonStyle());
|
|
this->settings.setValue("Autosave", this->config.autosaveCheckbox->checkState());
|
|
this->settings.sync();
|
|
}
|
|
|
|
// About
|
|
void MainWindow::on_actionAbout_triggered()
|
|
{
|
|
aboutDialog.show();
|
|
}
|
|
|
|
// About QT
|
|
void MainWindow::on_actionAbout_Qt_triggered()
|
|
{
|
|
QMessageBox::aboutQt(this);
|
|
}
|
|
|
|
// Activated when menu "change folder" is clicked
|
|
bool MainWindow::on_DefaultSaveFolder_triggered()
|
|
{
|
|
QFileDialog dialog;
|
|
QString folder;
|
|
QString path;
|
|
|
|
// if service not selected display a message
|
|
if (this->connexion.service.isEmpty())
|
|
{
|
|
QMessageBox::warning(
|
|
NULL,
|
|
"RsyncUI",
|
|
tr("Since the save path is linked to service, you need to select a service before you can select a folder"));
|
|
return false;
|
|
}
|
|
|
|
// Asking for directory to save files
|
|
path = dialog.getExistingDirectory(this, tr("Choose folder where to save file"), QDir::homePath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
|
if (!path.isEmpty())
|
|
{
|
|
this->downloading.savePath = path;
|
|
if (!this->connexion.service.isEmpty() and !this->connexion.server.isEmpty())
|
|
{
|
|
// saving save path in settings
|
|
folder = "Folder/" + this->connexion.server + "/" + this->connexion.service;
|
|
this->settings.setValue(folder, this->downloading.savePath);
|
|
this->settings.sync();
|
|
}
|
|
}else
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Activated when menu "settings" is clicked
|
|
void MainWindow::on_action_Settings_triggered()
|
|
{
|
|
config.UnitCombobox->setCurrentIndex(this->connexion.bandwidthLimitUnit);
|
|
config.spinBox->setValue(this->connexion.bandwidthLimit);
|
|
Configuration.show();
|
|
}
|
|
|
|
// Acivated when "Ok" is clicked in Configuration window
|
|
void MainWindow::on_buttonBox_accepted()
|
|
{
|
|
QString unit;
|
|
QString bw;
|
|
|
|
bw = config.spinBox->text();
|
|
if (bw.toInt() == 0)
|
|
{
|
|
// bandwidth = 0
|
|
this->connexion.bandwidthLimit = 0;
|
|
this->connexion.bandwidthLimitUnit = 0;
|
|
}else
|
|
{
|
|
this->connexion.bandwidthLimit = config.spinBox->value();
|
|
this->connexion.bandwidthLimitUnit = config.UnitCombobox->currentIndex();
|
|
}
|
|
this->settings.setValue("bandwidthlimit", this->connexion.bandwidthLimit);
|
|
this->settings.setValue("bandwidthlimitunit", this->connexion.bandwidthLimitUnit);
|
|
|
|
this->settings.setValue("Autosave", this->config.autosaveCheckbox->checkState());
|
|
|
|
this->settings.sync();
|
|
Configuration.hide();
|
|
}
|
|
|
|
// Saving download list
|
|
void MainWindow::saveDownloadList()
|
|
{
|
|
int nRows;
|
|
|
|
// remove list of downloads
|
|
this->settings.remove("Downloads/");
|
|
|
|
// Saving list of current downloads
|
|
nRows = ui->listDownload->count();
|
|
this->settings.beginGroup("Downloads");
|
|
this->settings.setValue("rows", nRows);
|
|
for (int i = 0; i < nRows; i++)
|
|
{
|
|
this->settings.setValue(QString::number(i), ui->listDownload->item(i)->text());
|
|
}
|
|
this->settings.endGroup();
|
|
this->settings.sync();
|
|
}
|
|
|
|
// Loading download list
|
|
void MainWindow::loadDownloadList()
|
|
{
|
|
QString path;
|
|
QString str;
|
|
int pos;
|
|
|
|
this->settings.sync();
|
|
this->settings.beginGroup("Downloads");
|
|
int size = this->settings.value("rows").toInt();
|
|
for (int i = 0; i < size; ++i)
|
|
{
|
|
ui->listDownload->addItem(this->settings.value(QString::number(i)).toString());
|
|
}
|
|
this->settings.endGroup();
|
|
|
|
path = ui->listDownload->item(0)->text();
|
|
pos = path.lastIndexOf("/");
|
|
this->downloading.service = path.midRef(pos+1).toString();
|
|
path.resize(pos);
|
|
pos = path.lastIndexOf(" => ");
|
|
this->downloading.server = path.midRef(pos+4).toString();
|
|
this->downloading.port = this->settings.value("connexion/server/" + this->downloading.server).toInt();
|
|
path.resize(pos);
|
|
this->downloading.path = path;
|
|
str = "Folder/" + this->downloading.server + "/" + this->downloading.service;
|
|
if (this->settings.contains(str))
|
|
{
|
|
this->downloading.savePath = this->settings.value(str).toString();
|
|
}
|
|
startDownloading();
|
|
}
|
|
|
|
// clear object downloading
|
|
void Downloading::clear()
|
|
{
|
|
this->path.clear();
|
|
this->server.clear();
|
|
this->savePath.clear();
|
|
this->service.clear();
|
|
this->user.clear();
|
|
this->password.clear();
|
|
this->port = 0;
|
|
this->process = nullptr;
|
|
this->quit = false;
|
|
}
|
|
|
|
// Context menu of file list clicked
|
|
void MainWindow::on_actionDownload_triggered()
|
|
{
|
|
// action made in qt-designer and added in init function.
|
|
QTreeWidgetItem *item;
|
|
item = ui->treeWidget->currentItem();
|
|
on_treeWidget_itemClicked(item, true);
|
|
}
|
|
|
|
/*void MainWindow::downloadingErrorSlot(QString errorString)
|
|
{
|
|
QMessageBox::warning(
|
|
this,
|
|
"RsyncUI",
|
|
errorString,
|
|
QMessageBox::Ok,
|
|
QMessageBox::Ok);
|
|
}
|
|
*/
|
|
|
|
// Change toolbar style
|
|
void MainWindow::on_comboBox_currentIndexChanged(int index)
|
|
{
|
|
ui->toolBar->setToolButtonStyle((Qt::ToolButtonStyle)index);
|
|
}
|
|
|
|
void MainWindow::on_actionExit_triggered()
|
|
{
|
|
quitApp();
|
|
}
|
|
|
|
void MainWindow::on_loginBox_accepted()
|
|
{
|
|
if (!loginD.loginEdit->text().isEmpty())
|
|
{
|
|
this->connexion.user = loginD.loginEdit->text();
|
|
if (!loginD.passwordEdit->text().isEmpty())
|
|
{
|
|
this->connexion.password = loginD.passwordEdit->text();
|
|
this->settings.setValue("Passwords/" + this->connexion.server + "/" + this->connexion.service + "/" + this->connexion.user, this->connexion.password);
|
|
this->settings.sync();
|
|
if (this->rescan == true)
|
|
{
|
|
this->rescan = false;
|
|
populateTree();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::setDlSpeed(QString speed)
|
|
{
|
|
speed.squeeze();
|
|
}
|
|
|
|
void MainWindow::on_actionHiddenService_triggered()
|
|
{
|
|
QInputDialog hiddenFolderDialog;
|
|
|
|
bool ok;
|
|
QString text = QInputDialog::getText(this, tr("RsyncUI Request"),
|
|
tr("Hidden service name"), QLineEdit::Normal,
|
|
"test", &ok);
|
|
if (ok && !text.isEmpty())
|
|
{
|
|
this->connexion.service = text;
|
|
this->settings.setValue("Hidden/" + this->connexion.server, text);
|
|
preparePopulateTree();
|
|
}
|
|
}
|