GUI: headers: reordering tracks by dragging & dropping

Part of the implementation of #3227.
This commit is contained in:
Moritz Bunkus 2021-11-13 20:32:35 +01:00
parent d815f46156
commit a68fa879b2
No known key found for this signature in database
GPG Key ID: 74AF00ADF2E32C85
5 changed files with 66 additions and 13 deletions

View File

@ -20,6 +20,8 @@
* MKVToolNix GUI: header editor: a new column has been added to the tree view
showing the status of the "track enabled" flag. The information is also
shown on the track overview page on the right. Implements #3228.
* MKVToolNix GUI: header editor: users can now reorder tracks by dragging &
dropping. Implements #3227.
## Bug fixes

View File

@ -8,6 +8,7 @@
#include "mkvtoolnix-gui/header_editor/page_base.h"
#include "mkvtoolnix-gui/header_editor/page_model.h"
#include "mkvtoolnix-gui/header_editor/top_level_page.h"
#include "mkvtoolnix-gui/header_editor/track_type_page.h"
#include "mkvtoolnix-gui/util/model.h"
namespace mtx::gui::HeaderEditor {
@ -25,6 +26,9 @@ PageModel::~PageModel() {
PageBase *
PageModel::selectedPage(QModelIndex const &idx)
const {
if (!idx.isValid())
return {};
auto selectedItem = itemFromIndex(idx.sibling(idx.row(), 0));
if (!selectedItem)
return {};
@ -189,20 +193,20 @@ PageModel::canDropMimeData(QMimeData const *data,
const {
if ( !data
|| (Qt::MoveAction != action)
|| !parent.isValid()
|| !m_lastSelectedIdx.isValid()
|| (0 > row))
return false;
auto draggedPage = selectedPage(m_lastSelectedIdx);
if (!draggedPage || !dynamic_cast<AttachedFilePage *>(draggedPage))
return false;
auto parentPage = selectedPage(parent);
auto parentPage = selectedPage(parent);
if (!parentPage || !dynamic_cast<AttachmentsPage *>(parentPage))
return false;
if (dynamic_cast<AttachedFilePage *>(draggedPage))
return dynamic_cast<AttachmentsPage *>(parentPage);
return true;
if (dynamic_cast<TrackTypePage *>(draggedPage))
return !parentPage && (row > 0) && (row < rowCount());
return false;
}
bool
@ -214,13 +218,30 @@ PageModel::dropMimeData(QMimeData const *data,
if (!canDropMimeData(data, action, row, column, parent))
return false;
auto draggedPage = selectedPage(m_lastSelectedIdx);
auto result = QStandardItemModel::dropMimeData(data, action, row, 0, parent);
Util::requestAllItems(*this);
Q_EMIT attachmentsReordered();
if (dynamic_cast<AttachedFilePage *>(draggedPage))
Q_EMIT attachmentsReordered();
else if (dynamic_cast<TrackTypePage *>(draggedPage))
Q_EMIT tracksReordered();
return result;
}
void
PageModel::rereadTopLevelPageIndexes() {
auto rootItem = invisibleRootItem();
for (int row = 0, numRows = rootItem->rowCount(); row < numRows; ++row) {
auto topLevelItem = rootItem->child(row);
auto pageId = topLevelItem->data(Util::HeaderEditorPageIdRole).value<int>();
m_pages[pageId]->m_pageIdx = topLevelItem->index();
}
}
}

View File

@ -48,6 +48,10 @@ public:
Q_SIGNALS:
void attachmentsReordered();
void tracksReordered();
public Q_SLOTS:
void rereadTopLevelPageIndexes();
};
}

View File

@ -93,6 +93,7 @@ Tab::resetData() {
m_eTracks.reset();
m_model->reset();
m_segmentinfoPage = nullptr;
m_tracksReordered = false;
}
void
@ -196,7 +197,7 @@ Tab::save() {
tracksModified = true;
}
if (!segmentinfoModified && !tracksModified && !attachmentsModified) {
if (!segmentinfoModified && !tracksModified && !attachmentsModified && !m_tracksReordered) {
Util::MessageBox::information(this)->title(QY("File has not been modified")).text(QY("The header values have not been modified. There is nothing to save.")).exec();
return;
}
@ -226,7 +227,9 @@ Tab::save() {
}
}
if (ok && tracksModified && m_eTracks) {
if (ok && m_eTracks && (tracksModified || m_tracksReordered)) {
updateTracksElementToMatchTrackOrder();
auto result = m_analyzer->update_element(m_eTracks, true);
if (kax_analyzer_c::uer_success != result) {
Util::KaxAnalyzer::displayUpdateElementResult(this, result, QY("Saving the modified track headers failed."));
@ -314,6 +317,13 @@ Tab::setupUi() {
connect(m_replaceAttachmentContentAction, &QAction::triggered, [this]() { replaceAttachmentContent(false); });
connect(m_replaceAttachmentContentSetValuesAction, &QAction::triggered, [this]() { replaceAttachmentContent(true); });
connect(m_model, &PageModel::attachmentsReordered, [this]() { m_attachmentsPage->rereadChildren(*m_model); });
connect(m_model, &PageModel::tracksReordered, this, &Tab::handleReorderedTracks);
}
void
Tab::handleReorderedTracks() {
m_tracksReordered = true;
m_model->rereadTopLevelPageIndexes();
}
void
@ -874,13 +884,15 @@ Tab::isClosingOrReloadingOkIfModified(ModifiedConfirmationMode mode) {
return true;
auto modifiedPage = hasBeenModified();
if (!modifiedPage)
if (!modifiedPage && !m_tracksReordered)
return true;
auto tool = MainWindow::headerEditorTool();
MainWindow::get()->switchToTool(tool);
tool->showTab(*this);
focusPage(modifiedPage);
if (modifiedPage)
focusPage(modifiedPage);
auto closing = mode == ModifiedConfirmationMode::Closing;
auto text = closing ? QY("The file \"%1\" has been modified. Do you really want to close? All changes will be lost.")
@ -898,4 +910,15 @@ Tab::isClosingOrReloadingOkIfModified(ModifiedConfirmationMode mode) {
return answer == QMessageBox::Yes;
}
void
Tab::updateTracksElementToMatchTrackOrder() {
auto &tracks = static_cast<libebml::EbmlMaster &>(*m_eTracks);
RemoveChildren<libmatroska::KaxTrackEntry>(tracks);
for (auto page : m_model->topLevelPages())
if (dynamic_cast<TrackTypePage *>(page))
tracks.PushElement(static_cast<TrackTypePage &>(*page).m_master);
}
}

View File

@ -45,7 +45,7 @@ protected:
PageModel *m_model;
PageBase *m_segmentinfoPage{};
AttachmentsPage *m_attachmentsPage{};
bool m_ignoreSelectionChanges{};
bool m_ignoreSelectionChanges{}, m_tracksReordered{};
QMenu *m_treeContextMenu;
QAction *m_expandAllAction, *m_collapseAllAction, *m_addAttachmentsAction, *m_removeAttachmentAction, *m_removeAllAttachmentsAction, *m_saveAttachmentContentAction;
@ -86,6 +86,7 @@ public Q_SLOTS:
virtual void replaceAttachmentContent(bool deriveNameAndMimeType);
virtual void handleDroppedFiles(QStringList const &fileNames, Qt::MouseButtons mouseButtons);
virtual void focusPage(PageBase *page);
virtual void handleReorderedTracks();
protected:
void setupUi();
@ -107,6 +108,8 @@ protected:
void pruneEmptyMastersForTrack(TrackTypePage &page);
void pruneEmptyMastersForAllTracks();
void updateTracksElementToMatchTrackOrder();
public:
static memory_cptr readFileData(QWidget *parent, QString const &fileName);
};