XPlor/app/xtreewidget.cpp

215 lines
7.7 KiB
C++
Raw Permalink Normal View History

2025-09-05 20:53:15 +00:00
#include "xtreewidget.h"
#include "exportmanager.h"
2025-09-05 20:53:15 +00:00
#include "qheaderview.h"
#include "qmenu.h"
#include "logmanager.h"
2026-01-01 22:18:51 -05:00
#include "xtreewidgetitem.h"
#include "../libs/dsl/dslkeys.h"
2026-01-01 22:18:51 -05:00
#include <QFileDialog>
2025-09-05 20:53:15 +00:00
XTreeWidget::XTreeWidget(QWidget *parent)
: QTreeWidget(parent) {
setContextMenuPolicy(Qt::CustomContextMenu);
setSelectionMode(QTreeWidget::SingleSelection);
setColumnCount(3);
header()->hide();
setMinimumWidth(350);
2026-01-01 22:18:51 -05:00
setSortingEnabled(false); // Preserve parse order instead of sorting alphabetically
2025-09-05 20:53:15 +00:00
setIconSize(QSize(16, 16));
header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
connect(this, &XTreeWidget::itemSelectionChanged, this, &XTreeWidget::ItemSelectionChanged);
connect(this, &XTreeWidget::customContextMenuRequested, this, &XTreeWidget::PrepareContextMenu);
}
int XTreeWidget::countExportableChildren(QTreeWidgetItem* parent) const {
int count = 0;
std::function<void(QTreeWidgetItem*)> countRecursive = [&](QTreeWidgetItem* item) {
QString kind = item->data(0, Qt::UserRole + 1).toString();
if (kind == "INSTANCE") {
count++;
}
for (int i = 0; i < item->childCount(); ++i) {
countRecursive(item->child(i));
}
};
for (int i = 0; i < parent->childCount(); ++i) {
countRecursive(parent->child(i));
}
return count;
}
int XTreeWidget::countExportableChildrenByType(QTreeWidgetItem* parent, int contentType) const {
int count = 0;
ExportManager& exp = ExportManager::instance();
std::function<void(QTreeWidgetItem*)> countRecursive = [&](QTreeWidgetItem* item) {
QString kind = item->data(0, Qt::UserRole + 1).toString();
if (kind == "INSTANCE") {
QVariantMap vars = item->data(0, Qt::UserRole + 3).toMap();
if (exp.detectContentType(vars) == contentType) {
count++;
}
}
for (int i = 0; i < item->childCount(); ++i) {
countRecursive(item->child(i));
}
};
for (int i = 0; i < parent->childCount(); ++i) {
countRecursive(parent->child(i));
}
return count;
}
2025-09-05 20:53:15 +00:00
void XTreeWidget::PrepareContextMenu(const QPoint &pos) {
auto activeItem = itemAt(pos);
if (!activeItem) { return; }
if (activeItem->text(0).isEmpty()) { return; }
QString kind = activeItem->data(0, Qt::UserRole + 1).toString();
2025-09-05 20:53:15 +00:00
QMenu *contextMenu = new QMenu(this);
2025-09-05 20:53:15 +00:00
if (kind == "INSTANCE") {
prepareInstanceContextMenu(contextMenu, activeItem);
} else if (kind == "CATEGORY" || kind == "SUBCATEGORY" || kind == "EXTENSION_GROUP") {
prepareContainerContextMenu(contextMenu, activeItem);
} else {
// No context menu for other item types
delete contextMenu;
return;
}
2025-09-05 20:53:15 +00:00
contextMenu->exec(mapToGlobal(pos));
2025-09-05 20:53:15 +00:00
delete contextMenu;
}
void XTreeWidget::prepareInstanceContextMenu(QMenu* menu, QTreeWidgetItem* item) {
QVariantMap vars = item->data(0, Qt::UserRole + 3).toMap();
ExportManager& exp = ExportManager::instance();
auto contentType = exp.detectContentType(vars);
// Quick Export - uses saved defaults
QAction* quickAction = menu->addAction("Quick Export");
quickAction->setShortcut(QKeySequence("Ctrl+Shift+E"));
connect(quickAction, &QAction::triggered, this, [this, item]() {
emit quickExportRequested(item);
});
// Export with dialog - full options
QAction* dialogAction = menu->addAction("Export...");
dialogAction->setShortcut(QKeySequence("Ctrl+E"));
connect(dialogAction, &QAction::triggered, this, [this, item]() {
emit exportDialogRequested(item);
});
menu->addSeparator();
// Raw export - always available
QAction* rawAction = menu->addAction("Export Raw Data...");
connect(rawAction, &QAction::triggered, this, [this, item]() {
emit exportRequested("raw", item);
});
menu->addSeparator();
// Format-specific exports based on content type
if (contentType == ExportManager::Image) {
QMenu* imgMenu = menu->addMenu("Export Image As");
for (const QString& fmt : exp.supportedImageFormats()) {
QAction* a = imgMenu->addAction(fmt.toUpper());
connect(a, &QAction::triggered, this, [this, item, fmt]() {
emit exportRequested(fmt, item);
});
}
}
else if (contentType == ExportManager::Audio) {
QMenu* audMenu = menu->addMenu("Export Audio As");
for (const QString& fmt : exp.supportedAudioFormats()) {
QAction* a = audMenu->addAction(fmt.toUpper());
// Disable non-WAV formats if FFmpeg not available
a->setEnabled(fmt == "wav" || exp.hasFFmpeg());
if (!a->isEnabled()) {
a->setText(a->text() + " (requires FFmpeg)");
}
connect(a, &QAction::triggered, this, [this, item, fmt]() {
emit exportRequested(fmt, item);
});
}
}
else if (contentType == ExportManager::Text) {
QAction* txtAction = menu->addAction("Export as Text...");
connect(txtAction, &QAction::triggered, this, [this, item]() {
emit exportRequested("txt", item);
});
}
menu->addSeparator();
// Clipboard operations
QAction* copyAction = menu->addAction("Copy to Clipboard");
connect(copyAction, &QAction::triggered, this, [this, item]() {
emit exportRequested("clipboard", item);
});
}
void XTreeWidget::prepareContainerContextMenu(QMenu* menu, QTreeWidgetItem* item) {
int totalCount = countExportableChildren(item);
if (totalCount == 0) {
QAction* emptyAction = menu->addAction("No exportable items");
emptyAction->setEnabled(false);
return;
}
// Export all children
QAction* exportAllAction = menu->addAction(QString("Export All Children... (%1 items)").arg(totalCount));
connect(exportAllAction, &QAction::triggered, this, [this, item]() {
emit batchExportRequested(item);
});
menu->addSeparator();
// Export by type
int imageCount = countExportableChildrenByType(item, ExportManager::Image);
int audioCount = countExportableChildrenByType(item, ExportManager::Audio);
int textCount = countExportableChildrenByType(item, ExportManager::Text);
if (imageCount > 0) {
QAction* imgAction = menu->addAction(QString("Export All Images... (%1)").arg(imageCount));
connect(imgAction, &QAction::triggered, this, [this, item]() {
emit batchExportByTypeRequested(item, ExportManager::Image);
});
}
if (audioCount > 0) {
QAction* audAction = menu->addAction(QString("Export All Audio... (%1)").arg(audioCount));
connect(audAction, &QAction::triggered, this, [this, item]() {
emit batchExportByTypeRequested(item, ExportManager::Audio);
});
}
if (textCount > 0) {
QAction* txtAction = menu->addAction(QString("Export All Text... (%1)").arg(textCount));
connect(txtAction, &QAction::triggered, this, [this, item]() {
emit batchExportByTypeRequested(item, ExportManager::Text);
});
}
}
2025-09-05 20:53:15 +00:00
void XTreeWidget::ItemSelectionChanged() {
if (selectedItems().isEmpty()) { return; }
XTreeWidgetItem *selectedItem = dynamic_cast<XTreeWidgetItem*>(selectedItems().first());
if (!selectedItem) { return; }
if (selectedItem->text(0).isEmpty()) { return; }
QString selectedText = selectedItem->text(0);
emit ItemSelected(selectedText, selectedItem);
2025-09-05 20:53:15 +00:00
}