Compare commits

..

3 Commits
1.8.3 ... 1.8.4

Author SHA1 Message Date
4b434fc393 version 1.8.4 2023-02-03 00:40:32 +01:00
5804e43d1f added context menu to download folders 2023-02-02 17:14:04 +01:00
d70d081139 a lot of debug 2023-02-02 16:10:51 +01:00
6 changed files with 239 additions and 89 deletions

View File

@ -4,12 +4,12 @@ Name=RsyncUI
GenericName=rsync client GenericName=rsync client
Comment=Client for rsync servers Comment=Client for rsync servers
Comment[fr]=Client pour serveur rsync Comment[fr]=Client pour serveur rsync
Version=1.8.2 Version=1.0
Exec=RsyncUI Exec=RsyncUI
Icon= Icon=
Type=Application Type=Application
Terminal=false Terminal=false
StartupNotify=true StartupNotify=true
Categories=Networking; Categories=Network
Keywords=internet; Keywords=internet,rsync

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.14.2, 2023-01-31T13:04:06. --> <!-- Written by QtCreator 4.14.2, 2023-02-02T16:28:47. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>

View File

@ -47,6 +47,9 @@ void downloadFile::download(MainWindow *mw)
vector<string> v; vector<string> v;
int value; int value;
char buffer[4096]; char buffer[4096];
Downloading d;
d = mw->downloading;
// Populating array with command and parameters for popen2 // Populating array with command and parameters for popen2
argv[0] = "/usr/bin/rsync"; argv[0] = "/usr/bin/rsync";
@ -58,13 +61,13 @@ void downloadFile::download(MainWindow *mw)
argv[1] = "--bwlimit=" + to_string(mw->connexion.bandwidthLimit) + mw->connexion.bandwidthLimitUnit; argv[1] = "--bwlimit=" + to_string(mw->connexion.bandwidthLimit) + mw->connexion.bandwidthLimitUnit;
} }
argv[2] = "--port=" + to_string(mw->connexion.port); argv[2] = "--port=" + to_string(mw->connexion.port);
argv[3] = "-P"; argv[3] = "-aP";
argv[4] = mw->downloading.server + "::" + mw->downloading.service + "/" + mw->downloading.path; argv[4] = d.server + "::" + d.service + "/" + d.path;
argv[5] = mw->downloading.savePath + "/"; argv[5] = d.savePath + "/";
argv[6].clear(); argv[6].clear();
//launching downloading thread //launching downloading thread
FILE * fp = popen2(argv, "r", mw->downloading.pid); FILE * fp = popen2(argv, "r", mw->pid);
if (fp <= (FILE *) 0) if (fp <= (FILE *) 0)
{ {
sprintf(buffer, "popen2() failed!: returning code:%d", fileno(fp)); sprintf(buffer, "popen2() failed!: returning code:%d", fileno(fp));
@ -98,7 +101,7 @@ void downloadFile::download(MainWindow *mw)
} }
// download ended // download ended
} }
pclose2(fp, mw->downloading.pid); pclose2(fp, mw->pid);
// ProgressBar to 100% and emit signal finished to main application // ProgressBar to 100% and emit signal finished to main application
emit progressSignal(100); emit progressSignal(100);

View File

