mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-16 02:03:07 -07:00
Merge Win32 fixes from stable branch
This commit is contained in:
parent
4e1366bf0d
commit
b719bfaecb
5 changed files with 95 additions and 24 deletions
|
@ -1538,6 +1538,9 @@ void Bittorrent::addConsoleMessage(QString msg, QString) {
|
||||||
if(consoleMessages.size() > 100) {
|
if(consoleMessages.size() > 100) {
|
||||||
consoleMessages.removeFirst();
|
consoleMessages.removeFirst();
|
||||||
}
|
}
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
msg = msg.replace("/", "\\");
|
||||||
|
#endif
|
||||||
consoleMessages.append(QString::fromUtf8("<font color='grey'>")+ QDateTime::currentDateTime().toString(QString::fromUtf8("dd/MM/yyyy hh:mm:ss")) + QString::fromUtf8("</font> - <font color='") + color.name() +QString::fromUtf8("'><i>") + msg + QString::fromUtf8("</i></font>"));
|
consoleMessages.append(QString::fromUtf8("<font color='grey'>")+ QDateTime::currentDateTime().toString(QString::fromUtf8("dd/MM/yyyy hh:mm:ss")) + QString::fromUtf8("</font> - <font color='") + color.name() +QString::fromUtf8("'><i>") + msg + QString::fromUtf8("</i></font>"));
|
||||||
#endif
|
#endif
|
||||||
emit newConsoleMessage(QDateTime::currentDateTime().toString("dd/MM/yyyy hh:mm:ss") + " - " + msg);
|
emit newConsoleMessage(QDateTime::currentDateTime().toString("dd/MM/yyyy hh:mm:ss") + " - " + msg);
|
||||||
|
|
|
@ -80,14 +80,22 @@ createtorrent::~createtorrent() {
|
||||||
|
|
||||||
void createtorrent::on_addFolder_button_clicked(){
|
void createtorrent::on_addFolder_button_clicked(){
|
||||||
QString dir = QFileDialog::getExistingDirectory(this, tr("Select a folder to add to the torrent"), QDir::homePath(), QFileDialog::ShowDirsOnly);
|
QString dir = QFileDialog::getExistingDirectory(this, tr("Select a folder to add to the torrent"), QDir::homePath(), QFileDialog::ShowDirsOnly);
|
||||||
if(!dir.isEmpty())
|
if(!dir.isEmpty()) {
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
dir = dir.replace("/", "\\");
|
||||||
|
#endif
|
||||||
textInputPath->setText(dir);
|
textInputPath->setText(dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void createtorrent::on_addFile_button_clicked(){
|
void createtorrent::on_addFile_button_clicked(){
|
||||||
QString file = QFileDialog::getOpenFileName(this, tr("Select a file to add to the torrent"), QDir::homePath());
|
QString file = QFileDialog::getOpenFileName(this, tr("Select a file to add to the torrent"), QDir::homePath());
|
||||||
if(!file.isEmpty())
|
if(!file.isEmpty()) {
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
file = file.replace("/", "\\");
|
||||||
|
#endif
|
||||||
textInputPath->setText(file);
|
textInputPath->setText(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void createtorrent::on_removeTracker_button_clicked() {
|
void createtorrent::on_removeTracker_button_clicked() {
|
||||||
|
|
|
@ -90,7 +90,7 @@ options_imp::options_imp(QWidget *parent):QDialog(parent){
|
||||||
locales << "nl_NL";
|
locales << "nl_NL";
|
||||||
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/spain.png"))), QString::fromUtf8("Español"));
|
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/spain.png"))), QString::fromUtf8("Español"));
|
||||||
locales << "es_ES";
|
locales << "es_ES";
|
||||||
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/spain_catalunya.png"))), QString::fromUtf8("Català"));
|
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/spain_catalunya.png"))), QString::fromUtf8("Català "));
|
||||||
locales << "ca_ES";
|
locales << "ca_ES";
|
||||||
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/portugal.png"))), QString::fromUtf8("Português"));
|
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/portugal.png"))), QString::fromUtf8("Português"));
|
||||||
locales << "pt_PT";
|
locales << "pt_PT";
|
||||||
|
@ -110,7 +110,7 @@ options_imp::options_imp(QWidget *parent):QDialog(parent){
|
||||||
locales << "ro_RO";
|
locales << "ro_RO";
|
||||||
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/turkey.png"))), QString::fromUtf8("Türkçe"));
|
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/turkey.png"))), QString::fromUtf8("Türkçe"));
|
||||||
locales << "tr_TR";
|
locales << "tr_TR";
|
||||||
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/saoudi_arabia.png"))), QString::fromUtf8("عربي"));
|
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/saoudi_arabia.png"))), QString::fromUtf8("عربي"));
|
||||||
locales << "ar_SA";
|
locales << "ar_SA";
|
||||||
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/greece.png"))), QString::fromUtf8("Ελληνικά"));
|
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/greece.png"))), QString::fromUtf8("Ελληνικά"));
|
||||||
locales << "el_GR";
|
locales << "el_GR";
|
||||||
|
@ -126,7 +126,7 @@ comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/saoudi_arabia.png")))
|
||||||
locales << "bg_BG";
|
locales << "bg_BG";
|
||||||
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/ukraine.png"))), QString::fromUtf8("Українська"));
|
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/ukraine.png"))), QString::fromUtf8("Українська"));
|
||||||
locales << "uk_UA";
|
locales << "uk_UA";
|
||||||
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/russia.png"))), QString::fromUtf8("Русский"));
|
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/russia.png"))), QString::fromUtf8("РуÑ<C692>Ñ<EFBFBD>кий"));
|
||||||
locales << "ru_RU";
|
locales << "ru_RU";
|
||||||
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/japan.png"))), QString::fromUtf8("日本語"));
|
comboI18n->addItem((QIcon(QString::fromUtf8(":/Icons/flags/japan.png"))), QString::fromUtf8("日本語"));
|
||||||
locales << "ja_JP";
|
locales << "ja_JP";
|
||||||
|
@ -391,9 +391,17 @@ void options_imp::saveOptions(){
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
// Downloads preferences
|
// Downloads preferences
|
||||||
settings.beginGroup("Downloads");
|
settings.beginGroup("Downloads");
|
||||||
settings.setValue(QString::fromUtf8("SavePath"), getSavePath());
|
QString save_path = getSavePath();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
save_path = save_path.replace("\\", "/");
|
||||||
|
#endif
|
||||||
|
settings.setValue(QString::fromUtf8("SavePath"), save_path);
|
||||||
settings.setValue(QString::fromUtf8("TempPathEnabled"), isTempPathEnabled());
|
settings.setValue(QString::fromUtf8("TempPathEnabled"), isTempPathEnabled());
|
||||||
settings.setValue(QString::fromUtf8("TempPath"), getTempPath());
|
QString temp_path = getTempPath();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
temp_path = temp_path.replace("\\", "/");
|
||||||
|
#endif
|
||||||
|
settings.setValue(QString::fromUtf8("TempPath"), temp_path);
|
||||||
settings.setValue(QString::fromUtf8("AppendLabel"), checkAppendLabel->isChecked());
|
settings.setValue(QString::fromUtf8("AppendLabel"), checkAppendLabel->isChecked());
|
||||||
#ifdef LIBTORRENT_0_15
|
#ifdef LIBTORRENT_0_15
|
||||||
settings.setValue(QString::fromUtf8("UseIncompleteExtension"), checkAppendqB->isChecked());
|
settings.setValue(QString::fromUtf8("UseIncompleteExtension"), checkAppendqB->isChecked());
|
||||||
|
@ -403,7 +411,11 @@ void options_imp::saveOptions(){
|
||||||
settings.setValue(QString::fromUtf8("StartInPause"), addTorrentsInPause());
|
settings.setValue(QString::fromUtf8("StartInPause"), addTorrentsInPause());
|
||||||
ScanFoldersModel::instance()->makePersistent(settings);
|
ScanFoldersModel::instance()->makePersistent(settings);
|
||||||
addedScanDirs.clear();
|
addedScanDirs.clear();
|
||||||
Preferences::setExportDir(getExportDir());
|
QString export_dir = getExportDir();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
export_dir = export_dir.replace("\\", "/");
|
||||||
|
#endif
|
||||||
|
Preferences::setExportDir(export_dir);
|
||||||
settings.setValue(QString::fromUtf8("DblClOnTorDl"), getActionOnDblClOnTorrentDl());
|
settings.setValue(QString::fromUtf8("DblClOnTorDl"), getActionOnDblClOnTorrentDl());
|
||||||
settings.setValue(QString::fromUtf8("DblClOnTorFn"), getActionOnDblClOnTorrentFn());
|
settings.setValue(QString::fromUtf8("DblClOnTorFn"), getActionOnDblClOnTorrentFn());
|
||||||
// End Downloads preferences
|
// End Downloads preferences
|
||||||
|
@ -489,7 +501,11 @@ void options_imp::saveOptions(){
|
||||||
settings.beginGroup("IPFilter");
|
settings.beginGroup("IPFilter");
|
||||||
settings.setValue(QString::fromUtf8("Enabled"), isFilteringEnabled());
|
settings.setValue(QString::fromUtf8("Enabled"), isFilteringEnabled());
|
||||||
if(isFilteringEnabled()){
|
if(isFilteringEnabled()){
|
||||||
settings.setValue(QString::fromUtf8("File"), textFilterPath->text());
|
QString filter_path = textFilterPath->text();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
filter_path = filter_path.replace("\\", "/");
|
||||||
|
#endif
|
||||||
|
settings.setValue(QString::fromUtf8("File"), filter_path);
|
||||||
}
|
}
|
||||||
// End IPFilter preferences
|
// End IPFilter preferences
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
@ -609,7 +625,11 @@ void options_imp::loadOptions(){
|
||||||
}
|
}
|
||||||
// End General preferences
|
// End General preferences
|
||||||
// Downloads preferences
|
// Downloads preferences
|
||||||
textSavePath->setText(Preferences::getSavePath());
|
QString save_path = Preferences::getSavePath();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
save_path = save_path.replace("/", "\\");
|
||||||
|
#endif
|
||||||
|
textSavePath->setText(save_path);
|
||||||
if(Preferences::isTempPathEnabled()) {
|
if(Preferences::isTempPathEnabled()) {
|
||||||
// enable
|
// enable
|
||||||
checkTempFolder->setChecked(true);
|
checkTempFolder->setChecked(true);
|
||||||
|
@ -618,7 +638,11 @@ void options_imp::loadOptions(){
|
||||||
checkTempFolder->setChecked(false);
|
checkTempFolder->setChecked(false);
|
||||||
enableTempPathInput(checkTempFolder->isChecked());
|
enableTempPathInput(checkTempFolder->isChecked());
|
||||||
}
|
}
|
||||||
textTempPath->setText(Preferences::getTempPath());
|
QString temp_path = Preferences::getTempPath();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
temp_path = temp_path.replace("/", "\\");
|
||||||
|
#endif
|
||||||
|
textTempPath->setText(temp_path);
|
||||||
checkAppendLabel->setChecked(Preferences::appendTorrentLabel());
|
checkAppendLabel->setChecked(Preferences::appendTorrentLabel());
|
||||||
#ifdef LIBTORRENT_0_15
|
#ifdef LIBTORRENT_0_15
|
||||||
checkAppendqB->setChecked(Preferences::useIncompleteFilesExtension());
|
checkAppendqB->setChecked(Preferences::useIncompleteFilesExtension());
|
||||||
|
@ -635,6 +659,9 @@ void options_imp::loadOptions(){
|
||||||
} else {
|
} else {
|
||||||
// enable
|
// enable
|
||||||
checkExportDir->setChecked(true);
|
checkExportDir->setChecked(true);
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
strValue = strValue.replace("/", "\\");
|
||||||
|
#endif
|
||||||
textExportDir->setText(strValue);
|
textExportDir->setText(strValue);
|
||||||
enableTorrentExport(checkExportDir->isChecked());
|
enableTorrentExport(checkExportDir->isChecked());
|
||||||
}
|
}
|
||||||
|
@ -1023,16 +1050,12 @@ float options_imp::getDeleteRatio() const{
|
||||||
|
|
||||||
// Return Save Path
|
// Return Save Path
|
||||||
QString options_imp::getSavePath() const{
|
QString options_imp::getSavePath() const{
|
||||||
#ifdef Q_WS_WIN
|
|
||||||
QString home = QDir::rootPath();
|
|
||||||
#else
|
|
||||||
QString home = QDir::homePath();
|
|
||||||
#endif
|
|
||||||
if(home[home.length()-1] != QDir::separator()){
|
|
||||||
home += QDir::separator();
|
|
||||||
}
|
|
||||||
if(textSavePath->text().trimmed().isEmpty()){
|
if(textSavePath->text().trimmed().isEmpty()){
|
||||||
textSavePath->setText(home+QString::fromUtf8("qBT_dir"));
|
QString save_path = Preferences::getSavePath();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
save_path = save_path.replace("/", "\\");
|
||||||
|
#endif
|
||||||
|
textSavePath->setText(save_path);
|
||||||
}
|
}
|
||||||
return misc::expandPath(textSavePath->text());
|
return misc::expandPath(textSavePath->text());
|
||||||
}
|
}
|
||||||
|
@ -1428,6 +1451,9 @@ void options_imp::on_browseExportDirButton_clicked() {
|
||||||
dir = QFileDialog::getExistingDirectory(this, tr("Choose export directory"), QDir::homePath());
|
dir = QFileDialog::getExistingDirectory(this, tr("Choose export directory"), QDir::homePath());
|
||||||
}
|
}
|
||||||
if(!dir.isNull()){
|
if(!dir.isNull()){
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
dir = dir.replace("/", "\\");
|
||||||
|
#endif
|
||||||
textExportDir->setText(dir);
|
textExportDir->setText(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1442,6 +1468,9 @@ void options_imp::on_browseFilterButton_clicked() {
|
||||||
ipfilter = QFileDialog::getOpenFileName(this, tr("Choose an ip filter file"), QDir::homePath(), tr("Filters")+QString(" (*.dat *.p2p *.p2b)"));
|
ipfilter = QFileDialog::getOpenFileName(this, tr("Choose an ip filter file"), QDir::homePath(), tr("Filters")+QString(" (*.dat *.p2p *.p2b)"));
|
||||||
}
|
}
|
||||||
if(!ipfilter.isNull()){
|
if(!ipfilter.isNull()){
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
ipfilter = ipfilter.replace("/", "\\");
|
||||||
|
#endif
|
||||||
textFilterPath->setText(ipfilter);
|
textFilterPath->setText(ipfilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1457,6 +1486,9 @@ void options_imp::on_browseSaveDirButton_clicked(){
|
||||||
dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), QDir::homePath());
|
dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), QDir::homePath());
|
||||||
}
|
}
|
||||||
if(!dir.isNull()){
|
if(!dir.isNull()){
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
dir = dir.replace("/", "\\");
|
||||||
|
#endif
|
||||||
textSavePath->setText(dir);
|
textSavePath->setText(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1471,6 +1503,9 @@ void options_imp::on_browseTempDirButton_clicked(){
|
||||||
dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), QDir::homePath());
|
dir = QFileDialog::getExistingDirectory(this, tr("Choose a save directory"), QDir::homePath());
|
||||||
}
|
}
|
||||||
if(!dir.isNull()){
|
if(!dir.isNull()){
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
dir = dir.replace("/", "\\");
|
||||||
|
#endif
|
||||||
textTempPath->setText(dir);
|
textTempPath->setText(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,6 +212,9 @@ void PropertiesWidget::updateSavePath(QTorrentHandle& _h) {
|
||||||
QString p = TorrentPersistentData::getSavePath(h.hash());
|
QString p = TorrentPersistentData::getSavePath(h.hash());
|
||||||
if(p.isEmpty())
|
if(p.isEmpty())
|
||||||
p = h.save_path();
|
p = h.save_path();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
p = p.replace("/", "\\");
|
||||||
|
#endif
|
||||||
save_path->setText(p);
|
save_path->setText(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,6 +239,9 @@ void PropertiesWidget::loadTorrentInfos(QTorrentHandle &_h) {
|
||||||
QString p = TorrentPersistentData::getSavePath(h.hash());
|
QString p = TorrentPersistentData::getSavePath(h.hash());
|
||||||
if(p.isEmpty())
|
if(p.isEmpty())
|
||||||
p = h.save_path();
|
p = h.save_path();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
p = p.replace("/", "\\");
|
||||||
|
#endif
|
||||||
save_path->setText(p);
|
save_path->setText(p);
|
||||||
// Creation date
|
// Creation date
|
||||||
lbl_creationDate->setText(h.creation_date());
|
lbl_creationDate->setText(h.creation_date());
|
||||||
|
@ -752,7 +758,11 @@ void PropertiesWidget::renameSelectedFile() {
|
||||||
if(!BTSession->useTemporaryFolder() || h.is_seed())
|
if(!BTSession->useTemporaryFolder() || h.is_seed())
|
||||||
h.move_storage(savePath.absolutePath());
|
h.move_storage(savePath.absolutePath());
|
||||||
// Update save_path in dialog
|
// Update save_path in dialog
|
||||||
save_path->setText(savePath.absolutePath());
|
QString display_path = savePath.absolutePath();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
display_path = display_path.replace("/", "\\");
|
||||||
|
#endif
|
||||||
|
save_path->setText(display_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,11 @@ public:
|
||||||
//torrentContentList->header()->setResizeMode(0, QHeaderView::Stretch);
|
//torrentContentList->header()->setResizeMode(0, QHeaderView::Stretch);
|
||||||
defaultSavePath = Preferences::getSavePath();
|
defaultSavePath = Preferences::getSavePath();
|
||||||
appendLabelToSavePath = Preferences::appendTorrentLabel();
|
appendLabelToSavePath = Preferences::appendTorrentLabel();
|
||||||
savePathTxt->setText(defaultSavePath);
|
QString display_path = defaultSavePath;
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
display_path = display_path.replace("/", "\\");
|
||||||
|
#endif
|
||||||
|
savePathTxt->setText(display_path);
|
||||||
if(Preferences::addTorrentsInPause()) {
|
if(Preferences::addTorrentsInPause()) {
|
||||||
addInPause->setChecked(true);
|
addInPause->setChecked(true);
|
||||||
//addInPause->setEnabled(false);
|
//addInPause->setEnabled(false);
|
||||||
|
@ -421,7 +425,11 @@ public slots:
|
||||||
|
|
||||||
void on_browseButton_clicked(){
|
void on_browseButton_clicked(){
|
||||||
QString dir;
|
QString dir;
|
||||||
const QString &save_path = misc::expandPath(savePathTxt->text());
|
QString save_path = savePathTxt->text();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
save_path = save_path.replace("\\", "/");
|
||||||
|
#endif
|
||||||
|
save_path = misc::expandPath(save_path);
|
||||||
const QDir &saveDir(save_path);
|
const QDir &saveDir(save_path);
|
||||||
if(!save_path.isEmpty() && saveDir.exists()){
|
if(!save_path.isEmpty() && saveDir.exists()){
|
||||||
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath());
|
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), saveDir.absolutePath());
|
||||||
|
@ -429,6 +437,9 @@ public slots:
|
||||||
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath());
|
dir = QFileDialog::getExistingDirectory(this, tr("Choose save path"), QDir::homePath());
|
||||||
}
|
}
|
||||||
if(!dir.isNull()){
|
if(!dir.isNull()){
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
dir = dir.replace("/", "\\");
|
||||||
|
#endif
|
||||||
savePathTxt->setText(dir);
|
savePathTxt->setText(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,7 +463,11 @@ public slots:
|
||||||
QMessageBox::critical(0, tr("Empty save path"), tr("Please enter a save path"));
|
QMessageBox::critical(0, tr("Empty save path"), tr("Please enter a save path"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QDir savePath(misc::expandPath(savePathTxt->text()));
|
QString save_path = savePathTxt->text();
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
save_path = save_path.replace("\\", "/");
|
||||||
|
#endif
|
||||||
|
QDir savePath(misc::expandPath(save_path));
|
||||||
// Check if savePath exists
|
// Check if savePath exists
|
||||||
if(!savePath.exists()){
|
if(!savePath.exists()){
|
||||||
if(!savePath.mkpath(savePath.path())){
|
if(!savePath.mkpath(savePath.path())){
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue