From 9671a5cea88dc3e8c740348a973438787ffb98e5 Mon Sep 17 00:00:00 2001 From: Daniel Tartavel Date: Fri, 10 Feb 2023 23:27:44 +0100 Subject: [PATCH] completely migrate to QT and some bugs corrected --- RsyncUI.desktop | 2 +- RsyncUI.pro.user | 2 +- downloadfile.cpp | 1 + main.cpp | 1 + mainwindow.cpp | 154 +++++++++++++++++++++++++++++++++-------------- tools.cpp | 1 + 6 files changed, 113 insertions(+), 48 deletions(-) diff --git a/RsyncUI.desktop b/RsyncUI.desktop index 2ad07f2..db983d1 100644 --- a/RsyncUI.desktop +++ b/RsyncUI.desktop @@ -6,7 +6,7 @@ Comment=Client for rsync servers Comment[fr]=Client pour serveur rsync Version=1.0 Exec=RsyncUI -Icon= +Icon=/usr/share/icons/RsyncUI.png Type=Application Terminal=false StartupNotify=true diff --git a/RsyncUI.pro.user b/RsyncUI.pro.user index 4c521a3..7d89b0c 100644 --- a/RsyncUI.pro.user +++ b/RsyncUI.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/downloadfile.cpp b/downloadfile.cpp index 8464ee2..e8edec5 100644 --- a/downloadfile.cpp +++ b/downloadfile.cpp @@ -96,6 +96,7 @@ void MainWindow::readRsyncOutput() ); }*/ +// process raise error void MainWindow::downloadProcessStderr() { QByteArray errorLine; diff --git a/main.cpp b/main.cpp index ca39f1d..3b8944c 100644 --- a/main.cpp +++ b/main.cpp @@ -9,6 +9,7 @@ int main(int argc, char *argv[]) QCoreApplication::setOrganizationName("RsyncUI"); QCoreApplication::setApplicationName("RsyncUI"); + // Initialization of localization QLocale localeName = QLocale::system(); QString localeFile = "/usr/share/locale/" + localeName.name() + "/LC_MESSAGES/RsyncUI_" + localeName.name() + ".qm"; diff --git a/mainwindow.cpp b/mainwindow.cpp index 1558e85..d5e67cf 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -40,10 +40,10 @@ MainWindow::MainWindow(QWidget *parent) QCoreApplication::setOrganizationName("RsyncUI"); QCoreApplication::setApplicationName("RsyncUI"); - // context menu for treewidget + // context menu for treewidget (list of files) ui->treeWidget->addAction(ui->actionDownload); - // init shortcut + // init configuration window config.setupUi(&Configuration); // init of About @@ -57,12 +57,14 @@ MainWindow::MainWindow(QWidget *parent) connect(config.comboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::on_comboBox_currentIndexChanged); // init of widgets - ui->ktreewidgetsearchline->setTreeWidget(ui->treeWidget); - ui->ktreewidgetsearchline->setCaseSensitivity(Qt::CaseInsensitive); - ui->treeWidget->setHeaderLabels({tr("Path"), tr("Type"), tr("Size")} ); + 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")} ); // set header of columns of tree widget + // 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 @@ -71,7 +73,7 @@ MainWindow::MainWindow(QWidget *parent) ui->khistorycombobox->clear(); } - // setting arrowcursor for treeWidget, listWidget and listDownload + // setting arrowcursor for treeWidget, listWidget and listDownload to arrow ui->treeWidget->setCursor(Qt::ArrowCursor); ui->listWidget->setCursor(Qt::ArrowCursor); ui->listDownload->setCursor(Qt::ArrowCursor); @@ -82,28 +84,32 @@ MainWindow::MainWindow(QWidget *parent) loadSettings(); //setting configuration window - config.comboBox->setCurrentIndex(ui->toolBar->toolButtonStyle()); + config.comboBox->setCurrentIndex(ui->toolBar->toolButtonStyle()); // setting combobox to saved settings + + //setting unit of bandwidth limit config.UnitCombobox->addItems({tr("KB"), tr("MB"), tr("GB"), tr("TB"), tr("PB")}); + //if exists list of donwloads in saved settings if (this->settings.value("Downloads/rows").toInt() != 0) { - //this->settings.endArray(); + // 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 *remove = msgBox.addButton(tr("Remove"), QMessageBox::ActionRole); 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(); } @@ -112,11 +118,12 @@ MainWindow::~MainWindow() delete ui; } -// Closing window has been clicked +// Close window has been clicked void MainWindow::closeEvent (QCloseEvent *event) { QMessageBox::StandardButton reply; QMessageBox::StandardButtons param; + QString displayText; // saving settings saveSettings(); @@ -128,13 +135,15 @@ void MainWindow::closeEvent (QCloseEvent *event) 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.\nYou can save the list of downloads\nDo you want to exit ?"), + tr("Exiting will stop downloading, and will clear the download queue.\nDo you want to exit ?") + displayText, param, QMessageBox::No); + if (reply == QMessageBox::No) { // continuing @@ -155,7 +164,6 @@ void MainWindow::closeEvent (QCloseEvent *event) // Populate treeview with list of files void MainWindow::populateTree(QTreeWidgetItem * parent) { - stringstream ss; QString path; // Clear treewidget @@ -165,6 +173,7 @@ void MainWindow::populateTree(QTreeWidgetItem * parent) // setting cursor to "Wait" QGuiApplication::setOverrideCursor(Qt::WaitCursor); + // validating server's address if (validateServer(this->connexion.server)) { // server is validated @@ -179,8 +188,6 @@ void MainWindow::populateTree(QTreeWidgetItem * parent) // Populate Listview with list of services void MainWindow::populateList() { - //stringstream ss; - QString str; QString server; int port; @@ -190,9 +197,11 @@ void MainWindow::populateList() { // 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 @@ -203,6 +212,8 @@ void MainWindow::populateList() port = this->settings.value(server).toUInt(); ui->portEdit->setText(QString::number(port)); this->connexion.port = port; + + //display list of services listServices(); }else { @@ -211,6 +222,7 @@ void MainWindow::populateList() if (validateServer(server)) { cout << server.toStdString() << endl; + // storing serverURL and port in settings this->settings.setValue(server, port); this->settings.sync(); @@ -219,14 +231,13 @@ void MainWindow::populateList() // storing in history of combobox ui->khistorycombobox->addToHistory(server); - // "waiting" cursor // load and display rsync services of the rsync server listServices(); } } } this->settings.endGroup(); - QGuiApplication::restoreOverrideCursor(); //setOverrideCursor(Qt::ArrowCursor); + QGuiApplication::restoreOverrideCursor(); //setting cursor to default } } @@ -247,26 +258,32 @@ void MainWindow::listServices() 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(myProcess); } @@ -276,10 +293,8 @@ void MainWindow::scanDir(QString server, int portN, QTreeWidgetItem *parent, QSt QString cmd; QStringList param; QString line; - QString errorRsync; QString size; QString filename; - QString dir; QTreeWidgetItem * item; QProcess * myProcess; bool isDir = false; @@ -291,16 +306,19 @@ void MainWindow::scanDir(QString server, int portN, QTreeWidgetItem *parent, QSt myProcess = new QProcess(this); myProcess->start(cmd, param); + // waiting for response of the server with a timeout of 10 seconds while(myProcess->waitForReadyRead(100000)) { 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 is dir/file line = line.simplified(); size = line.section(" ", 1, 1); filename = line.section(" ", 4); @@ -315,16 +333,19 @@ void MainWindow::scanDir(QString server, int portN, QTreeWidgetItem *parent, QSt } if (parent != NULL) { + //adding item to tree item = addTreeChild(parent, filename, size, isDir); }else { + //adding item to tree (as directory) item = addTreeRoot(filename, size, isDir); } } } + flag = false; } - + // buffer empty go to waiting new datas testRsyncReturn(myProcess); } @@ -333,7 +354,6 @@ bool MainWindow::isIpAddress(QString server) { QStringList r; int elementN; - QString qr; bool ok; r = server.split('.'); @@ -360,9 +380,9 @@ bool MainWindow::validateServer(QString server) QString cmd; QStringList param; QString line; - QString errorDig; QProcess * myProcess; bool flag = false; + bool bflag = false; cmd = "dig"; param << server; @@ -370,23 +390,35 @@ bool MainWindow::validateServer(QString server) myProcess = new QProcess(this); myProcess->start(cmd, param); + // maiking a dig on the server's address while(myProcess->waitForReadyRead()) { - line = QString::fromUtf8(myProcess->readAllStandardOutput()); - if (line.indexOf(";; ANSWER SECTION:") != -1) + while (!bflag) { - flag = true; + 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", @@ -412,15 +444,15 @@ void MainWindow::on_connectButton_clicked() // add a dir in treeview QTreeWidgetItem * MainWindow::addTreeRoot(QString name, QString fileSize, bool isDir) { - // QTreeWidgetItem(QTreeWidget * parent, int type = Type) QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui->treeWidget); - // QTreeWidgetItem::setText(int column, const QString & text) if (isDir == true) { + // item is a dir treeItem->setText(1, tr("Dir")); }else { + // item is a file treeItem->setText(1,tr("File")); } treeItem->setText(0, name); @@ -432,15 +464,15 @@ QTreeWidgetItem * MainWindow::addTreeRoot(QString name, QString fileSize, bool i // add a file in treeview QTreeWidgetItem * MainWindow::addTreeChild(QTreeWidgetItem *parent, QString name, QString fileSize, bool isDir) { - // QTreeWidgetItem(QTreeWidget * parent, int type = Type) QTreeWidgetItem *treeItem = new QTreeWidgetItem(); - // QTreeWidgetItem::setText(int column, const QString & text) if (isDir == true) { + // item is a dir treeItem->setText(1, tr("Dir")); }else { + // item is a file treeItem->setText(1,("File")); } treeItem->setText(0, name); @@ -454,13 +486,14 @@ QTreeWidgetItem * MainWindow::addTreeChild(QTreeWidgetItem *parent, QString name // Slot acivated when a service in the list is clicked void MainWindow::on_listWidget_clicked() { - QString service; QString str; this->connexion.service = ui->listWidget->currentItem()->text().section("\n", 0 ,0); 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(); } populateTree(NULL); @@ -477,17 +510,18 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadD itemR = item; + // assembling path from treewidget path = item->text(0); while(itemR->parent() != NULL) { itemR = itemR->parent(); - path = itemR->text(0) + "/" + path; + // concatening parent to path + path.prepend(itemR->text(0) + "/"); }; if (item->text(1) == tr("File") or downloadDir == true) { // Item is a file - if(ui->listDownload->findItems(path, Qt::MatchStartsWith).empty()) { // exists saving path in settings ? @@ -550,9 +584,10 @@ void MainWindow::stoppingDownload() void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) { QString path; - int pos; QString str; + int pos; + // test if process crashed if (exitStatus == QProcess::CrashExit) { QMessageBox::warning( @@ -560,25 +595,36 @@ void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) "RsyncUI", tr("Rsync process crashed")); } + //test result code of command (if 20 then command stopped by user) if (exitCode != 0 and exitCode != 20) { + // displaying warning with exit code QMessageBox::warning( NULL, "RsyncUI", rsyncErrorStrings[exitCode]); } + // disconnecting signals to slots disconnect(this->downloading.process, 0, 0, 0); + + // reset variables and window this->downloading.process= nullptr; ui->progressBar->hide(); delete ui->listDownload->takeItem(0); this->downloading.clear(); + + // Some downloads staying in queue if (ui->listDownload->count() != 0) { + // autosave is activated if (config.autosaveCheckbox->checkState() == Qt::Checked) { + // saving download list saveDownloadList(); } + + // initializing download path = ui->listDownload->item(0)->text(); pos = path.lastIndexOf("/"); this->downloading.service = path.midRef(pos+1).toString(); @@ -587,12 +633,17 @@ void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) this->downloading.server = path.midRef(pos+4).toString(); path.resize(pos); this->downloading.path = path; + + // save path 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"; @@ -600,7 +651,6 @@ void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) return; } } - startDownloading(); } } @@ -608,13 +658,12 @@ void MainWindow::downloadFinished(int exitCode, QProcess::ExitStatus exitStatus) // Slot activated when a line is clicked in queue list void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item) { - QFileDialog dialog; QMessageBox::StandardButton reply; - //cout << item->text().toStdString() << endl; if (item->listWidget()->row(item) == 0) { - reply = QMessageBox::question( + // 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 ?"), @@ -622,10 +671,12 @@ void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item) 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", @@ -634,10 +685,12 @@ void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item) 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(); } } @@ -694,7 +747,6 @@ void MainWindow::saveSettings() // About void MainWindow::on_actionAbout_triggered() { - //TODO => initialisation QString text = this->about.description + "\n\n" + tr("Version") + ": " + this->about.version + "\n" + tr("Licence") + ": " + this->about.licence + "\n" + @@ -717,20 +769,24 @@ bool MainWindow::on_DefaultSaveFolder_triggered() 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; + 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(); @@ -759,6 +815,7 @@ void MainWindow::on_buttonBox_accepted() bw = config.spinBox->text(); if (bw.toInt() == 0) { + // bandwidth = 0 this->connexion.bandwidthLimit = 0; this->connexion.bandwidthLimitUnit = 0; }else @@ -780,9 +837,11 @@ void MainWindow::saveDownloadList() { int nRows; + // remove list of downloads this->settings.remove("Downloads/"); + + // Saving list of current downloads nRows = ui->listDownload->count(); - //this->settings.beginWriteArray("Downloads/"); this->settings.beginGroup("Downloads"); this->settings.setValue("rows", nRows); for (int i = 0; i < nRows; i++) @@ -793,12 +852,14 @@ void MainWindow::saveDownloadList() 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) @@ -807,8 +868,6 @@ void MainWindow::loadDownloadList() } this->settings.endGroup(); - this->settings.sync(); - path = ui->listDownload->item(0)->text(); pos = path.lastIndexOf("/"); this->downloading.service = path.midRef(pos+1).toString(); @@ -825,6 +884,7 @@ void MainWindow::loadDownloadList() startDownloading(); } +// clear object downloading void Downloading::clear() { this->path.clear(); @@ -833,6 +893,7 @@ void Downloading::clear() this->service.clear(); } +// Context menu of file list clicked void MainWindow::on_actionDownload_triggered() { // action made in qt-designer and added in init function. @@ -852,6 +913,7 @@ void MainWindow::on_actionDownload_triggered() } */ +// Chnage toolbar style void MainWindow::on_comboBox_currentIndexChanged(int index) { ui->toolBar->setToolButtonStyle((Qt::ToolButtonStyle)index); diff --git a/tools.cpp b/tools.cpp index b0cd9e6..2eb3d32 100644 --- a/tools.cpp +++ b/tools.cpp @@ -43,6 +43,7 @@ const vector explode(const string& s, const char& c, int n = 0) return v; } +// test return code of rsync bool testRsyncReturn(QProcess * myProcess) { if (myProcess->exitStatus() != 0)