329 lines
8.4 KiB
C++
329 lines
8.4 KiB
C++
/*
|
|
* Copyright (C) 2022 Paul Davis <paul@linuxaudiosystems.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include <cmath>
|
|
#include <iostream>
|
|
|
|
#include <glib/gstdio.h>
|
|
|
|
#include "pbd/downloader.h"
|
|
#include "pbd/inflater.h"
|
|
#include "pbd/i18n.h"
|
|
|
|
#include <glibmm/markup.h>
|
|
|
|
#include "ardour/rc_configuration.h"
|
|
#include "ardour/library.h"
|
|
|
|
#include "gui_thread.h"
|
|
#include "library_download_dialog.h"
|
|
#include "ui_config.h"
|
|
|
|
using namespace PBD;
|
|
using namespace ARDOUR;
|
|
using std::string;
|
|
|
|
LibraryDownloadDialog::LibraryDownloadDialog ()
|
|
: ArdourDialog (_("Loop Download Manager"), true) /* modal */
|
|
, inflater(0)
|
|
{
|
|
/* pick some vaguely reasonable window size so that we do not just
|
|
* grow to show all available rows in the listview
|
|
*/
|
|
set_size_request (-1, 600);
|
|
|
|
_model = Gtk::ListStore::create (_columns);
|
|
_display.set_model (_model);
|
|
|
|
_display.append_column (_("Name"), _columns.name);
|
|
_display.append_column (_("Author"), _columns.author);
|
|
_display.append_column (_("License"), _columns.license);
|
|
_display.append_column (_("Size"), _columns.size);
|
|
|
|
append_install_column ();
|
|
append_progress_column ();
|
|
|
|
_display.set_headers_visible (true);
|
|
_display.set_hover_selection (true);
|
|
|
|
_display.signal_button_press_event().connect (sigc::mem_fun (*this, &LibraryDownloadDialog::display_button_press), false);
|
|
|
|
scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
|
|
scroller.add (_display);
|
|
|
|
Gtk::HBox* h = new Gtk::HBox;
|
|
h->set_spacing (8);
|
|
h->set_border_width (8);
|
|
h->pack_start (scroller);
|
|
|
|
get_vbox()->set_spacing (8);
|
|
get_vbox()->set_border_width (12);
|
|
get_vbox()->pack_start (*Gtk::manage (h));
|
|
|
|
_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
|
|
_display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LibraryDownloadDialog::library_selected));
|
|
|
|
description_view.set_size_request (-1, 80);
|
|
description_view.set_wrap_mode (Gtk::WRAP_WORD);
|
|
get_vbox()->pack_start (description_view, Gtk::PACK_SHRINK);
|
|
|
|
}
|
|
|
|
LibraryDownloadDialog::~LibraryDownloadDialog ()
|
|
{
|
|
delete inflater;
|
|
}
|
|
|
|
void
|
|
LibraryDownloadDialog::refill ()
|
|
{
|
|
ARDOUR::LibraryFetcher lf;
|
|
lf.get_descriptions ();
|
|
|
|
if (lf.n_descriptions()) {
|
|
_model->clear ();
|
|
}
|
|
|
|
lf.foreach_description (boost::bind (&LibraryDownloadDialog::add_library, this, _1));
|
|
}
|
|
|
|
void
|
|
LibraryDownloadDialog::on_show ()
|
|
{
|
|
ArdourDialog::on_show ();
|
|
refill ();
|
|
}
|
|
|
|
void
|
|
LibraryDownloadDialog::library_selected ()
|
|
{
|
|
if (_display.get_selection()->count_selected_rows() == 0) {
|
|
description_view.get_buffer()->set_text (string());
|
|
return;
|
|
}
|
|
|
|
Gtk::TreeModel::iterator row = _display.get_selection()->get_selected();
|
|
string txt = (*row)[_columns.description];
|
|
description_view.get_buffer()->set_text (txt);
|
|
}
|
|
|
|
void
|
|
LibraryDownloadDialog::append_progress_column ()
|
|
{
|
|
progress_renderer = new Gtk::CellRendererProgress();
|
|
progress_renderer->property_width() = 100;
|
|
Gtk::TreeViewColumn* tvc = manage (new Gtk::TreeViewColumn ("", *progress_renderer));
|
|
tvc->add_attribute (*progress_renderer, "value", _columns.progress);
|
|
_display.append_column (*tvc);
|
|
}
|
|
|
|
void
|
|
LibraryDownloadDialog::append_install_column ()
|
|
{
|
|
install_renderer = new Gtk::CellRendererText();
|
|
Gtk::TreeViewColumn* tvc = manage (new Gtk::TreeViewColumn ("", *install_renderer));
|
|
tvc->set_data (X_("index"), (void*) (intptr_t (_columns.install.index())));
|
|
tvc->add_attribute (*install_renderer, "text", _columns.install);
|
|
_display.append_column (*tvc);
|
|
}
|
|
|
|
|
|
void
|
|
LibraryDownloadDialog::add_library (ARDOUR::LibraryDescription const & ld)
|
|
{
|
|
|
|
Gtk::TreeModel::iterator i = _model->append();
|
|
(*i)[_columns.name] = ld.name();
|
|
(*i)[_columns.author] = ld.author();
|
|
(*i)[_columns.license] = ld.license();
|
|
(*i)[_columns.size] = ld.size();
|
|
(*i)[_columns.installed] = ld.installed();
|
|
(*i)[_columns.url] = ld.url();
|
|
(*i)[_columns.toplevel] = ld.toplevel_dir();
|
|
|
|
if (ld.installed()) {
|
|
(*i)[_columns.install] = string (_("Installed"));
|
|
} else {
|
|
(*i)[_columns.install] = string (_("Install"));
|
|
}
|
|
|
|
/* tooltip must be escape for pango markup
|
|
*/
|
|
|
|
(*i)[_columns.description] = Glib::Markup::escape_text (ld.description());
|
|
}
|
|
|
|
void
|
|
LibraryDownloadDialog::install (std::string const & path, Gtk::TreePath const & treepath)
|
|
{
|
|
std::string destdir = Glib::path_get_dirname (path);
|
|
|
|
inflater = new Inflater (path, destdir);
|
|
inflater->Progress.connect (install_connection, invalidator(*this), boost::bind (&LibraryDownloadDialog::install_progress, this, _1, path, treepath), gui_context());
|
|
inflater->start (); /* starts unpacking in a thread */
|
|
}
|
|
|
|
void
|
|
LibraryDownloadDialog::install_progress (float p, std::string path, Gtk::TreePath treepath)
|
|
{
|
|
Gtk::TreeModel::iterator row = _model->get_iter (treepath);
|
|
|
|
if (!inflater) {
|
|
return;
|
|
}
|
|
|
|
if (inflater->status() >= 0) {
|
|
LibraryDownloadDialog::install_finished (row, path, inflater->status());
|
|
return;
|
|
}
|
|
|
|
(*row)[_columns.progress] = (int) round (100.0 * p);
|
|
}
|
|
|
|
void
|
|
LibraryDownloadDialog::install_finished (Gtk::TreeModel::iterator row, std::string path, int status)
|
|
{
|
|
if (status == 0) {
|
|
|
|
std::string toplevel = (*row)[_columns.toplevel];
|
|
toplevel = Glib::build_filename (Glib::path_get_dirname (path), toplevel);
|
|
|
|
LibraryFetcher lf;
|
|
|
|
lf.add (toplevel);
|
|
|
|
(*row)[_columns.installed] = true;
|
|
(*row)[_columns.install] = string (_("Installed"));
|
|
(*row)[_columns.progress] = 100;
|
|
} else {
|
|
(*row)[_columns.installed] = false;
|
|
(*row)[_columns.install] = _("Install");
|
|
(*row)[_columns.progress] = 0;
|
|
}
|
|
|
|
/* Always unlink (remove) the downloaded archive */
|
|
|
|
::g_unlink (path.c_str());
|
|
|
|
/* reap thread */
|
|
|
|
install_connection.disconnect ();
|
|
delete inflater;
|
|
inflater = 0;
|
|
}
|
|
|
|
|
|
void
|
|
LibraryDownloadDialog::download (Gtk::TreePath const & path)
|
|
{
|
|
Gtk::TreeModel::iterator row = _model->get_iter (path);
|
|
std::string url = (*row)[_columns.url];
|
|
PBD::Downloader* downloader;
|
|
|
|
try {
|
|
downloader = new PBD::Downloader (url, ARDOUR::Config->get_clip_library_dir());
|
|
} catch (...) {
|
|
(*row)[_columns.install] = _("Error");
|
|
return;
|
|
}
|
|
|
|
/* setup timer callback to update progressbar */
|
|
|
|
Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &LibraryDownloadDialog::dl_timer_callback), downloader, path), 40);
|
|
|
|
(*row)[_columns.downloader] = downloader;
|
|
|
|
/* and go ... */
|
|
|
|
downloader->start ();
|
|
|
|
/* and back to the GUI event loop, though we're modal so not much is possible */
|
|
}
|
|
|
|
bool
|
|
LibraryDownloadDialog::dl_timer_callback (Downloader* dl, Gtk::TreePath treepath)
|
|
{
|
|
Gtk::TreeModel::iterator row = _model->get_iter (treepath);
|
|
|
|
/* zero status indicates still running; positive status indicates
|
|
* success; negative value indicates failure
|
|
*/
|
|
|
|
if (dl->status() == 0) {
|
|
(*row)[_columns.progress] = (int) round (dl->progress() * 100.0);
|
|
return true; /* call again */
|
|
}
|
|
|
|
(*row)[_columns.progress] = 0.;
|
|
(*row)[_columns.downloader] = 0;
|
|
|
|
if (dl->status() < 0) {
|
|
(*row)[_columns.install] = _("Install");;
|
|
} else {
|
|
(*row)[_columns.install] = _("Installing");
|
|
install (dl->download_path(), treepath);
|
|
}
|
|
|
|
delete dl;
|
|
|
|
return false; /* no more calls, done or cancelled */
|
|
}
|
|
|
|
bool
|
|
LibraryDownloadDialog::display_button_press (GdkEventButton* ev)
|
|
{
|
|
if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 1)) {
|
|
|
|
Gtk::TreeModel::Path path;
|
|
Gtk::TreeViewColumn* column;
|
|
int cellx, celly;
|
|
|
|
if (!_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
|
|
return false;
|
|
}
|
|
|
|
int col = (intptr_t) column->get_data (X_("index"));
|
|
|
|
if (col != _columns.install.index()) {
|
|
return false;
|
|
}
|
|
|
|
Gtk::TreeIter iter = _model->get_iter (path);
|
|
|
|
string cur = (*iter)[_columns.install];
|
|
if (cur == _("Install")) {
|
|
if (!(*iter)[_columns.installed]) {
|
|
(*iter)[_columns.install] = _("Cancel");
|
|
download (path);
|
|
}
|
|
} else {
|
|
Downloader* dl = (*iter)[_columns.downloader];
|
|
|
|
if (dl) {
|
|
dl->cancel ();
|
|
}
|
|
|
|
(*iter)[_columns.install] = _("Install");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|