diff --git a/src/plugins/score-plugin-packagemanager/PackageManager/Presenter.cpp b/src/plugins/score-plugin-packagemanager/PackageManager/Presenter.cpp index 93dc18c97c..7dba13f9b9 100644 --- a/src/plugins/score-plugin-packagemanager/PackageManager/Presenter.cpp +++ b/src/plugins/score-plugin-packagemanager/PackageManager/Presenter.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -37,20 +38,34 @@ PluginSettingsPresenter::PluginSettingsPresenter( auto& ps_model = static_cast(model); auto& ps_view = static_cast(view); - ps_view.localView()->setModel(&ps_model.localPlugins); + ps_view.m_remoteModel = &ps_model.remotePlugins; + ps_view.m_localModel = &ps_model.localPlugins; + + QSortFilterProxyModel* localProxyModel = new QSortFilterProxyModel(this); + localProxyModel->setSourceModel(&ps_model.localPlugins); + localProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + + QSortFilterProxyModel* remoteProxyModel = new QSortFilterProxyModel(this); + remoteProxyModel->setSourceModel(&ps_model.remotePlugins); + remoteProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + + ps_view.localView()->setModel(localProxyModel); ps_view.localView()->setColumnWidth(0, 200); ps_view.localView()->setColumnWidth(1, 40); ps_view.localView()->setColumnWidth(2, 40); + ps_view.localView()->setColumnWidth(3, 300); + ps_view.localView()->setColumnWidth(4, 30); ps_view.localView()->horizontalHeader()->setStretchLastSection(true); - ps_view.remoteView()->setModel(&ps_model.remotePlugins); + ps_view.remoteView()->setModel(remoteProxyModel); ps_view.remoteView()->setColumnWidth(0, 200); - ps_view.remoteView()->setColumnWidth(1, 40); - ps_view.remoteView()->setColumnWidth(2, 40); + ps_view.remoteView()->setColumnWidth(1, 50); + ps_view.remoteView()->setColumnWidth(2, 50); + ps_view.remoteView()->setColumnWidth(3, 300); + ps_view.remoteView()->setColumnWidth(4, 30); ps_view.remoteView()->horizontalHeader()->setStretchLastSection(true); - ps_view.remoteView()->setSelectionModel(&ps_model.remoteSelection); - + // ps_view.remoteView()->setSelectionModel(&ps_model.remoteSelection); connect( &ps_model.remoteSelection, &QItemSelectionModel::currentRowChanged, this, [&](const QModelIndex& current, const QModelIndex& previous) { diff --git a/src/plugins/score-plugin-packagemanager/PackageManager/View.cpp b/src/plugins/score-plugin-packagemanager/PackageManager/View.cpp index cb826368e3..e9b35f02c5 100644 --- a/src/plugins/score-plugin-packagemanager/PackageManager/View.cpp +++ b/src/plugins/score-plugin-packagemanager/PackageManager/View.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -37,721 +38,660 @@ W_OBJECT_IMPL(PM::PluginSettingsView) namespace PM { -namespace zip_helper -{ + namespace zip_helper + { -QString get_path(const QString& str) -{ - auto idx = str.lastIndexOf('/'); - if(idx != -1) + QString get_path(const QString& str) { - return str.mid(0, idx); + auto idx = str.lastIndexOf('/'); + if(idx != -1) + { + return str.mid(0, idx); + } + return ""; } - return ""; -} - -QString slash_path(const QString& str) -{ - return {}; -} -QString relative_path(const QString& base, const QString& filename) -{ - return filename; -} + QString slash_path(const QString& str) + { + return {}; + } -QString combine_path(const QString& path, const QString& filename) -{ - return path + "/" + filename; -} + QString relative_path(const QString& base, const QString& filename) + { + return filename; + } -bool make_folder(const QString& str) -{ - QDir d; - return d.mkpath(str); -} + QString combine_path(const QString& path, const QString& filename) + { + return path + "/" + filename; + } -} + bool make_folder(const QString& str) + { + QDir d; + return d.mkpath(str); + } -PluginSettingsView::PluginSettingsView() -{ - storage = QStorageInfo( - score::AppContext().settings().getPackagesPath()); + } - m_progress->setMinimum(0); - m_progress->setMaximum(100); - m_progress->setHidden(true); + PluginSettingsView::PluginSettingsView() + { + storage = QStorageInfo( + score::AppContext().settings().getPackagesPath()); - auto grid = new QGridLayout{m_widget}; - grid->setContentsMargins(0, 0, 0, 0); - m_widget->setLayout(grid); + m_progress->setMinimum(0); + m_progress->setMaximum(100); + m_progress->setHidden(true); - auto tab_widget = new QTabWidget; - grid->addWidget(tab_widget, 0, 0); - grid->addWidget(m_progress, 1, 0); + auto grid = new QGridLayout{m_widget}; + grid->setContentsMargins(0, 0, 0, 0); + m_widget->setLayout(grid); - { - auto local_widget = new QWidget; - auto local_layout = new QVBoxLayout{local_widget}; - local_widget->setLayout(local_layout); - local_layout->addWidget(m_addonsOnSystem); + auto tab_widget = new QTabWidget; + grid->addWidget(tab_widget, 0, 0); + grid->addWidget(m_progress, 1, 0); - tab_widget->addTab(local_widget, tr("Local packages")); - } + { + auto local_widget = new QWidget; + auto local_layout = new QVBoxLayout{local_widget}; + local_widget->setLayout(local_layout); + local_layout->addWidget(m_addonsOnSystem); - { - auto remote_widget = new QWidget; - auto remote_layout = new QVBoxLayout{remote_widget}; - remote_widget->setLayout(remote_layout); - remote_layout->addWidget(m_remoteAddons); + tab_widget->addTab(local_widget, tr("Local packages")); + } - tab_widget->addTab(remote_widget, tr("Available packages")); - } + { + auto remote_widget = new QWidget; + auto remote_layout = new QVBoxLayout{remote_widget}; + remote_widget->setLayout(remote_layout); + remote_layout->addWidget(m_remoteAddons); - auto side_widget = new QWidget; - auto vlay = new QVBoxLayout{side_widget}; - grid->addWidget(side_widget, 0, 1, 2, 1); + tab_widget->addTab(remote_widget, tr("Available packages")); + } - auto categoryLabel = new QLabel("Select Kind:"); - vlay->addWidget(categoryLabel); + auto side_widget = new QWidget; + auto vlay = new QVBoxLayout{side_widget}; + grid->addWidget(side_widget, 0, 1, 2, 1); - categoryComboBox = new QComboBox(m_widget); - vlay->addWidget(categoryComboBox); - vlay->addSpacing(20); + vlay->addSpacing(20); - m_link->setToolTip(tr("Open external package link in default browser.")); - auto icon = makeIcons( + m_link->setToolTip(tr("Open external package link in default browser.")); + auto icon = makeIcons( QStringLiteral(":/icons/undock_on.png"), QStringLiteral(":/icons/undock_off.png"), - QStringLiteral(":/icons/undock_off.png")); - m_link->setIcon(icon); + QStringLiteral(":/icons/undock_off.png")); + m_link->setIcon(icon); - vlay->addWidget(m_link); + vlay->addWidget(m_link); - vlay->addSpacing(20); + vlay->addSpacing(20); - vlay->addWidget(m_uninstall); - m_install->setVisible(false); - vlay->addWidget(m_install); - vlay->addSpacing(20); + vlay->addWidget(m_uninstall); + m_install->setVisible(false); + vlay->addWidget(m_install); + vlay->addSpacing(20); - vlay->addWidget(m_update); - vlay->addWidget(m_updateAll); - vlay->addStretch(); + vlay->addWidget(m_update); + vlay->addWidget(m_updateAll); + vlay->addStretch(); - set_info(); - vlay->addWidget(m_storage); - - for(QTableView* v : {m_addonsOnSystem, m_remoteAddons}) - { - v->verticalHeader()->hide(); - v->verticalHeader()->sectionResizeMode(QHeaderView::Fixed); - v->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - v->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); - v->setSelectionBehavior(QAbstractItemView::SelectRows); - v->setEditTriggers(QAbstractItemView::NoEditTriggers); - v->setSelectionMode(QAbstractItemView::SingleSelection); - v->setShowGrid(false); - } + set_info(); + vlay->addWidget(m_storage); - connect(tab_widget, &QTabWidget::tabBarClicked, this, [this](int i) { - if(i == 1) // Remote + for(QTableView* v : {m_addonsOnSystem, m_remoteAddons}) { - m_uninstall->setVisible(false); - m_install->setVisible(true); - m_update->setVisible(false); - m_updateAll->setVisible(false); + v->verticalHeader()->hide(); + v->verticalHeader()->sectionResizeMode(QHeaderView::Fixed); + v->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + v->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + v->setSelectionBehavior(QAbstractItemView::SelectRows); + v->setEditTriggers(QAbstractItemView::NoEditTriggers); + v->setSelectionMode(QAbstractItemView::SingleSelection); + v->setShowGrid(false); + } - RemotePackagesModel* model - = static_cast(m_remoteAddons->model()); - model->clear(); + connect(tab_widget, &QTabWidget::tabBarClicked, this, [this](int i) { + if(i == 1) // Remote + { + m_uninstall->setVisible(false); + m_install->setVisible(true); + m_update->setVisible(false); + m_updateAll->setVisible(false); - m_progress->setVisible(true); - m_progress->setValue(0); + m_remoteModel->clear(); - refresh(); - updateCategoryComboBox(1); - } - else // Local - { - m_uninstall->setVisible(true); - m_install->setVisible(false); - m_update->setVisible(true); - m_updateAll->setVisible(true); - updateCategoryComboBox(0); - } - }); + m_progress->setVisible(true); + m_progress->setValue(0); - connect(m_link, &QPushButton::pressed, this, &PluginSettingsView::openLink); + refresh(); + } + else // Local + { + m_uninstall->setVisible(true); + m_install->setVisible(false); + m_update->setVisible(true); + m_updateAll->setVisible(true); + } + }); - connect(m_uninstall, &QPushButton::pressed, this, &PluginSettingsView::uninstall); + connect(m_link, &QPushButton::pressed, this, &PluginSettingsView::openLink); - connect(m_install, &QPushButton::pressed, this, &PluginSettingsView::install); + connect(m_uninstall, &QPushButton::pressed, this, &PluginSettingsView::uninstall); - connect(m_update, &QPushButton::pressed, this, &PluginSettingsView::update); + connect(m_install, &QPushButton::pressed, this, &PluginSettingsView::install); - connect(m_updateAll, &QPushButton::pressed, this, &PluginSettingsView::updateAll); + connect(m_update, &QPushButton::pressed, this, &PluginSettingsView::update); - connect(&mgr, &QNetworkAccessManager::finished, this, &PluginSettingsView::on_message); + connect(m_updateAll, &QPushButton::pressed, this, &PluginSettingsView::updateAll); - refresh(); -} + connect( + &mgr, &QNetworkAccessManager::finished, this, &PluginSettingsView::on_message); -QWidget* PluginSettingsView::getWidget() -{ - return m_widget; -} + m_addonsOnSystem->setSortingEnabled(true); -void PluginSettingsView::firstTimeLibraryDownload() -{ - const auto& lib = score::GUIAppContext().settings(); - const QString lib_folder = lib.getPackagesPath() + "/default"; - const QString lib_info = lib_folder + "/package.json"; - if(QFile file{lib_info}; !file.exists()) + m_remoteAddons->setSortingEnabled(true); + + refresh(); + } + + QWidget* PluginSettingsView::getWidget() { - auto dl = score::question( - qApp->activeWindow(), tr("Download the user library ?"), - tr("The user library has not been found. \n" - "Do you want to download it from the internet ? \n\n" - "Note: you can always download it later from : \n" - "https://github.com/ossia/score-user-library")); - - if(dl == QMessageBox::Yes) + return m_widget; + } + + void PluginSettingsView::firstTimeLibraryDownload() + { + const auto& lib = score::GUIAppContext().settings(); + const QString lib_folder = lib.getPackagesPath() + "/default"; + const QString lib_info = lib_folder + "/package.json"; + if(QFile file{lib_info}; !file.exists()) { - zdl::download_and_extract( - QUrl{"https://github.com/ossia/score-user-library/archive/master.zip"}, - lib.getPackagesPath(), - [](const auto&) mutable { - auto& lib = score::GUIAppContext().settings(); - QDir packages_dir{lib.getPackagesPath()}; - packages_dir.rename("score-user-library-master", "default"); - - lib.rescanLibrary(); - }, - [](qint64 bytesReceived, qint64 bytesTotal) { - qDebug() << (((bytesReceived / 1024.) / (bytesTotal / 1024.)) * 100) - << "% downloaded"; - }, - [] {}); + auto dl = score::question( + qApp->activeWindow(), tr("Download the user library ?"), + tr("The user library has not been found. \n" + "Do you want to download it from the internet ? \n\n" + "Note: you can always download it later from : \n" + "https://github.com/ossia/score-user-library")); + + if(dl == QMessageBox::Yes) + { + zdl::download_and_extract( + QUrl{"https://github.com/ossia/score-user-library/archive/master.zip"}, + lib.getPackagesPath(), + [](const auto&) mutable { + auto& lib = score::GUIAppContext().settings(); + QDir packages_dir{lib.getPackagesPath()}; + packages_dir.rename("score-user-library-master", "default"); + + lib.rescanLibrary(); + }, + [](qint64 bytesReceived, qint64 bytesTotal) { + qDebug() << (((bytesReceived / 1024.) / (bytesTotal / 1024.)) * 100) + << "% downloaded"; + }, + [] {}); + } + } + else + { + checkAll(); } } - else + + void PluginSettingsView::refresh() { - checkAll(); + if(qEnvironmentVariableIsSet("SCORE_SANITIZE_SKIP_CHECKS")) + return; + QNetworkRequest rqst{ + QUrl("https://raw.githubusercontent.com/ossia/score-addons/refs/heads/" + "add-ai-models/addons.json")}; + mgr.get(rqst); } -} - -void PluginSettingsView::refresh() -{ - if(qEnvironmentVariableIsSet("SCORE_SANITIZE_SKIP_CHECKS")) - return; - QNetworkRequest rqst{ - QUrl("https://raw.githubusercontent.com/ossia/score-addons/refs/heads/" - "add-ai-models/addons.json")}; - mgr.get(rqst); -} -void PluginSettingsView::handleAddonList(const QJsonObject& obj) -{ - m_progress->setVisible(true); - auto arr = obj["addons"].toArray(); - m_addonsToRetrieve = arr.size(); - int delay = 0; - for(QJsonValue elt : arr) + void PluginSettingsView::handleAddonList(const QJsonObject& obj) { - QTimer::singleShot(delay, this, [this, url = QUrl(elt.toString())] { - QNetworkRequest rqst{url}; - mgr.get(rqst); - }); - delay += 16; + m_progress->setVisible(true); + auto arr = obj["addons"].toArray(); + m_addonsToRetrieve = arr.size(); + int delay = 0; + for(QJsonValue elt : arr) + { + QTimer::singleShot(delay, this, [this, url = QUrl(elt.toString())] { + QNetworkRequest rqst{url}; + mgr.get(rqst); + }); + delay += 16; + } } -} - -void PluginSettingsView::handleAddon(const QJsonObject& obj) -{ - RemotePackagesModel* model - = static_cast(m_remoteAddons->model()); - - if(m_addonsToRetrieve == std::ssize(model->m_vec)) - reset_progress(); - else - m_progress->setValue(m_progress->value() + (100.0 / m_addonsToRetrieve)); - - auto addon = Package::fromJson(obj); - if(!addon) - return; - - auto& add = *addon; - // Load images - if(!add.smallImagePath.isEmpty()) + void PluginSettingsView::handleAddon(const QJsonObject& obj) { - // c.f. https://wiki.qt.io/Download_Data_from_URL - auto dl = new score::FileDownloader{QUrl{add.smallImagePath}}; - connect(dl, &score::FileDownloader::downloaded, this, [=](QByteArray arr) { - model->updateAddon( - add.key, [=](Package& add) { add.smallImage.loadFromData(arr); }); - dl->deleteLater(); - }); - } + if(m_addonsToRetrieve == std::ssize(m_remoteModel->m_vec)) + reset_progress(); + else + m_progress->setValue(m_progress->value() + (100.0 / m_addonsToRetrieve)); - if(!add.largeImagePath.isEmpty()) - { - // c.f. https://wiki.qt.io/Download_Data_from_URL - auto dl = new score::FileDownloader{QUrl{add.largeImagePath}}; - connect(dl, &score::FileDownloader::downloaded, this, [=](QByteArray arr) { - model->updateAddon( - add.key, [=](Package& add) { add.largeImage.loadFromData(arr); }); + auto addon = Package::fromJson(obj); + if(!addon) + return; - dl->deleteLater(); - }); - } + auto& add = *addon; - model->addAddon(std::move(add)); -} + // Load images + if(!add.smallImagePath.isEmpty()) + { + // c.f. https://wiki.qt.io/Download_Data_from_URL + auto dl = new score::FileDownloader{QUrl{add.smallImagePath}}; + connect(dl, &score::FileDownloader::downloaded, this, [=](QByteArray arr) { + m_remoteModel->updateAddon( + add.key, [=](Package& add) { add.smallImage.loadFromData(arr); }); + + dl->deleteLater(); + }); + } -void PluginSettingsView::on_message(QNetworkReply* rep) -{ - auto res = rep->readAll(); - auto json = QJsonDocument::fromJson(res).object(); + if(!add.largeImagePath.isEmpty()) + { + // c.f. https://wiki.qt.io/Download_Data_from_URL + auto dl = new score::FileDownloader{QUrl{add.largeImagePath}}; + connect(dl, &score::FileDownloader::downloaded, this, [=](QByteArray arr) { + m_remoteModel->updateAddon( + add.key, [=](Package& add) { add.largeImage.loadFromData(arr); }); + + dl->deleteLater(); + }); + } - if(json.contains("addons")) - { - handleAddonList(json); + m_remoteModel->addAddon(std::move(add)); } - else if(json.contains("name")) - { - handleAddon(json); - } - else - { - qDebug() << rep->request().url().toString() << ' ' << res; - reset_progress(); - } - rep->deleteLater(); - if(m_install->isVisible()) - updateCategoryComboBox(1); - else - updateCategoryComboBox(0); - - if(!m_firstTimeCheck) + void PluginSettingsView::on_message(QNetworkReply * rep) { - m_firstTimeCheck = true; - QTimer::singleShot(3000, this, &PluginSettingsView::firstTimeLibraryDownload); - } -} + auto res = rep->readAll(); + auto json = QJsonDocument::fromJson(res).object(); -// the install button set to visible means we are browsing -PackagesModel* PluginSettingsView::getCurrentModel() -{ - if(m_install->isVisible()) - return static_cast(m_remoteAddons->model()); - else - return static_cast(m_addonsOnSystem->model()); -} + if(json.contains("addons")) + { + handleAddonList(json); + } + else if(json.contains("name")) + { + handleAddon(json); + } + else + { + qDebug() << rep->request().url().toString() << ' ' << res; + reset_progress(); + } + rep->deleteLater(); -int PluginSettingsView::getCurrentRow(const QTableView* t = nullptr) -{ - QModelIndexList rows{}; + if(!m_firstTimeCheck) + { + m_firstTimeCheck = true; + QTimer::singleShot(3000, this, &PluginSettingsView::firstTimeLibraryDownload); + } + } - if(t) - rows = t->selectionModel()->selectedRows(0); - else + // the install button set to visible means we are browsing + PackagesModel* PluginSettingsView::getCurrentModel() { if(m_install->isVisible()) - rows = m_remoteAddons->selectionModel()->selectedRows(0); + return m_remoteModel; else - rows = m_addonsOnSystem->selectionModel()->selectedRows(0); + return m_localModel; } - if(rows.isEmpty()) - return -1; - - return rows.first().row(); -} - -Package PluginSettingsView::selectedPackage(const PackagesModel* model, int row) -{ - if(row == -1) - return {}; - - SCORE_ASSERT(int(model->addons().size()) > row); - - return model->addons().at(row); -} - -void PluginSettingsView::openLink() -{ - const auto& addon = selectedPackage(getCurrentModel(), getCurrentRow()); - - QDesktopServices::openUrl(addon.url); -} - -void PluginSettingsView::install_package(const Package& addon) -{ - if(addon.kind == "addon" || addon.kind == "nodes") - installAddon(addon); - else if(addon.kind == "sdk") - installSDK(); - else if(addon.kind == "media") - installLibrary(addon); - else if(addon.kind == "presets") - installLibrary(addon); -} + int PluginSettingsView::getCurrentRow(const QTableView* t = nullptr) + { + QModelIndexList rows{}; -void PluginSettingsView::install() -{ - const auto& addon = selectedPackage( - static_cast(m_remoteAddons->model()), - getCurrentRow(m_remoteAddons)); + if(t) + rows = t->selectionModel()->selectedRows(0); + else + { + if(m_install->isVisible()) + rows = m_remoteAddons->selectionModel()->selectedRows(0); + else + rows = m_addonsOnSystem->selectionModel()->selectedRows(0); + } - m_progress->setVisible(true); + if(rows.isEmpty()) + return -1; - install_package(addon); -} + return rows.first().row(); + } -void PluginSettingsView::uninstall() -{ - const auto& addon = selectedPackage( - static_cast(m_addonsOnSystem->model()), - getCurrentRow(m_addonsOnSystem)); + Package PluginSettingsView::selectedPackage(const PackagesModel* model, int row) + { + if(row == -1) + return {}; - bool success{false}; + SCORE_ASSERT(int(model->addons().size()) > row); - const auto& library{score::AppContext().settings()}; + return model->addons().at(row); + } - if(addon.kind == "addon" || addon.kind == "nodes" || addon.kind == "media") + void PluginSettingsView::openLink() { - success = QDir{library.getPackagesPath() + '/' + addon.raw_name}.removeRecursively(); + const auto& addon = selectedPackage(getCurrentModel(), getCurrentRow()); + + QDesktopServices::openUrl(addon.url); } - else if(addon.kind == "sdk") + + void PluginSettingsView::install_package(const Package& addon) { - success = QDir{library.getSDKPath()}.removeRecursively(); + if(addon.kind == "addon" || addon.kind == "nodes") + installAddon(addon); + else if(addon.kind == "sdk") + installSDK(); + else if(addon.kind == "media") + installLibrary(addon); + else if(addon.kind == "presets") + installLibrary(addon); } - if(success) + void PluginSettingsView::install() { - const auto& localPlugins - = static_cast(m_addonsOnSystem->model()); + const auto& addon = selectedPackage(m_remoteModel, getCurrentRow(m_remoteAddons)); - localPlugins->removeAddon(addon); - set_info(); + m_progress->setVisible(true); + + install_package(addon); } -} -void PluginSettingsView::update() -{ - auto local_model = static_cast(m_addonsOnSystem->model()); - auto remote_model = static_cast(m_remoteAddons->model()); - const auto& addon = selectedPackage(local_model, getCurrentRow(m_addonsOnSystem)); - - auto key = addon.key; - auto it = ossia::find_if( - remote_model->addons(), [&](auto& pkg) { return pkg.key == addon.key; }); - if(it == remote_model->addons().end()) + void PluginSettingsView::uninstall() { - qDebug() << "Addon " << addon.name << "not found on the server!"; - return; - } + const auto& addon = selectedPackage(m_localModel, getCurrentRow(m_addonsOnSystem)); - m_progress->setVisible(true); - install_package(*it); -} + bool success{false}; -void PluginSettingsView::checkAll() -{ - auto local_model = static_cast(m_addonsOnSystem->model()); - auto remote_model = static_cast(m_remoteAddons->model()); + const auto& library{score::AppContext().settings()}; - std::vector to_update; - for(auto& addon : local_model->addons()) - { - auto key = addon.key; - auto it = ossia::find_if( - remote_model->addons(), [&](auto& pkg) { return pkg.key == addon.key; }); - if(it == remote_model->addons().end()) + if(addon.kind == "addon" || addon.kind == "nodes" || addon.kind == "media") { - qDebug() << "Addon " << addon.name << "not found on the server!"; - continue; + success + = QDir{library.getPackagesPath() + '/' + addon.raw_name}.removeRecursively(); + } + else if(addon.kind == "sdk") + { + success = QDir{library.getSDKPath()}.removeRecursively(); } - if(it->version <= addon.version) - continue; - - to_update.push_back(&*it); - } - - if(!to_update.empty()) - { - QString s = tr("Some installed packages are out-of-date: \n"); - for(auto pkg : to_update) + if(success) { - s += tr("- %1 (version %3)\n").arg(pkg->name).arg(pkg->version); + m_localModel->removeAddon(addon); + set_info(); } - s += tr("Head to Settings > Packages to update them"); - score::information(qApp->activeWindow(), tr("Packages can be updated"), s); } -} -void PluginSettingsView::updateAll() -{ - auto local_model = static_cast(m_addonsOnSystem->model()); - auto remote_model = static_cast(m_remoteAddons->model()); - - for(auto& addon : local_model->addons()) + void PluginSettingsView::update() { + const auto& addon = selectedPackage(m_localModel, getCurrentRow(m_addonsOnSystem)); + auto key = addon.key; auto it = ossia::find_if( - remote_model->addons(), [&](auto& pkg) { return pkg.key == addon.key; }); - if(it == remote_model->addons().end()) + m_remoteModel->addons(), [&](auto& pkg) { return pkg.key == addon.key; }); + if(it == m_remoteModel->addons().end()) { qDebug() << "Addon " << addon.name << "not found on the server!"; - continue; + return; } - if(it->version <= addon.version) - continue; - m_progress->setVisible(true); install_package(*it); } -} -void PluginSettingsView::installAddon(const Package& addon) -{ - if(addon.files.empty()) + void PluginSettingsView::checkAll() { - reset_progress(); - return; + + std::vector to_update; + for(auto& addon : m_localModel->addons()) + { + auto key = addon.key; + auto it = ossia::find_if( + m_remoteModel->addons(), [&](auto& pkg) { return pkg.key == addon.key; }); + if(it == m_remoteModel->addons().end()) + { + qDebug() << "Addon " << addon.name << "not found on the server!"; + continue; + } + + if(it->version <= addon.version) + continue; + + to_update.push_back(&*it); + } + + if(!to_update.empty()) + { + QString s = tr("Some installed packages are out-of-date: \n"); + for(auto pkg : to_update) + { + s += tr("- %1 (version %3)\n").arg(pkg->name).arg(pkg->version); + } + s += tr("Head to Settings > Packages to update them"); + score::information(qApp->activeWindow(), tr("Packages can be updated"), s); + } } - const QString& installPath - = score::AppContext().settings().getPackagesPath(); - for(auto f : addon.files) - zdl::download_and_extract( - f, QDir{installPath}.absolutePath(), - [this, installPath, addon](const std::vector& res) { - reset_progress(); - if(res.empty()) - return; - // We want the extracted folder to have the name of the addon + void PluginSettingsView::updateAll() + { + for(auto& addon : m_localModel->addons()) + { + auto key = addon.key; + auto it = ossia::find_if( + m_remoteModel->addons(), [&](auto& pkg) { return pkg.key == addon.key; }); + if(it == m_remoteModel->addons().end()) { - QDir addons_dir{installPath}; - QFileInfo a_file(res[0]); - auto d = a_file.dir(); - auto old_d = d; - while(d.cdUp() && !d.isRoot()) + qDebug() << "Addon " << addon.name << "not found on the server!"; + continue; + } + + if(it->version <= addon.version) + continue; + + m_progress->setVisible(true); + install_package(*it); + } + } + + void PluginSettingsView::installAddon(const Package& addon) + { + if(addon.files.empty()) + { + reset_progress(); + return; + } + + const QString& installPath + = score::AppContext().settings().getPackagesPath(); + for(auto f : addon.files) + zdl::download_and_extract( + f, QDir{installPath}.absolutePath(), + [this, installPath, addon](const std::vector& res) { + reset_progress(); + if(res.empty()) + return; + // We want the extracted folder to have the name of the addon { - if(d == addons_dir) + QDir addons_dir{installPath}; + QFileInfo a_file(res[0]); + auto d = a_file.dir(); + auto old_d = d; + while(d.cdUp() && !d.isRoot()) { - addons_dir.rename(old_d.dirName(), addon.raw_name); - break; + if(d == addons_dir) + { + addons_dir.rename(old_d.dirName(), addon.raw_name); + break; + } + old_d = d; } - old_d = d; } - } - QMessageBox::information( - m_widget, tr("Addon downloaded"), - tr("The addon %1 has been successfully installed in :\n" - "%2\n\n" - "It will be built and enabled shortly.\nCheck the message " - "console for errors if nothing happens.") - .arg(addon.name) - .arg(QFileInfo(installPath).absoluteFilePath())); + QMessageBox::information( + m_widget, tr("Addon downloaded"), + tr("The addon %1 has been successfully installed in :\n" + "%2\n\n" + "It will be built and enabled shortly.\nCheck the message " + "console for errors if nothing happens.") + .arg(addon.name) + .arg(QFileInfo(installPath).absoluteFilePath())); }, [this](qint64 received, qint64 total) { progress_from_bytes(received, total); }, - [this, addon] { - reset_progress(); - QMessageBox::warning( - m_widget, tr("Download failed"), - tr("The package %1 could not be downloaded.").arg(addon.name)); - }); -} + [this, addon] { + reset_progress(); + QMessageBox::warning( + m_widget, tr("Download failed"), + tr("The package %1 could not be downloaded.").arg(addon.name)); + }); + } -void PluginSettingsView::installSDK() -{ - constexpr const char* platform = + void PluginSettingsView::installSDK() + { + constexpr const char* platform = #if defined(_WIN32) - "windows" + "windows" #elif defined(__APPLE__) - "mac" + "mac" #else - "linux" + "linux" #endif - ; + ; - const QString sdk_path{ - score::AppContext().settings().getSDKPath() + '/' - + SCORE_TAG_NO_V}; - QDir{}.mkpath(sdk_path); + const QString sdk_path{ + score::AppContext().settings().getSDKPath() + '/' + + SCORE_TAG_NO_V}; + QDir{}.mkpath(sdk_path); - const QUrl sdk_url - = QString("https://github.com/ossia/score/releases/download/%1/%2-sdk.zip") - .arg(SCORE_TAG) - .arg(platform); + const QUrl sdk_url + = QString("https://github.com/ossia/score/releases/download/%1/%2-sdk.zip") + .arg(SCORE_TAG) + .arg(platform); - zdl::download_and_extract( - sdk_url, QFileInfo{sdk_path}.absoluteFilePath(), - [this](const std::vector& res) { - reset_progress(); - if(res.empty()) - return; + zdl::download_and_extract( + sdk_url, QFileInfo{sdk_path}.absoluteFilePath(), + [this](const std::vector& res) { + reset_progress(); + if(res.empty()) + return; - QMessageBox::information( - m_widget, tr("SDK downloaded"), - tr("The SDK has been successfully installed in the user library.")); + QMessageBox::information( + m_widget, tr("SDK downloaded"), + tr("The SDK has been successfully installed in the user library.")); - set_info(); - }, - [this](qint64 received, qint64 total) { progress_from_bytes(received, total); }, - [this] { - reset_progress(); - QMessageBox::warning( - m_widget, tr("Download failed"), tr("The SDK could not be downloaded.")); - }); -} + set_info(); + }, + [this](qint64 received, qint64 total) { progress_from_bytes(received, total); }, + [this] { + reset_progress(); + QMessageBox::warning( + m_widget, tr("Download failed"), tr("The SDK could not be downloaded.")); + }); + } -void PluginSettingsView::installLibrary(const Package& addon) -{ - const QString destination{ - score::AppContext().settings().getPackagesPath() + "/" - + addon.raw_name}; + void PluginSettingsView::installLibrary(const Package& addon) + { + const QString destination{ + score::AppContext().settings().getPackagesPath() + "/" + + addon.raw_name}; - if(QDir dest{destination}; dest.exists()) - dest.removeRecursively(); + if(QDir dest{destination}; dest.exists()) + dest.removeRecursively(); - QDir{}.mkpath(destination); + QDir{}.mkpath(destination); - for(auto f : addon.files) - zdl::download_and_extract( - f, QFileInfo{destination}.absoluteFilePath(), - [this, addon, destination](const std::vector& res) { - on_packageInstallSuccess(addon, destination, res); + for(auto f : addon.files) + zdl::download_and_extract( + f, QFileInfo{destination}.absoluteFilePath(), + [this, addon, destination](const std::vector& res) { + on_packageInstallSuccess(addon, destination, res); }, [this](qint64 received, qint64 total) { progress_from_bytes(received, total); }, - [this, addon] { on_packageInstallFailure(addon); }); -} + [this, addon] { on_packageInstallFailure(addon); }); + } -void PluginSettingsView::on_packageInstallSuccess( - const Package& addon, const QDir& destination, const std::vector& res) -{ - reset_progress(); - if(res.empty()) - return; - - // Often zip files contain a single, empty directory. - // In that case, we move everything up a level to make the library cleaner. - QDir dir{destination}; - auto files = dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); - if(files.size() == 1) + void PluginSettingsView::on_packageInstallSuccess( + const Package& addon, const QDir& destination, const std::vector& res) { - auto child = files[0]; - QFileInfo info{dir.absoluteFilePath(child)}; - if(info.isDir()) - { - dir.rename(child, "___score_tmp___"); - QDir subdir{dir.absoluteFilePath("___score_tmp___")}; + reset_progress(); + if(res.empty()) + return; - for(auto& entry : - subdir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) + // Often zip files contain a single, empty directory. + // In that case, we move everything up a level to make the library cleaner. + QDir dir{destination}; + auto files = dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + if(files.size() == 1) + { + auto child = files[0]; + QFileInfo info{dir.absoluteFilePath(child)}; + if(info.isDir()) { - dir.rename( - QString{"___score_tmp___%1%2"}.arg(QDir::separator()).arg(entry), entry); - } + dir.rename(child, "___score_tmp___"); + QDir subdir{dir.absoluteFilePath("___score_tmp___")}; - subdir.removeRecursively(); + for(auto& entry : + subdir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) + { + dir.rename( + QString{"___score_tmp___%1%2"}.arg(QDir::separator()).arg(entry), entry); + } + + subdir.removeRecursively(); + } } - } - { - QFile f{dir.absoluteFilePath("package.json")}; - if(f.open(QIODevice::WriteOnly)) { - QJsonObject obj; - obj["name"] = addon.name; - obj["raw_name"] = addon.raw_name; - obj["version"] = addon.version; - obj["kind"] = addon.kind; - obj["url"] = addon.url; - obj["short"] = addon.shortDescription; - obj["long"] = addon.longDescription; - obj["size"] = addon.size; - // TODO images - obj["key"] = QString{score::uuids::toByteArray(addon.key.impl())}; - - f.write(QJsonDocument{obj}.toJson()); + QFile f{dir.absoluteFilePath("package.json")}; + if(f.open(QIODevice::WriteOnly)) + { + QJsonObject obj; + obj["name"] = addon.name; + obj["raw_name"] = addon.raw_name; + obj["version"] = addon.version; + obj["kind"] = addon.kind; + obj["url"] = addon.url; + obj["short"] = addon.shortDescription; + obj["long"] = addon.longDescription; + obj["size"] = addon.size; + // TODO images + obj["key"] = QString{score::uuids::toByteArray(addon.key.impl())}; + + f.write(QJsonDocument{obj}.toJson()); + } } - } - - QMessageBox::information( - m_widget, tr("Package downloaded"), - tr("The package %1 has been successfully installed in the user library.") - .arg(addon.name)); - - auto& localPlugins = *static_cast(m_addonsOnSystem->model()); - - localPlugins.registerAddon(dir.absolutePath()); - set_info(); -} - -void PluginSettingsView::on_packageInstallFailure(const Package& addon) -{ - reset_progress(); - QMessageBox::warning( - m_widget, tr("Download failed"), - tr("The package %1 could not be downloaded.").arg(addon.name)); -} - -void PluginSettingsView::set_info() -{ - m_storage->setText( - QString::number(storage.bytesAvailable() / 1024.0 / 1024.0 / 1024) + " G\n" - + tr("available on volume")); -}; - -void PluginSettingsView::reset_progress() -{ - m_progress->setHidden(true); - m_progress->setValue(0); -} - -void PluginSettingsView::progress_from_bytes(qint64 bytesReceived, qint64 bytesTotal) -{ - m_progress->setValue(((bytesReceived / 1024.) / (bytesTotal / 1024.)) * 100); -} -void PluginSettingsView::updateCategoryComboBox(int tabIndex) -{ - categoryComboBox->clear(); - categoryComboBox->addItem("All"); + QMessageBox::information( + m_widget, tr("Package downloaded"), + tr("The package %1 has been successfully installed in the user library.") + .arg(addon.name)); - PackagesModel* model = nullptr; - if(tabIndex == 0) // Local packages tab - { - model = static_cast(m_addonsOnSystem->model()); + m_localModel->registerAddon(dir.absolutePath()); + set_info(); } - else if(tabIndex == 1) // Remote packages tab + + void PluginSettingsView::on_packageInstallFailure(const Package& addon) { - model = static_cast(m_remoteAddons->model()); + reset_progress(); + QMessageBox::warning( + m_widget, tr("Download failed"), + tr("The package %1 could not be downloaded.").arg(addon.name)); } - // If the model exists, add uniqueKind - if(model) + void PluginSettingsView::set_info() { - QList uniqueKinds; + m_storage->setText( + QString::number(storage.bytesAvailable() / 1024.0 / 1024.0 / 1024) + " G\n" + + tr("available on volume")); + }; - for(const auto& addon : model->addons()) - { - if(!uniqueKinds.contains(addon.kind)) - { - uniqueKinds.append(addon.kind); - } - } + void PluginSettingsView::reset_progress() + { + m_progress->setHidden(true); + m_progress->setValue(0); + } - for(const QString& kind : uniqueKinds) - { - categoryComboBox->addItem(kind); - } + void PluginSettingsView::progress_from_bytes(qint64 bytesReceived, qint64 bytesTotal) + { + m_progress->setValue(((bytesReceived / 1024.) / (bytesTotal / 1024.)) * 100); } } -} diff --git a/src/plugins/score-plugin-packagemanager/PackageManager/View.hpp b/src/plugins/score-plugin-packagemanager/PackageManager/View.hpp index 5380885f55..f200560d4f 100644 --- a/src/plugins/score-plugin-packagemanager/PackageManager/View.hpp +++ b/src/plugins/score-plugin-packagemanager/PackageManager/View.hpp @@ -22,6 +22,8 @@ class QObject; namespace PM { class PluginSettingsPresenter; +class LocalPackagesModel; +class RemotePackagesModel; class PluginSettingsView : public score::GlobalSettingsView { W_OBJECT(PluginSettingsView) @@ -35,6 +37,9 @@ class PluginSettingsView : public score::GlobalSettingsView QWidget* getWidget() override; + RemotePackagesModel* m_remoteModel{}; + LocalPackagesModel* m_localModel{}; + private: void firstTimeLibraryDownload();