Warning, file /graphics/glaxnimate/src/gui/emoji/emoji_set_dialog.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "emoji_set_dialog.hpp" 0008 #include "ui_emoji_set_dialog.h" 0009 0010 #include <array> 0011 0012 #include <QEvent> 0013 #include <QUrl> 0014 #include <QJsonDocument> 0015 #include <QPainter> 0016 #include <QSvgRenderer> 0017 #include <QNetworkAccessManager> 0018 #include <QNetworkReply> 0019 #include <QNetworkRequest> 0020 #include <QDesktopServices> 0021 0022 #include <KLocalizedContext> 0023 0024 #include "utils/tar.hpp" 0025 #include "emoji/emoji_set.hpp" 0026 #include "glaxnimate_app.hpp" 0027 #include "emoji_dialog.hpp" 0028 0029 class glaxnimate::emoji::EmojiSetDialog::Private 0030 { 0031 public: 0032 Ui::EmojiSetDialog ui; 0033 std::vector<EmojiSet> sets; 0034 QNetworkAccessManager downloader; 0035 QString selected; 0036 0037 static const int preview_count = 6; 0038 static const int icon_size = 72; 0039 0040 enum Columns 0041 { 0042 Name, 0043 License, 0044 Preview0, 0045 Downloaded = Preview0 + preview_count, 0046 }; 0047 0048 void set_download_status(int row, const char* theme_icon, const QString& msg) 0049 { 0050 auto item_loaded = new QTableWidgetItem(); 0051 item_loaded->setIcon(QIcon::fromTheme(theme_icon)); 0052 item_loaded->setToolTip(msg); 0053 ui.emoji_set_view->setItem(row, Private::Downloaded, item_loaded); 0054 } 0055 0056 void show_preview(QIODevice* file, int row, int i) 0057 { 0058 QPixmap pix(icon_size, icon_size); 0059 pix.fill(Qt::transparent); 0060 QPainter painter(&pix); 0061 QSvgRenderer renderer(file->readAll()); 0062 renderer.render(&painter); 0063 if ( !pix.isNull() ) 0064 { 0065 auto item = new QTableWidgetItem; 0066 item->setData(Qt::DecorationRole, pix); 0067 item->setSizeHint(pix.size() + QSize(5, 5)); 0068 ui.emoji_set_view->setItem(row, Private::Preview0 + i, item); 0069 } 0070 } 0071 }; 0072 0073 glaxnimate::emoji::EmojiSetDialog::EmojiSetDialog(QWidget* parent) 0074 : QDialog(parent), d(std::make_unique<Private>()) 0075 { 0076 d->ui.setupUi(this); 0077 0078 d->ui.emoji_set_view->verticalHeader()->setVisible(false); 0079 d->ui.emoji_set_view->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); 0080 0081 d->ui.emoji_set_view->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); 0082 d->ui.emoji_set_view->verticalHeader()->setMaximumSectionSize(Private::icon_size); 0083 d->ui.emoji_set_view->verticalHeader()->setMinimumSectionSize(Private::icon_size); 0084 d->ui.emoji_set_view->verticalHeader()->setDefaultSectionSize(Private::icon_size); 0085 d->ui.emoji_set_view->setIconSize(QSize(Private::icon_size, Private::icon_size)); 0086 0087 0088 d->ui.progress_bar->setVisible(false); 0089 0090 reload_sets(); 0091 } 0092 0093 glaxnimate::emoji::EmojiSetDialog::~EmojiSetDialog() = default; 0094 0095 void glaxnimate::emoji::EmojiSetDialog::changeEvent ( QEvent* e ) 0096 { 0097 QWidget::changeEvent(e); 0098 0099 if ( e->type() == QEvent::LanguageChange) 0100 { 0101 d->ui.retranslateUi(this); 0102 } 0103 } 0104 0105 void glaxnimate::emoji::EmojiSetDialog::reload_sets() 0106 { 0107 d->ui.emoji_set_view->setRowCount(0); 0108 0109 auto sets_path = gui::GlaxnimateApp::instance()->data_file("emoji/sets.json"); 0110 if ( sets_path.isEmpty() ) 0111 return; 0112 0113 QFile sets_file(sets_path); 0114 if ( !sets_file.open(QFile::ReadOnly) ) 0115 return; 0116 0117 QJsonDocument doc = QJsonDocument::fromJson(sets_file.readAll()); 0118 sets_file.close(); 0119 0120 d->sets.clear(); 0121 0122 for ( const auto& val : doc.array() ) 0123 d->sets.push_back(EmojiSet::load(val.toObject())); 0124 0125 0126 static const std::array<QString, Private::preview_count> preview_emoji = { 0127 "1f61c", // ;P 0128 "1f336", // hot pepper 0129 "1f432", // dragon face 0130 "1f1ea-1f1fa", // EU flag 0131 "1faa2", // knot 0132 "2764", // red heart 0133 }; 0134 0135 int row = 0; 0136 for ( auto& p : d->sets ) 0137 { 0138 p.path = QDir(gui::GlaxnimateApp::instance()->writable_data_path("emoji/" + p.name)); 0139 d->ui.emoji_set_view->setRowCount(row+1); 0140 d->ui.emoji_set_view->setItem(row, Private::Name, new QTableWidgetItem(p.name)); 0141 d->ui.emoji_set_view->setItem(row, Private::License, new QTableWidgetItem(p.license)); 0142 0143 for ( int i = 0; i < Private::preview_count; i++ ) 0144 { 0145 QString path = p.image_path(EmojiSetDirectory::Scalable, preview_emoji[i]); 0146 if ( p.path.exists(path) ) 0147 { 0148 QFile file(path); 0149 file.open(QIODevice::ReadOnly); 0150 d->show_preview(&file, row, i); 0151 } 0152 else 0153 { 0154 auto reply = d->downloader.get(QNetworkRequest(p.preview_url(preview_emoji[i]))); 0155 connect(reply, &QNetworkReply::finished, this, [this, row, i, reply]{ 0156 if ( reply->error() ) 0157 return; 0158 d->show_preview(reply, row, i); 0159 }); 0160 } 0161 } 0162 0163 if ( p.path.exists() ) 0164 d->set_download_status(row, "package-installed-updated", i18nc("Package install status", "Installed")); 0165 else 0166 d->set_download_status(row, "package-available", i18nc("Package install status", "Not Installed")); 0167 0168 row++; 0169 } 0170 } 0171 0172 void glaxnimate::emoji::EmojiSetDialog::download_selected() 0173 { 0174 int row = d->ui.emoji_set_view->currentRow(); 0175 if ( row < 0 || row >= int(d->sets.size()) ) 0176 return; 0177 0178 QNetworkRequest request(d->sets[row].download.url); 0179 request.setMaximumRedirectsAllowed(3); 0180 request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); 0181 auto reply = d->downloader.get(request); 0182 d->ui.progress_bar->setVisible(true); 0183 d->ui.progress_bar->setValue(0); 0184 d->ui.progress_bar->setMaximum(100); 0185 d->set_download_status(row, "package-installed-outdated", i18nc("Package install status", "Downloading")); 0186 connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 received, qint64 total){ 0187 d->ui.progress_bar->setValue(received); 0188 d->ui.progress_bar->setMaximum(total); 0189 }); 0190 connect(reply, &QNetworkReply::finished, this, [this, row, reply]{ 0191 0192 if ( reply->error() || reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200 ) 0193 { 0194 d->ui.progress_bar->setVisible(false); 0195 auto reason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); 0196 d->set_download_status(row, "package-broken", i18nc("Package install status, %1 reason", "Could not download: %1", reason)); 0197 return; 0198 } 0199 0200 QString prefix_scalable = d->sets[row].download.paths[EmojiSetDirectory::Scalable].path; 0201 QString prefix_raster = d->sets[row].download.paths[72].path; 0202 0203 QByteArray data = reply->readAll(); 0204 reply->close(); 0205 QDir output = d->sets[row].path; 0206 glaxnimate::utils::tar::TapeArchive tar(data); 0207 for ( const auto& entry : tar ) 0208 { 0209 if ( entry.path().startsWith(prefix_scalable) || entry.path().startsWith(prefix_raster) ) 0210 tar.extract(entry, output); 0211 } 0212 if ( !tar.error().isEmpty() ) 0213 d->set_download_status(row, "package-broken", tar.error()); 0214 else if ( !output.exists() ) 0215 d->set_download_status(row, "package-broken", i18nc("Package install status", "Didn't download any files")); 0216 else 0217 d->set_download_status(row, "package-installed-updated", i18nc("Package install status", "Installed")); 0218 0219 d->ui.button_add_emoji->setEnabled(d->sets[row].path.exists()); 0220 d->ui.progress_bar->setVisible(false); 0221 }); 0222 } 0223 0224 0225 void glaxnimate::emoji::EmojiSetDialog::set_selected(int row) 0226 { 0227 bool enabled = row >= 0 && row < int(d->sets.size()); 0228 d->ui.button_download->setEnabled(enabled); 0229 d->ui.button_view_website->setEnabled(enabled); 0230 d->ui.button_add_emoji->setEnabled(enabled && d->sets[row].path.exists()); 0231 } 0232 0233 void glaxnimate::emoji::EmojiSetDialog::view_website() 0234 { 0235 int row = d->ui.emoji_set_view->currentRow(); 0236 if ( row < 0 || row >= int(d->sets.size()) ) 0237 return; 0238 QDesktopServices::openUrl(d->sets[row].url); 0239 } 0240 0241 0242 void glaxnimate::emoji::EmojiSetDialog::add_emoji() 0243 { 0244 int row = d->ui.emoji_set_view->currentRow(); 0245 if ( row < 0 || row >= int(d->sets.size()) ) 0246 return; 0247 0248 d->selected.clear(); 0249 const auto& set = d->sets[row]; 0250 EmojiDialog dialog; 0251 int size = 72; 0252 if ( !set.download.paths.count(72) ) 0253 size = set.download.paths.rbegin()->first; 0254 dialog.from_emoji_set(set, size); 0255 dialog.load_emoji(EmojiDialog::Image); 0256 if ( dialog.exec() ) 0257 { 0258 d->selected = set.image_path(EmojiSetDirectory::Scalable, dialog.current_slug()); 0259 accept(); 0260 } 0261 } 0262 0263 const QString & glaxnimate::emoji::EmojiSetDialog::selected_svg() const 0264 { 0265 return d->selected; 0266 }