#include "xtreewidget.h" #include "exportmanager.h" #include "qheaderview.h" #include "qmenu.h" #include "logmanager.h" #include "xtreewidgetitem.h" #include "../libs/dsl/dslkeys.h" #include XTreeWidget::XTreeWidget(QWidget *parent) : QTreeWidget(parent) { setContextMenuPolicy(Qt::CustomContextMenu); setSelectionMode(QTreeWidget::SingleSelection); setColumnCount(3); header()->hide(); setMinimumWidth(350); setSortingEnabled(false); // Preserve parse order instead of sorting alphabetically 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 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 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; } 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(); QMenu *contextMenu = new QMenu(this); 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; } contextMenu->exec(mapToGlobal(pos)); 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); }); } } void XTreeWidget::ItemSelectionChanged() { if (selectedItems().isEmpty()) { return; } XTreeWidgetItem *selectedItem = dynamic_cast(selectedItems().first()); if (!selectedItem) { return; } if (selectedItem->text(0).isEmpty()) { return; } QString selectedText = selectedItem->text(0); emit ItemSelected(selectedText, selectedItem); }