QModelIndex SourceFileModel::indexFromSourceFile(SourceFile *sourceFile) const { if (!sourceFile) return QModelIndex{}; return indexFromSourceFile(reinterpret_cast<quint64>(sourceFile), QModelIndex{}); }
bool SourceFileModel::dropSourceFiles(QMimeData const *data, Qt::DropAction action, int row, QModelIndex const &parent) { if (action != Qt::MoveAction) return QAbstractItemModel::dropMimeData(data, action, row, 0, parent); auto encoded = data->data(mtx::gui::MimeTypes::MergeSourceFileModelItem); QDataStream stream{&encoded, QIODevice::ReadOnly}; while (!stream.atEnd()) { quint64 value; stream >> value; auto sourceFile = m_sourceFileMap[value]; auto sourceIdx = indexFromSourceFile(sourceFile.get()); if (!sourceIdx.isValid()) continue; auto sourceParent = sourceIdx.parent(); auto sourceParentItem = sourceParent.isValid() ? itemFromIndex(sourceParent) : invisibleRootItem(); auto rowItems = sourceParentItem->takeRow(sourceIdx.row()); if (!parent.isValid()) { if ((sourceParent == parent) && (sourceIdx.row() < row)) --row; invisibleRootItem()->insertRow(row, rowItems); ++row; } else { auto parentFile = fromIndex(parent); Q_ASSERT(parentFile); if (sourceFile->isAdditionalPart()) row = std::min(row, parentFile->m_additionalParts.size()); else row = std::max(row, parentFile->m_additionalParts.size()); if ((sourceParent == parent) && (sourceIdx.row() < row)) --row; itemFromIndex(parent)->insertRow(row, rowItems); ++row; } updateSourceFileLists(); } return false; }
void SourceFileModel::sourceFileUpdated(SourceFile *sourceFile) { auto idx = indexFromSourceFile(sourceFile); if (!idx.isValid()) return; auto items = QList<QStandardItem *>{}; for (auto column = 0, numColumns = columnCount(); column < numColumns; ++column) items << itemFromIndex(idx.sibling(idx.row(), column)); setItemsFromSourceFile(items, sourceFile); }
QModelIndex SourceFileModel::indexFromSourceFile(quint64 value, QModelIndex const &parent) const { auto currentValue = storageValueFromIndex(parent); if (currentValue == value) return parent; auto invalidIdx = QModelIndex{}; for (auto row = 0, numRows = rowCount(parent); row < numRows; ++row) { auto idx = indexFromSourceFile(value, index(row, 0, parent)); if (idx != invalidIdx) return idx; } return invalidIdx; }
void SourceFileModel::sortSourceFiles(QList<SourceFile *> &files, bool reverse) { auto rows = QHash<SourceFile *, int>{}; for (auto const &file : files) rows[file] = indexFromSourceFile(file).row(); auto totalNumFiles = m_sourceFiles->count(); for (auto const &file : *m_sourceFiles) totalNumFiles += file->m_appendedFiles.count() + file->m_additionalParts.count(); std::sort(files.begin(), files.end(), [&rows](SourceFile *a, SourceFile *b) -> bool { auto rowA = rows[a]; auto rowB = rows[b]; if ( a->isRegular() && b->isRegular()) return rowA < rowB; if ( a->isRegular() && !b->isRegular()) return true; if (!a->isRegular() && b->isRegular()) return false; auto parentA = rows[a->m_appendedTo]; auto parentB = rows[b->m_appendedTo]; return (parentA < parentB) || ((parentA == parentB) && (rowA < rowB)); }); if (reverse) { std::reverse(files.begin(), files.end()); std::stable_partition(files.begin(), files.end(), [](SourceFile *file) { return file->isRegular(); }); } }
bool SourceFileModel::dropSourceFiles(QMimeData const *data, Qt::DropAction action, int row, QModelIndex const &parent) { if (action != Qt::MoveAction) return QAbstractItemModel::dropMimeData(data, action, row, 0, parent); mxinfo(boost::format("dropMimeData row %1% parent %2%/%3%\n") % row % parent.row() % parent.column()); auto encoded = data->data(MIME_TYPE); QDataStream stream{&encoded, QIODevice::ReadOnly}; while (!stream.atEnd()) { quint64 value; stream >> value; auto sourceFile = m_sourceFileMap[value]; auto sourceIdx = indexFromSourceFile(sourceFile.get()); if (!sourceIdx.isValid()) continue; mxinfo(boost::format(" val %|1$08x| ptr %2% idx %3%/%4%\n") % value % sourceFile.get() % sourceIdx.row() % sourceIdx.column()); auto sourceParent = sourceIdx.parent(); auto sourceParentItem = sourceParent.isValid() ? itemFromIndex(sourceParent) : invisibleRootItem(); auto priorRow = row; auto rowItems = sourceParentItem->takeRow(sourceIdx.row()); if (!parent.isValid()) { if ((sourceParent == parent) && (sourceIdx.row() < row)) --row; mxinfo(boost::format("tried moving case 1 from %1% row %2% to new parent %3% row %4% new row %5%\n") % dumpIdx(sourceIdx.parent()) % sourceIdx.row() % dumpIdx(parent) % priorRow % (row + 1)); invisibleRootItem()->insertRow(row, rowItems); ++row; } else { auto parentFile = fromIndex(parent); Q_ASSERT(parentFile); if (sourceFile->isAdditionalPart()) row = std::min(row, parentFile->m_additionalParts.size()); else row = std::max(row, parentFile->m_additionalParts.size()); if ((sourceParent == parent) && (sourceIdx.row() < row)) --row; mxinfo(boost::format("tried moving case 2 from %1% row %2% to new parent %3% row %4% new row %5%\n") % dumpIdx(sourceIdx.parent()) % sourceIdx.row() % dumpIdx(parent) % priorRow % (row + 1)); itemFromIndex(parent)->insertRow(row, rowItems); ++row; } updateSourceFileLists(); } return false; }
void SourceFileModel::moveSourceFilesUpOrDown(QList<SourceFile *> files, bool up) { sortSourceFiles(files, !up); // qDebug() << "move up?" << up << "files" << files; auto couldNotBeMoved = QHash<SourceFile *, bool>{}; auto isSelected = QHash<SourceFile *, bool>{}; auto const direction = up ? -1 : +1; auto const topRows = rowCount(); for (auto const &file : files) { isSelected[file] = true; if (!file->isRegular() && isSelected[file->m_appendedTo]) continue; auto idx = indexFromSourceFile(file); Q_ASSERT(idx.isValid()); auto targetRow = idx.row() + direction; if (couldNotBeMoved[fromIndex(idx.sibling(targetRow, 0)).get()]) { couldNotBeMoved[file] = true; continue; } if (file->isRegular()) { if (!((0 <= targetRow) && (targetRow < topRows))) { couldNotBeMoved[file] = true; continue; } // qDebug() << "top level: would like to move" << idx.row() << "to" << targetRow; insertRow(targetRow, takeRow(idx.row())); continue; } auto parentItem = itemFromIndex(idx.parent()); auto const appendedAdditionalRows = countAppendedAndAdditionalParts(parentItem); auto const additionalPartsRows = appendedAdditionalRows.first; auto const appendedRows = appendedAdditionalRows.second; auto const lowerLimit = (file->isAdditionalPart() ? 0 : additionalPartsRows); auto const upperLimit = (file->isAdditionalPart() ? 0 : appendedRows) + additionalPartsRows; if ((lowerLimit <= targetRow) && (targetRow < upperLimit)) { // qDebug() << "appended level normal: would like to move" << idx.row() << "to" << targetRow; parentItem->insertRow(targetRow, parentItem->takeRow(idx.row())); continue; } auto parentIdx = parentItem->index(); Q_ASSERT(parentIdx.isValid()); auto newParentRow = parentIdx.row() + direction; if ((0 > newParentRow) || (rowCount() <= newParentRow)) { // qDebug() << "appended, cannot move further"; couldNotBeMoved[file] = true; continue; } auto newParent = fromIndex(index(newParentRow, 0)); auto newParentItem = itemFromIndex(index(newParentRow, 0)); auto rowItems = parentItem->takeRow(idx.row()); auto newParentNumbers = countAppendedAndAdditionalParts(newParentItem); targetRow = up && file->isAdditionalPart() ? newParentNumbers.first : up ? newParentNumbers.first + newParentNumbers.second : !up && file->isAdditionalPart() ? 0 : newParentNumbers.first; Q_ASSERT(!!newParent); // qDebug() << "appended level cross: would like to move" << idx.row() << "from" << file->m_appendedTo << "to" << newParent.get() << "as" << targetRow; newParentItem->insertRow(targetRow, rowItems); file->m_appendedTo = newParent.get(); } updateSourceFileLists(); }