File indexing completed on 2025-02-23 04:34:18
0001 /** 0002 * \file serverimportdialog.cpp 0003 * Generic dialog to import from a server. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 09 Oct 2006 0008 * 0009 * Copyright (C) 2006-2024 Urs Fleisch 0010 * 0011 * This file is part of Kid3. 0012 * 0013 * Kid3 is free software; you can redistribute it and/or modify 0014 * it under the terms of the GNU General Public License as published by 0015 * the Free Software Foundation; either version 2 of the License, or 0016 * (at your option) any later version. 0017 * 0018 * Kid3 is distributed in the hope that it will be useful, 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0021 * GNU General Public License for more details. 0022 * 0023 * You should have received a copy of the GNU General Public License 0024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0025 */ 0026 0027 #include "serverimportdialog.h" 0028 #include <QLayout> 0029 #include <QPushButton> 0030 #include <QLineEdit> 0031 #include <QComboBox> 0032 #include <QCheckBox> 0033 #include <QLabel> 0034 #include <QStatusBar> 0035 #include <QVBoxLayout> 0036 #include <QHBoxLayout> 0037 #include <QListView> 0038 #include <QCoreApplication> 0039 #include "serverimporter.h" 0040 #include "serverimporterconfig.h" 0041 #include "contexthelp.h" 0042 #include "trackdata.h" 0043 0044 /** 0045 * Constructor. 0046 * 0047 * @param parent parent widget 0048 */ 0049 ServerImportDialog::ServerImportDialog(QWidget* parent) : QDialog(parent), 0050 m_serverComboBox(nullptr), m_cgiLineEdit(nullptr), m_tokenLineEdit(nullptr), 0051 m_standardTagsCheckBox(nullptr), m_additionalTagsCheckBox(nullptr), 0052 m_coverArtCheckBox(nullptr), m_source(nullptr) 0053 { 0054 setObjectName(QLatin1String("ServerImportDialog")); 0055 0056 auto vlayout = new QVBoxLayout(this); 0057 0058 auto findLayout = new QHBoxLayout; 0059 m_artistLineEdit = new QComboBox(this); 0060 m_albumLineEdit = new QComboBox(this); 0061 m_findButton = new QPushButton(tr("&Find"), this); 0062 m_artistLineEdit->setEditable(true); 0063 m_artistLineEdit->setDuplicatesEnabled(false); 0064 m_albumLineEdit->setEditable(true); 0065 m_albumLineEdit->setDuplicatesEnabled(false); 0066 m_artistLineEdit->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); 0067 m_albumLineEdit->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); 0068 findLayout->addWidget(m_artistLineEdit); 0069 findLayout->addWidget(m_albumLineEdit); 0070 findLayout->addWidget(m_findButton); 0071 connect(m_findButton, &QAbstractButton::clicked, this, &ServerImportDialog::slotFind); 0072 vlayout->addLayout(findLayout); 0073 0074 auto serverLayout = new QHBoxLayout; 0075 m_serverLabel = new QLabel(tr("&Server:"), this); 0076 m_serverComboBox = new QComboBox(this); 0077 m_serverComboBox->setEditable(true); 0078 m_cgiLabel = new QLabel(tr("C&GI Path:"), this); 0079 m_cgiLineEdit = new QLineEdit(this); 0080 serverLayout->addWidget(m_serverLabel); 0081 serverLayout->addWidget(m_serverComboBox); 0082 m_serverLabel->setBuddy(m_serverComboBox); 0083 serverLayout->addWidget(m_cgiLabel); 0084 serverLayout->addWidget(m_cgiLineEdit); 0085 m_cgiLabel->setBuddy(m_cgiLineEdit); 0086 vlayout->addLayout(serverLayout); 0087 0088 auto tokenLayout = new QHBoxLayout; 0089 m_tokenLabel = new QLabel(tr("&Token:"), this); 0090 m_tokenLineEdit = new QLineEdit(this); 0091 tokenLayout->addWidget(m_tokenLabel); 0092 tokenLayout->addWidget(m_tokenLineEdit); 0093 m_tokenLabel->setBuddy(m_tokenLineEdit); 0094 vlayout->addLayout(tokenLayout); 0095 0096 auto hlayout = new QHBoxLayout; 0097 m_standardTagsCheckBox = new QCheckBox(tr("&Standard Tags"), this); 0098 m_additionalTagsCheckBox = new QCheckBox(tr("&Additional Tags"), this); 0099 m_coverArtCheckBox = new QCheckBox(tr("C&over Art"), this); 0100 hlayout->addWidget(m_standardTagsCheckBox); 0101 hlayout->addWidget(m_additionalTagsCheckBox); 0102 hlayout->addWidget(m_coverArtCheckBox); 0103 vlayout->addLayout(hlayout); 0104 0105 m_albumListBox = new QListView(this); 0106 m_albumListBox->setEditTriggers(QAbstractItemView::NoEditTriggers); 0107 vlayout->addWidget(m_albumListBox); 0108 connect(m_albumListBox, &QAbstractItemView::activated, 0109 this, static_cast<void (ServerImportDialog::*)(const QModelIndex&)>( 0110 &ServerImportDialog::requestTrackList)); 0111 0112 auto buttonLayout = new QHBoxLayout; 0113 m_helpButton = new QPushButton(tr("&Help"), this); 0114 m_helpButton->setAutoDefault(false); 0115 m_saveButton = new QPushButton(tr("&Save Settings"), this); 0116 m_saveButton->setAutoDefault(false); 0117 auto closeButton = new QPushButton(tr("&Close"), this); 0118 closeButton->setAutoDefault(false); 0119 buttonLayout->addWidget(m_helpButton); 0120 connect(m_helpButton, &QAbstractButton::clicked, this, &ServerImportDialog::showHelp); 0121 buttonLayout->addWidget(m_saveButton); 0122 connect(m_saveButton, &QAbstractButton::clicked, this, &ServerImportDialog::saveConfig); 0123 auto hspacer = new QSpacerItem(16, 0, QSizePolicy::Expanding, 0124 QSizePolicy::Minimum); 0125 buttonLayout->addItem(hspacer); 0126 buttonLayout->addWidget(closeButton); 0127 connect(closeButton, &QAbstractButton::clicked, this, &QDialog::accept); 0128 vlayout->addLayout(buttonLayout); 0129 0130 m_statusBar = new QStatusBar(this); 0131 vlayout->addWidget(m_statusBar); 0132 showStatusMessage(tr("Ready.")); 0133 } 0134 0135 /** 0136 * Set importer to be used. 0137 * 0138 * @param source import source to use 0139 */ 0140 void ServerImportDialog::setImportSource(ServerImporter* source) 0141 { 0142 if (m_source) { 0143 disconnect(m_source, &HttpClient::progress, 0144 this, &ServerImportDialog::showStatusMessage); 0145 disconnect(m_source, &ImportClient::findFinished, 0146 this, &ServerImportDialog::slotFindFinished); 0147 disconnect(m_source, &ImportClient::albumFinished, 0148 this, &ServerImportDialog::slotAlbumFinished); 0149 } 0150 m_source = source; 0151 0152 if (m_source) { 0153 connect(m_source, &HttpClient::progress, 0154 this, &ServerImportDialog::showStatusMessage); 0155 connect(m_source, &ImportClient::findFinished, 0156 this, &ServerImportDialog::slotFindFinished); 0157 connect(m_source, &ImportClient::albumFinished, 0158 this, &ServerImportDialog::slotAlbumFinished); 0159 0160 setWindowTitle(QCoreApplication::translate("@default", m_source->name())); 0161 if (m_source->defaultServer()) { 0162 m_serverLabel->show(); 0163 m_serverComboBox->show(); 0164 if (m_source->defaultCgiPath()) { 0165 m_cgiLabel->show(); 0166 m_cgiLineEdit->show(); 0167 } else { 0168 m_cgiLabel->hide(); 0169 m_cgiLineEdit->hide(); 0170 } 0171 if (m_source->serverList()) { 0172 QStringList strList; 0173 for (const char** sl = m_source->serverList(); *sl != nullptr; ++sl) { 0174 strList += QString::fromLatin1(*sl); // clazy:exclude=reserve-candidates 0175 } 0176 m_serverComboBox->clear(); 0177 m_serverComboBox->addItems(strList); 0178 } 0179 } else { 0180 m_serverLabel->hide(); 0181 m_serverComboBox->hide(); 0182 m_cgiLabel->hide(); 0183 m_cgiLineEdit->hide(); 0184 } 0185 if (qstrcmp(m_source->name(), "Discogs") == 0) { 0186 m_tokenLabel->show(); 0187 m_tokenLineEdit->show(); 0188 } else { 0189 m_tokenLabel->hide(); 0190 m_tokenLineEdit->hide(); 0191 } 0192 if (m_source->additionalTags()) { 0193 m_standardTagsCheckBox->show(); 0194 m_additionalTagsCheckBox->show(); 0195 m_coverArtCheckBox->show(); 0196 } else { 0197 m_standardTagsCheckBox->hide(); 0198 m_additionalTagsCheckBox->hide(); 0199 m_coverArtCheckBox->hide(); 0200 } 0201 0202 m_albumListBox->setModel(m_source->getAlbumListModel()); 0203 0204 if (m_source->helpAnchor()) { 0205 m_helpButton->show(); 0206 } else { 0207 m_helpButton->hide(); 0208 } 0209 if (m_source->config()) { 0210 m_saveButton->show(); 0211 } else { 0212 m_saveButton->hide(); 0213 } 0214 0215 // Pressing Enter will trigger the Find button. 0216 m_findButton->setDefault(true); 0217 } 0218 } 0219 0220 /** 0221 * Display message in status bar. 0222 * 0223 * @param msg status message 0224 */ 0225 void ServerImportDialog::showStatusMessage(const QString& msg) 0226 { 0227 m_statusBar->showMessage(msg); 0228 } 0229 0230 /** 0231 * Get string with server and port. 0232 * 0233 * @return "servername:port". 0234 */ 0235 QString ServerImportDialog::getServer() const 0236 { 0237 if (m_serverComboBox) { 0238 QString server(m_serverComboBox->currentText()); 0239 if (server.isEmpty() && m_source) { 0240 server = QString::fromLatin1(m_source->defaultServer()); 0241 } 0242 return server; 0243 } 0244 return QString(); 0245 } 0246 0247 /** 0248 * Set string with server and port. 0249 * 0250 * @param srv "servername:port" 0251 */ 0252 void ServerImportDialog::setServer(const QString& srv) 0253 { 0254 if (m_serverComboBox) { 0255 if (int idx = m_serverComboBox->findText(srv); idx >= 0) { 0256 m_serverComboBox->setCurrentIndex(idx); 0257 } else { 0258 m_serverComboBox->addItem(srv); 0259 m_serverComboBox->setCurrentIndex(m_serverComboBox->count() - 1); 0260 } 0261 } 0262 } 0263 0264 /** 0265 * Get string with CGI path. 0266 * 0267 * @return CGI path, e.g. "/~cddb/cddb.cgi". 0268 */ 0269 QString ServerImportDialog::getCgiPath() const 0270 { 0271 if (m_cgiLineEdit) { 0272 QString cgi(m_cgiLineEdit->text()); 0273 if (cgi.isEmpty() && m_source) { 0274 cgi = QString::fromLatin1(m_source->defaultCgiPath()); 0275 } 0276 return cgi; 0277 } 0278 return QString(); 0279 } 0280 0281 /** 0282 * Set string with CGI path. 0283 * 0284 * @param cgi CGI path, e.g. "/~cddb/cddb.cgi". 0285 */ 0286 void ServerImportDialog::setCgiPath(const QString& cgi) 0287 { 0288 if (m_cgiLineEdit) { 0289 m_cgiLineEdit->setText(cgi); 0290 } 0291 } 0292 0293 /** 0294 * Get token to access API server. 0295 * @return token. 0296 */ 0297 QString ServerImportDialog::getToken() const 0298 { 0299 return m_tokenLineEdit ? m_tokenLineEdit->text() : QString(); 0300 } 0301 0302 /** 0303 * Set token to access API server. 0304 * @param token access token 0305 */ 0306 void ServerImportDialog::setToken(const QString& token) 0307 { 0308 if (m_tokenLineEdit) { 0309 m_tokenLineEdit->setText(token); 0310 } 0311 } 0312 0313 /** 0314 * Get standard tags option. 0315 * 0316 * @return true if standard tags are enabled. 0317 */ 0318 bool ServerImportDialog::getStandardTags() const 0319 { 0320 return m_standardTagsCheckBox ? 0321 m_standardTagsCheckBox->checkState() == Qt::Checked 0322 : false; 0323 } 0324 0325 /** 0326 * Set standard tags option. 0327 * 0328 * @param enable true if standard tags are enabled 0329 */ 0330 void ServerImportDialog::setStandardTags(bool enable) 0331 { 0332 if (m_standardTagsCheckBox) { 0333 m_standardTagsCheckBox->setCheckState( 0334 enable ? Qt::Checked : Qt::Unchecked); 0335 } 0336 } 0337 0338 /** 0339 * Get additional tags option. 0340 * 0341 * @return true if additional tags are enabled. 0342 */ 0343 bool ServerImportDialog::getAdditionalTags() const 0344 { 0345 return m_additionalTagsCheckBox ? 0346 m_additionalTagsCheckBox->checkState() == Qt::Checked 0347 : false; 0348 } 0349 0350 /** 0351 * Set additional tags option. 0352 * 0353 * @param enable true if additional tags are enabled 0354 */ 0355 void ServerImportDialog::setAdditionalTags(bool enable) 0356 { 0357 if (m_additionalTagsCheckBox) { 0358 m_additionalTagsCheckBox->setCheckState( 0359 enable ? Qt::Checked : Qt::Unchecked); 0360 } 0361 } 0362 0363 /** 0364 * Get cover art option. 0365 * 0366 * @return true if cover art are enabled. 0367 */ 0368 bool ServerImportDialog::getCoverArt() const 0369 { 0370 return m_coverArtCheckBox ? 0371 m_coverArtCheckBox->checkState() == Qt::Checked 0372 : false; 0373 } 0374 0375 /** 0376 * Set cover art option. 0377 * 0378 * @param enable true if cover art are enabled 0379 */ 0380 void ServerImportDialog::setCoverArt(bool enable) 0381 { 0382 if (m_coverArtCheckBox) { 0383 m_coverArtCheckBox->setCheckState( 0384 enable ? Qt::Checked : Qt::Unchecked); 0385 } 0386 } 0387 0388 /** 0389 * Get the local configuration. 0390 * 0391 * @param cfg configuration 0392 */ 0393 void ServerImportDialog::getImportSourceConfig(ServerImporterConfig* cfg) const 0394 { 0395 cfg->setServer(getServer()); 0396 cfg->setCgiPath(getCgiPath()); 0397 cfg->setStandardTags(getStandardTags()); 0398 cfg->setAdditionalTags(getAdditionalTags()); 0399 cfg->setCoverArt(getCoverArt()); 0400 cfg->setWindowGeometry(saveGeometry()); 0401 0402 if (QString token = getToken(); 0403 !token.isEmpty() || cfg->property("token").isValid()) { 0404 cfg->setProperty("token", token); 0405 } 0406 } 0407 0408 /** 0409 * Save the local settings to the configuration. 0410 */ 0411 void ServerImportDialog::saveConfig() 0412 { 0413 if (m_source && m_source->config()) { 0414 getImportSourceConfig(m_source->config()); 0415 } 0416 } 0417 0418 /** 0419 * Set a find string from artist and album information. 0420 * 0421 * @param artist artist 0422 * @param album album 0423 */ 0424 void ServerImportDialog::setArtistAlbum(const QString& artist, const QString& album) 0425 { 0426 if (m_source && m_source->config()) { 0427 ServerImporterConfig* cf = m_source->config(); 0428 setServer(cf->server()); 0429 setCgiPath(cf->cgiPath()); 0430 setStandardTags(cf->standardTags()); 0431 setAdditionalTags(cf->additionalTags()); 0432 setCoverArt(cf->coverArt()); 0433 if (!cf->windowGeometry().isEmpty()) { 0434 restoreGeometry(cf->windowGeometry()); 0435 } 0436 0437 setToken(cf->property("token").toString()); 0438 } 0439 0440 if (!(artist.isEmpty() && album.isEmpty())) { 0441 int idx = m_artistLineEdit->findText(artist); 0442 if (idx >= 0) { 0443 m_artistLineEdit->setCurrentIndex(idx); 0444 } else { 0445 m_artistLineEdit->addItem(artist); 0446 m_artistLineEdit->setCurrentIndex(m_artistLineEdit->count() - 1); 0447 } 0448 idx = m_albumLineEdit->findText(album); 0449 if (idx >= 0) { 0450 m_albumLineEdit->setCurrentIndex(idx); 0451 } else { 0452 m_albumLineEdit->addItem(album); 0453 m_albumLineEdit->setCurrentIndex(m_albumLineEdit->count() - 1); 0454 } 0455 if (QLineEdit* lineEdit = m_artistLineEdit->lineEdit()) { 0456 lineEdit->selectAll(); 0457 } 0458 m_artistLineEdit->setFocus(); 0459 } 0460 } 0461 0462 /** 0463 * Query a search for a keyword from the server. 0464 */ 0465 void ServerImportDialog::slotFind() 0466 { 0467 ServerImporterConfig cfg; 0468 getImportSourceConfig(&cfg); 0469 if (m_source) { 0470 m_source->find(&cfg, m_artistLineEdit->currentText(), 0471 m_albumLineEdit->currentText()); 0472 // Pressing Enter will activate the selected album result and no longer 0473 // the Find button. 0474 m_findButton->setDefault(false); 0475 } 0476 } 0477 0478 /** 0479 * Process finished find request. 0480 * 0481 * @param searchStr search data received 0482 */ 0483 void ServerImportDialog::slotFindFinished(const QByteArray& searchStr) 0484 { 0485 if (m_source) 0486 m_source->parseFindResults(searchStr); 0487 m_albumListBox->setFocus(); 0488 if (QItemSelectionModel* selModel = m_albumListBox->selectionModel()) { 0489 if (QAbstractItemModel* model = m_albumListBox->model()) { 0490 if (model->rowCount() > 0) { 0491 selModel->select(model->index(0, 0), 0492 QItemSelectionModel::Select | QItemSelectionModel::Rows); 0493 } 0494 } 0495 } 0496 } 0497 0498 /** 0499 * Process finished album data. 0500 * 0501 * @param albumStr album track data received 0502 */ 0503 void ServerImportDialog::slotAlbumFinished(const QByteArray& albumStr) 0504 { 0505 if (m_source) { 0506 m_source->setStandardTags(getStandardTags()); 0507 m_source->setAdditionalTags(getAdditionalTags()); 0508 m_source->setCoverArt(getCoverArt()); 0509 m_source->parseAlbumResults(albumStr); 0510 } 0511 emit trackDataUpdated(); 0512 } 0513 0514 /** 0515 * Request track list from server. 0516 * 0517 * @param category category, e.g. "release" 0518 * @param id internal ID 0519 */ 0520 void ServerImportDialog::requestTrackList(const QString& category, 0521 const QString& id) 0522 { 0523 ServerImporterConfig cfg; 0524 getImportSourceConfig(&cfg); 0525 if (m_source) 0526 m_source->getTrackList(&cfg, category, id); 0527 } 0528 0529 /** 0530 * Request track list from server. 0531 * 0532 * @param index model index of list containing an AlbumListItem 0533 */ 0534 void ServerImportDialog::requestTrackList(const QModelIndex& index) 0535 { 0536 if (m_source) { 0537 QString text, category, id; 0538 m_source->getAlbumListModel()->getItem(index.row(), text, category, id); 0539 if (!id.isEmpty()) { 0540 requestTrackList(category, id); 0541 } 0542 } 0543 } 0544 0545 /** 0546 * Show help. 0547 */ 0548 void ServerImportDialog::showHelp() 0549 { 0550 if (m_source && m_source->helpAnchor()) { 0551 ContextHelp::displayHelp(QString::fromLatin1(m_source->helpAnchor())); 0552 } 0553 }