File indexing completed on 2025-02-23 04:34:18
0001 /** 0002 * \file importdialog.cpp 0003 * Import dialog. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 17 Sep 2003 0008 * 0009 * Copyright (C) 2003-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 "importdialog.h" 0028 #include <QLayout> 0029 #include <QPushButton> 0030 #include <QToolButton> 0031 #include <QLabel> 0032 #include <QCheckBox> 0033 #include <QSpinBox> 0034 #include <QString> 0035 #include <QVBoxLayout> 0036 #include <QHBoxLayout> 0037 #include <QComboBox> 0038 #include <QLineEdit> 0039 #include <QBitArray> 0040 #include <QToolTip> 0041 #include <QTableView> 0042 #include <QHeaderView> 0043 #include <QList> 0044 #include <QGridLayout> 0045 #include <QGroupBox> 0046 #include <QDir> 0047 #include <QMenu> 0048 #include <QCoreApplication> 0049 #include "config.h" 0050 #include "importconfig.h" 0051 #include "genres.h" 0052 #include "serverimporter.h" 0053 #include "servertrackimporter.h" 0054 #include "serverimportdialog.h" 0055 #include "servertrackimportdialog.h" 0056 #include "textimportdialog.h" 0057 #include "tagimportdialog.h" 0058 #include "contexthelp.h" 0059 #include "taggedfile.h" 0060 #include "trackdata.h" 0061 #include "trackdatamodel.h" 0062 #include "frameitemdelegate.h" 0063 #include "trackdatamatcher.h" 0064 #include "iplatformtools.h" 0065 0066 namespace { 0067 0068 /** 0069 * Get list of frame types whose visibility can be changed using a context menu. 0070 * @return list of frame types of Frame::Type or 0071 * TrackDataModel::TrackProperties. 0072 */ 0073 QList<int> checkableFrameTypes() { 0074 return QList<int>() 0075 << TrackDataModel::FT_FileName << TrackDataModel::FT_FilePath; 0076 } 0077 0078 } 0079 0080 /** 0081 * Constructor. 0082 * 0083 * @param platformTools platform tools 0084 * @param parent parent widget 0085 * @param caption dialog title 0086 * @param genreModel genre model 0087 * @param trackDataModel track data to be filled with imported values, 0088 * is passed with durations of files set 0089 * @param importers server importers 0090 * @param trackImporters server track importers 0091 */ 0092 ImportDialog::ImportDialog(IPlatformTools* platformTools, 0093 QWidget* parent, const QString& caption, 0094 TrackDataModel* trackDataModel, 0095 GenreModel* genreModel, 0096 const QList<ServerImporter*>& importers, 0097 const QList<ServerTrackImporter*>& trackImporters) 0098 : QDialog(parent), m_platformTools(platformTools), 0099 m_autoStartSubDialog(-1), m_columnVisibility(0ULL), 0100 m_trackDataModel(trackDataModel), m_importers(importers), 0101 m_trackImporters(trackImporters) 0102 { 0103 setObjectName(QLatin1String("ImportDialog")); 0104 setModal(false); 0105 setWindowTitle(caption); 0106 setSizeGripEnabled(true); 0107 0108 auto vlayout = new QVBoxLayout(this); 0109 0110 m_trackDataTable = new QTableView(this); 0111 m_trackDataTable->setModel(m_trackDataModel); 0112 m_trackDataTable->resizeColumnsToContents(); 0113 m_trackDataTable->setItemDelegateForColumn( 0114 m_trackDataModel->columnForFrameType(Frame::FT_Genre), 0115 new FrameItemDelegate(genreModel, this)); 0116 m_trackDataTable->verticalHeader()->setSectionsMovable(true); 0117 m_trackDataTable->horizontalHeader()->setSectionsMovable(true); 0118 m_trackDataTable->horizontalHeader()->setContextMenuPolicy( 0119 Qt::CustomContextMenu); 0120 connect(m_trackDataTable->verticalHeader(), &QHeaderView::sectionMoved, 0121 this, &ImportDialog::moveTableRow); 0122 connect(m_trackDataTable->horizontalHeader(), 0123 &QWidget::customContextMenuRequested, 0124 this, &ImportDialog::showTableHeaderContextMenu); 0125 vlayout->addWidget(m_trackDataTable); 0126 0127 auto accuracyLayout = new QHBoxLayout; 0128 auto accuracyLabel = new QLabel(tr("Accuracy:")); 0129 accuracyLayout->addWidget(accuracyLabel); 0130 m_accuracyPercentLabel = new QLabel(QLatin1String("-")); 0131 #if QT_VERSION >= 0x050b00 0132 m_accuracyPercentLabel->setMinimumWidth( 0133 m_accuracyPercentLabel->fontMetrics().horizontalAdvance(QLatin1String("100%"))); 0134 #else 0135 m_accuracyPercentLabel->setMinimumWidth( 0136 m_accuracyPercentLabel->fontMetrics().width(QLatin1String("100%"))); 0137 #endif 0138 accuracyLayout->addWidget(m_accuracyPercentLabel); 0139 auto coverArtLabel = new QLabel(tr("Cover Art:")); 0140 accuracyLayout->addWidget(coverArtLabel); 0141 m_coverArtUrlLabel = new QLabel(QLatin1String(" -")); 0142 m_coverArtUrlLabel->setSizePolicy(QSizePolicy::Ignored, 0143 QSizePolicy::Preferred); 0144 accuracyLayout->addWidget(m_coverArtUrlLabel, 1); 0145 vlayout->addLayout(accuracyLayout); 0146 0147 auto butlayout = new QHBoxLayout; 0148 auto fileButton = new QPushButton(tr("From F&ile/Clipboard...")); 0149 fileButton->setAutoDefault(false); 0150 butlayout->addWidget(fileButton); 0151 auto tagsButton = new QPushButton(tr("From T&ags...")); 0152 tagsButton->setAutoDefault(false); 0153 butlayout->addWidget(tagsButton); 0154 auto serverButton = new QPushButton(tr("&From Server...")); 0155 serverButton->setAutoDefault(false); 0156 butlayout->addWidget(serverButton); 0157 m_serverComboBox = new QComboBox; 0158 m_serverComboBox->setEditable(false); 0159 const auto sis = m_importers; 0160 for (const ServerImporter* si : sis) { 0161 m_serverComboBox->addItem(QCoreApplication::translate("@default", si->name())); 0162 } 0163 const auto stis = m_trackImporters; 0164 for (const ServerTrackImporter* si : stis) { 0165 m_serverComboBox->addItem(QCoreApplication::translate("@default", si->name())); 0166 } 0167 butlayout->addWidget(m_serverComboBox); 0168 if (m_serverComboBox->count() == 0) { 0169 serverButton->hide(); 0170 m_serverComboBox->hide(); 0171 } 0172 auto butspacer = new QSpacerItem(16, 0, QSizePolicy::Expanding, 0173 QSizePolicy::Minimum); 0174 butlayout->addItem(butspacer); 0175 auto destLabel = new QLabel; 0176 destLabel->setText(tr("D&estination:")); 0177 butlayout->addWidget(destLabel); 0178 m_destComboBox = new QComboBox; 0179 m_destComboBox->setEditable(false); 0180 const QList<QPair<Frame::TagVersion, QString> > tagVersions = 0181 Frame::availableTagVersions(); 0182 for (auto it = tagVersions.constBegin(); it != tagVersions.constEnd(); ++it) { 0183 m_destComboBox->addItem(it->second, it->first); 0184 } 0185 destLabel->setBuddy(m_destComboBox); 0186 butlayout->addWidget(m_destComboBox); 0187 auto revertButton = new QToolButton; 0188 revertButton->setIcon( 0189 m_platformTools->iconFromTheme(QLatin1String("document-revert"))); 0190 revertButton->setToolTip(tr("Revert")); 0191 revertButton->setShortcut(QKeySequence::Undo); 0192 connect(revertButton, &QAbstractButton::clicked, 0193 this, &ImportDialog::changeTagDestination); 0194 butlayout->addWidget(revertButton); 0195 vlayout->addLayout(butlayout); 0196 0197 auto matchLayout = new QHBoxLayout; 0198 m_mismatchCheckBox = new QCheckBox( 0199 tr("Check maximum allowable time &difference (sec):")); 0200 matchLayout->addWidget(m_mismatchCheckBox); 0201 m_maxDiffSpinBox = new QSpinBox; 0202 m_maxDiffSpinBox->setMaximum(9999); 0203 matchLayout->addWidget(m_maxDiffSpinBox); 0204 auto matchSpacer = new QSpacerItem(16, 0, QSizePolicy::Expanding, 0205 QSizePolicy::Minimum); 0206 matchLayout->addItem(matchSpacer); 0207 auto matchLabel = new QLabel(tr("Match with:")); 0208 matchLayout->addWidget(matchLabel); 0209 auto lengthButton = new QPushButton(tr("&Length")); 0210 lengthButton->setAutoDefault(false); 0211 matchLayout->addWidget(lengthButton); 0212 auto trackButton = new QPushButton(tr("T&rack")); 0213 trackButton->setAutoDefault(false); 0214 matchLayout->addWidget(trackButton); 0215 auto titleButton = new QPushButton(tr("&Title")); 0216 titleButton->setAutoDefault(false); 0217 matchLayout->addWidget(titleButton); 0218 vlayout->addLayout(matchLayout); 0219 0220 connect(fileButton, &QAbstractButton::clicked, 0221 this, &ImportDialog::fromText); 0222 connect(tagsButton, &QAbstractButton::clicked, 0223 this, &ImportDialog::fromTags); 0224 connect(serverButton, &QAbstractButton::clicked, 0225 this, &ImportDialog::fromServer); 0226 connect(m_serverComboBox, static_cast<void (QComboBox::*)(int)>( 0227 &QComboBox::activated), this, &ImportDialog::fromServer); 0228 connect(lengthButton, &QAbstractButton::clicked, 0229 this, &ImportDialog::matchWithLength); 0230 connect(trackButton, &QAbstractButton::clicked, 0231 this, &ImportDialog::matchWithTrack); 0232 connect(titleButton, &QAbstractButton::clicked, 0233 this, &ImportDialog::matchWithTitle); 0234 connect(m_mismatchCheckBox, &QAbstractButton::toggled, 0235 this, &ImportDialog::showPreview); 0236 connect(m_maxDiffSpinBox, static_cast<void (QSpinBox::*)(int)>( 0237 &QSpinBox::valueChanged), this, &ImportDialog::maxDiffChanged); 0238 connect(this, &QDialog::finished, this, &ImportDialog::hideSubdialogs); 0239 0240 auto hlayout = new QHBoxLayout; 0241 auto hspacer = new QSpacerItem(16, 0, QSizePolicy::Expanding, 0242 QSizePolicy::Minimum); 0243 auto helpButton = new QPushButton(tr("&Help"), this); 0244 helpButton->setAutoDefault(false); 0245 auto saveButton = new QPushButton(tr("&Save Settings"), this); 0246 saveButton->setAutoDefault(false); 0247 auto okButton = new QPushButton(tr("&OK"), this); 0248 auto cancelButton = new QPushButton(tr("&Cancel"), this); 0249 cancelButton->setAutoDefault(false); 0250 hlayout->addWidget(helpButton); 0251 hlayout->addWidget(saveButton); 0252 hlayout->addItem(hspacer); 0253 hlayout->addWidget(okButton); 0254 hlayout->addWidget(cancelButton); 0255 connect(helpButton, &QAbstractButton::clicked, 0256 this, &ImportDialog::showHelp); 0257 connect(saveButton, &QAbstractButton::clicked, 0258 this, &ImportDialog::saveConfig); 0259 connect(okButton, &QAbstractButton::clicked, this, &QDialog::accept); 0260 connect(cancelButton, &QAbstractButton::clicked, this, &QDialog::reject); 0261 vlayout->addLayout(hlayout); 0262 } 0263 0264 /** 0265 * Destructor. 0266 */ 0267 ImportDialog::~ImportDialog() 0268 { 0269 // Must not be inline because of forwared declared QScopedPointer. 0270 } 0271 0272 /** 0273 * Import from server and preview in table. 0274 */ 0275 void ImportDialog::fromServer() 0276 { 0277 if (m_serverComboBox) 0278 displayServerImportDialog(m_serverComboBox->currentIndex()); 0279 } 0280 0281 /** 0282 * Import from text. 0283 */ 0284 void ImportDialog::fromText() 0285 { 0286 if (!m_textImportDialog) { 0287 m_textImportDialog.reset(new TextImportDialog( 0288 m_platformTools, this, m_trackDataModel)); 0289 connect(m_textImportDialog.data(), &TextImportDialog::trackDataUpdated, 0290 this, &ImportDialog::showPreview); 0291 } 0292 m_textImportDialog->clear(); 0293 m_textImportDialog->show(); 0294 } 0295 0296 /** 0297 * Import from tags. 0298 */ 0299 void ImportDialog::fromTags() 0300 { 0301 if (!m_tagImportDialog) { 0302 m_tagImportDialog.reset(new TagImportDialog(this, m_trackDataModel)); 0303 connect(m_tagImportDialog.data(), &TagImportDialog::trackDataUpdated, 0304 this, &ImportDialog::showPreview); 0305 } 0306 m_tagImportDialog->clear(); 0307 m_tagImportDialog->show(); 0308 } 0309 0310 /** 0311 * Display server import dialog. 0312 * 0313 * @param importerIdx importer index, if invalid but not negative the 0314 * MusicBrainz Fingerprint dialog is displayed 0315 */ 0316 void ImportDialog::displayServerImportDialog(int importerIdx) 0317 { 0318 if (importerIdx >= 0) { 0319 if (importerIdx < m_importers.size()) { 0320 displayServerImportDialog(m_importers.at(importerIdx)); 0321 } else if (importerIdx - m_importers.size() < m_trackImporters.size()) { 0322 displayServerTrackImportDialog( 0323 m_trackImporters.at(importerIdx - m_importers.size())); 0324 } 0325 } 0326 } 0327 0328 /** 0329 * Display server import dialog. 0330 * 0331 * @param source import source 0332 */ 0333 void ImportDialog::displayServerImportDialog(ServerImporter* source) 0334 { 0335 if (!m_serverImportDialog) { 0336 m_serverImportDialog.reset(new ServerImportDialog(this)); 0337 connect(m_serverImportDialog.data(), &ServerImportDialog::trackDataUpdated, 0338 this, &ImportDialog::showPreview); 0339 connect(m_serverImportDialog.data(), &QDialog::accepted, 0340 this, &ImportDialog::onServerImportDialogClosed); 0341 } 0342 m_serverImportDialog->setImportSource(source); 0343 m_serverImportDialog->setArtistAlbum( 0344 m_trackDataModel->trackData().getArtist(), 0345 m_trackDataModel->trackData().getAlbum()); 0346 m_serverImportDialog->show(); 0347 } 0348 0349 /** 0350 * Import from track server and preview in table. 0351 * 0352 * @param source import source 0353 */ 0354 void ImportDialog::displayServerTrackImportDialog(ServerTrackImporter* source) 0355 { 0356 if (!m_serverTrackImportDialog) { 0357 m_serverTrackImportDialog.reset(new ServerTrackImportDialog(this, m_trackDataModel)); 0358 connect(m_serverTrackImportDialog.data(), &ServerTrackImportDialog::trackDataUpdated, 0359 this, &ImportDialog::showPreview); 0360 } 0361 m_serverTrackImportDialog->setImportSource(source); 0362 m_serverTrackImportDialog->initTable(); 0363 m_serverTrackImportDialog->exec(); 0364 } 0365 0366 /** 0367 * Hide subdialogs. 0368 */ 0369 void ImportDialog::hideSubdialogs() 0370 { 0371 if (m_serverImportDialog) 0372 m_serverImportDialog->hide(); 0373 if (m_textImportDialog) 0374 m_textImportDialog->hide(); 0375 if (m_tagImportDialog) 0376 m_tagImportDialog->hide(); 0377 } 0378 0379 /** 0380 * Shows the dialog as a modeless dialog. 0381 * 0382 * @param importerIndex index of importer to use, -1 for none 0383 */ 0384 void ImportDialog::showWithSubDialog(int importerIndex) 0385 { 0386 m_autoStartSubDialog = importerIndex; 0387 0388 if (importerIndex >= 0 && importerIndex < m_serverComboBox->count()) { 0389 m_serverComboBox->setCurrentIndex(importerIndex); 0390 } 0391 0392 show(); 0393 if (m_autoStartSubDialog >= 0) { 0394 displayServerImportDialog(m_autoStartSubDialog); 0395 } 0396 } 0397 0398 /** 0399 * Clear dialog data. 0400 */ 0401 void ImportDialog::clear() 0402 { 0403 const ImportConfig& importCfg = ImportConfig::instance(); 0404 m_serverComboBox->setCurrentIndex(importCfg.importServer()); 0405 Frame::TagVersion importDest = importCfg.importDest(); 0406 int index = m_destComboBox->findData(importDest); 0407 m_destComboBox->setCurrentIndex(index); 0408 0409 if (!m_trackDataModel->trackData().isTagSupported( 0410 Frame::tagNumberFromMask(importDest))) { 0411 index = m_destComboBox->findData(Frame::TagV2); 0412 m_destComboBox->setCurrentIndex(index); 0413 changeTagDestination(); 0414 } 0415 0416 m_mismatchCheckBox->setChecked(importCfg.enableTimeDifferenceCheck()); 0417 m_maxDiffSpinBox->setValue(importCfg.maxTimeDifference()); 0418 m_columnVisibility = importCfg.importVisibleColumns(); 0419 0420 const auto frameTypes = checkableFrameTypes(); 0421 for (int frameType : frameTypes) { 0422 if (frameType < 64) { 0423 if (int column = m_trackDataModel->columnForFrameType(frameType); 0424 column != -1) { 0425 m_trackDataTable->setColumnHidden( 0426 column, (m_columnVisibility & (1ULL << frameType)) == 0ULL); 0427 } 0428 } 0429 } 0430 0431 if (!importCfg.importWindowGeometry().isEmpty()) { 0432 restoreGeometry(importCfg.importWindowGeometry()); 0433 } 0434 0435 showPreview(); 0436 } 0437 0438 /** 0439 * Show fields to import in text as preview in table. 0440 */ 0441 void ImportDialog::showPreview() 0442 { 0443 // make time difference check 0444 bool diffCheckEnable; 0445 int maxDiff; 0446 getTimeDifferenceCheck(diffCheckEnable, maxDiff); 0447 m_trackDataModel->setTimeDifferenceCheck(diffCheckEnable, maxDiff); 0448 m_trackDataTable->scrollToTop(); 0449 m_trackDataTable->resizeColumnsToContents(); 0450 m_trackDataTable->resizeRowsToContents(); 0451 0452 int accuracy = m_trackDataModel->calculateAccuracy(); 0453 m_accuracyPercentLabel->setText(accuracy >= 0 && accuracy <= 100 0454 ? QString::number(accuracy) + QLatin1Char('%') 0455 : QLatin1String("-")); 0456 QUrl coverArtUrl = m_trackDataModel->getTrackData().getCoverArtUrl(); 0457 m_coverArtUrlLabel->setText(coverArtUrl.isEmpty() ? QLatin1String("-") 0458 : coverArtUrl.toString()); 0459 } 0460 0461 /** 0462 * Called when server import dialog is closed. 0463 */ 0464 void ImportDialog::onServerImportDialogClosed() 0465 { 0466 // This is used to prevent that the import dialog is brought behind the 0467 // main window when the server import dialog is closed, which happened 0468 // with Qt 5 on Mac OS X. 0469 show(); 0470 raise(); 0471 activateWindow(); 0472 } 0473 0474 /** 0475 * Get import destination. 0476 * 0477 * @return TagV1, TagV2 or TagV2V1 for ID3v1, ID3v2 or both. 0478 */ 0479 Frame::TagVersion ImportDialog::getDestination() const 0480 { 0481 return Frame::tagVersionCast( 0482 m_destComboBox->itemData(m_destComboBox->currentIndex()).toInt()); 0483 } 0484 0485 /** 0486 * Show help. 0487 */ 0488 void ImportDialog::showHelp() 0489 { 0490 ContextHelp::displayHelp(QLatin1String("import")); 0491 } 0492 0493 /** 0494 * Save the local settings to the configuration. 0495 */ 0496 void ImportDialog::saveConfig() 0497 { 0498 ImportConfig& importCfg = ImportConfig::instance(); 0499 importCfg.setImportDest(Frame::tagVersionCast( 0500 m_destComboBox->itemData(m_destComboBox->currentIndex()).toInt())); 0501 0502 importCfg.setImportServer(m_serverComboBox->currentIndex()); 0503 bool enable; 0504 int maxDiff; 0505 getTimeDifferenceCheck(enable, maxDiff); 0506 importCfg.setEnableTimeDifferenceCheck(enable); 0507 importCfg.setMaxTimeDifference(maxDiff); 0508 importCfg.setImportVisibleColumns(m_columnVisibility); 0509 0510 importCfg.setImportWindowGeometry(saveGeometry()); 0511 } 0512 0513 /** 0514 * Get time difference check configuration. 0515 * 0516 * @param enable true if check is enabled 0517 * @param maxDiff maximum allowed time difference 0518 */ 0519 void ImportDialog::getTimeDifferenceCheck(bool& enable, int& maxDiff) const 0520 { 0521 enable = m_mismatchCheckBox->isChecked(); 0522 maxDiff = m_maxDiffSpinBox->value(); 0523 } 0524 0525 /** 0526 * Called when the maximum time difference value is changed. 0527 */ 0528 void ImportDialog::maxDiffChanged() { 0529 if (m_mismatchCheckBox->isChecked()) { 0530 showPreview(); 0531 } 0532 } 0533 0534 /** 0535 * Move a table row. 0536 * 0537 * The first parameter @a section is not used. 0538 * @param fromIndex index of position moved from 0539 * @param toIndex index of position moved to 0540 */ 0541 void ImportDialog::moveTableRow(int, int fromIndex, int toIndex) { 0542 if (auto vHeader = qobject_cast<QHeaderView*>(sender())) { 0543 // revert movement, but avoid recursion 0544 disconnect(vHeader, &QHeaderView::sectionMoved, nullptr, nullptr); 0545 vHeader->moveSection(toIndex, fromIndex); 0546 connect(vHeader, &QHeaderView::sectionMoved, 0547 this, &ImportDialog::moveTableRow); 0548 } 0549 0550 // Allow dragging multiple rows when pressing Ctrl by adding selected rows. 0551 ImportTrackDataVector trackDataVector(m_trackDataModel->getTrackData()); 0552 auto numTracks = trackDataVector.size(); 0553 0554 int diff = toIndex - fromIndex; 0555 QList<int> fromList; 0556 if (fromIndex >= 0 && fromIndex < numTracks && 0557 toIndex >= 0 && toIndex < numTracks) { 0558 fromList.append(fromIndex); 0559 } 0560 const QModelIndexList selectedRows = 0561 m_trackDataTable->selectionModel()->selectedRows(); 0562 for (const QModelIndex& index : selectedRows) { 0563 int from = index.row(); 0564 int to = from + diff; 0565 if (!fromList.contains(from) && 0566 from >= 0 && from < numTracks && 0567 to >= 0 && to < numTracks) { 0568 fromList.append(from); 0569 } 0570 } 0571 std::sort(fromList.begin(), fromList.end()); 0572 0573 for (auto it = fromList.constBegin(); it != fromList.constEnd(); ++it) { 0574 fromIndex = *it; 0575 toIndex = fromIndex + diff; 0576 // swap elements but keep file durations and names 0577 ImportTrackData fromData(trackDataVector[fromIndex]); 0578 ImportTrackData toData(trackDataVector[toIndex]); 0579 trackDataVector[fromIndex].setFrameCollection(toData.getFrameCollection()); 0580 trackDataVector[toIndex].setFrameCollection(fromData.getFrameCollection()); 0581 trackDataVector[fromIndex].setImportDuration(toData.getImportDuration()); 0582 trackDataVector[toIndex].setImportDuration(fromData.getImportDuration()); 0583 } 0584 if (!fromList.isEmpty()) { 0585 m_trackDataModel->setTrackData(trackDataVector); 0586 // redisplay the table 0587 showPreview(); 0588 } 0589 } 0590 0591 /** 0592 * Called when the destination combo box value is changed. 0593 */ 0594 void ImportDialog::changeTagDestination() 0595 { 0596 ImportTrackDataVector trackDataVector(m_trackDataModel->getTrackData()); 0597 trackDataVector.readTags(getDestination()); 0598 m_trackDataModel->setTrackData(trackDataVector); 0599 showPreview(); 0600 } 0601 0602 /** 0603 * Match import data with length. 0604 */ 0605 void ImportDialog::matchWithLength() 0606 { 0607 bool diffCheckEnable; 0608 int maxDiff; 0609 getTimeDifferenceCheck(diffCheckEnable, maxDiff); 0610 if (TrackDataMatcher::matchWithLength(m_trackDataModel, diffCheckEnable, maxDiff)) 0611 showPreview(); 0612 } 0613 0614 /** 0615 * Match import data with track number. 0616 */ 0617 void ImportDialog::matchWithTrack() 0618 { 0619 if (TrackDataMatcher::matchWithTrack(m_trackDataModel)) 0620 showPreview(); 0621 } 0622 0623 /** 0624 * Match import data with title. 0625 */ 0626 void ImportDialog::matchWithTitle() 0627 { 0628 if (TrackDataMatcher::matchWithTitle(m_trackDataModel)) 0629 showPreview(); 0630 } 0631 0632 /** 0633 * Display custom context menu for horizontal table header. 0634 * 0635 * @param pos position where context menu is drawn on screen 0636 */ 0637 void ImportDialog::showTableHeaderContextMenu(const QPoint& pos) 0638 { 0639 if (QWidget* widget = qobject_cast<QWidget*>(sender())) { 0640 QMenu menu(widget); 0641 const auto frameTypes = checkableFrameTypes(); 0642 for (int frameType : frameTypes) { 0643 if (int column = m_trackDataModel->columnForFrameType(frameType); 0644 column != -1) { 0645 auto action = new QAction(&menu); 0646 action->setText( 0647 m_trackDataModel->headerData(column, Qt::Horizontal).toString()); 0648 action->setData(frameType); 0649 action->setCheckable(true); 0650 action->setChecked((m_columnVisibility & (1ULL << frameType)) != 0ULL); 0651 connect(action, &QAction::triggered, 0652 this, &ImportDialog::toggleTableColumnVisibility); 0653 menu.addAction(action); 0654 } 0655 } 0656 menu.setMouseTracking(true); 0657 menu.exec(widget->mapToGlobal(pos)); 0658 } 0659 } 0660 0661 /** 0662 * Toggle visibility of table column. 0663 * 0664 * @param visible true to make column visible 0665 */ 0666 void ImportDialog::toggleTableColumnVisibility(bool visible) 0667 { 0668 if (auto action = qobject_cast<QAction*>(sender())) { 0669 bool ok; 0670 if (int frameType = action->data().toInt(&ok); ok && frameType < 64) { 0671 if (visible) { 0672 m_columnVisibility |= 1ULL << frameType; 0673 } else { 0674 m_columnVisibility &= ~(1ULL << frameType); 0675 } 0676 if (int column = m_trackDataModel->columnForFrameType(frameType); 0677 column != -1) { 0678 m_trackDataTable->setColumnHidden(column, !visible); 0679 } 0680 } 0681 if (visible) { 0682 m_trackDataTable->resizeColumnsToContents(); 0683 } 0684 } 0685 }