File indexing completed on 2024-03-24 04:50:56
0001 /* AUDEX CDDA EXTRACTOR 0002 * SPDX-FileCopyrightText: Copyright (C) 2007 Marco Nelles 0003 * <https://userbase.kde.org/Audex> 0004 * 0005 * SPDX-License-Identifier: GPL-3.0-or-later 0006 */ 0007 0008 #include "cddamodel.h" 0009 #include <QRegularExpression> 0010 0011 CDDAModel::CDDAModel(QObject *parent) 0012 : QAbstractTableModel(parent) 0013 { 0014 p_cdio = nullptr; 0015 device_file.clear(); 0016 udi.clear(); 0017 0018 devices = new CDDADevices(this); 0019 if (!devices) { 0020 qDebug() << "Unable to create devices object. low mem?"; 0021 error = Error(i18n("Unable to create devices object."), 0022 i18n("This is an internal error. Check your hardware. If all okay please make bug report."), 0023 Error::ERROR, 0024 this); 0025 return; 0026 } 0027 connect(devices, SIGNAL(audioDiscDetected(const QString &)), this, SLOT(new_audio_disc_available(const QString &))); 0028 connect(devices, SIGNAL(audioDiscRemoved(const QString &)), this, SLOT(audio_disc_removed(const QString &))); 0029 0030 cddb = new KCDDB::Client(); 0031 if (!cddb) { 0032 qDebug() << "Unable to create KCDDB object. Low mem?"; 0033 error = Error(i18n("Unable to create KCDDB object."), 0034 i18n("This is an internal error. Check your hardware. If all okay please make bug report."), 0035 Error::ERROR, 0036 this); 0037 return; 0038 } 0039 connect(cddb, SIGNAL(finished(KCDDB::Result)), this, SLOT(lookup_cddb_done(KCDDB::Result))); 0040 0041 cddb_transaction_pending = false; 0042 0043 cd_info.clear(); 0044 modified = false; 0045 p_empty = true; 0046 0047 QTimer::singleShot(200, devices, SLOT(scanBus())); 0048 } 0049 0050 CDDAModel::~CDDAModel() 0051 { 0052 delete cddb; 0053 delete devices; 0054 0055 if (p_cdio) 0056 delete p_cdio; 0057 } 0058 0059 int CDDAModel::rowCount(const QModelIndex &parent) const 0060 { 0061 if (!p_cdio) 0062 return 0; 0063 return parent.isValid() ? 0 : p_cdio->numOfTracks(); 0064 } 0065 0066 int CDDAModel::columnCount(const QModelIndex &parent) const 0067 { 0068 Q_UNUSED(parent); 0069 return CDDA_MODEL_COLUMN_COUNT; 0070 } 0071 0072 QVariant CDDAModel::data(const QModelIndex &index, int role) const 0073 { 0074 if (!p_cdio) 0075 return QVariant(); 0076 0077 if (!index.isValid()) 0078 return QVariant(); 0079 0080 if ((index.row() < 0) || (index.row() >= numOfTracks())) 0081 return QVariant(); 0082 0083 if (role == Qt::TextAlignmentRole) 0084 return int(Qt::AlignLeft | Qt::AlignVCenter); 0085 0086 /*if (role == Qt::ForegroundRole) { 0087 switch (index.column()) { 0088 case CDDA_MODEL_COLUMN_ARTIST_INDEX : 0089 if (!isTrackArtistValid(index.row()+1)) return qVariantFromValue(QColor(Qt::gray)); 0090 break; 0091 case CDDA_MODEL_COLUMN_TITLE_INDEX : 0092 if (!isTrackTitleValid(index.row()+1)) return qVariantFromValue(QColor(Qt::gray)); 0093 break; 0094 } 0095 }*/ 0096 0097 if ((role == Qt::DisplayRole) || (role == Qt::CheckStateRole && index.column() == CDDA_MODEL_COLUMN_RIP_INDEX) || (role == CDDA_MODEL_INTERNAL_ROLE) 0098 || (role == Qt::EditRole)) { 0099 switch (index.column()) { 0100 case CDDA_MODEL_COLUMN_RIP_INDEX: 0101 if (role == Qt::CheckStateRole) { 0102 return isTrackInSelection(index.row() + 1) ? Qt::Checked : Qt::Unchecked; 0103 } 0104 break; 0105 case CDDA_MODEL_COLUMN_TRACK_INDEX: 0106 return index.row() + 1 + (trackOffset() > 1 ? trackOffset() : 0); 0107 case CDDA_MODEL_COLUMN_LENGTH_INDEX: 0108 if (role == CDDA_MODEL_INTERNAL_ROLE) 0109 return lengthOfTrack(index.row() + 1); 0110 else 0111 return QString("%1:%2").arg(lengthOfTrack(index.row() + 1) / 60, 2, 10, QChar('0')).arg(lengthOfTrack(index.row() + 1) % 60, 2, 10, QChar('0')); 0112 case CDDA_MODEL_COLUMN_ARTIST_INDEX: 0113 if (isAudioTrack(index.row() + 1)) { 0114 QString a = cd_info.track(index.row()).get(KCDDB::Artist).toString(); 0115 return a; 0116 } 0117 break; 0118 case CDDA_MODEL_COLUMN_TITLE_INDEX: 0119 if (isAudioTrack(index.row() + 1)) { 0120 QString t = cd_info.track(index.row()).get(KCDDB::Title).toString(); 0121 if (t.isEmpty()) 0122 return i18n("Track %1", index.row() + 1); 0123 return t; 0124 } 0125 break; 0126 default:; 0127 } 0128 } 0129 0130 return QVariant(); 0131 } 0132 0133 bool CDDAModel::setData(const QModelIndex &index, const QVariant &value, int role) 0134 { 0135 if (!p_cdio) 0136 return false; 0137 0138 if (!index.isValid()) 0139 return false; 0140 0141 if ((index.row() < 0) || (index.row() >= numOfTracks())) 0142 return false; 0143 0144 if (role == Qt::EditRole) { 0145 bool changed = false; 0146 switch (index.column()) { 0147 case CDDA_MODEL_COLUMN_ARTIST_INDEX: 0148 if (value != cd_info.track(index.row()).get(KCDDB::Artist)) { 0149 cd_info.track(index.row()).set(KCDDB::Artist, value); 0150 changed = true; 0151 } 0152 break; 0153 case CDDA_MODEL_COLUMN_TITLE_INDEX: 0154 if (value != cd_info.track(index.row()).get(KCDDB::Title)) { 0155 cd_info.track(index.row()).set(KCDDB::Title, value); 0156 changed = true; 0157 } 0158 break; 0159 default: 0160 return false; 0161 } 0162 if (changed) { 0163 Q_EMIT dataChanged(index, index); 0164 modify(); 0165 } 0166 return changed; 0167 } 0168 0169 return false; 0170 } 0171 0172 QVariant CDDAModel::headerData(int section, Qt::Orientation orientation, int role) const 0173 { 0174 Q_UNUSED(orientation); 0175 0176 if (orientation == Qt::Horizontal) { 0177 switch (role) { 0178 case Qt::DisplayRole: 0179 switch (section) { 0180 case CDDA_MODEL_COLUMN_RIP_INDEX: 0181 return CDDA_MODEL_COLUMN_RIP_LABEL; 0182 case CDDA_MODEL_COLUMN_TRACK_INDEX: 0183 return CDDA_MODEL_COLUMN_TRACK_LABEL; 0184 case CDDA_MODEL_COLUMN_LENGTH_INDEX: 0185 return CDDA_MODEL_COLUMN_LENGTH_LABEL; 0186 case CDDA_MODEL_COLUMN_ARTIST_INDEX: 0187 return CDDA_MODEL_COLUMN_ARTIST_LABEL; 0188 case CDDA_MODEL_COLUMN_TITLE_INDEX: 0189 return CDDA_MODEL_COLUMN_TITLE_LABEL; 0190 default:; 0191 } 0192 break; 0193 case Qt::TextAlignmentRole: 0194 return Qt::AlignLeft; 0195 default:; 0196 } 0197 } else if (orientation == Qt::Vertical) { 0198 if (role == Qt::DisplayRole) { 0199 return QVariant(section + 1); 0200 } 0201 } 0202 0203 return QVariant(); 0204 } 0205 0206 Qt::ItemFlags CDDAModel::flags(const QModelIndex &index) const 0207 { 0208 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; 0209 if ((index.column() == CDDA_MODEL_COLUMN_ARTIST_INDEX) || (index.column() == CDDA_MODEL_COLUMN_TITLE_INDEX)) { 0210 flags |= Qt::ItemIsEditable; 0211 } 0212 if (!isAudioTrack(index.row() + 1)) 0213 return Qt::ItemIsEnabled; 0214 return flags; 0215 } 0216 0217 void CDDAModel::setArtist(const QString &a) 0218 { 0219 if (!p_cdio) 0220 return; 0221 if (a != cd_info.get(KCDDB::Artist).toString()) { 0222 beginResetModel(); 0223 cd_info.set(KCDDB::Artist, a); 0224 modify(); 0225 endResetModel(); 0226 } 0227 } 0228 0229 const QString CDDAModel::artist() const 0230 { 0231 if (!p_cdio) 0232 return QString(); 0233 QString a = cd_info.get(KCDDB::Artist).toString(); 0234 return a; 0235 } 0236 0237 void CDDAModel::setTitle(const QString &t) 0238 { 0239 if (!p_cdio) 0240 return; 0241 if (t != cd_info.get(KCDDB::Title).toString()) { 0242 beginResetModel(); 0243 cd_info.set(KCDDB::Title, t); 0244 modify(); 0245 endResetModel(); 0246 } 0247 } 0248 0249 const QString CDDAModel::title() const 0250 { 0251 if (!p_cdio) 0252 return QString(); 0253 QString t = cd_info.get(KCDDB::Title).toString(); 0254 return t; 0255 } 0256 0257 void CDDAModel::setCategory(const QString &c) 0258 { 0259 if (!p_cdio) 0260 return; 0261 0262 QStringList validCategories; 0263 validCategories << "blues" 0264 << "classical" 0265 << "country" 0266 << "data" 0267 << "folk" 0268 << "jazz" 0269 << "misc" 0270 << "newage" 0271 << "reggae" 0272 << "rock" 0273 << "soundtrack"; 0274 if (!validCategories.contains(c)) 0275 return; 0276 0277 if (c != cd_info.get(KCDDB::Category).toString()) { 0278 beginResetModel(); 0279 cd_info.set(KCDDB::Category, c); 0280 modify(); 0281 endResetModel(); 0282 } 0283 } 0284 0285 const QString CDDAModel::category() const 0286 { 0287 if (!p_cdio) 0288 return QString(); 0289 return cd_info.get(KCDDB::Category).toString(); 0290 } 0291 0292 void CDDAModel::setGenre(const QString &g) 0293 { 0294 if (!p_cdio) 0295 return; 0296 if (g != cd_info.get(KCDDB::Genre).toString()) { 0297 beginResetModel(); 0298 cd_info.set(KCDDB::Genre, g); 0299 modify(); 0300 endResetModel(); 0301 } 0302 } 0303 0304 const QString CDDAModel::genre() const 0305 { 0306 if (!p_cdio) 0307 return QString(); 0308 return cd_info.get(KCDDB::Genre).toString(); 0309 } 0310 0311 void CDDAModel::setYear(const QString &year) 0312 { 0313 if (!p_cdio) 0314 return; 0315 if (year != cd_info.get(KCDDB::Year).toString()) { 0316 beginResetModel(); 0317 cd_info.set(KCDDB::Year, year); 0318 modify(); 0319 endResetModel(); 0320 } 0321 } 0322 0323 const QString CDDAModel::year() const 0324 { 0325 if (!p_cdio) 0326 return QString(); 0327 return cd_info.get(KCDDB::Year).toString(); 0328 } 0329 0330 void CDDAModel::setExtendedData(const QStringList &e) 0331 { 0332 if (!p_cdio) 0333 return; 0334 if (e != cd_info.get(KCDDB::Comment).toStringList()) { 0335 beginResetModel(); 0336 cd_info.set(KCDDB::Comment, e); 0337 modify(); 0338 endResetModel(); 0339 } 0340 } 0341 0342 const QStringList CDDAModel::extendedData() const 0343 { 0344 if (!p_cdio) 0345 return QStringList(); 0346 return cd_info.get(KCDDB::Comment).toStringList(); 0347 } 0348 0349 void CDDAModel::setCDNum(const int n) 0350 { 0351 if (!p_cdio) 0352 return; 0353 if (n != cd_info.get("DNO").toInt()) { 0354 beginResetModel(); 0355 cd_info.set("DNO", n); 0356 modify(); 0357 endResetModel(); 0358 } 0359 } 0360 0361 int CDDAModel::cdNum() const 0362 { 0363 if (!p_cdio) 0364 return -1; 0365 if (!isMultiCD()) 0366 return 0; 0367 return cd_info.get("DNO").toInt(); 0368 } 0369 0370 void CDDAModel::setTrackOffset(const int n) 0371 { 0372 if (!p_cdio) 0373 return; 0374 if (n != cd_info.get("DTRACKOFFSET").toInt()) { 0375 beginResetModel(); 0376 cd_info.set("DTRACKOFFSET", n); 0377 modify(); 0378 endResetModel(); 0379 } 0380 } 0381 0382 int CDDAModel::trackOffset() const 0383 { 0384 if (!p_cdio) 0385 return -1; 0386 return cd_info.get("DTRACKOFFSET").toInt(); 0387 } 0388 0389 int CDDAModel::guessMultiCD(QString &newTitle) const 0390 { 0391 if (!p_cdio) 0392 return -1; 0393 0394 QString t = cd_info.get(KCDDB::Title).toString(); 0395 static QRegularExpression rx1("[\\(|\\[]* *([c|C][d|D]|[d|D][i|I][s|S][k|c|K|C]) *[0-9]* *[\\)|\\]]* *$"); 0396 int i = t.indexOf(rx1); 0397 if (i >= 0) { 0398 QString frac = t.mid(i); 0399 static QRegularExpression rx2("(\\d+)"); 0400 auto match = rx2.match(frac); 0401 bool ok; 0402 int cdnum = match.captured(0).toInt(&ok); 0403 if (ok) { 0404 if (cdnum < 0) 0405 return -1; 0406 if (cdnum == 0) 0407 cdnum = 1; 0408 newTitle = t.left(i).trimmed(); 0409 return cdnum; 0410 } 0411 } 0412 return -1; 0413 } 0414 0415 void CDDAModel::setMultiCD(const bool multi) 0416 { 0417 if (!p_cdio) 0418 return; 0419 if (multi != cd_info.get("DMULTICD").toBool()) { 0420 beginResetModel(); 0421 cd_info.set("DMULTICD", multi); 0422 modify(); 0423 endResetModel(); 0424 } 0425 } 0426 0427 bool CDDAModel::isMultiCD() const 0428 { 0429 if (!p_cdio) 0430 return false; 0431 return cd_info.get("DMULTICD").toBool(); 0432 } 0433 0434 void CDDAModel::setCustomData(const QString &type, const QVariant &data) 0435 { 0436 if (!p_cdio) 0437 return; 0438 if (data != cd_info.get(type)) { 0439 beginResetModel(); 0440 cd_info.set(type, data); 0441 modify(); 0442 endResetModel(); 0443 } 0444 } 0445 0446 const QVariant CDDAModel::customData(const QString &type) const 0447 { 0448 if (!p_cdio) 0449 return QVariant(); 0450 return cd_info.get(type); 0451 } 0452 0453 void CDDAModel::setCustomDataPerTrack(const int n, const QString &type, const QVariant &data) 0454 { 0455 if (!p_cdio) 0456 return; 0457 if (data != cd_info.track(n).get(type)) { 0458 beginResetModel(); 0459 cd_info.track(n).set(type, data); 0460 modify(); 0461 endResetModel(); 0462 } 0463 } 0464 0465 const QVariant CDDAModel::getCustomDataPerTrack(const int n, const QString &type) 0466 { 0467 if (!p_cdio) 0468 return QVariant(); 0469 return cd_info.track(n).get(type); 0470 } 0471 0472 const QImage &CDDAModel::cover() const 0473 { 0474 return p_cover; 0475 } 0476 0477 bool CDDAModel::setCover(const QByteArray &data) 0478 { 0479 if (p_cover.load(data)) { 0480 beginResetModel(); 0481 endResetModel(); 0482 return true; 0483 } 0484 return false; 0485 } 0486 0487 bool CDDAModel::setCover(const QString &filename) 0488 { 0489 if (p_cover.load(filename)) { 0490 beginResetModel(); 0491 endResetModel(); 0492 return true; 0493 } 0494 return false; 0495 } 0496 0497 bool CDDAModel::saveCoverToFile(const QString &filename) 0498 { 0499 if (p_cover.save(filename)) { 0500 return true; 0501 } 0502 return false; 0503 } 0504 0505 bool CDDAModel::isCoverEmpty() const 0506 { 0507 return p_cover.isNull(); 0508 } 0509 0510 void CDDAModel::clearCover() 0511 { 0512 beginResetModel(); 0513 p_cover = QImage(); 0514 endResetModel(); 0515 } 0516 0517 const QString CDDAModel::coverSupportedMimeTypeList() const 0518 { 0519 QList<QByteArray> supp_list = QImageReader::supportedImageFormats(); 0520 QMap<QString, QStringList> map; 0521 QMimeDatabase db; 0522 QMimeType mime = db.mimeTypeForData(QByteArray("")); 0523 for (int i = 0; i < supp_list.count(); ++i) { 0524 map[db.mimeTypeForUrl("dummy." + QString(supp_list[i]).toLower()).comment()].append("*." + QString(supp_list[i]).toLower()); 0525 } 0526 QString result = i18n("Common image formats") + " (*.jpg *.jpeg *.png *.bmp *.tif *.tiff *.gif *.avif)"; 0527 QMap<QString, QStringList>::const_iterator i = map.constBegin(); 0528 while (i != map.constEnd()) { 0529 if (i.key() == mime.comment()) { 0530 ++i; 0531 continue; 0532 } 0533 result += ";;"; 0534 QStringList extensions = i.value(); 0535 extensions.removeDuplicates(); 0536 result += i.key() + " (" + extensions.join(" ") + ')'; 0537 ++i; 0538 } 0539 return result; 0540 } 0541 0542 bool CDDAModel::guessVarious() const 0543 { 0544 if (!p_cdio) 0545 return false; 0546 QString a; 0547 for (int i = 0; i < cd_info.numberOfTracks(); ++i) { 0548 if ((i > 0) && (cd_info.track(i).get(KCDDB::Artist).toString().toLower() != a.toLower())) 0549 return true; 0550 a = cd_info.track(i).get(KCDDB::Artist).toString(); 0551 } 0552 return false; 0553 } 0554 0555 void CDDAModel::setVarious(bool various) 0556 { 0557 if (!p_cdio) 0558 return; 0559 if (various != cd_info.get("DVARIOUS").toBool()) { 0560 cd_info.set("DVARIOUS", various); 0561 modify(); 0562 } 0563 } 0564 0565 bool CDDAModel::isVarious() 0566 { 0567 if (!p_cdio) 0568 return false; 0569 return cd_info.get("DVARIOUS").toBool(); 0570 } 0571 0572 void CDDAModel::swapArtistAndTitleOfTracks() 0573 { 0574 if (!p_cdio) 0575 return; 0576 0577 beginResetModel(); 0578 for (int i = 0; i < cd_info.numberOfTracks(); ++i) { 0579 QVariant tmp = cd_info.track(i).get(KCDDB::Artist); 0580 cd_info.track(i).set(KCDDB::Artist, cd_info.track(i).get(KCDDB::Title)); 0581 cd_info.track(i).set(KCDDB::Title, tmp); 0582 } 0583 modified = true; 0584 endResetModel(); 0585 Q_EMIT cddbDataModified(); 0586 } 0587 0588 void CDDAModel::swapArtistAndTitle() 0589 { 0590 if (!p_cdio) 0591 return; 0592 QVariant tmp = cd_info.get(KCDDB::Title); 0593 beginResetModel(); 0594 cd_info.set(KCDDB::Title, cd_info.get(KCDDB::Artist)); 0595 cd_info.set(KCDDB::Artist, tmp); 0596 modified = true; 0597 endResetModel(); 0598 Q_EMIT cddbDataModified(); 0599 } 0600 0601 void CDDAModel::splitTitleOfTracks(const QString ÷r) 0602 { 0603 if (!p_cdio) 0604 return; 0605 0606 beginResetModel(); 0607 for (int i = 0; i < cd_info.numberOfTracks(); ++i) { 0608 int splitPos = cd_info.track(i).get(KCDDB::Title).toString().indexOf(divider); 0609 if (splitPos >= 0) { 0610 // split 0611 QString title = cd_info.track(i).get(KCDDB::Title).toString().mid(splitPos + divider.length()); 0612 QString artist = cd_info.track(i).get(KCDDB::Title).toString().left(splitPos); 0613 cd_info.track(i).set(KCDDB::Artist, artist); 0614 cd_info.track(i).set(KCDDB::Title, title); 0615 } 0616 } 0617 modified = true; 0618 Q_EMIT cddbDataModified(); 0619 endResetModel(); 0620 } 0621 0622 void CDDAModel::capitalizeTracks() 0623 { 0624 if (!p_cdio) 0625 return; 0626 0627 beginResetModel(); 0628 for (int i = 0; i < cd_info.numberOfTracks(); ++i) { 0629 cd_info.track(i).set(KCDDB::Artist, capitalize(cd_info.track(i).get(KCDDB::Artist).toString())); 0630 cd_info.track(i).set(KCDDB::Title, capitalize(cd_info.track(i).get(KCDDB::Title).toString())); 0631 } 0632 modified = true; 0633 endResetModel(); 0634 Q_EMIT cddbDataModified(); 0635 } 0636 0637 void CDDAModel::capitalizeHeader() 0638 { 0639 if (!p_cdio) 0640 return; 0641 0642 beginResetModel(); 0643 cd_info.set(KCDDB::Artist, capitalize(cd_info.get(KCDDB::Artist).toString())); 0644 cd_info.set(KCDDB::Title, capitalize(cd_info.get(KCDDB::Title).toString())); 0645 modified = true; 0646 endResetModel(); 0647 Q_EMIT cddbDataModified(); 0648 } 0649 0650 void CDDAModel::setTitleArtistsFromHeader() 0651 { 0652 if (!p_cdio) 0653 return; 0654 0655 beginResetModel(); 0656 for (int i = 0; i < cd_info.numberOfTracks(); ++i) { 0657 cd_info.track(i).set(KCDDB::Artist, cd_info.get(KCDDB::Artist)); 0658 } 0659 modified = true; 0660 endResetModel(); 0661 Q_EMIT cddbDataModified(); 0662 } 0663 0664 int CDDAModel::numOfTracks() const 0665 { 0666 if (!p_cdio) 0667 return 0; 0668 return p_cdio->numOfTracks(); 0669 } 0670 0671 int CDDAModel::numOfAudioTracks() const 0672 { 0673 int c = 0; 0674 for (int i = 1; i <= numOfTracks(); ++i) { 0675 if (isAudioTrack(i)) 0676 ++c; 0677 } 0678 return c; 0679 } 0680 0681 int CDDAModel::numOfAudioTracksInSelection() const 0682 { 0683 return sel_tracks.count(); 0684 } 0685 0686 int CDDAModel::length() const 0687 { 0688 if (!p_cdio) 0689 return 0; 0690 return p_cdio->length(); 0691 } 0692 0693 int CDDAModel::lengthOfAudioTracks() const 0694 { 0695 int c = 0; 0696 for (int i = 1; i <= numOfTracks(); ++i) { 0697 if (isAudioTrack(i)) 0698 c += lengthOfTrack(i); 0699 } 0700 return c; 0701 } 0702 0703 int CDDAModel::lengthOfAudioTracksInSelection() const 0704 { 0705 QSet<int>::ConstIterator it(sel_tracks.begin()), end(sel_tracks.end()); 0706 int l = 0; 0707 for (; it != end; ++it) { 0708 if (isAudioTrack(*it)) 0709 l += lengthOfTrack(*it); 0710 } 0711 return l; 0712 } 0713 0714 int CDDAModel::lengthOfTrack(int n) const 0715 { 0716 if (!p_cdio) 0717 return 0; 0718 return p_cdio->lengthOfTrack(n); 0719 } 0720 0721 const QList<quint32> CDDAModel::discSignature() const 0722 { 0723 if (!p_cdio) 0724 return QList<quint32>(); 0725 return p_cdio->discSignature(); 0726 } 0727 0728 bool CDDAModel::isAudioTrack(int n) const 0729 { 0730 if (!p_cdio) 0731 return false; 0732 return p_cdio->isAudioTrack(n); 0733 } 0734 0735 void CDDAModel::clear() 0736 { 0737 beginResetModel(); 0738 cd_info.clear(); 0739 clearCover(); 0740 endResetModel(); 0741 } 0742 0743 void CDDAModel::toggle(int row) 0744 { 0745 p_toggle(row + 1); 0746 0747 Q_EMIT hasSelection(0 != sel_tracks.count()); 0748 Q_EMIT selectionChanged(sel_tracks.count()); 0749 } 0750 0751 bool CDDAModel::isTrackInSelection(int n) const 0752 { 0753 return sel_tracks.contains(n); 0754 } 0755 0756 void CDDAModel::invertSelection() 0757 { 0758 for (int i = 1; i <= numOfTracks(); ++i) { 0759 if (isAudioTrack(i)) 0760 p_toggle(i); 0761 } 0762 Q_EMIT hasSelection(0 != sel_tracks.count()); 0763 Q_EMIT selectionChanged(sel_tracks.count()); 0764 } 0765 0766 void CDDAModel::selectAll() 0767 { 0768 sel_tracks.clear(); 0769 invertSelection(); 0770 } 0771 0772 void CDDAModel::selectNone() 0773 { 0774 sel_tracks.clear(); 0775 Q_EMIT hasSelection(false); 0776 Q_EMIT selectionChanged(0); 0777 } 0778 0779 bool CDDAModel::isModified() const 0780 { 0781 return modified; 0782 } 0783 0784 void CDDAModel::confirm() 0785 { 0786 modified = false; 0787 } 0788 0789 Error CDDAModel::lastError() const 0790 { 0791 return error; 0792 } 0793 0794 void CDDAModel::lookupCDDB() 0795 { 0796 if (!p_cdio) 0797 return; 0798 0799 qDebug() << "lookupCDDB called"; 0800 0801 if (cddb_transaction_pending) { 0802 qDebug() << "CDDB transaction already in progress."; 0803 return; 0804 } 0805 cddb_transaction_pending = true; 0806 0807 Q_EMIT cddbLookupStarted(); 0808 0809 cddb->config().reparse(); 0810 cddb->setBlockingMode(false); 0811 cddb->lookup(p_cdio->discSignature()); 0812 } 0813 0814 bool CDDAModel::submitCDDB() 0815 { 0816 if (!p_cdio) 0817 return true; 0818 0819 qDebug() << "submitCDDB called"; 0820 0821 if (cddb_transaction_pending) { 0822 qDebug() << "CDDB transaction already in progress."; 0823 error = Error(i18n("CDDB transaction already in progress."), 0824 i18n("A CDDB transaction is already in progress. Please wait until it has finished and try again."), 0825 Error::ERROR, 0826 this); 0827 return false; 0828 } 0829 0830 cddb_transaction_pending = true; 0831 0832 cddb->config().reparse(); 0833 cddb->setBlockingMode(true); 0834 if (category().isEmpty()) { 0835 setCategory("rock"); 0836 } 0837 KCDDB::Result result = cddb->submit(cd_info, p_cdio->discSignature()); 0838 0839 if (result != KCDDB::Success) { 0840 switch (result) { 0841 case KCDDB::ServerError: 0842 error = Error(KCDDB::resultToString(result), 0843 i18n("There is an error with the CDDB server. Please wait or contact the administrator of the CDDB server."), 0844 Error::ERROR, 0845 this); 0846 break; 0847 case KCDDB::HostNotFound: 0848 error = Error(KCDDB::resultToString(result), 0849 i18n("Cannot find the CDDB server. Check your network. Maybe the CDDB server is offline."), 0850 Error::ERROR, 0851 this); 0852 break; 0853 case KCDDB::NoResponse: 0854 error = Error(KCDDB::resultToString(result), 0855 i18n("Please wait, maybe the server is busy, or contact the CDDB server administrator."), 0856 Error::ERROR, 0857 this); 0858 break; 0859 case KCDDB::CannotSave: 0860 error = Error(KCDDB::resultToString(result), i18n("Please contact the CDDB server administrator."), Error::ERROR, this); 0861 break; 0862 case KCDDB::InvalidCategory: 0863 error = Error(KCDDB::resultToString(result), i18n("This should not happen. Please make a bug report."), Error::ERROR, this); 0864 break; 0865 case KCDDB::UnknownError:; 0866 case KCDDB::NoRecordFound:; 0867 case KCDDB::MultipleRecordFound:; 0868 case KCDDB::Success:; 0869 default: 0870 error = Error(KCDDB::resultToString(result), i18n("Please make a bug report and contact the CDDB server administrator."), Error::ERROR, this); 0871 break; 0872 } 0873 return false; 0874 } 0875 0876 error = Error(); 0877 0878 confirm(); 0879 0880 cddb_transaction_pending = false; 0881 0882 Q_EMIT cddbDataSubmited(true); 0883 0884 return true; 0885 } 0886 0887 void CDDAModel::eject() 0888 { 0889 devices->eject(udi); 0890 } 0891 0892 void CDDAModel::new_audio_disc_available(const QString &udi) 0893 { 0894 if (p_cdio) 0895 return; 0896 0897 device_file = devices->blockDevice(udi); 0898 this->udi = udi; 0899 0900 p_cdio = new CDDACDIO(this); 0901 if (!p_cdio) { 0902 qDebug() << "Unable to create cdio class. low mem?"; 0903 error = Error(i18n("Unable to create CDIO object."), 0904 i18n("This is an internal error. Check your hardware. If all okay please make bug report."), 0905 Error::ERROR, 0906 this); 0907 return; 0908 } 0909 p_cdio->init(device_file); 0910 0911 qDebug() << "new audio disc detected (" << udi << ", " << device_file << ")"; 0912 0913 clear(); 0914 confirm(); 0915 0916 sel_tracks.clear(); 0917 for (int i = 1; i <= p_cdio->numOfTracks(); ++i) { 0918 if (isAudioTrack(i)) 0919 sel_tracks.insert(i); 0920 } 0921 0922 Q_EMIT hasSelection(0 != sel_tracks.size()); 0923 0924 Q_EMIT audioDiscDetected(); 0925 } 0926 0927 void CDDAModel::audio_disc_removed(const QString &udi) 0928 { 0929 qDebug() << "audio disc removed (" << udi << ")"; 0930 0931 device_file.clear(); 0932 this->udi.clear(); 0933 0934 if (p_cdio) 0935 delete p_cdio; 0936 p_cdio = nullptr; 0937 0938 Q_EMIT audioDiscRemoved(); 0939 } 0940 0941 void CDDAModel::disc_information_modified() 0942 { 0943 qDebug() << "disc info changed"; 0944 0945 beginResetModel(); 0946 set_default_values(); 0947 setVarious(guessVarious()); 0948 endResetModel(); 0949 } 0950 0951 void CDDAModel::lookup_cddb_done(KCDDB::Result result) 0952 { 0953 if ((result != KCDDB::Success) && (result != KCDDB::MultipleRecordFound)) { 0954 switch (result) { 0955 case KCDDB::ServerError: 0956 error = Error(KCDDB::resultToString(result), 0957 i18n("There is an error with the CDDB server. Please wait or contact the administrator of the CDDB server."), 0958 Error::ERROR, 0959 this); 0960 break; 0961 case KCDDB::HostNotFound: 0962 error = Error(KCDDB::resultToString(result), 0963 i18n("Cannot find the CDDB server. Check your network. Maybe the CDDB server is offline."), 0964 Error::ERROR, 0965 this); 0966 break; 0967 case KCDDB::NoResponse: 0968 error = Error(KCDDB::resultToString(result), 0969 i18n("Please wait, maybe the server is busy, or contact the CDDB server administrator."), 0970 Error::ERROR, 0971 this); 0972 break; 0973 case KCDDB::InvalidCategory: 0974 error = Error(KCDDB::resultToString(result), i18n("This should not happen. Please make a bug report."), Error::ERROR, this); 0975 break; 0976 case KCDDB::UnknownError: 0977 error = Error(KCDDB::resultToString(result), i18n("Please make a bug report and contact the CDDB server administrator."), Error::ERROR, this); 0978 break; 0979 case KCDDB::NoRecordFound:; 0980 case KCDDB::MultipleRecordFound:; 0981 case KCDDB::Success:; 0982 default: 0983 error = Error(KCDDB::resultToString(result), i18n("This means no data found in the CDDB database."), Error::ERROR, this); 0984 } 0985 Q_EMIT cddbLookupDone(false); 0986 return; 0987 } 0988 0989 KCDDB::CDInfo info = cddb->lookupResponse().constFirst(); 0990 if (cddb->lookupResponse().count() > 1) { 0991 KCDDB::CDInfoList cddb_info = cddb->lookupResponse(); 0992 KCDDB::CDInfoList::iterator it; 0993 QStringList list; 0994 for (it = cddb_info.begin(); it != cddb_info.end(); ++it) { 0995 list.append(QString("%1, %2, %3, %4") 0996 .arg((it->get(KCDDB::Artist).toString()), 0997 it->get(KCDDB::Title).toString(), 0998 it->get(KCDDB::Genre).toString(), 0999 it->get(KCDDB::Year).toString())); 1000 } 1001 1002 bool ok = false; 1003 // Uses a ComboBox, could use UseListViewForComboBoxItems if necessary 1004 QString res = QInputDialog::getItem(nullptr, i18n("Select CDDB Entry"), i18n("Select a CDDB entry:"), list, 0, false, &ok, {}); 1005 1006 if (ok) { 1007 // The user selected an item and pressed OK 1008 int c = 0; 1009 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) { 1010 if (*it == res) 1011 break; 1012 c++; 1013 } 1014 if (c < cddb_info.size()) 1015 info = cddb_info[c]; 1016 } else { 1017 Q_EMIT cddbLookupDone(true); 1018 return; 1019 // user pressed cancel 1020 } 1021 } 1022 1023 beginResetModel(); 1024 1025 cd_info = info; 1026 set_default_values(); 1027 setVarious(guessVarious()); 1028 if (isVarious() && QLatin1String("Various") == artist()) { 1029 setArtist(i18n("Various Artists")); 1030 } 1031 1032 QString newTitle; 1033 int cdnum = guessMultiCD(newTitle); 1034 if (cdnum > 0) { 1035 setMultiCD(true); 1036 setCDNum(cdnum); 1037 setTitle(newTitle); 1038 } 1039 endResetModel(); 1040 1041 cddb_transaction_pending = false; 1042 1043 p_empty = false; 1044 1045 Q_EMIT cddbLookupDone(true); 1046 } 1047 1048 void CDDAModel::p_toggle(const unsigned int track) 1049 { 1050 if (sel_tracks.contains(track)) { 1051 sel_tracks.remove(track); 1052 } else { 1053 sel_tracks.insert(track); 1054 } 1055 } 1056 1057 const QString CDDAModel::capitalize(const QString &s) 1058 { 1059 QStringList stringlist = s.split(' ', Qt::SkipEmptyParts); 1060 for (int i = 0; i < stringlist.count(); i++) { 1061 QString string = stringlist[i].toLower(); 1062 int j = 0; 1063 while (((string[j] == '(') || (string[j] == '[') || (string[j] == '{')) && (j < string.length())) 1064 j++; 1065 string[j] = string[j].toUpper(); 1066 stringlist[i] = string; 1067 } 1068 return stringlist.join(" "); 1069 } 1070 1071 void CDDAModel::set_default_values() 1072 { 1073 if (cd_info.get(KCDDB::Year).toString().isEmpty()) 1074 cd_info.set(KCDDB::Year, QString("%1").arg(QDate::currentDate().year())); 1075 cd_info.set("DNO", 1); 1076 cd_info.set("DTRACKOFFSET", 1); 1077 cd_info.set("DMULTICD", false); 1078 } 1079 1080 void CDDAModel::modify() 1081 { 1082 modified = true; 1083 p_empty = false; 1084 Q_EMIT cddbDataModified(); 1085 }