1 #include "common/common_pch.h"
2
3 #include <QMenu>
4
5 #include "common/bluray/disc_library.h"
6 #include "common/mime.h"
7 #include "common/qt.h"
8 #include "common/strings/formatting.h"
9 #include "mkvtoolnix-gui/merge/tab.h"
10 #include "mkvtoolnix-gui/merge/tab_p.h"
11 #include "mkvtoolnix-gui/forms/merge/tab.h"
12 #include "mkvtoolnix-gui/util/file_dialog.h"
13 #include "mkvtoolnix-gui/util/files_drag_drop_widget.h"
14 #include "mkvtoolnix-gui/util/header_view_manager.h"
15 #include "mkvtoolnix-gui/util/message_box.h"
16 #include "mkvtoolnix-gui/util/model.h"
17 #include "mkvtoolnix-gui/util/settings.h"
18 #include "mkvtoolnix-gui/util/widget.h"
19
20 namespace mtx::gui::Merge {
21
22 using namespace mtx::gui;
23
24 void
setupAttachmentsControls()25 Tab::setupAttachmentsControls() {
26 auto &p = *p_func();
27
28 p.ui->attachedFiles->setModel(p.attachedFilesModel);
29 p.ui->attachments->setModel(p.attachmentsModel);
30
31 p.ui->attachedFiles->enterActivatesAllSelected(true);
32
33 // Attached files context menu
34 p.attachedFilesMenu->addAction(p.enableSelectedAttachedFilesAction);
35 p.attachedFilesMenu->addAction(p.disableSelectedAttachedFilesAction);
36 p.attachedFilesMenu->addSeparator();
37 p.attachedFilesMenu->addAction(p.enableAllAttachedFilesAction);
38 p.attachedFilesMenu->addAction(p.disableAllAttachedFilesAction);
39
40 // Attachments context menu
41 p.attachmentsMenu->addAction(p.addAttachmentsAction);
42 p.attachmentsMenu->addSeparator();
43 p.attachmentsMenu->addAction(p.removeAttachmentsAction);
44 p.attachmentsMenu->addAction(p.removeAllAttachmentsAction);
45 p.attachmentsMenu->addSeparator();
46 p.attachmentsMenu->addAction(p.selectAllAttachmentsAction);
47
48 // MIME type
49 for (auto const &name : mtx::mime::sorted_type_names())
50 p.ui->attachmentMIMEType->addItem(Q(name), Q(name));
51
52 p.ui->attachmentMIMEType->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
53 p.ui->attachmentStyle ->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
54
55 Util::fixComboBoxViewWidth(*p.ui->attachmentMIMEType);
56 Util::fixComboBoxViewWidth(*p.ui->attachmentStyle);
57
58 p.ui->attachmentMIMEType->lineEdit()->setClearButtonEnabled(true);
59
60 auto &cfg = Util::Settings::get();
61 cfg.handleSplitterSizes(p.ui->mergeAttachmentsSplitter);
62
63 Util::HeaderViewManager::create(*p.ui->attachedFiles, "Merge::AttachedFiles").setDefaultSizes({ { Q("name"), 180 }, { Q("mimeType"), 180 }, { Q("size"), 100 } });
64
65 p.enableSelectedAttachedFilesAction->setIcon(QIcon{Q(":/icons/16x16/checkbox.png")});
66 p.disableSelectedAttachedFilesAction->setIcon(QIcon{Q(":/icons/16x16/checkbox-unchecked.png")});
67 p.enableAllAttachedFilesAction->setIcon(QIcon{Q(":/icons/16x16/checkbox.png")});
68 p.disableAllAttachedFilesAction->setIcon(QIcon{Q(":/icons/16x16/checkbox-unchecked.png")});
69
70 p.addAttachmentsAction->setIcon(QIcon{Q(":/icons/16x16/list-add.png")});
71 p.removeAttachmentsAction->setIcon(QIcon{Q(":/icons/16x16/list-remove.png")});
72 p.selectAllAttachmentsAction->setIcon(QIcon{Q(":/icons/16x16/edit-select-all.png")});
73
74 // Q_SIGNALS & Q_SLOTS
75 connect(p.addAttachmentsAction, &QAction::triggered, this, &Tab::onAddAttachments);
76 connect(p.removeAttachmentsAction, &QAction::triggered, this, &Tab::onRemoveAttachments);
77 connect(p.removeAllAttachmentsAction, &QAction::triggered, this, &Tab::onRemoveAllAttachments);
78 connect(p.selectAllAttachmentsAction, &QAction::triggered, this, &Tab::onSelectAllAttachments);
79
80 connect(p.enableAllAttachedFilesAction, &QAction::triggered, this, [=]() { enableDisableAllAttachedFiles(true); });
81 connect(p.disableAllAttachedFilesAction, &QAction::triggered, this, [=]() { enableDisableAllAttachedFiles(false); });
82 connect(p.enableSelectedAttachedFilesAction, &QAction::triggered, this, [=]() { enableDisableSelectedAttachedFiles(true); });
83 connect(p.disableSelectedAttachedFilesAction, &QAction::triggered, this, [=]() { enableDisableSelectedAttachedFiles(false); });
84
85 connect(p.ui->attachmentDescription, &QLineEdit::textChanged, this, &Tab::onAttachmentDescriptionChanged);
86 connect(p.ui->attachmentMIMEType, &QComboBox::currentTextChanged, this, &Tab::onAttachmentMIMETypeChanged);
87 connect(p.ui->attachmentMIMEType, &QComboBox::editTextChanged, this, &Tab::onAttachmentMIMETypeChanged);
88 connect(p.ui->attachmentName, &QLineEdit::textChanged, this, &Tab::onAttachmentNameChanged);
89 connect(p.ui->attachmentStyle, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &Tab::onAttachmentStyleChanged);
90 connect(p.ui->attachments, &Util::BasicTreeView::ctrlDownPressed, this, &Tab::onMoveAttachmentsDown);
91 connect(p.ui->attachments, &Util::BasicTreeView::ctrlUpPressed, this, &Tab::onMoveAttachmentsUp);
92 connect(p.ui->attachments, &Util::BasicTreeView::customContextMenuRequested, this, &Tab::showAttachmentsContextMenu);
93 connect(p.ui->attachments, &Util::BasicTreeView::deletePressed, this, &Tab::onRemoveAttachments);
94 connect(p.ui->attachments, &Util::BasicTreeView::insertPressed, this, &Tab::onAddAttachments);
95 connect(p.ui->attachments->selectionModel(), &QItemSelectionModel::selectionChanged, this, &Tab::onAttachmentSelectionChanged);
96 connect(p.ui->attachmentsTab, &Util::FilesDragDropWidget::filesDropped, this, &Tab::addAttachments);
97 connect(p.ui->moveAttachmentsDown, &QPushButton::clicked, this, &Tab::onMoveAttachmentsDown);
98 connect(p.ui->moveAttachmentsUp, &QPushButton::clicked, this, &Tab::onMoveAttachmentsUp);
99 connect(p.ui->attachedFiles, &Util::BasicTreeView::doubleClicked, this, &Tab::toggleMuxThisForSelectedAttachedFiles);
100 connect(p.ui->attachedFiles, &Util::BasicTreeView::allSelectedActivated, this, &Tab::toggleMuxThisForSelectedAttachedFiles);
101 connect(p.ui->attachedFiles, &Util::BasicTreeView::customContextMenuRequested, this, &Tab::showAttachedFilesContextMenu);
102 connect(p.attachedFilesModel, &AttachedFileModel::itemChanged, this, &Tab::attachedFileItemChanged);
103
104 onAttachmentSelectionChanged();
105
106 Util::HeaderViewManager::create(*p.ui->attachments, "Merge::Attachments").setDefaultSizes({ { Q("name"), 180 }, { Q("mimeType"), 180 }, { Q("attachTo"), 130 }, { Q("size"), 100 } });
107 }
108
109 void
withSelectedAttachedFiles(std::function<void (Track &)> code)110 Tab::withSelectedAttachedFiles(std::function<void(Track &)> code) {
111 auto &p = *p_func();
112
113 if (p.currentlySettingInputControlValues)
114 return;
115
116 for (auto const &attachedFile : selectedAttachedFiles()) {
117 code(*attachedFile);
118 p.attachedFilesModel->attachedFileUpdated(*attachedFile);
119 }
120 }
121
122 void
withSelectedAttachments(std::function<void (Attachment &)> code)123 Tab::withSelectedAttachments(std::function<void(Attachment &)> code) {
124 auto &p = *p_func();
125
126 if (p.currentlySettingInputControlValues)
127 return;
128
129 for (auto const &attachment : selectedAttachments()) {
130 code(*attachment);
131 p.attachmentsModel->attachmentUpdated(*attachment);
132 }
133 }
134
135 QList<Track *>
selectedAttachedFiles() const136 Tab::selectedAttachedFiles()
137 const {
138 auto &p = *p_func();
139
140 auto attachedFiles = QList<Track *>{};
141 Util::withSelectedIndexes(p.ui->attachedFiles, [&attachedFiles, &p](QModelIndex const &idx) {
142 auto attachedFile = p.attachedFilesModel->attachedFileForRow(idx.row());
143 if (attachedFile)
144 attachedFiles << attachedFile.get();
145 });
146
147 return attachedFiles;
148 }
149
150 QList<Attachment *>
selectedAttachments() const151 Tab::selectedAttachments()
152 const {
153 auto &p = *p_func();
154 auto attachments = QList<Attachment *>{};
155 Util::withSelectedIndexes(p.ui->attachments, [&attachments, &p](QModelIndex const &idx) {
156 auto attachment = p.attachmentsModel->attachmentForRow(idx.row());
157 if (attachment)
158 attachments << attachment.get();
159 });
160
161 return attachments;
162 }
163
164 void
selectAttachments(QList<Attachment * > const & attachments)165 Tab::selectAttachments(QList<Attachment *> const &attachments) {
166 auto &p = *p_func();
167 auto numColumns = p.attachmentsModel->columnCount() - 1;
168 auto selection = QItemSelection{};
169
170 for (auto const &attachment : attachments) {
171 auto row = p.attachmentsModel->rowForAttachment(*attachment);
172 selection.select(p.attachmentsModel->index(row, 0), p.attachmentsModel->index(row, numColumns));
173 }
174
175 p.ui->attachments->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
176 }
177
178 void
enableDisableSelectedAttachedFiles(bool enable)179 Tab::enableDisableSelectedAttachedFiles(bool enable) {
180 withSelectedAttachedFiles([=](Track &attachedFile) {
181 attachedFile.m_muxThis = enable;
182 });
183 }
184
185 void
enableDisableAllAttachedFiles(bool enable)186 Tab::enableDisableAllAttachedFiles(bool enable) {
187 auto &p = *p_func();
188
189 if (p.currentlySettingInputControlValues)
190 return;
191
192 for (int row = 0, numRows = p.attachedFilesModel->rowCount(); row < numRows; ++row) {
193 auto attachedFile = p.attachedFilesModel->attachedFileForRow(row);
194 if (attachedFile) {
195 attachedFile->m_muxThis = enable;
196 p.attachedFilesModel->attachedFileUpdated(*attachedFile);
197 }
198 }
199 }
200
201 void
onAttachmentNameChanged(QString newValue)202 Tab::onAttachmentNameChanged(QString newValue) {
203 withSelectedAttachments([&newValue](auto &attachment) { attachment.m_name = newValue; });
204 }
205
206 void
onAttachmentDescriptionChanged(QString newValue)207 Tab::onAttachmentDescriptionChanged(QString newValue) {
208 withSelectedAttachments([&newValue](auto &attachment) { attachment.m_description = newValue; });
209 }
210
211 void
onAttachmentMIMETypeChanged(QString newValue)212 Tab::onAttachmentMIMETypeChanged(QString newValue) {
213 withSelectedAttachments([&newValue](auto &attachment) { attachment.m_MIMEType = newValue; });
214 }
215
216 void
onAttachmentStyleChanged(int newValue)217 Tab::onAttachmentStyleChanged(int newValue) {
218 auto &p = *p_func();
219 auto data = p.ui->attachmentStyle->itemData(newValue);
220 if (!data.isValid())
221 return;
222
223 auto style = data.toInt() == Attachment::ToAllFiles ? Attachment::ToAllFiles : Attachment::ToFirstFile;
224 withSelectedAttachments([style](auto &attachment) { attachment.m_style = style; });
225 }
226
227 AttachmentPtr
prepareFileForAttaching(QString const & fileName,bool alwaysAdd)228 Tab::prepareFileForAttaching(QString const &fileName,
229 bool alwaysAdd) {
230 auto info = QFileInfo{fileName};
231 if (info.size() > 0x7fffffff) {
232 Util::MessageBox::critical(this)
233 ->title(QY("Reading failed"))
234 .text(Q("%1 %2")
235 .arg(QY("The file (%1) is too big (%2).").arg(fileName).arg(Q(mtx::string::format_file_size(info.size()))))
236 .arg(QY("Only files smaller than 2 GiB are supported.")))
237 .exec();
238 return {};
239 }
240
241 auto &cfg = Util::Settings::get();
242
243 if (!alwaysAdd) {
244 auto existingFileName = findExistingAttachmentFileName(info.fileName());
245 if (existingFileName) {
246 if (cfg.m_mergeAttachmentsAlwaysSkipForExistingName)
247 return {};
248
249 auto const answer = Util::MessageBox::question(this)
250 ->title(QY("Attachment with same name present"))
251 .text(Q("%1 %2")
252 .arg(QY("An attachment with the name '%1' is already present.").arg(*existingFileName))
253 .arg(QY("Do you really want to add '%1' as another attachment?").arg(QDir::toNativeSeparators(fileName))))
254 .buttons(QMessageBox::Yes | QMessageBox::No | QMessageBox::NoToAll)
255 .buttonLabel(QMessageBox::Yes, QY("&Add attachment"))
256 .buttonLabel(QMessageBox::No, QY("&Skip file"))
257 .buttonLabel(QMessageBox::NoToAll, QY("Always s&kip files"))
258 .defaultButton(QMessageBox::No)
259 .exec();
260
261 if (answer == QMessageBox::NoToAll) {
262 cfg.m_mergeAttachmentsAlwaysSkipForExistingName = true;
263 cfg.save();
264 }
265
266 if (answer != QMessageBox::Yes)
267 return {};
268 }
269 }
270
271 auto attachment = std::make_shared<Attachment>(fileName);
272 attachment->guessMIMEType();
273
274 return attachment;
275 }
276
277 void
addAttachments(QStringList const & fileNames)278 Tab::addAttachments(QStringList const &fileNames) {
279 QList<AttachmentPtr> attachmentsToAdd;
280 for (auto &fileName : fileNames) {
281 auto attachment = prepareFileForAttaching(fileName, false);
282 if (attachment)
283 attachmentsToAdd << attachment;
284 }
285
286 p_func()->attachmentsModel->addAttachments(attachmentsToAdd);
287 }
288
289 void
onAddAttachments()290 Tab::onAddAttachments() {
291 auto fileNames = selectAttachmentsToAdd();
292 if (!fileNames.isEmpty())
293 addAttachments(fileNames);
294 }
295
296 QStringList
selectAttachmentsToAdd()297 Tab::selectAttachmentsToAdd() {
298 auto fileNames = Util::getOpenFileNames(this, QY("Add attachments"), Util::Settings::get().lastOpenDirPath(), QY("All files") + Q(" (*)"));
299
300 if (!fileNames.isEmpty())
301 Util::Settings::get().m_lastOpenDir.setPath(QFileInfo{fileNames[0]}.path());
302
303 return fileNames;
304 }
305
306 void
onRemoveAttachments()307 Tab::onRemoveAttachments() {
308 auto &p = *p_func();
309
310 p.attachmentsModel->removeSelectedAttachments(p.ui->attachments->selectionModel()->selection());
311
312 onAttachmentSelectionChanged();
313 }
314
315 void
onRemoveAllAttachments()316 Tab::onRemoveAllAttachments() {
317 p_func()->attachmentsModel->reset();
318 onAttachmentSelectionChanged();
319 }
320
321 void
onSelectAllAttachments()322 Tab::onSelectAllAttachments() {
323 auto &p = *p_func();
324 auto numRows = p.attachmentsModel->rowCount();
325 if (!numRows)
326 return;
327
328 auto selection = QItemSelection{};
329 selection.select(p.attachmentsModel->index(0, 0), p.attachmentsModel->index(numRows - 1, p.attachmentsModel->columnCount() - 1));
330
331 p.ui->attachments->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);
332 }
333
334 void
onAttachmentSelectionChanged()335 Tab::onAttachmentSelectionChanged() {
336 auto &p = *p_func();
337 auto selection = p.ui->attachments->selectionModel()->selection();
338 auto numRows = Util::numSelectedRows(selection);
339
340 p.ui->moveAttachmentsUp->setEnabled(!!numRows);
341 p.ui->moveAttachmentsDown->setEnabled(!!numRows);
342
343 if (!numRows) {
344 setAttachmentControlValues(nullptr);
345 enableAttachmentControls(false);
346 return;
347 }
348
349 enableAttachmentControls(true);
350
351 if (1 < numRows) {
352 setAttachmentControlValues(nullptr);
353 return;
354 }
355
356 auto idxs = selection.at(0).indexes();
357 if (idxs.isEmpty() || !idxs.at(0).isValid())
358 return;
359
360 auto attachment = p.attachmentsModel->attachmentForRow(idxs.at(0).row());
361 if (!attachment)
362 return;
363
364 setAttachmentControlValues(attachment.get());
365 }
366
367 void
enableAttachmentControls(bool enable)368 Tab::enableAttachmentControls(bool enable) {
369 auto &p = *p_func();
370 auto controls = std::vector<QWidget *>{p.ui->attachmentName, p.ui->attachmentNameLabel, p.ui->attachmentDescription, p.ui->attachmentDescriptionLabel,
371 p.ui->attachmentMIMEType, p.ui->attachmentMIMETypeLabel, p.ui->attachmentStyle, p.ui->attachmentStyleLabel,};
372 for (auto &control : controls)
373 control->setEnabled(enable);
374 }
375
376 void
enableAttachedFilesActions()377 Tab::enableAttachedFilesActions() {
378 auto &p = *p_func();
379 auto numSelected = selectedAttachedFiles().size();
380 auto hasSelection = !!numSelected;
381 auto hasEntries = !!p.attachedFilesModel->rowCount();
382
383 p.enableSelectedAttachedFilesAction->setEnabled(hasSelection);
384 p.disableSelectedAttachedFilesAction->setEnabled(hasSelection);
385 p.enableAllAttachedFilesAction->setEnabled(hasEntries);
386 p.disableAllAttachedFilesAction->setEnabled(hasEntries);
387
388 p.enableSelectedAttachedFilesAction->setText(QNY("&Enable selected attachment", "&Enable selected attachments", numSelected));
389 p.disableSelectedAttachedFilesAction->setText(QNY("&Disable selected attachment", "&Disable selected attachments", numSelected));
390 }
391
392 void
enableAttachmentsActions()393 Tab::enableAttachmentsActions() {
394 auto &p = *p_func();
395 auto numSelected = selectedAttachments().size();
396 auto hasSelection = !!numSelected;
397 auto hasEntries = !!p.attachmentsModel->rowCount();
398
399 p.removeAttachmentsAction->setEnabled(hasSelection);
400 p.removeAllAttachmentsAction->setEnabled(hasEntries);
401 p.selectAllAttachmentsAction->setEnabled(hasEntries);
402
403 p.removeAttachmentsAction->setText(QNY("&Remove attachment", "&Remove attachments", numSelected));
404 }
405
406 void
setAttachmentControlValues(Attachment * attachment)407 Tab::setAttachmentControlValues(Attachment *attachment) {
408 auto &p = *p_func();
409
410 p.currentlySettingInputControlValues = true;
411
412 if (!attachment && p.ui->attachmentStyle->itemData(0).isValid())
413 p.ui->attachmentStyle->insertItem(0, QY("<Do not change>"));
414
415 else if (attachment && !p.ui->attachmentStyle->itemData(0).isValid())
416 p.ui->attachmentStyle->removeItem(0);
417
418 if (!attachment) {
419 p.ui->attachmentName->setText(Q(""));
420 p.ui->attachmentDescription->setText(Q(""));
421 p.ui->attachmentMIMEType->setEditText(Q(""));
422 p.ui->attachmentStyle->setCurrentIndex(0);
423
424 } else {
425 p.ui->attachmentName->setText( attachment->m_name);
426 p.ui->attachmentDescription->setText( attachment->m_description);
427 p.ui->attachmentMIMEType->setEditText(attachment->m_MIMEType);
428
429 Util::setComboBoxIndexIf(p.ui->attachmentStyle, [&attachment](auto const &, auto const &data) { return data.isValid() && (data.toInt() == static_cast<int>(attachment->m_style)); });
430 }
431
432 p.currentlySettingInputControlValues = false;
433 }
434
435 void
retranslateAttachmentsUI()436 Tab::retranslateAttachmentsUI() {
437 auto &p = *p_func();
438
439 p.attachedFilesModel->retranslateUi();
440 p.attachmentsModel->retranslateUi();
441
442 p.enableAllAttachedFilesAction->setText(QY("E&nable all attachments"));
443 p.disableAllAttachedFilesAction->setText(QY("Di&sable all attachments"));
444
445 p.addAttachmentsAction->setText(QY("&Add attachments"));
446 p.removeAllAttachmentsAction->setText(QY("Remove a&ll attachments"));
447 p.selectAllAttachmentsAction->setText(QY("&Select all attachments"));
448
449 // Attachment style
450 p.ui->attachmentStyle->setItemData(0, static_cast<int>(Attachment::ToAllFiles));
451 p.ui->attachmentStyle->setItemData(1, static_cast<int>(Attachment::ToFirstFile));
452
453 setupAttachmentsToolTips();
454 }
455
456 void
setupAttachmentsToolTips()457 Tab::setupAttachmentsToolTips() {
458 Util::setToolTip(p_func()->ui->attachments, QY("Right-click for attachment actions"));
459 }
460
461 void
moveAttachmentsUpOrDown(bool up)462 Tab::moveAttachmentsUpOrDown(bool up) {
463 auto &p = *p_func();
464 auto attachments = selectedAttachments();
465
466 p.attachmentsModel->moveAttachmentsUpOrDown(attachments, up);
467
468 selectAttachments(attachments);
469
470 p.ui->attachments->scrollToFirstSelected();
471 }
472
473 void
onMoveAttachmentsUp()474 Tab::onMoveAttachmentsUp() {
475 moveAttachmentsUpOrDown(true);
476 }
477
478 void
onMoveAttachmentsDown()479 Tab::onMoveAttachmentsDown() {
480 moveAttachmentsUpOrDown(false);
481 }
482
483 void
showAttachmentsContextMenu(QPoint const & pos)484 Tab::showAttachmentsContextMenu(QPoint const &pos) {
485 auto &p = *p_func();
486
487 enableAttachmentsActions();
488 p.attachmentsMenu->exec(p.ui->attachments->viewport()->mapToGlobal(pos));
489 }
490
491 void
showAttachedFilesContextMenu(QPoint const & pos)492 Tab::showAttachedFilesContextMenu(QPoint const &pos) {
493 auto &p = *p_func();
494
495 enableAttachedFilesActions();
496 p.attachedFilesMenu->exec(p.ui->attachedFiles->viewport()->mapToGlobal(pos));
497 }
498
499 void
toggleMuxThisForSelectedAttachedFiles()500 Tab::toggleMuxThisForSelectedAttachedFiles() {
501 auto allEnabled = true;
502 auto attachedFilesSelected = false;
503
504 withSelectedAttachedFiles([&allEnabled, &attachedFilesSelected](Track const &attachedFile) {
505 attachedFilesSelected = true;
506
507 if (!attachedFile.m_muxThis)
508 allEnabled = false;
509 });
510
511 if (!attachedFilesSelected)
512 return;
513
514 auto newEnabled = !allEnabled;
515
516 withSelectedAttachedFiles([newEnabled](Track &attachedFile) { attachedFile.m_muxThis = newEnabled; });
517 }
518
519 void
attachedFileItemChanged(QStandardItem * item)520 Tab::attachedFileItemChanged(QStandardItem *item) {
521 auto &p = *p_func();
522
523 if (!item)
524 return;
525
526 auto idx = p.attachedFilesModel->indexFromItem(item);
527 if (idx.column())
528 return;
529
530 auto attachedFile = p.attachedFilesModel->attachedFileForRow(idx.row());
531 if (!attachedFile)
532 return;
533
534 auto newMuxThis = item->checkState() == Qt::Checked;
535 if (newMuxThis == attachedFile->m_muxThis)
536 return;
537
538 attachedFile->m_muxThis = newMuxThis;
539 p.attachedFilesModel->attachedFileUpdated(*attachedFile);
540 }
541
542 std::optional<QString>
findExistingAttachmentFileName(QString const & fileName)543 Tab::findExistingAttachmentFileName(QString const &fileName) {
544 auto &p = *p_func();
545 auto lowerFileName = fileName.toLower();
546
547 for (int row = 0, numRows = p.attachedFilesModel->rowCount(); row < numRows; ++row) {
548 auto attachedFile = p.attachedFilesModel->attachedFileForRow(row);
549
550 if (!attachedFile || !attachedFile->m_muxThis)
551 continue;
552
553 auto existingFileName = QFileInfo{attachedFile->m_name}.fileName();
554 if (lowerFileName == existingFileName.toLower())
555 return existingFileName;
556 }
557
558 for (int row = 0, numRows = p.attachmentsModel->rowCount(); row < numRows; ++row) {
559 auto attachment = p.attachmentsModel->attachmentForRow(row);
560
561 if (!attachment)
562 continue;
563
564 auto existingFileName = QFileInfo{attachment->m_fileName}.fileName();
565 if (lowerFileName == existingFileName.toLower())
566 return existingFileName;
567 }
568
569 return {};
570 }
571
572 void
addAttachmentsFromIdentifiedBluray(mtx::bluray::disc_library::info_t const & info)573 Tab::addAttachmentsFromIdentifiedBluray(mtx::bluray::disc_library::info_t const &info) {
574 unsigned int maxSize = 0;
575 std::filesystem::path fileName;
576
577 for (auto const &thumbnail : info.m_thumbnails) {
578 auto size = thumbnail.m_width * thumbnail.m_height;
579 if (size < maxSize)
580 continue;
581
582 maxSize = size;
583 fileName = thumbnail.m_file_name;
584 }
585
586 if (fileName.empty() || !std::filesystem::is_regular_file(fileName))
587 return;
588
589 auto attachment = prepareFileForAttaching(Q(fileName.u8string()), true);
590 if (!attachment)
591 return;
592
593 attachment->m_name = Q("cover%2").arg(Q(fileName.extension().u8string()).toLower());
594
595 p_func()->attachmentsModel->addAttachments(QList<AttachmentPtr>{} << attachment);
596 }
597
598 }
599