#include "csvexporter.h" #include "../model/specificationpcbtablemodel.h" #include "../model/specificationtablemodel.h" #include "../model/perechentablemodel.h" #include "../model/vedomosttablemodel.h" #include "../model/simplelisttablemodel.h" #include #include #include #include #include CSVExporter::CSVExporter(QObject *parent) : QObject(parent) { } bool CSVExporter::exportSpecificationPCB(const QString &filePath, SpecificationPCBTableModel *model) { if (!model) { m_lastError = "Модель таблицы не указана"; return false; } return exportTableModel(filePath, model, true); } bool CSVExporter::exportSpecification(const QString &filePath, SpecificationTableModel *model) { if (!model) { m_lastError = "Модель таблицы не указана"; return false; } return exportTableModel(filePath, model, true); } bool CSVExporter::exportPerechen(const QString &filePath, PerechenTableModel *model) { if (!model) { m_lastError = "Модель таблицы не указана"; return false; } return exportTableModel(filePath, model, true); } bool CSVExporter::exportVedomost(const QString &filePath, VedomostTableModel *model) { if (!model) { m_lastError = "Модель таблицы не указана"; return false; } return exportTableModel(filePath, model, true); } bool CSVExporter::exportSimpleList(const QString &filePath, SimpleListTableModel *model) { if (!model) { m_lastError = "Модель таблицы не указана"; return false; } return exportTableModel(filePath, model, true); } bool CSVExporter::exportTableModel(const QString &filePath, QAbstractTableModel *model, bool includeHeaders) { if (!model) { m_lastError = "Модель таблицы не указана"; return false; } QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { m_lastError = QString("Не удалось открыть файл для записи: %1").arg(file.errorString()); return false; } // Записываем UTF-8 BOM напрямую в файл для корректного отображения в Excel QByteArray bom; bom.append(static_cast(0xEF)); bom.append(static_cast(0xBB)); bom.append(static_cast(0xBF)); if (file.write(bom) != 3) { m_lastError = "Не удалось записать BOM в файл"; file.close(); return false; } QTextStream out(&file); // Устанавливаем кодировку UTF-8 для корректного отображения в Excel QTextCodec *codec = QTextCodec::codecForName("UTF-8"); if (codec) { out.setCodec(codec); } else { // Fallback на строковое имя кодировки out.setCodec("UTF-8"); } // Отключаем автоматическое определение Unicode, так как мы уже записали BOM out.setAutoDetectUnicode(false); // Разделитель для CSV (точка с запятой для Excel в русской локали) const QString delimiter = ";"; try { // Записываем заголовки, если нужно if (includeHeaders) { QStringList headers; int columnCount = model->columnCount(); for (int col = 0; col < columnCount; ++col) { QVariant header = model->headerData(col, Qt::Horizontal, Qt::DisplayRole); headers << escapeCsvValue(header.toString()); } out << formatCsvRow(headers) << "\n"; } // Записываем данные int rowCount = model->rowCount(); for (int row = 0; row < rowCount; ++row) { QStringList values; int columnCount = model->columnCount(); for (int col = 0; col < columnCount; ++col) { QModelIndex index = model->index(row, col); QVariant data = model->data(index, Qt::DisplayRole); values << escapeCsvValue(data.toString()); } out << formatCsvRow(values) << "\n"; } file.close(); m_lastError.clear(); return true; } catch (const std::exception &e) { m_lastError = QString("Ошибка при записи в файл: %1").arg(e.what()); file.close(); return false; } catch (...) { m_lastError = "Неизвестная ошибка при записи в файл"; file.close(); return false; } } QString CSVExporter::escapeCsvValue(const QString &value) const { // Если значение содержит разделитель, кавычки или перенос строки, заключаем в кавычки if (value.contains(";") || value.contains("\"") || value.contains("\n") || value.contains("\r")) { // Экранируем кавычки удвоением QString escaped = value; escaped.replace("\"", "\"\""); return "\"" + escaped + "\""; } return value; } QString CSVExporter::formatCsvRow(const QStringList &values) const { return values.join(";"); } QString CSVExporter::lastError() const { return m_lastError; }