@ -12,11 +12,16 @@ MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
, ui(new Ui::MainWindow) , ui(new Ui::MainWindow)
{ {
QAbstractButton * reply;
QMessageBox msgBox;
ui->setupUi(this); ui->setupUi(this);
QCoreApplication::setOrganizationName("RsyncUI"); QCoreApplication::setOrganizationName("RsyncUI");
QCoreApplication::setApplicationName("RsyncUI"); QCoreApplication::setApplicationName("RsyncUI");
ui->treeWidget->addAction(ui->actionDownload);
// init shortcut // init shortcut
loadSettings(); loadSettings();
config.setupUi(&Configuration); config.setupUi(&Configuration);
@ -54,6 +59,29 @@ MainWindow::MainWindow(QWidget *parent)
// Hiding progress bar // Hiding progress bar
ui->progressBar->hide(); ui->progressBar->hide();
if (this->settings.value("Downloads/rows").toInt() != 0)
{
this->settings.endArray();
msgBox.setWindowTitle("RsyncUI");
msgBox.setInformativeText(tr("A list of interrupted downloads exists, do you want to continue downloading ? or you can delete the list" ));
QPushButton *remove = msgBox.addButton(tr("Remove"), QMessageBox::ActionRole);
QPushButton *yes = msgBox.addButton(QMessageBox::Yes);
msgBox.addButton(QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
msgBox.exec();
reply = msgBox.clickedButton();
if(reply == yes)
{
loadDownloadList();
}else if (reply == remove)
{
this->settings.remove("Downloads");
}
}
populateList(); populateList();
} }
@ -76,19 +104,22 @@ void MainWindow::closeEvent (QCloseEvent *event)
reply = QMessageBox::question( reply = QMessageBox::question(
this, this,
"RsyncUI", "RsyncUI",
tr("Exiting will stop downloading, and will clear the download queue.\n Do you want to exit ?"), tr("Exiting will stop downloading, and will clear the download queue.\nYou can save the list of downloads\nDo you want to exit ?"),
QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes|QMessageBox::Save|QMessageBox::No,
QMessageBox::No); QMessageBox::No);
if (reply == QMessageBox::No) if (reply == QMessageBox::No)
{ {
// continuing // continuing
event->ignore(); event->ignore();
return; return;
}else }else if(reply == QMessageBox::Yes)
{ {
// emission of signal to downloading thread and stopping // emission of signal to downloading thread and stopping
emit (stopDownloading(this->downloading.pid)); emit (stopDownloading(this->pid));
waitpid(this->downloading.pid, NULL, WUNTRACED); waitpid(this->pid, NULL, WUNTRACED);
}else
{
saveDownloadList();
} }
} }
event->accept(); event->accept();
@ -135,21 +166,22 @@ void MainWindow::populateList()
this->connexion.server.assign(server.toStdString()); this->connexion.server.assign(server.toStdString());
this->connexion.port = port; this->connexion.port = port;
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
// verify if server is in history // verify if server is in history
this->settings.beginGroup("connexion/server"); this->settings.beginGroup("connexion/server");
if (this->settings.contains(server)) if (this->settings.contains(server))
{ {
// server is in history and completing port value // server is in history => setting port value
port = this->settings.value(server).toUInt(); port = this->settings.value(server).toUInt();
ui->portEdit->setText(QString::number(port)); ui->portEdit->setText(QString::number(port));
this->connexion.port = port; this->connexion.port = port;
} listServices();
}else
if (!server.isEmpty() and (port > 0 and port < 65536))
{ {
if (validateServer(server.toStdString())) if (!server.isEmpty() and (port > 0 and port < 65536))
{ {
if (!this->settings.contains(server)) if (validateServer(server.toStdString()))
{ {
cout << server.toStdString() << endl; cout << server.toStdString() << endl;
// storing serverURL and port in settings // storing serverURL and port in settings
@ -159,13 +191,13 @@ void MainWindow::populateList()
// storing in history of combobox // storing in history of combobox
ui->khistorycombobox->addToHistory(server); ui->khistorycombobox->addToHistory(server);
// "waiting" cursor
// load and display rsync services of the rsync server
listServices();
} }
// "waiting" cursor
// load and display rsync services of the rsync server
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
listServices();
QGuiApplication::restoreOverrideCursor(); //setOverrideCursor(Qt::ArrowCursor);
} }
} }
this->settings.endGroup(); this->settings.endGroup();
QGuiApplication::restoreOverrideCursor(); //setOverrideCursor(Qt::ArrowCursor); QGuiApplication::restoreOverrideCursor(); //setOverrideCursor(Qt::ArrowCursor);
@ -393,8 +425,8 @@ void MainWindow::on_listWidget_clicked()
QString str; QString str;
v = explode(ui->listWidget->currentItem()->text().toStdString(), '\n', 2); v = explode(ui->listWidget->currentItem()->text().toStdString(), '\n', 2);
this->downloading.service = v[0]; this->connexion.service = v[0];
str = QString::fromStdString("Folder/" + this->connexion.server + "/" + this->downloading.service); str = QString::fromStdString("Folder/" + this->connexion.server + "/" + this->connexion.service);
if (this->settings.contains(str)) if (this->settings.contains(str))
{ {
this->downloading.savePath = this->settings.value(str).toString().toStdString(); this->downloading.savePath = this->settings.value(str).toString().toStdString();
@ -403,7 +435,7 @@ void MainWindow::on_listWidget_clicked()
} }
//Slot activated when a file is clicked in the treeview //Slot activated when a file is clicked in the treeview
void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item) void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadDir)
{ {
QFuture<void> future; QFuture<void> future;
QFileDialog dialog; QFileDialog dialog;
@ -421,32 +453,41 @@ void MainWindow::on_treeWidget_itemClicked(QTreeWidgetItem *item)
path = itemR->text(0).toStdString() + "/" + path; path = itemR->text(0).toStdString() + "/" + path;
}; };
if (item->text(1) == tr("File")) if (item->text(1) == tr("File") or downloadDir == true)
{ {
// Item is a file // Item is a file
this->downloading.path = path; this->downloading.path = path;
if (this->downloading.savePath.empty()) this->downloading.server = this->connexion.server;
{ this->downloading.service = this->connexion.service;
on_DefaultSaveFolder_triggered();
}else if (this->downloading.pid == 0)
{
str = QString::fromStdString("Folder/" + this->connexion.server + "/" + this->downloading.service);
if(this->settings.value(str).toString().isEmpty() and !this->downloading.savePath.empty())
{
this->settings.setValue(str, this->downloading.savePath.c_str());
this->settings.sync();
}
this->downloading.server = this->connexion.server;
startDownloading();
sleep(1);
// exists saving path in settings ?
str = QString::fromStdString("Folder/" + this->connexion.server + "/" + this->downloading.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;
}
} }
// is there a downloading process ?
if (this->pid == 0)
{
// no downloading process launching it
startDownloading();
// wit 1 second to process start
//sleep(1);
}
// Adding download in download list
str = QString::fromStdString(this->downloading.path + " => " + this->connexion.server + "/" + this->downloading.service); str = QString::fromStdString(this->downloading.path + " => " + this->connexion.server + "/" + this->downloading.service);
ui->listDownload->addItem(str); ui->listDownload->addItem(str);
}else }else
{ {
//Item is a Directory //Item is a Directory
scanDir(this->connexion.server, this->connexion.port, item, this->downloading.service + "/" + path +"/"); scanDir(this->connexion.server, this->connexion.port, item, this->connexion.service + "/" + path +"/");
item->setExpanded(true); item->setExpanded(true);
} }
@ -465,7 +506,7 @@ void MainWindow::startDownloading()
// Slot stopping download // Slot stopping download
void MainWindow::stoppingDownload() void MainWindow::stoppingDownload()
{ {
emit (stopDownloading(this->downloading.pid)); emit (stopDownloading(this->pid));
} }
// when download is finished, launch download of next file in queue // when download is finished, launch download of next file in queue
@ -475,9 +516,10 @@ void MainWindow::downloadFinished()
int pos; int pos;
string str; string str;
this->pid = 0;
ui->progressBar->hide(); ui->progressBar->hide();
delete ui->listDownload->takeItem(0); delete ui->listDownload->takeItem(0);
this->downloading.pid = 0; this->downloading.clear();
if (ui->listDownload->count() != 0) if (ui->listDownload->count() != 0)
{ {
path = ui->listDownload->item(0)->text().toStdString(); path = ui->listDownload->item(0)->text().toStdString();
@ -489,14 +531,23 @@ void MainWindow::downloadFinished()
path.resize(pos); path.resize(pos);
this->downloading.path = path; this->downloading.path = path;
str = "Folder/" + this->downloading.server + "/" + this->downloading.service; str = "Folder/" + this->downloading.server + "/" + this->downloading.service;
if (this->settings.contains(str.c_str())) if (this->settings.contains(QString::fromStdString(str)))
{ {
this->downloading.savePath = this->settings.value(str.c_str()).toString().toStdString(); this->downloading.savePath = this->settings.value(QString::fromStdString(str)).toString().toStdString();
}else
{
if(!on_DefaultSaveFolder_triggered())
{
cout << "Error no save path so deleting download";
downloadFinished();
return;
}
} }
startDownloading(); startDownloading();
} }
} }
// Slot activated when a line is clicked in queue list // Slot activated when a line is clicked in queue list
void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item) void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item)
{ {
@ -514,7 +565,7 @@ void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item)
QMessageBox::No); QMessageBox::No);
if (reply == QMessageBox::Yes) if (reply == QMessageBox::Yes)
{ {
emit (stopDownloading(this->downloading.pid)); emit (stopDownloading(this->pid));
} }
}else }else
{ {
@ -536,12 +587,12 @@ void MainWindow::on_listDownload_itemClicked(QListWidgetItem *item)
void MainWindow::loadSettings() void MainWindow::loadSettings()
{ {
// restoring geometry and state of window and widgets // restoring geometry and state of window and widgets
this->restoreGeometry(settings.value("window/geometry").toByteArray()); this->restoreGeometry(this->settings.value("window/geometry").toByteArray());
this->restoreState(settings.value("window/state").toByteArray()); this->restoreState(this->settings.value("window/state").toByteArray());
ui->treeWidget->header()->restoreState(settings.value("treeWidget/state").toByteArray()); ui->treeWidget->header()->restoreState(this->settings.value("treeWidget/state").toByteArray());
ui->splitter->restoreState(settings.value("splitter/state").toByteArray()); ui->splitter->restoreState(this->settings.value("splitter/state").toByteArray());
ui->splitter_2->restoreState(settings.value("splitter2/state").toByteArray()); ui->splitter_2->restoreState(this->settings.value("splitter2/state").toByteArray());
ui->toolBar->setToolButtonStyle((Qt::ToolButtonStyle)settings.value("toolbar/state").toInt()); ui->toolBar->setToolButtonStyle((Qt::ToolButtonStyle)this->settings.value("toolbar/state").toInt());
// loading connexion settings // loading connexion settings
// loading servers history // loading servers history
@ -578,6 +629,7 @@ void MainWindow::saveSettings()
// About // About
void MainWindow::on_actionAbout_triggered() void MainWindow::on_actionAbout_triggered()
{ {
//TODO => initialisation
QString text = this->about.description + "\n\n" + QString text = this->about.description + "\n\n" +
tr("Version") + ": " + this->about.version + "\n" + tr("Version") + ": " + this->about.version + "\n" +
tr("Licence") + ": " + this->about.licence + "\n" + tr("Licence") + ": " + this->about.licence + "\n" +
@ -594,23 +646,35 @@ void MainWindow::on_actionAbout_Qt_triggered()
} }
// Activated when menu "change folder" is clicked // Activated when menu "change folder" is clicked
void MainWindow::on_DefaultSaveFolder_triggered() bool MainWindow::on_DefaultSaveFolder_triggered()
{ {
QFileDialog dialog; QFileDialog dialog;
string folder; string folder;
string path; string path;
path = dialog.getExistingDirectory(this, tr("Choose directory to save file"), QString::fromStdString(this->downloading.savePath), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks).toStdString(); if (this->connexion.service.empty())
{
QMessageBox::warning(
NULL,
"RsyncUI",
"Since the save path is linked to service, you need to select a service before you can select a folder");
return false;
}
path = dialog.getExistingDirectory(this, tr("Choose directory to save file"), QString::fromStdString(getpwuid(getuid())->pw_dir), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks).toStdString();
if (!path.empty()) if (!path.empty())
{ {
this->downloading.savePath = path; this->downloading.savePath = path;
if (!this->downloading.service.empty() and !this->connexion.server.empty()) if (!this->connexion.service.empty() and !this->connexion.server.empty())
{ {
folder = "Folder/" + this->connexion.server + "/" + this->downloading.service; folder = "Folder/" + this->connexion.server + "/" + this->connexion.service;
this->settings.setValue(folder.c_str(), this->downloading.savePath.c_str()); this->settings.setValue(folder.c_str(), this->downloading.savePath.c_str());
this->settings.sync(); this->settings.sync();
} }
}else
{
return false;
} }
return true;
} }
// Activated when menu "settings" is clicked // Activated when menu "settings" is clicked
@ -642,3 +706,69 @@ void MainWindow::on_buttonBox_accepted()
this->settings.sync(); this->settings.sync();
Configuration.hide(); Configuration.hide();
} }
// Saving download list
void MainWindow::saveDownloadList()
{
int nRows;
nRows = ui->listDownload->count();
//this->settings.beginWriteArray("Downloads/");
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();
}
void MainWindow::loadDownloadList()
{
string path;
string str;
int pos;
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();
this->settings.remove("Downloads");
this->settings.sync();
path = ui->listDownload->item(0)->text().toStdString();
pos = path.rfind("/");
this->downloading.service = path.substr(pos+1);
path.resize(pos);
pos = path.rfind(" => ");
this->downloading.server = path.substr(pos+4);
path.resize(pos);
this->downloading.path = path;
str = "Folder/" + this->downloading.server + "/" + this->downloading.service;
if (this->settings.contains(QString::fromStdString(str)))
{
this->downloading.savePath = this->settings.value(QString::fromStdString(str)).toString().toStdString();
}
startDownloading();
}
void Downloading::clear()
{
this->path.clear();
this->server.clear();
this->savePath.clear();
this->service.clear();
}
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);
}

