XPlor/app/binaryexportdialog.cpp
njohnson d7488c5fa9 Add comprehensive export system with format-specific dialogs
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>
2026-01-12 20:54:38 -05:00

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);
}