mirror of
https://github.com/transmission/transmission
synced 2024-12-22 07:42:37 +00:00
7ec7607bbc
Label update is made when slider changes its value, and on source change slider value is being set to a newly calculated, but not necessarily different from the previous one, value. This means that the slider change signal may not be emitted, in which case label continues to show previous text, including "No source selected", which is misleading.
333 lines
8.3 KiB
C++
333 lines
8.3 KiB
C++
// This file Copyright © Mnemosyne LLC.
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
// License text can be found in the licenses/ folder.
|
|
|
|
#include "MakeDialog.h"
|
|
|
|
#include <chrono>
|
|
#include <cmath>
|
|
#include <future>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <QDialogButtonBox>
|
|
#include <QDir>
|
|
#include <QFileInfo>
|
|
#include <QMimeData>
|
|
#include <QPushButton>
|
|
#include <QString>
|
|
#include <QTimer>
|
|
|
|
#include <libtransmission/error.h>
|
|
#include <libtransmission/makemeta.h>
|
|
#include <libtransmission/transmission.h>
|
|
|
|
#include "ColumnResizer.h"
|
|
#include "Formatter.h"
|
|
#include "Session.h"
|
|
#include "Utils.h"
|
|
|
|
#include "ui_MakeProgressDialog.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
class MakeProgressDialog : public BaseDialog
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
MakeProgressDialog(
|
|
Session& session,
|
|
tr_metainfo_builder& builder,
|
|
std::future<tr_error> future,
|
|
QString outfile,
|
|
QWidget* parent = nullptr);
|
|
|
|
private slots:
|
|
void onButtonBoxClicked(QAbstractButton* button);
|
|
void onProgress();
|
|
|
|
private:
|
|
Session& session_;
|
|
tr_metainfo_builder& builder_;
|
|
std::future<tr_error> future_;
|
|
QString const outfile_;
|
|
Ui::MakeProgressDialog ui_ = {};
|
|
QTimer timer_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
MakeProgressDialog::MakeProgressDialog(
|
|
Session& session,
|
|
tr_metainfo_builder& builder,
|
|
std::future<tr_error> future,
|
|
QString outfile,
|
|
QWidget* parent)
|
|
: BaseDialog{ parent }
|
|
, session_{ session }
|
|
, builder_{ builder }
|
|
, future_{ std::move(future) }
|
|
, outfile_{ std::move(outfile) }
|
|
{
|
|
ui_.setupUi(this);
|
|
|
|
connect(ui_.dialogButtons, &QDialogButtonBox::clicked, this, &MakeProgressDialog::onButtonBoxClicked);
|
|
|
|
connect(&timer_, &QTimer::timeout, this, &MakeProgressDialog::onProgress);
|
|
timer_.start(100);
|
|
|
|
onProgress();
|
|
}
|
|
|
|
void MakeProgressDialog::onButtonBoxClicked(QAbstractButton* button)
|
|
{
|
|
switch (ui_.dialogButtons->standardButton(button))
|
|
{
|
|
case QDialogButtonBox::Open:
|
|
session_.addNewlyCreatedTorrent(outfile_, QFileInfo{ QString::fromStdString(builder_.top()) }.dir().path());
|
|
break;
|
|
|
|
case QDialogButtonBox::Abort:
|
|
builder_.cancel_checksums();
|
|
break;
|
|
|
|
default: // QDialogButtonBox::Ok:
|
|
break;
|
|
}
|
|
|
|
close();
|
|
}
|
|
|
|
void MakeProgressDialog::onProgress()
|
|
{
|
|
auto const is_done = !future_.valid() || future_.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
|
|
|
|
if (is_done)
|
|
{
|
|
timer_.stop();
|
|
}
|
|
|
|
// progress bar
|
|
auto progress = int{ 100 }; // [0..100]
|
|
if (!is_done)
|
|
{
|
|
auto const [current, total] = builder_.checksum_status();
|
|
progress = static_cast<int>((100.0 * current) / total);
|
|
}
|
|
ui_.progressBar->setValue(progress);
|
|
|
|
// progress label
|
|
auto const top = QString::fromStdString(builder_.top());
|
|
auto const base = QFileInfo{ top }.completeBaseName();
|
|
QString str;
|
|
|
|
auto success = false;
|
|
if (!is_done)
|
|
{
|
|
str = tr("Creating \"%1\"").arg(base);
|
|
}
|
|
else
|
|
{
|
|
auto error = future_.get();
|
|
|
|
if (!error)
|
|
{
|
|
builder_.save(outfile_.toStdString(), &error);
|
|
}
|
|
|
|
if (!error)
|
|
{
|
|
str = tr("Created \"%1\"!").arg(base);
|
|
success = true;
|
|
}
|
|
else
|
|
{
|
|
auto err_msg = QString::fromUtf8(std::data(error.message()), std::size(error.message()));
|
|
str = tr("Couldn't create \"%1\": %2 (%3)").arg(base).arg(err_msg).arg(error.code());
|
|
}
|
|
}
|
|
|
|
ui_.progressLabel->setText(str);
|
|
|
|
// buttons
|
|
ui_.dialogButtons->button(QDialogButtonBox::Abort)->setEnabled(!is_done);
|
|
ui_.dialogButtons->button(QDialogButtonBox::Ok)->setEnabled(is_done);
|
|
ui_.dialogButtons->button(QDialogButtonBox::Open)->setEnabled(is_done && success);
|
|
}
|
|
|
|
#include "MakeDialog.moc"
|
|
|
|
/***
|
|
****
|
|
***/
|
|
|
|
void MakeDialog::makeTorrent()
|
|
{
|
|
if (!builder_)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// get the announce list
|
|
auto trackers = tr_announce_list();
|
|
trackers.parse(ui_.trackersEdit->toPlainText().toStdString());
|
|
builder_->set_announce_list(std::move(trackers));
|
|
|
|
// the file to create
|
|
auto const path = QString::fromStdString(builder_->top());
|
|
auto const torrent_name = QFileInfo{ path }.completeBaseName() + QStringLiteral(".torrent");
|
|
auto const outfile = QDir{ ui_.destinationButton->path() }.filePath(torrent_name);
|
|
|
|
// comment
|
|
if (ui_.commentCheck->isChecked())
|
|
{
|
|
builder_->set_comment(ui_.commentEdit->text().toStdString());
|
|
}
|
|
|
|
// source
|
|
if (ui_.sourceCheck->isChecked())
|
|
{
|
|
builder_->set_source(ui_.sourceEdit->text().toStdString());
|
|
}
|
|
|
|
builder_->set_private(ui_.privateCheck->isChecked());
|
|
|
|
// pop up the dialog
|
|
auto* dialog = new MakeProgressDialog{ session_, *builder_, builder_->make_checksums(), outfile, this };
|
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
|
dialog->open();
|
|
}
|
|
|
|
/***
|
|
****
|
|
***/
|
|
|
|
QString MakeDialog::getSource() const
|
|
{
|
|
return (ui_.sourceFileRadio->isChecked() ? ui_.sourceFileButton : ui_.sourceFolderButton)->path();
|
|
}
|
|
|
|
/***
|
|
****
|
|
***/
|
|
|
|
void MakeDialog::onSourceChanged()
|
|
{
|
|
builder_.reset();
|
|
|
|
if (auto const filename = getSource(); !filename.isEmpty())
|
|
{
|
|
builder_.emplace(filename.toStdString());
|
|
}
|
|
|
|
updatePiecesLabel();
|
|
|
|
if (builder_)
|
|
{
|
|
ui_.pieceSizeSlider->setValue(log2(builder_->piece_size()));
|
|
}
|
|
}
|
|
|
|
MakeDialog::MakeDialog(Session& session, QWidget* parent)
|
|
: BaseDialog{ parent }
|
|
, session_{ session }
|
|
{
|
|
ui_.setupUi(this);
|
|
|
|
ui_.destinationButton->setMode(PathButton::DirectoryMode);
|
|
ui_.destinationButton->setPath(QDir::homePath());
|
|
|
|
ui_.sourceFolderButton->setMode(PathButton::DirectoryMode);
|
|
ui_.sourceFileButton->setMode(PathButton::FileMode);
|
|
|
|
auto* cr = new ColumnResizer{ this };
|
|
cr->addLayout(ui_.filesSectionLayout);
|
|
cr->addLayout(ui_.propertiesSectionLayout);
|
|
cr->update();
|
|
|
|
resize(minimumSizeHint());
|
|
|
|
connect(ui_.sourceFolderRadio, &QAbstractButton::toggled, this, &MakeDialog::onSourceChanged);
|
|
connect(ui_.sourceFolderButton, &PathButton::pathChanged, this, &MakeDialog::onSourceChanged);
|
|
connect(ui_.sourceFileRadio, &QAbstractButton::toggled, this, &MakeDialog::onSourceChanged);
|
|
connect(ui_.sourceFileButton, &PathButton::pathChanged, this, &MakeDialog::onSourceChanged);
|
|
|
|
connect(ui_.dialogButtons, &QDialogButtonBox::accepted, this, &MakeDialog::makeTorrent);
|
|
connect(ui_.dialogButtons, &QDialogButtonBox::rejected, this, &MakeDialog::close);
|
|
connect(ui_.pieceSizeSlider, &QSlider::valueChanged, this, &MakeDialog::onPieceSizeUpdated);
|
|
|
|
onSourceChanged();
|
|
}
|
|
|
|
/***
|
|
****
|
|
***/
|
|
|
|
void MakeDialog::dragEnterEvent(QDragEnterEvent* event)
|
|
{
|
|
QMimeData const* mime = event->mimeData();
|
|
|
|
if (!mime->urls().isEmpty() && QFileInfo{ mime->urls().front().path() }.exists())
|
|
{
|
|
event->acceptProposedAction();
|
|
}
|
|
}
|
|
|
|
void MakeDialog::dropEvent(QDropEvent* event)
|
|
{
|
|
auto const filename = event->mimeData()->urls().front().path();
|
|
auto const file_info = QFileInfo{ filename };
|
|
|
|
if (file_info.exists())
|
|
{
|
|
if (file_info.isDir())
|
|
{
|
|
ui_.sourceFolderRadio->setChecked(true);
|
|
ui_.sourceFolderButton->setPath(filename);
|
|
}
|
|
else // it's a file
|
|
{
|
|
ui_.sourceFileRadio->setChecked(true);
|
|
ui_.sourceFileButton->setPath(filename);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MakeDialog::updatePiecesLabel()
|
|
{
|
|
QString text;
|
|
|
|
if (!builder_)
|
|
{
|
|
text = tr("<i>No source selected</i>");
|
|
ui_.pieceSizeSlider->setEnabled(false);
|
|
}
|
|
else
|
|
{
|
|
auto const files = tr("%Ln File(s)", nullptr, builder_->file_count());
|
|
auto const pieces = tr("%Ln Piece(s)", nullptr, builder_->piece_count());
|
|
text = tr("%1 in %2; %3 @ %4")
|
|
.arg(Formatter::storage_to_string(builder_->total_size()))
|
|
.arg(files)
|
|
.arg(pieces)
|
|
.arg(Formatter::memory_to_string(static_cast<uint64_t>(builder_->piece_size())));
|
|
ui_.pieceSizeSlider->setEnabled(true);
|
|
}
|
|
|
|
ui_.sourceSizeLabel->setText(text);
|
|
}
|
|
|
|
void MakeDialog::onPieceSizeUpdated(int value)
|
|
{
|
|
auto new_size = static_cast<uint64_t>(pow(2, value));
|
|
|
|
if (builder_)
|
|
{
|
|
builder_->set_piece_size(new_size);
|
|
}
|
|
|
|
updatePiecesLabel();
|
|
}
|