View File

@ -1,6 +1,7 @@
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
#define QT_USE_FAST_CONCATENATION
#define QT_USE_FAST_OPERATOR_PLUS
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "ui_configuration.h" #include "ui_configuration.h"
#include "downloadfile.h" #include "downloadfile.h"
@ -33,6 +34,8 @@
#include <unistd.h> #include <unistd.h>
#include <magic.h> #include <magic.h>
#include <QComboBox> #include <QComboBox>
#include <QStringBuilder>
#include <pwd.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; } namespace Ui { class MainWindow; }
@ -44,6 +47,8 @@ class Connexion
int bandwidthLimit = 0; int bandwidthLimit = 0;
std::string bandwidthLimitUnit = ""; std::string bandwidthLimitUnit = "";
std::string server; std::string server;
std::string service;
int port = 873; int port = 873;
}; };
@ -54,14 +59,15 @@ class Downloading
std::string service; std::string service;
std::string path; std::string path;
std::string savePath; std::string savePath;
int pid = 0;
void clear();
}; };
class About class About
{ {
public: public:
QString title = "RsyncUI"; QString title = "RsyncUI";
QString version = "1.6"; QString version = "1.8.4";
QString author = "Daniel TARTAVEL-JEANNOT"; QString author = "Daniel TARTAVEL-JEANNOT";
QString licence = "GPL_V3"; QString licence = "GPL_V3";
QString description; QString description;
@ -78,20 +84,7 @@ class MainWindow : public QMainWindow
MainWindow(QWidget *parent = nullptr); MainWindow(QWidget *parent = nullptr);
~MainWindow(); ~MainWindow();
QProgressDialog *progress; QProgressDialog *progress;
void displayTree(); int pid = 0;
void populateTree(QTreeWidgetItem * parent);
void populateList();
void listServices();
bool validateServer(std::string server);
bool isIpAddress(std::string server);
QTreeWidgetItem * addTreeRoot(QString name, QString description, bool isDir);
QTreeWidgetItem * addTreeChild(QTreeWidgetItem *parent, QString name, QString size, bool isDir);
void scanDir(std::string server, int portN, QTreeWidgetItem *parent = NULL, std::string path = "" );
void startDownloading();
void loadSettings();
void saveSettings();
void closeEvent (QCloseEvent *event);
Connexion connexion; Connexion connexion;
Downloading downloading; Downloading downloading;
downloadFile downloadO; downloadFile downloadO;
@ -108,11 +101,27 @@ class MainWindow : public QMainWindow
{'P', 4} {'P', 4}
}; };
void displayTree();
void populateTree(QTreeWidgetItem * parent);
void populateList();
void listServices();
bool validateServer(std::string server);
bool isIpAddress(std::string server);
QTreeWidgetItem * addTreeRoot(QString name, QString description, bool isDir);
QTreeWidgetItem * addTreeChild(QTreeWidgetItem *parent, QString name, QString size, bool isDir);
void scanDir(std::string server, int portN, QTreeWidgetItem *parent = NULL, std::string path = "" );
void startDownloading();
void loadSettings();
void saveSettings();
void closeEvent (QCloseEvent *event);
void saveDownloadList();
void loadDownloadList();
private slots: private slots:
void on_listWidget_clicked(); void on_listWidget_clicked();
void on_treeWidget_itemClicked(QTreeWidgetItem *item); void on_treeWidget_itemClicked(QTreeWidgetItem *item, bool downloadDir = false);
void downloadFinished(); void downloadFinished();
@ -126,18 +135,19 @@ class MainWindow : public QMainWindow
void on_khistorycombobox_currentIndexChanged(int); void on_khistorycombobox_currentIndexChanged(int);
void on_DefaultSaveFolder_triggered(); bool on_DefaultSaveFolder_triggered();
void on_connectButton_clicked(); void on_connectButton_clicked();
void on_action_Settings_triggered(); void on_action_Settings_triggered();
void on_actionDownload_triggered();
public slots: public slots:
void on_buttonBox_accepted(); void on_buttonBox_accepted();
signals: signals:
void stopDownloading(int); void stopDownloading(int);
// void accepted();
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View File

@ -250,7 +250,7 @@
<enum>Qt::WheelFocus</enum> <enum>Qt::WheelFocus</enum>
</property> </property>
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum> <enum>Qt::ActionsContextMenu</enum>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Click to add to download queue</string> <string>Click to add to download queue</string>
@ -396,14 +396,10 @@
<addaction name="actionAbout"/> <addaction name="actionAbout"/>
<addaction name="actionAbout_Qt"/> <addaction name="actionAbout_Qt"/>
</widget> </widget>
<action name="actionMenu">
<property name="text">
<string>Menu</string>
</property>
</action>
<action name="DefaultSaveFolder"> <action name="DefaultSaveFolder">
<property name="icon"> <property name="icon">
<iconset theme="system-file-manager"/> <iconset theme="system-file-manager">
<normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Change save folder</string> <string>Change save folder</string>
@ -414,7 +410,8 @@
</action> </action>
<action name="actionAbout"> <action name="actionAbout">
<property name="icon"> <property name="icon">
<iconset theme="help-about"/> <iconset theme="help-about">
<normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>About</string> <string>About</string>
@ -422,7 +419,8 @@
</action> </action>
<action name="actionAbout_Qt"> <action name="actionAbout_Qt">
<property name="icon"> <property name="icon">
<iconset theme="help-browser"/> <iconset theme="help-browser">
<normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>About Qt</string> <string>About Qt</string>
@ -430,12 +428,21 @@
</action> </action>
<action name="action_Settings"> <action name="action_Settings">
<property name="icon"> <property name="icon">
<iconset theme="preferences-other"/> <iconset theme="preferences-other">
<normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Settings</string> <string>Settings</string>
</property> </property>
</action> </action>
<action name="actionDownload">
<property name="text">
<string>Download</string>
</property>
<property name="toolTip">
<string>Click on menu button to download the entire folder</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>