Implement a unified export system for extracting data from parsed files: ExportManager (singleton): - Centralized export handling for all content types - Content type detection (image, audio, video, text, binary) - Batch export support with progress tracking Format-specific export dialogs: - ImageExportDialog: PNG, JPEG, BMP, TGA with quality options - AudioExportDialog: WAV, MP3, OGG with FFmpeg integration - BinaryExportDialog: Raw data export with optional decompression - BatchExportDialog: Recursive export with filtering options - Base ExportDialog class for common functionality Settings additions: - FFmpeg path configuration with auto-detection - Search common install locations and PATH Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
159 lines
4.4 KiB
C++
159 lines
4.4 KiB
C++
#include "binaryexportdialog.h"
|
|
#include "settings.h"
|
|
|
|
#include <QVBoxLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QLabel>
|
|
#include <QPlainTextEdit>
|
|
#include <QFont>
|
|
#include <QComboBox>
|
|
#include <QGroupBox>
|
|
|
|
BinaryExportDialog::BinaryExportDialog(QWidget *parent)
|
|
: ExportDialog(ContentType::Binary, parent)
|
|
, mHexPreview(nullptr)
|
|
, mSizeLabel(nullptr)
|
|
, mBytesPerLine(16)
|
|
, mPreviewBytes(512) // Show first 512 bytes in preview
|
|
{
|
|
// Populate format combo
|
|
for (const QString& fmt : supportedFormats()) {
|
|
formatCombo()->addItem(fmt.toUpper());
|
|
}
|
|
|
|
setupPreview();
|
|
}
|
|
|
|
void BinaryExportDialog::setupPreview()
|
|
{
|
|
// Create hex preview inside preview container
|
|
QVBoxLayout* previewLayout = new QVBoxLayout(previewContainer());
|
|
previewLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
mHexPreview = new QPlainTextEdit(previewContainer());
|
|
mHexPreview->setReadOnly(true);
|
|
mHexPreview->setLineWrapMode(QPlainTextEdit::NoWrap);
|
|
|
|
// Use monospace font for hex display
|
|
QFont monoFont("Consolas", 9);
|
|
monoFont.setStyleHint(QFont::Monospace);
|
|
mHexPreview->setFont(monoFont);
|
|
|
|
// Dark theme styling
|
|
mHexPreview->setStyleSheet(
|
|
"QPlainTextEdit {"
|
|
" background-color: #1e1e1e;"
|
|
" color: #d4d4d4;"
|
|
" border: none;"
|
|
" selection-background-color: #264f78;"
|
|
"}"
|
|
);
|
|
|
|
mHexPreview->setPlaceholderText("No data loaded");
|
|
previewLayout->addWidget(mHexPreview);
|
|
|
|
// Size info label
|
|
QHBoxLayout* infoLayout = new QHBoxLayout();
|
|
mSizeLabel = new QLabel("Size: --", this);
|
|
infoLayout->addWidget(mSizeLabel);
|
|
infoLayout->addStretch();
|
|
previewLayout->addLayout(infoLayout);
|
|
|
|
// Add description to options container
|
|
QVBoxLayout* optionsLayout = qobject_cast<QVBoxLayout*>(optionsContainer()->layout());
|
|
if (optionsLayout) {
|
|
QLabel* descLabel = new QLabel("Raw binary export preserves data exactly as-is.", this);
|
|
descLabel->setStyleSheet("color: #808080;");
|
|
descLabel->setWordWrap(true);
|
|
optionsLayout->addWidget(descLabel);
|
|
optionsLayout->addStretch();
|
|
}
|
|
}
|
|
|
|
void BinaryExportDialog::updatePreview()
|
|
{
|
|
if (mData.isEmpty()) {
|
|
mHexPreview->setPlainText("");
|
|
mSizeLabel->setText("Size: --");
|
|
return;
|
|
}
|
|
|
|
// Update size label
|
|
qint64 size = mData.size();
|
|
QString sizeStr;
|
|
if (size >= 1024 * 1024) {
|
|
sizeStr = QString("Size: %1 MB (%2 bytes)")
|
|
.arg(size / (1024.0 * 1024.0), 0, 'f', 2)
|
|
.arg(size);
|
|
} else if (size >= 1024) {
|
|
sizeStr = QString("Size: %1 KB (%2 bytes)")
|
|
.arg(size / 1024.0, 0, 'f', 1)
|
|
.arg(size);
|
|
} else {
|
|
sizeStr = QString("Size: %1 bytes").arg(size);
|
|
}
|
|
mSizeLabel->setText(sizeStr);
|
|
|
|
updateHexPreview();
|
|
}
|
|
|
|
QStringList BinaryExportDialog::supportedFormats() const
|
|
{
|
|
return {"bin", "dat", "raw"};
|
|
}
|
|
|
|
void BinaryExportDialog::updateHexPreview()
|
|
{
|
|
if (mData.isEmpty()) {
|
|
mHexPreview->setPlainText("");
|
|
return;
|
|
}
|
|
|
|
QString hexText;
|
|
int bytesToShow = qMin(mPreviewBytes, static_cast<int>(mData.size()));
|
|
const unsigned char* data = reinterpret_cast<const unsigned char*>(mData.constData());
|
|
|
|
for (int i = 0; i < bytesToShow; i += mBytesPerLine) {
|
|
// Offset
|
|
QString line = QString("%1 ").arg(i, 8, 16, QChar('0')).toUpper();
|
|
|
|
// Hex bytes
|
|
QString hexPart;
|
|
QString asciiPart;
|
|
|
|
for (int j = 0; j < mBytesPerLine; ++j) {
|
|
int idx = i + j;
|
|
if (idx < bytesToShow) {
|
|
unsigned char byte = data[idx];
|
|
hexPart += QString("%1 ").arg(byte, 2, 16, QChar('0')).toUpper();
|
|
|
|
// ASCII representation
|
|
if (byte >= 32 && byte < 127) {
|
|
asciiPart += QChar(byte);
|
|
} else {
|
|
asciiPart += '.';
|
|
}
|
|
} else {
|
|
hexPart += " ";
|
|
asciiPart += ' ';
|
|
}
|
|
|
|
// Add extra space in middle for readability
|
|
if (j == 7) {
|
|
hexPart += ' ';
|
|
}
|
|
}
|
|
|
|
line += hexPart + " |" + asciiPart + "|";
|
|
hexText += line + "\n";
|
|
}
|
|
|
|
// Add truncation notice if needed
|
|
if (mData.size() > mPreviewBytes) {
|
|
hexText += QString("\n... (%1 more bytes not shown)")
|
|
.arg(mData.size() - mPreviewBytes);
|
|
}
|
|
|
|
mHexPreview->setPlainText(hexText);
|
|
}
|