diff --git a/src/gui/Src/BasicView/AbstractStdTable.cpp b/src/gui/Src/BasicView/AbstractStdTable.cpp index 253a25b1..0bb980b8 100644 --- a/src/gui/Src/BasicView/AbstractStdTable.cpp +++ b/src/gui/Src/BasicView/AbstractStdTable.cpp @@ -19,6 +19,7 @@ AbstractStdTable::AbstractStdTable(QWidget* parent) : AbstractTableView(parent) mCopyLineToLog = makeShortcutAction(DIcon("copy_table_line.png"), tr("Line, To Log"), SLOT(copyLineToLogSlot()), "ActionCopyLineToLog"); mCopyTableToLog = makeShortcutAction(DIcon("copy_cropped_table.png"), tr("Cropped Table, To Log"), SLOT(copyTableToLogSlot()), "ActionCopyCroppedTableToLog"); mCopyTableResizeToLog = makeShortcutAction(DIcon("copy_full_table.png"), tr("Full Table, To Log"), SLOT(copyTableResizeToLogSlot()), "ActionCopyTableToLog"); + mExportTableCSV = makeShortcutAction(DIcon("copy_full_table.png"), tr("Export Table"), SLOT(exportTableSlot()), "ActionExport"); } QString AbstractStdTable::paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h) @@ -884,6 +885,18 @@ void AbstractStdTable::copyEntrySlot() Bridge::CopyToClipboard(finalText); } +void AbstractStdTable::exportTableSlot() +{ + std::vector headers; + headers.reserve(getColumnCount()); + for(int i = 0; i < getColumnCount(); i++) + headers.push_back(getColTitle(i)); + ExportCSV(getRowCount(), getColumnCount(), headers, [this](duint row, duint column) + { + return getCellContent(row, column); + }); +} + void AbstractStdTable::setupCopyMenu(QMenu* copyMenu) { if(!getColumnCount()) @@ -903,6 +916,8 @@ void AbstractStdTable::setupCopyMenu(QMenu* copyMenu) copyMenu->addAction(mCopyTableToLog); //Copy->Full Table To Log copyMenu->addAction(mCopyTableResizeToLog); + //Copy->Export Table + copyMenu->addAction(mExportTableCSV); //Copy->Separator copyMenu->addSeparator(); //Copy->ColName @@ -943,6 +958,8 @@ void AbstractStdTable::setupCopyMenu(MenuBuilder* copyMenu) copyMenu->addAction(mCopyTableToLog); //Copy->Full Table copyMenu->addAction(mCopyTableResizeToLog); + //Copy->Export Table + copyMenu->addAction(mExportTableCSV); //Copy->Separator copyMenu->addSeparator(); //Copy->ColName diff --git a/src/gui/Src/BasicView/AbstractStdTable.h b/src/gui/Src/BasicView/AbstractStdTable.h index 285d2c90..2c542484 100644 --- a/src/gui/Src/BasicView/AbstractStdTable.h +++ b/src/gui/Src/BasicView/AbstractStdTable.h @@ -89,6 +89,7 @@ public slots: void copyTableToLogSlot(); void copyTableResizeToLogSlot(); void copyEntrySlot(); + void exportTableSlot(); void contextMenuRequestedSlot(const QPoint & pos); void headerButtonPressedSlot(int col); @@ -151,4 +152,5 @@ protected: QAction* mCopyLineToLog; QAction* mCopyTableToLog; QAction* mCopyTableResizeToLog; + QAction* mExportTableCSV; }; diff --git a/src/gui/Src/Utils/Configuration.cpp b/src/gui/Src/Utils/Configuration.cpp index f6418948..5623de3f 100644 --- a/src/gui/Src/Utils/Configuration.cpp +++ b/src/gui/Src/Utils/Configuration.cpp @@ -620,6 +620,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false) defaultShortcuts.insert("ActionCopyLineToLog", Shortcut({tr("Actions"), tr("Copy -> Line, To Log")})); defaultShortcuts.insert("ActionCopyCroppedTableToLog", Shortcut({tr("Actions"), tr("Copy -> Cropped Table, To Log")})); defaultShortcuts.insert("ActionCopyTableToLog", Shortcut({tr("Actions"), tr("Copy -> Table, To Log")})); + defaultShortcuts.insert("ActionExport", Shortcut({tr("Actions"), tr("Copy -> Export Table")})); Shortcuts = defaultShortcuts; diff --git a/src/gui/Src/Utils/MiscUtil.cpp b/src/gui/Src/Utils/MiscUtil.cpp index 77da0380..b99d68f1 100644 --- a/src/gui/Src/Utils/MiscUtil.cpp +++ b/src/gui/Src/Utils/MiscUtil.cpp @@ -1,9 +1,11 @@ #include "MiscUtil.h" #include +#include +#include #include "LineEditDialog.h" #include "ComboBoxDialog.h" -#include #include "StringUtil.h" +#include "BrowseDialog.h" void SetApplicationIcon(WId winId) { @@ -156,6 +158,120 @@ QString getSymbolicNameStr(duint addr) return finalText; } +bool ExportCSV(dsint rows, dsint columns, std::vector headers, std::function getCellContent) +{ + BrowseDialog browse(nullptr, QApplication::translate("ExportCSV", "Export data in CSV format"), QApplication::translate("ExportCSV", "Enter the CSV file name to export"), QApplication::translate("ExportCSV", "CSV files (*.csv);;All files (*.*)"), QCoreApplication::applicationDirPath(), true); + if(browse.exec() == QDialog::Accepted) + { + FILE* csv; + bool utf16; + csv = _wfopen(browse.path.toStdWString().c_str(), L"wb"); + if(csv == NULL) + { + GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData()); + return false; + } + else + { + duint setting; + if(BridgeSettingGetUint("Misc", "Utf16LogRedirect", &setting)) + utf16 = !!setting; + else + utf16 = false; + if(utf16 && ftell(csv) == 0) + { + unsigned short BOM = 0xfeff; + fwrite(&BOM, 2, 1, csv); + } + dsint row, column; + QString text; + QString cell; + if(headers.size() > 0) + { + for(column = 0; column < columns; column++) + { + cell = headers.at(column); + if(cell.contains('"') || cell.contains(',') || cell.contains('\r') || cell.contains('\n')) + { + if(cell.contains('"')) + cell = cell.replace("\"", "\"\""); + cell = "\"" + cell + "\""; + } + if(column != columns - 1) + cell = cell + ","; + text = text + cell; + } + if(utf16) + { + text = text + "\r\n"; + if(!fwrite(text.utf16(), text.length(), 2, csv)) + { + fclose(csv); + GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData()); + return false; + } + } + else + { + text = text + "\n"; + QByteArray utf8; + utf8 = text.toUtf8(); + if(!fwrite(utf8.constData(), utf8.size(), 1, csv)) + { + fclose(csv); + GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData()); + return false; + } + } + } + for(row = 0; row < rows; row++) + { + text.clear(); + for(column = 0; column < columns; column++) + { + cell = getCellContent(row, column); + if(cell.contains('"') || cell.contains(',') || cell.contains('\r') || cell.contains('\n')) + { + if(cell.contains('"')) + cell = cell.replace("\"", "\"\""); + cell = "\"" + cell + "\""; + } + if(column != columns - 1) + cell = cell + ","; + text = text + cell; + } + if(utf16) + { + text = text + "\r\n"; + if(!fwrite(text.utf16(), text.length(), 2, csv)) + { + fclose(csv); + GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData()); + return false; + } + } + else + { + text = text + "\n"; + QByteArray utf8; + utf8 = text.toUtf8(); + if(!fwrite(utf8.constData(), utf8.size(), 1, csv)) + { + fclose(csv); + GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData()); + return false; + } + } + } + fclose(csv); + GuiAddLogMessage(QApplication::translate("ExportCSV", "Saved CSV data at %1\n").arg(browse.path).toUtf8().constData()); + return true; + } + } + else + return false; +} + static bool allowSeasons() { srand(GetTickCount()); diff --git a/src/gui/Src/Utils/MiscUtil.h b/src/gui/Src/Utils/MiscUtil.h index db12ead4..06156b37 100644 --- a/src/gui/Src/Utils/MiscUtil.h +++ b/src/gui/Src/Utils/MiscUtil.h @@ -2,6 +2,7 @@ #define MISCUTIL_H #include +#include #include "Imports.h" class QWidget; @@ -17,6 +18,7 @@ void SimpleWarningBox(QWidget* parent, const QString & title, const QString & te void SimpleInfoBox(QWidget* parent, const QString & title, const QString & text); QString getSymbolicName(duint addr); QString getSymbolicNameStr(duint addr); +bool ExportCSV(dsint rows, dsint columns, std::vector headers, std::function getCellContent); bool isEaster(); QString couldItBeSeasonal(QString icon);