Add initial project structure with essential files including .gitignore, application resources, and various model and view components for the application. Implemented asynchronous parsing support and database structure checks.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,188 @@
|
||||
#ifndef ALTIUMPARSER_H
|
||||
#define ALTIUMPARSER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QRegularExpression>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QTextCodec>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#include <QtConcurrent>
|
||||
|
||||
// Структуры данных для парсинга
|
||||
struct ComponentProperty {
|
||||
QString name;
|
||||
QString text;
|
||||
};
|
||||
|
||||
struct VariantInfo {
|
||||
QString name;
|
||||
QStringList dnfDesignators;
|
||||
QStringList fittedDesignators;
|
||||
QList<QList<ComponentProperty>> componentVariants;
|
||||
QList<QMap<QString, QString>> parameters;
|
||||
};
|
||||
|
||||
struct DielProperty {
|
||||
QString name;
|
||||
QString value;
|
||||
double height; // толщина материала в мм
|
||||
int dielType; // 1 - ядро, 2 - препрег
|
||||
int layerNumber; // номер слоя
|
||||
};
|
||||
|
||||
struct ProjectParameterData {
|
||||
QString name;
|
||||
QString value;
|
||||
QString variantName;
|
||||
};
|
||||
|
||||
// Структура для хранения данных проекта
|
||||
struct ProjectData {
|
||||
QStringList variantNames;
|
||||
QList<QList<ComponentProperty>> componentsList;
|
||||
QList<QList<QList<ComponentProperty>>> componentsVariantList;
|
||||
QList<QList<ComponentProperty>> componentsPropVariantList;
|
||||
QList<ComponentProperty> componentVariantPropList;
|
||||
QStringList dnfDesignatorsList;
|
||||
QList<QStringList> dnfVariantDesignatorsList;
|
||||
QStringList fittedDesignatorsList;
|
||||
QList<QStringList> fittedVariantDesignatorsList;
|
||||
QList<QList<QStringList>> prjParamsVariantList;
|
||||
|
||||
// PCB данные
|
||||
int pcbLayerCount;
|
||||
QList<DielProperty> pcbDielMaterials;
|
||||
|
||||
// Переменные состояния парсинга
|
||||
bool isWaitingVariantDescription = false;
|
||||
int currentVariantNumber = 0;
|
||||
};
|
||||
|
||||
// Forward declarations
|
||||
class DataBaseController;
|
||||
class ComponentModel;
|
||||
|
||||
class AltiumParser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AltiumParser(QObject *parent = nullptr);
|
||||
~AltiumParser();
|
||||
|
||||
// Основные методы парсинга
|
||||
bool parseSchFile(const QString &filename, ComponentModel *model);
|
||||
bool parsePcbFile(const QString &filename, ComponentModel *model);
|
||||
bool parseBomFile(const QString &filename, ComponentModel *model);
|
||||
|
||||
// Парсинг специфичных форматов Altium
|
||||
bool parseSchDoc(const QString &filename, ComponentModel *model);
|
||||
bool parsePcbDoc(const QString &filename, ComponentModel *model);
|
||||
bool parseCsvBom(const QString &filename, ComponentModel *model);
|
||||
bool parseXlsBom(const QString &filename, ComponentModel *model);
|
||||
bool parsePrjPcbFile(const QString &filename, ComponentModel *model);
|
||||
|
||||
// Утилиты для работы с данными
|
||||
QString extractComponentDesignation(const QString &line);
|
||||
QString extractComponentName(const QString &line);
|
||||
QString extractComponentValue(const QString &line);
|
||||
QString extractComponentFootprint(const QString &line);
|
||||
QString extractComponentManufacturer(const QString &line);
|
||||
QString extractComponentPartNumber(const QString &line);
|
||||
int extractComponentQuantity(const QString &line);
|
||||
|
||||
// Обработка ошибок
|
||||
QString lastError() const;
|
||||
void clearError();
|
||||
|
||||
// Доступ к базе данных
|
||||
DataBaseController* getDatabase() const;
|
||||
void setDatabase(DataBaseController *database);
|
||||
|
||||
// Асинхронный парсинг
|
||||
bool parseFileAsync(const QString &filename, ComponentModel *model);
|
||||
bool isParsingAsync() const;
|
||||
void cancelParsing();
|
||||
|
||||
signals:
|
||||
void parsingStarted();
|
||||
void parsingProgress(int percentage);
|
||||
void parsingFinished(bool success);
|
||||
void parsingError(const QString &error);
|
||||
|
||||
private:
|
||||
QString m_lastError;
|
||||
|
||||
// Асинхронный парсинг
|
||||
QFutureWatcher<bool> *m_parseWatcher;
|
||||
bool m_isParsingAsync;
|
||||
|
||||
// Регулярные выражения для парсинга
|
||||
QRegularExpression m_designationRegex;
|
||||
QRegularExpression m_nameRegex;
|
||||
QRegularExpression m_valueRegex;
|
||||
QRegularExpression m_footprintRegex;
|
||||
QRegularExpression m_manufacturerRegex;
|
||||
QRegularExpression m_partNumberRegex;
|
||||
QRegularExpression m_quantityRegex;
|
||||
|
||||
// Вспомогательные методы
|
||||
void initializeRegex();
|
||||
bool parseSchLine(const QString &line, QMap<QString, QString> &component);
|
||||
bool parsePcbLine(const QString &line, QMap<QString, QString> &component);
|
||||
bool parseBomLine(const QString &line, QMap<QString, QString> &component);
|
||||
QString cleanString(const QString &str);
|
||||
bool isValidComponent(const QMap<QString, QString> &component);
|
||||
void setError(const QString &error);
|
||||
|
||||
// Методы для парсинга PrjPcb
|
||||
bool parseProjectFile(const QString &filename, ComponentModel *model);
|
||||
bool parseSchDocFile(const QString &filename, QList<QList<ComponentProperty>> &componentsList);
|
||||
bool parsePcbDocFile(const QString &filename, QList<DielProperty> &dielMaterials, int &pcbLayersCount);
|
||||
QString makeComplexStringIfItIs(const QString &text, const QList<ComponentProperty> &componentProps);
|
||||
QString makeDesignatorForOrdering(const QString &designator);
|
||||
QString findParamDesignator(QTextStream &reader, const QString ¶mNumber);
|
||||
|
||||
// Новые методы для улучшенного парсера
|
||||
void parseProjectVariantSection(const QString &prjStr, ProjectData &data);
|
||||
void parseComponentVariations(const QString &prjStr, ProjectData &data);
|
||||
void parseProjectParameters(const QString &prevPrevPrjStr, const QString &prevPrjStr, const QString &prjStr, ProjectData &data);
|
||||
void parseSchDocFiles(const QString &prjStr, const QString &filename, ProjectData &data);
|
||||
void parsePcbDocFiles(const QString &prjStr, const QString &filename, ProjectData &data);
|
||||
void finalizeCurrentVariant(ProjectData &data);
|
||||
void parseVariationDesignator(const QStringList &prjStrArray, const QStringList &valuesArray, ProjectData &data);
|
||||
void parseParamVariation(const QStringList &prjStrArray, const QStringList &valuesArray, ProjectData &data);
|
||||
void printParsingResults(const ProjectData &data);
|
||||
void saveDataToDatabase(const ProjectData &data);
|
||||
void saveVariantsToDatabase(const ProjectData &data);
|
||||
void saveRegularComponents(const ProjectData &data);
|
||||
void saveVariantProperties(const ProjectData &data);
|
||||
void saveProjectParameters(const ProjectData &data);
|
||||
void savePCBDataToDatabase(const ProjectData &data);
|
||||
void setupModelData(const ProjectData &data, ComponentModel *model);
|
||||
|
||||
// Слоты для асинхронного парсинга
|
||||
void onParseFinished();
|
||||
void onParseProgress(int progress);
|
||||
|
||||
// Данные проекта Altium
|
||||
QList<QList<ComponentProperty>> m_componentsList;
|
||||
QList<VariantInfo> m_variantsList;
|
||||
QList<DielProperty> m_dielMaterialsList;
|
||||
QList<ProjectParameterData> m_projectParamsList;
|
||||
QStringList m_variantNamesList;
|
||||
bool m_isPcbMultilayer;
|
||||
|
||||
// База данных для хранения компонентов
|
||||
DataBaseController *m_database;
|
||||
};
|
||||
|
||||
#endif // ALTIUMPARSER_H
|
||||
@@ -0,0 +1,160 @@
|
||||
#include "csvexporter.h"
|
||||
#include "../model/specificationpcbtablemodel.h"
|
||||
#include "../model/specificationtablemodel.h"
|
||||
#include "../model/perechentablemodel.h"
|
||||
#include "../model/vedomosttablemodel.h"
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QTextCodec>
|
||||
#include <QDebug>
|
||||
#include <QStandardPaths>
|
||||
|
||||
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::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<char>(0xEF));
|
||||
bom.append(static_cast<char>(0xBB));
|
||||
bom.append(static_cast<char>(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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#ifndef CSVEXPORTER_H
|
||||
#define CSVEXPORTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
class SpecificationPCBTableModel;
|
||||
class SpecificationTableModel;
|
||||
class PerechenTableModel;
|
||||
class VedomostTableModel;
|
||||
|
||||
/**
|
||||
* @brief Класс для экспорта таблиц в формат CSV
|
||||
*
|
||||
* Поддерживает экспорт следующих типов таблиц:
|
||||
* - SpecificationPCBTableModel (Спецификация PCB)
|
||||
* - SpecificationTableModel (Спецификация материалов)
|
||||
* - PerechenTableModel (Перечень элементов)
|
||||
* - VedomostTableModel (Ведомость покупных изделий)
|
||||
*/
|
||||
class CSVExporter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CSVExporter(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Экспортирует таблицу спецификации PCB в CSV
|
||||
* @param filePath Путь к файлу для сохранения
|
||||
* @param model Модель таблицы спецификации PCB
|
||||
* @return true если экспорт успешен, false в противном случае
|
||||
*/
|
||||
bool exportSpecificationPCB(const QString &filePath, SpecificationPCBTableModel *model);
|
||||
|
||||
/**
|
||||
* @brief Экспортирует таблицу спецификации материалов в CSV
|
||||
* @param filePath Путь к файлу для сохранения
|
||||
* @param model Модель таблицы спецификации материалов
|
||||
* @return true если экспорт успешен, false в противном случае
|
||||
*/
|
||||
bool exportSpecification(const QString &filePath, SpecificationTableModel *model);
|
||||
|
||||
/**
|
||||
* @brief Экспортирует таблицу перечня элементов в CSV
|
||||
* @param filePath Путь к файлу для сохранения
|
||||
* @param model Модель таблицы перечня элементов
|
||||
* @return true если экспорт успешен, false в противном случае
|
||||
*/
|
||||
bool exportPerechen(const QString &filePath, PerechenTableModel *model);
|
||||
|
||||
/**
|
||||
* @brief Экспортирует таблицу ведомости покупных изделий в CSV
|
||||
* @param filePath Путь к файлу для сохранения
|
||||
* @param model Модель таблицы ведомости покупных изделий
|
||||
* @return true если экспорт успешен, false в противном случае
|
||||
*/
|
||||
bool exportVedomost(const QString &filePath, VedomostTableModel *model);
|
||||
|
||||
/**
|
||||
* @brief Экспортирует любую модель таблицы в CSV
|
||||
* @param filePath Путь к файлу для сохранения
|
||||
* @param model Модель таблицы
|
||||
* @param includeHeaders Включать ли заголовки колонок
|
||||
* @return true если экспорт успешен, false в противном случае
|
||||
*/
|
||||
bool exportTableModel(const QString &filePath, QAbstractTableModel *model, bool includeHeaders = true);
|
||||
|
||||
/**
|
||||
* @brief Возвращает последнюю ошибку
|
||||
* @return Текст ошибки
|
||||
*/
|
||||
QString lastError() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Экранирует значение для CSV
|
||||
* @param value Значение для экранирования
|
||||
* @return Экранированное значение
|
||||
*/
|
||||
QString escapeCsvValue(const QString &value) const;
|
||||
|
||||
/**
|
||||
* @brief Формирует строку CSV из списка значений
|
||||
* @param values Список значений
|
||||
* @return Строка CSV
|
||||
*/
|
||||
QString formatCsvRow(const QStringList &values) const;
|
||||
|
||||
QString m_lastError;
|
||||
};
|
||||
|
||||
#endif // CSVEXPORTER_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,206 @@
|
||||
#ifndef DATABASECONTROLLER_H
|
||||
#define DATABASECONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlError>
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
#include <QList>
|
||||
#include "altiumparser.h"
|
||||
|
||||
struct ComponentData {
|
||||
int id;
|
||||
QString designator;
|
||||
QMap<QString, QString> baseProperties;
|
||||
QMap<QString, QMap<QString, QString>> variantProperties;
|
||||
QMap<QString, bool> variantFitted;
|
||||
};
|
||||
|
||||
struct VariantData {
|
||||
int id;
|
||||
QString name;
|
||||
};
|
||||
|
||||
struct ProjectParamData {
|
||||
int id;
|
||||
QString name;
|
||||
QString value;
|
||||
};
|
||||
|
||||
struct DesignatorMappingData {
|
||||
int id;
|
||||
QString designator;
|
||||
QString singularName;
|
||||
QString pluralName;
|
||||
bool isCustom;
|
||||
};
|
||||
|
||||
struct PCBData {
|
||||
int id;
|
||||
int layerCount;
|
||||
QList<DielProperty> dielMaterials;
|
||||
};
|
||||
|
||||
class DataBaseController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DataBaseController(QObject *parent = nullptr);
|
||||
~DataBaseController();
|
||||
|
||||
// Инициализация БД
|
||||
bool initializeDatabase(const QString &dbPath = "components.db", const QString &connectionName = QString());
|
||||
bool createTables();
|
||||
|
||||
// Работа с вариантами
|
||||
int addVariant(const QString &name);
|
||||
bool removeVariant(int variantId);
|
||||
QList<VariantData> getAllVariants();
|
||||
int getVariantId(const QString &name);
|
||||
|
||||
// Работа с компонентами
|
||||
int addComponent(const QString &designator);
|
||||
bool removeComponent(int componentId);
|
||||
bool updateComponentDesignator(int componentId, const QString &designator);
|
||||
QList<ComponentData> getAllComponents();
|
||||
ComponentData getComponent(int componentId);
|
||||
ComponentData getComponent(const QString &designator);
|
||||
bool saveComponents(const QList<ComponentData> &components);
|
||||
|
||||
// Пакетная вставка компонентов (оптимизация)
|
||||
bool beginTransaction();
|
||||
bool commitTransaction();
|
||||
bool rollbackTransaction();
|
||||
bool addComponentBatch(const QString &designator, const QMap<QString, QString> &properties);
|
||||
bool addComponentPropertiesBatch(int componentId, const QMap<QString, QString> &properties);
|
||||
bool addComponentVariantsBatch(int componentId, const QStringList &variantNames);
|
||||
|
||||
// Работа со свойствами компонентов
|
||||
bool setComponentProperty(int componentId, const QString &propertyName, const QString &propertyValue);
|
||||
bool removeComponentProperty(int componentId, const QString &propertyName);
|
||||
QMap<QString, QString> getComponentProperties(int componentId);
|
||||
|
||||
// Работа с вариантами компонентов
|
||||
bool setComponentVariantFitted(int componentId, int variantId, bool fitted);
|
||||
bool setVariantProperty(int componentId, int variantId, const QString &propertyName, const QString &propertyValue);
|
||||
bool removeVariantProperty(int componentId, int variantId, const QString &propertyName);
|
||||
|
||||
// Работа с параметрами проекта
|
||||
int addProjectParam(const QString &name, const QString &value);
|
||||
bool updateProjectParam(int paramId, const QString &name, const QString &value);
|
||||
bool removeProjectParam(int paramId);
|
||||
QList<ProjectParamData> getAllProjectParams();
|
||||
ProjectParamData getProjectParam(int paramId);
|
||||
bool setProjectParam(const QString &name, const QString &value);
|
||||
|
||||
// Работа с данными PCB
|
||||
int addPCBData(int layerCount);
|
||||
bool updatePCBLayerCount(int pcbId, int layerCount);
|
||||
bool addDielMaterial(int pcbId, const QString &name, const QString &value, double height, int dielType = 0, int layerNumber = 0);
|
||||
bool updateDielMaterial(int pcbId, const QString &name, const QString &value, double height, int dielType = 0, int layerNumber = 0);
|
||||
bool removeDielMaterial(int pcbId, int layerNumber);
|
||||
PCBData getPCBData(int pcbId);
|
||||
PCBData getPCBData(); // Получить последние данные PCB
|
||||
QList<DielProperty> getDielMaterials(int pcbId);
|
||||
QList<DielProperty> getDielMaterials(); // Получить все материалы
|
||||
bool savePCBData(const PCBData &pcbData);
|
||||
bool clearPCBData();
|
||||
|
||||
// Работа с настройками проекта
|
||||
bool setProjectSetting(const QString &key, const QString &value);
|
||||
QString getProjectSetting(const QString &key, const QString &defaultValue = QString());
|
||||
bool setProjectSettingList(const QString &key, const QStringList &value);
|
||||
QStringList getProjectSettingList(const QString &key, const QStringList &defaultValue = QStringList());
|
||||
|
||||
// Работа с маппингами дезигнаторов
|
||||
int addDesignatorMapping(const QString &designator, const QString &singularName,
|
||||
const QString &pluralName, bool isCustom = false);
|
||||
bool updateDesignatorMapping(int mappingId, const QString &designator,
|
||||
const QString &singularName, const QString &pluralName, bool isCustom);
|
||||
bool removeDesignatorMapping(int mappingId);
|
||||
bool removeDesignatorMapping(const QString &designator);
|
||||
QList<DesignatorMappingData> getAllDesignatorMappings();
|
||||
DesignatorMappingData getDesignatorMapping(int mappingId);
|
||||
DesignatorMappingData getDesignatorMapping(const QString &designator);
|
||||
bool saveDesignatorMappings(const QList<DesignatorMappingData> &mappings);
|
||||
bool clearCustomDesignatorMappings();
|
||||
bool resetDesignatorMappingsToDefaults();
|
||||
|
||||
// Работа с надписями титульного листа
|
||||
bool saveTitleInscriptions(const QMap<int, QString> &inscriptions, const QString &projectName = QString());
|
||||
bool loadTitleInscriptions(QMap<int, QString> &inscriptions, const QString &projectName = QString());
|
||||
bool deleteTitleInscriptions(const QString &projectName = QString());
|
||||
QStringList getAvailableTitleInscriptionProjects();
|
||||
|
||||
// Работа с перечнем элементов
|
||||
bool savePerechenTable(const QByteArray &tableData, const QString &projectName = QString());
|
||||
QByteArray loadPerechenTable(const QString &projectName = QString());
|
||||
bool deletePerechenTable(const QString &projectName = QString());
|
||||
QStringList getAvailablePerechenProjects();
|
||||
|
||||
// Метод для получения информации о структуре перечня в БД
|
||||
QString getPerechenTableInfo(const QString &projectName = QString());
|
||||
|
||||
// Работа со спецификацией платы
|
||||
bool saveSpecificationPCBTable(const QByteArray &tableData, const QString &projectName = QString());
|
||||
QByteArray loadSpecificationPCBTable(const QString &projectName = QString());
|
||||
bool deleteSpecificationPCBTable(const QString &projectName = QString());
|
||||
QStringList getAvailableSpecificationPCBProjects();
|
||||
|
||||
// Метод для получения информации о структуре спецификации платы в БД
|
||||
QString getSpecificationPCBTableInfo(const QString &projectName = QString());
|
||||
|
||||
// Работа со спецификацией материалов
|
||||
bool saveSpecificationTable(const QByteArray &tableData, const QString &projectName = QString());
|
||||
QByteArray loadSpecificationTable(const QString &projectName = QString());
|
||||
bool deleteSpecificationTable(const QString &projectName = QString());
|
||||
QStringList getAvailableSpecificationProjects();
|
||||
|
||||
// Метод для получения информации о структуре спецификации материалов в БД
|
||||
QString getSpecificationTableInfo(const QString &projectName = QString());
|
||||
|
||||
// Работа с ведомостью покупных изделий
|
||||
bool saveVedomostTable(const QByteArray &tableData, const QString &projectName = QString());
|
||||
QByteArray loadVedomostTable(const QString &projectName = QString());
|
||||
bool deleteVedomostTable(const QString &projectName = QString());
|
||||
QStringList getAvailableVedomostProjects();
|
||||
|
||||
// Метод для получения информации о структуре ведомости покупных изделий в БД
|
||||
QString getVedomostTableInfo(const QString &projectName = QString());
|
||||
|
||||
// Получение данных для отображения
|
||||
QList<ComponentData> getComponentsForVariant(int variantId);
|
||||
QList<ComponentData> getComponentsForVariant(const QString &variantName);
|
||||
|
||||
// Получение всех уникальных свойств
|
||||
QStringList getAllPropertyNames();
|
||||
|
||||
// Очистка БД
|
||||
void clearAllData();
|
||||
|
||||
// Проверка состояния БД
|
||||
bool isDatabaseOpen() const;
|
||||
QString lastError() const;
|
||||
QString getDatabasePath() const;
|
||||
|
||||
signals:
|
||||
void databaseError(const QString &error);
|
||||
void dataChanged();
|
||||
|
||||
private:
|
||||
QSqlDatabase m_database;
|
||||
QString m_lastError;
|
||||
static int s_connectionCounter;
|
||||
|
||||
// Вспомогательные методы
|
||||
bool executeQuery(const QString &query, const QVariantMap ¶ms = QVariantMap());
|
||||
QSqlQuery prepareQuery(const QString &query);
|
||||
void setLastError(const QString &error);
|
||||
|
||||
// Миграции базы данных
|
||||
void migrateAddCellStretchesColumn();
|
||||
};
|
||||
|
||||
#endif // DATABASECONTROLLER_H
|
||||
@@ -0,0 +1,938 @@
|
||||
#include "maincontroller.h"
|
||||
#include "../model/componenttablemodel.h"
|
||||
#include "../model/projectparamtablemodel.h"
|
||||
#include "../model/projectsettingsmodel.h"
|
||||
#include "../model/designatormappingmodel.h"
|
||||
#include "../model/perechentablemodel.h"
|
||||
#include "../model/specificationpcbtablemodel.h"
|
||||
#include "../model/specificationtablemodel.h"
|
||||
#include "../model/vedomosttablemodel.h"
|
||||
#include "../model/titleinscriptionsmodel.h"
|
||||
#include "../model/pcbmaterialmodel.h"
|
||||
#include "perechentablecontroller.h"
|
||||
#include "specificationpcbcontroller.h"
|
||||
#include "specificationcontroller.h"
|
||||
#include "vedomostcontroller.h"
|
||||
#include "databasecontroller.h"
|
||||
#include "altiumparser.h"
|
||||
#include "csvexporter.h"
|
||||
#include <QDateTime>
|
||||
#include <QFileInfo>
|
||||
#include <QStandardPaths>
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QMap>
|
||||
|
||||
MainController::MainController(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_componentTableModel(new ComponentTableModel(this))
|
||||
, m_projectParamTableModel(new ProjectParamTableModel(this))
|
||||
, m_projectSettingsModel(new ProjectSettingsModel(this))
|
||||
, m_designatorMappingModel(new DesignatorMappingModel(this))
|
||||
, m_perechenTableModel(new PerechenTableModel(this))
|
||||
, m_perechenTableController(new PerechenTableController(this))
|
||||
, m_specificationPCBTableModel(new SpecificationPCBTableModel(this))
|
||||
, m_specificationPCBController(new SpecificationPCBController(this))
|
||||
, m_specificationTableModel(new SpecificationTableModel(this))
|
||||
, m_specificationController(new SpecificationController(this))
|
||||
, m_vedomostTableModel(new VedomostTableModel(this))
|
||||
, m_vedomostController(new VedomostController(this))
|
||||
, m_titleInscriptionsModel(new TitleInscriptionsModel(this))
|
||||
, m_pcbMaterialModel(new PCBMaterialModel(this))
|
||||
, m_databaseController(new DataBaseController(this))
|
||||
, m_globalDatabaseController(new DataBaseController(this))
|
||||
, m_altiumParser(new AltiumParser(this))
|
||||
, m_currentVariant(QString())
|
||||
, m_pdfController(new PDFController(this))
|
||||
, m_csvExporter(new CSVExporter(this))
|
||||
{
|
||||
// Устанавливаем глобальный контроллер БД в модель маппинга дезигнаторов
|
||||
m_designatorMappingModel->setDatabaseController(m_globalDatabaseController);
|
||||
|
||||
// Устанавливаем модель маппинга дезигнаторов в контроллер перечня
|
||||
m_perechenTableController->setDesignatorMappingModel(m_designatorMappingModel);
|
||||
|
||||
// Устанавливаем контроллер БД в модель настроек проекта
|
||||
m_projectSettingsModel->setDatabaseController(m_databaseController);
|
||||
|
||||
// Устанавливаем модель настроек проекта в контроллеры
|
||||
m_perechenTableController->setProjectSettingsModel(m_projectSettingsModel);
|
||||
m_specificationPCBController->setProjectSettingsModel(m_projectSettingsModel);
|
||||
m_specificationController->setProjectSettingsModel(m_projectSettingsModel);
|
||||
m_vedomostController->setProjectSettingsModel(m_projectSettingsModel);
|
||||
|
||||
// Устанавливаем MainController в контроллеры
|
||||
m_specificationPCBController->setMainController(this);
|
||||
m_specificationController->setMainController(this);
|
||||
m_vedomostController->setMainController(this);
|
||||
|
||||
// Устанавливаем модель маппинга дезигнаторов в контроллеры
|
||||
m_specificationPCBController->setDesignatorMappingModel(m_designatorMappingModel);
|
||||
m_vedomostController->setDesignatorMappingModel(m_designatorMappingModel);
|
||||
|
||||
// Устанавливаем связь между PerechenTableModel и PerechenTableController
|
||||
m_perechenTableController->setModel(m_perechenTableModel);
|
||||
|
||||
// Устанавливаем настройки колонок по умолчанию в контроллер перечня
|
||||
QStringList defaultColumnMappings = QStringList() << "Designator" << "Name" << "Quantity" << "Note";
|
||||
m_perechenTableController->setColumnMappings(defaultColumnMappings);
|
||||
|
||||
// Устанавливаем настройки колонок по умолчанию в контроллер спецификации платы
|
||||
QStringList defaultSpecPCBColumnMappings = QStringList() << "Format" << "Zone" << "Position" << "Designator" << "Name" << "Quantity" << "Note";
|
||||
m_specificationPCBController->setColumnMappings(defaultSpecPCBColumnMappings);
|
||||
|
||||
// Устанавливаем настройки колонок по умолчанию в контроллер спецификации материалов
|
||||
QStringList defaultSpecColumnMappings = QStringList() << "Format" << "Zone" << "Position" << "Designation" << "Name" << "Quantity" << "Note";
|
||||
m_specificationController->setColumnMappings(defaultSpecColumnMappings);
|
||||
|
||||
// Устанавливаем настройки колонок по умолчанию в контроллер ведомости покупных изделий
|
||||
QStringList defaultVedomostColumnMappings = QStringList() << "Name" << "ProductCode" << "DocumentCode" << "Supplier"
|
||||
<< "WhereUsed" << "QuantityPerItem" << "QuantityInSet"
|
||||
<< "QuantityForReg" << "TotalQuantity" << "Note";
|
||||
m_vedomostController->setColumnMappings(defaultVedomostColumnMappings);
|
||||
|
||||
// Устанавливаем модель ведомости в контроллер
|
||||
m_vedomostController->setModel(m_vedomostTableModel);
|
||||
|
||||
connect(m_databaseController, &DataBaseController::databaseError,
|
||||
this, &MainController::databaseError);
|
||||
|
||||
// Подключаем сигналы от парсера к контроллеру
|
||||
connect(m_altiumParser, &AltiumParser::parsingStarted,
|
||||
this, &MainController::parsingStarted);
|
||||
connect(m_altiumParser, &AltiumParser::parsingProgress,
|
||||
this, &MainController::parsingProgress);
|
||||
connect(m_altiumParser, &AltiumParser::parsingFinished,
|
||||
this, &MainController::parsingFinished);
|
||||
connect(m_altiumParser, &AltiumParser::parsingError,
|
||||
this, &MainController::error);
|
||||
|
||||
// Устанавливаем базу данных в парсер
|
||||
m_altiumParser->setDatabase(m_databaseController);
|
||||
|
||||
// Устанавливаем базу данных в модель материалов платы
|
||||
m_pcbMaterialModel->setDatabase(m_databaseController);
|
||||
}
|
||||
|
||||
MainController::~MainController() {
|
||||
}
|
||||
|
||||
ComponentTableModel* MainController::componentTableModel() const {
|
||||
return m_componentTableModel;
|
||||
}
|
||||
|
||||
ProjectParamTableModel* MainController::projectParamTableModel() const {
|
||||
return m_projectParamTableModel;
|
||||
}
|
||||
|
||||
ProjectSettingsModel* MainController::projectSettingsModel() const {
|
||||
return m_projectSettingsModel;
|
||||
}
|
||||
|
||||
DesignatorMappingModel* MainController::designatorMappingModel() const {
|
||||
return m_designatorMappingModel;
|
||||
}
|
||||
|
||||
PerechenTableModel* MainController::perechenTableModel() const {
|
||||
return m_perechenTableModel;
|
||||
}
|
||||
|
||||
PerechenTableController* MainController::perechenTableController() const {
|
||||
return m_perechenTableController;
|
||||
}
|
||||
|
||||
SpecificationPCBTableModel* MainController::specificationPCBTableModel() const {
|
||||
return m_specificationPCBTableModel;
|
||||
}
|
||||
|
||||
SpecificationPCBController* MainController::specificationPCBController() const {
|
||||
return m_specificationPCBController;
|
||||
}
|
||||
|
||||
SpecificationTableModel* MainController::specificationTableModel() const {
|
||||
return m_specificationTableModel;
|
||||
}
|
||||
|
||||
SpecificationController* MainController::specificationController() const {
|
||||
return m_specificationController;
|
||||
}
|
||||
|
||||
VedomostTableModel* MainController::vedomostTableModel() const {
|
||||
return m_vedomostTableModel;
|
||||
}
|
||||
|
||||
VedomostController* MainController::vedomostController() const {
|
||||
return m_vedomostController;
|
||||
}
|
||||
|
||||
TitleInscriptionsModel* MainController::titleInscriptionsModel() const {
|
||||
return m_titleInscriptionsModel;
|
||||
}
|
||||
|
||||
PCBMaterialModel* MainController::pcbMaterialModel() const {
|
||||
return m_pcbMaterialModel;
|
||||
}
|
||||
|
||||
bool MainController::initializeDatabase(const QString &dbPath) {
|
||||
// Генерируем уникальное имя соединения для проектной БД
|
||||
QString connectionName = "project_db_" + QString::number(QDateTime::currentMSecsSinceEpoch());
|
||||
|
||||
if (!m_databaseController->initializeDatabase(dbPath, connectionName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainController::initializeGlobalDatabase() {
|
||||
// Используем абсолютный путь для глобальной БД, чтобы она находилась в правильном месте
|
||||
// независимо от рабочей директории приложения
|
||||
QString globalDbPath;
|
||||
|
||||
// Пробуем использовать стандартную директорию для данных приложения
|
||||
QString appDataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
if (!appDataPath.isEmpty()) {
|
||||
QDir appDataDir(appDataPath);
|
||||
if (!appDataDir.exists()) {
|
||||
appDataDir.mkpath(".");
|
||||
}
|
||||
globalDbPath = appDataDir.absoluteFilePath("components.db");
|
||||
} else {
|
||||
// Fallback: используем директорию приложения
|
||||
globalDbPath = QCoreApplication::applicationDirPath() + "/components.db";
|
||||
}
|
||||
|
||||
// Инициализируем глобальную БД для настроек с уникальным именем соединения
|
||||
if (!m_globalDatabaseController->initializeDatabase(globalDbPath, "global_db")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Загружаем данные маппинга дезигнаторов из БД
|
||||
m_designatorMappingModel->loadDataFromDatabase();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainController::isDatabaseOpen() const {
|
||||
return m_databaseController->isDatabaseOpen();
|
||||
}
|
||||
|
||||
QString MainController::lastError() const {
|
||||
return m_databaseController->lastError();
|
||||
}
|
||||
|
||||
void MainController::clearAllData() {
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_databaseController->clearAllData();
|
||||
|
||||
// Сначала загружаем настройки проекта, чтобы установить правильный текущий вариант
|
||||
loadProjectSettingsFromDatabase();
|
||||
|
||||
// Затем загружаем компоненты с правильным текущим вариантом
|
||||
loadComponentsFromDatabase();
|
||||
loadProjectParamsFromDatabase();
|
||||
loadPCBMaterialsFromDatabase();
|
||||
}
|
||||
|
||||
bool MainController::setCurrentVariant(const QString &variant) {
|
||||
m_currentVariant = variant;
|
||||
|
||||
// Обновляем вариант в модели настроек
|
||||
if (m_projectSettingsModel) {
|
||||
m_projectSettingsModel->setCurrentVariant(variant);
|
||||
}
|
||||
|
||||
// Проверяем, открыта ли база данных
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
if (!m_databaseController->initializeDatabase("components.db")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return loadComponentsFromDatabase();
|
||||
}
|
||||
|
||||
bool MainController::loadComponentsFromDatabase() {
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Загружаем список вариантов
|
||||
QList<VariantData> variants = m_databaseController->getAllVariants();
|
||||
QStringList variantNames;
|
||||
for (const auto &variant : variants) {
|
||||
variantNames.append(variant.name);
|
||||
}
|
||||
|
||||
// Устанавливаем варианты в модель таблицы
|
||||
m_componentTableModel->setVariants(variantNames);
|
||||
|
||||
QList<ComponentData> components = m_databaseController->getAllComponents();
|
||||
|
||||
m_componentTableModel->clearComponents();
|
||||
|
||||
// Получаем текущий вариант из контроллера
|
||||
QString currentVariant = m_currentVariant;
|
||||
if (currentVariant.isEmpty()) {
|
||||
currentVariant = "No Variations";
|
||||
}
|
||||
|
||||
// Собираем все уникальные имена свойств
|
||||
QSet<QString> allPropertyNames;
|
||||
|
||||
for (const auto &data : components) {
|
||||
ComponentModel* component = new ComponentModel();
|
||||
component->setId(data.id);
|
||||
component->setDesignator(data.designator);
|
||||
component->setBaseProperties(data.baseProperties);
|
||||
|
||||
// Устанавливаем текущий вариант для компонента
|
||||
component->setCurrentVariant(currentVariant);
|
||||
|
||||
// Добавляем свойства вариантов
|
||||
for (auto it = data.variantProperties.begin(); it != data.variantProperties.end(); ++it) {
|
||||
QString variantName = it.key();
|
||||
QMap<QString, QString> variantProps = it.value();
|
||||
|
||||
component->setVariantProperties(variantName, variantProps);
|
||||
}
|
||||
|
||||
m_componentTableModel->addComponent(component);
|
||||
|
||||
// Собираем имена всех свойств (базовых и вариативных)
|
||||
allPropertyNames.unite(data.baseProperties.keys().toSet());
|
||||
for (auto it = data.variantProperties.begin(); it != data.variantProperties.end(); ++it) {
|
||||
allPropertyNames.unite(it.value().keys().toSet());
|
||||
}
|
||||
}
|
||||
|
||||
// Обновляем список имен свойств в модели таблицы
|
||||
QStringList propertyNames = allPropertyNames.values();
|
||||
propertyNames.sort();
|
||||
m_componentTableModel->setPropertyNames(propertyNames);
|
||||
|
||||
// Устанавливаем текущий вариант в модели таблицы и обновляем свойства компонентов
|
||||
m_componentTableModel->setCurrentVariant(currentVariant);
|
||||
|
||||
// Обновляем компоненты в контроллере перечня
|
||||
if (m_perechenTableController) {
|
||||
m_perechenTableController->setComponents(m_componentTableModel->getComponents());
|
||||
}
|
||||
|
||||
// Обновляем компоненты в контроллере ведомости покупных изделий
|
||||
if (m_vedomostController) {
|
||||
m_vedomostController->setComponents(m_componentTableModel->getComponents());
|
||||
}
|
||||
|
||||
// Загружаем материалы платы
|
||||
loadPCBMaterialsFromDatabase();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainController::saveComponentsToDatabase() {
|
||||
// При ручном сохранении сохраняем только основные данные компонентов
|
||||
// Свойства и варианты сохраняются только во время парсинга
|
||||
QList<ComponentModel*> components = m_componentTableModel->getComponents();
|
||||
|
||||
bool success = true;
|
||||
for (ComponentModel* c : components) {
|
||||
// Обновляем только designator компонента
|
||||
if (!m_databaseController->updateComponentDesignator(c->id(), c->designator())) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MainController::saveProjectParamsToDatabase() {
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Сохраняем параметры проекта
|
||||
QList<ProjectParamTableData> params = m_projectParamTableModel->getData();
|
||||
bool success = true;
|
||||
|
||||
for (const auto ¶m : params) {
|
||||
if (!m_databaseController->setProjectParam(param.name, param.value)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MainController::loadProjectParamsFromDatabase() {
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<ProjectParamData> params = m_databaseController->getAllProjectParams();
|
||||
|
||||
m_projectParamTableModel->clear();
|
||||
for (const auto &p : params) {
|
||||
ProjectParamTableData param;
|
||||
param.id = p.id;
|
||||
param.name = p.name;
|
||||
param.value = p.value;
|
||||
m_projectParamTableModel->addProjectParam(param);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainController::loadPCBMaterialsFromDatabase() {
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Загружаем материалы платы через модель
|
||||
m_pcbMaterialModel->loadMaterials();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainController::loadProjectSettingsFromDatabase() {
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Загружаем настройки из БД
|
||||
QString currentVariant = m_databaseController->getProjectSetting("currentVariant", "No Variations");
|
||||
QStringList columnMappings = m_databaseController->getProjectSettingList("columnMappings", QStringList() << "Designator" << "<Пусто>" << "<Пусто>" << "<Пусто>");
|
||||
|
||||
// Устанавливаем настройки в модель
|
||||
m_projectSettingsModel->setCurrentVariant(currentVariant);
|
||||
m_projectSettingsModel->setColumnMappings(columnMappings);
|
||||
|
||||
// Загружаем настройки маппинга для разных типов документов
|
||||
QStringList documentTypes = {"Perechen", "SpecificationPCB", "Specification", "Vedomost"};
|
||||
for (const QString &docType : documentTypes) {
|
||||
QString key = QString("columnMappings_%1").arg(docType);
|
||||
QStringList mappings = m_databaseController->getProjectSettingList(key, QStringList());
|
||||
if (!mappings.isEmpty()) {
|
||||
// Устанавливаем маппинги в модель
|
||||
for (int i = 0; i < mappings.size(); ++i) {
|
||||
m_projectSettingsModel->setColumnMapping(docType, i, mappings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Загружаем размер шрифта для каждого типа документа
|
||||
QString fontSizeKey = QString("fontSize_%1").arg(docType);
|
||||
int fontSize = m_databaseController->getProjectSetting(fontSizeKey, "12").toInt();
|
||||
m_projectSettingsModel->setFontSize(docType, fontSize);
|
||||
|
||||
// Загружаем поджим по ширине для каждого типа документа
|
||||
QString stretchKey = QString("fontStretch_%1").arg(docType);
|
||||
int stretch = m_databaseController->getProjectSetting(stretchKey, "100").toInt();
|
||||
m_projectSettingsModel->setFontStretch(docType, stretch);
|
||||
}
|
||||
|
||||
m_projectSettingsModel->setModified(false);
|
||||
|
||||
// Устанавливаем текущий вариант в контроллере
|
||||
m_currentVariant = currentVariant;
|
||||
|
||||
// Обновляем текущий вариант в модели компонентов
|
||||
if (m_componentTableModel) {
|
||||
m_componentTableModel->setCurrentVariant(currentVariant);
|
||||
}
|
||||
|
||||
// Синхронизируем настройки колонок со всеми контроллерами
|
||||
syncColumnMappingsWithPerechenController();
|
||||
syncColumnMappingsWithSpecificationPCBController();
|
||||
syncColumnMappingsWithSpecificationController();
|
||||
syncColumnMappingsWithVedomostController();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainController::saveProjectSettingsToDatabase() {
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Сохраняем настройки в БД
|
||||
bool success = true;
|
||||
success &= m_databaseController->setProjectSetting("currentVariant", m_projectSettingsModel->currentVariant());
|
||||
success &= m_databaseController->setProjectSettingList("columnMappings", m_projectSettingsModel->columnMappings());
|
||||
|
||||
// Сохраняем настройки маппинга для разных типов документов
|
||||
QStringList documentTypes = {"Perechen", "SpecificationPCB", "Specification", "Vedomost"};
|
||||
for (const QString &docType : documentTypes) {
|
||||
QStringList mappings = m_projectSettingsModel->getColumnMappings(docType);
|
||||
if (!mappings.isEmpty()) {
|
||||
QString key = QString("columnMappings_%1").arg(docType);
|
||||
success &= m_databaseController->setProjectSettingList(key, mappings);
|
||||
}
|
||||
|
||||
// Сохраняем размер шрифта для каждого типа документа
|
||||
QString fontSizeKey = QString("fontSize_%1").arg(docType);
|
||||
int fontSize = m_projectSettingsModel->getFontSize(docType);
|
||||
success &= m_databaseController->setProjectSetting(fontSizeKey, QString::number(fontSize));
|
||||
|
||||
// Сохраняем поджим по ширине для каждого типа документа
|
||||
QString stretchKey = QString("fontStretch_%1").arg(docType);
|
||||
int stretch = m_projectSettingsModel->getFontStretch(docType);
|
||||
success &= m_databaseController->setProjectSetting(stretchKey, QString::number(stretch));
|
||||
}
|
||||
|
||||
// Сохраняем маппинг дезигнаторов в глобальную БД
|
||||
if (m_designatorMappingModel->isModified()) {
|
||||
m_designatorMappingModel->saveToDatabase();
|
||||
}
|
||||
|
||||
if (success) {
|
||||
m_projectSettingsModel->setModified(false);
|
||||
|
||||
// Синхронизируем настройки колонок со всеми контроллерами
|
||||
syncColumnMappingsWithPerechenController();
|
||||
syncColumnMappingsWithSpecificationPCBController();
|
||||
syncColumnMappingsWithSpecificationController();
|
||||
syncColumnMappingsWithVedomostController();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MainController::parseFile(const QString &filePath) {
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
emit error("База данных проекта не открыта");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Определяем тип файла и вызываем соответствующий метод парсинга
|
||||
QFileInfo fileInfo(filePath);
|
||||
QString extension = fileInfo.suffix().toLower();
|
||||
bool success = false;
|
||||
|
||||
if (extension == "prjpcb") {
|
||||
// Создаем временную модель для парсинга
|
||||
ComponentModel tempModel;
|
||||
success = m_altiumParser->parsePrjPcbFile(filePath, &tempModel);
|
||||
} else if (extension == "schdoc") {
|
||||
ComponentModel tempModel;
|
||||
success = m_altiumParser->parseSchDoc(filePath, &tempModel);
|
||||
} else if (extension == "pcbdoc") {
|
||||
ComponentModel tempModel;
|
||||
success = m_altiumParser->parsePcbDoc(filePath, &tempModel);
|
||||
} else if (extension == "csv") {
|
||||
ComponentModel tempModel;
|
||||
success = m_altiumParser->parseCsvBom(filePath, &tempModel);
|
||||
} else if (extension == "xls" || extension == "xlsx") {
|
||||
ComponentModel tempModel;
|
||||
success = m_altiumParser->parseXlsBom(filePath, &tempModel);
|
||||
} else {
|
||||
emit error("Неподдерживаемый тип файла: " + extension);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
loadComponentsFromDatabase();
|
||||
loadProjectParamsFromDatabase();
|
||||
loadPCBMaterialsFromDatabase();
|
||||
emit parsingFinished(true);
|
||||
} else {
|
||||
emit error("Ошибка парсинга: " + m_altiumParser->lastError());
|
||||
emit parsingFinished(false);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MainController::parseFileAsync(const QString &filePath)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
emit error("База данных проекта не открыта");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Определяем тип файла и вызываем соответствующий метод парсинга
|
||||
QFileInfo fileInfo(filePath);
|
||||
QString extension = fileInfo.suffix().toLower();
|
||||
|
||||
if (extension == "prjpcb") {
|
||||
// Создаем временную модель для парсинга
|
||||
ComponentModel tempModel;
|
||||
return m_altiumParser->parseFileAsync(filePath, &tempModel);
|
||||
} else {
|
||||
emit error("Асинхронный парсинг поддерживается только для .PrjPcb файлов");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MainController::isParsingAsync() const
|
||||
{
|
||||
return m_altiumParser->isParsingAsync();
|
||||
}
|
||||
|
||||
void MainController::cancelParsing()
|
||||
{
|
||||
m_altiumParser->cancelParsing();
|
||||
}
|
||||
|
||||
bool MainController::exportPerechen()
|
||||
{
|
||||
if(!m_pdfController)
|
||||
return false;
|
||||
|
||||
// Этот метод устарел, используйте exportPerechenToPdf
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MainController::exportPerechenToPdf(const QString &filePath)
|
||||
{
|
||||
if (!m_pdfController) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Передаем MainController в PDFController
|
||||
return m_pdfController->exportPerechenToPdf(filePath, this);
|
||||
}
|
||||
|
||||
bool MainController::exportSpecificationPcbToPdf(const QString &filePath)
|
||||
{
|
||||
if (!m_pdfController) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Передаем MainController в PDFController
|
||||
return m_pdfController->exportSpecificationPcbToPdf(filePath, this);
|
||||
}
|
||||
|
||||
void MainController::syncColumnMappingsWithPerechenController()
|
||||
{
|
||||
if (m_perechenTableController && m_projectSettingsModel) {
|
||||
// Используем документ-специфичные настройки для Perechen
|
||||
QStringList columnMappings = m_projectSettingsModel->getColumnMappings("Perechen");
|
||||
|
||||
if (!columnMappings.isEmpty()) {
|
||||
m_perechenTableController->setColumnMappings(columnMappings);
|
||||
|
||||
// Дополнительно проверяем, что настройки передались в модель
|
||||
if (m_perechenTableModel) {
|
||||
QStringList modelMappings = m_perechenTableModel->columnMappings();
|
||||
|
||||
if (modelMappings != columnMappings) {
|
||||
m_perechenTableModel->setColumnMappings(columnMappings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainController::syncColumnMappingsWithSpecificationPCBController()
|
||||
{
|
||||
if (m_specificationPCBController && m_projectSettingsModel) {
|
||||
// Используем документ-специфичные настройки для SpecificationPCB
|
||||
QStringList columnMappings = m_projectSettingsModel->getColumnMappings("SpecificationPCB");
|
||||
m_specificationPCBController->setColumnMappings(columnMappings);
|
||||
}
|
||||
}
|
||||
|
||||
void MainController::syncColumnMappingsWithSpecificationController()
|
||||
{
|
||||
if (m_specificationController && m_projectSettingsModel) {
|
||||
// Используем документ-специфичные настройки для Specification
|
||||
QStringList columnMappings = m_projectSettingsModel->getColumnMappings("Specification");
|
||||
m_specificationController->setColumnMappings(columnMappings);
|
||||
}
|
||||
}
|
||||
|
||||
void MainController::syncColumnMappingsWithVedomostController()
|
||||
{
|
||||
if (m_vedomostController && m_projectSettingsModel) {
|
||||
// Используем документ-специфичные настройки для Vedomost
|
||||
QStringList columnMappings = m_projectSettingsModel->getColumnMappings("Vedomost");
|
||||
m_vedomostController->setColumnMappings(columnMappings);
|
||||
}
|
||||
}
|
||||
|
||||
bool MainController::saveTitleInscriptionsToDatabase(const QMap<int, QString> &inscriptions)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Получаем имя текущего проекта из пути к файлу БД
|
||||
QString projectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
|
||||
bool success = m_databaseController->saveTitleInscriptions(inscriptions, projectName);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MainController::loadTitleInscriptionsFromDatabase(QMap<int, QString> &inscriptions)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Получаем имя текущего проекта из пути к файлу БД
|
||||
QString projectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
|
||||
bool success = m_databaseController->loadTitleInscriptions(inscriptions, projectName);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MainController::savePerechenTableToDatabase(const QByteArray &tableData, const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Если имя проекта не указано, получаем его из пути к файлу БД
|
||||
QString actualProjectName = projectName;
|
||||
if (actualProjectName.isEmpty()) {
|
||||
actualProjectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
}
|
||||
|
||||
bool success = m_databaseController->savePerechenTable(tableData, actualProjectName);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
QByteArray MainController::loadPerechenTableFromDatabase(const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
// Если имя проекта не указано, получаем его из пути к файлу БД
|
||||
QString actualProjectName = projectName;
|
||||
if (actualProjectName.isEmpty()) {
|
||||
actualProjectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
}
|
||||
|
||||
QByteArray tableData = m_databaseController->loadPerechenTable(actualProjectName);
|
||||
|
||||
return tableData;
|
||||
}
|
||||
|
||||
QString MainController::getPerechenTableInfo(const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return m_databaseController->getPerechenTableInfo(projectName);
|
||||
}
|
||||
|
||||
bool MainController::saveSpecificationPCBTableToDatabase(const QByteArray &tableData, const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Если имя проекта не указано, получаем его из пути к файлу БД
|
||||
QString actualProjectName = projectName;
|
||||
if (actualProjectName.isEmpty()) {
|
||||
actualProjectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
}
|
||||
|
||||
bool success = m_databaseController->saveSpecificationPCBTable(tableData, actualProjectName);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
QByteArray MainController::loadSpecificationPCBTableFromDatabase(const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
// Если имя проекта не указано, получаем его из пути к файлу БД
|
||||
QString actualProjectName = projectName;
|
||||
if (actualProjectName.isEmpty()) {
|
||||
actualProjectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
}
|
||||
|
||||
QByteArray tableData = m_databaseController->loadSpecificationPCBTable(actualProjectName);
|
||||
|
||||
return tableData;
|
||||
}
|
||||
|
||||
QString MainController::getSpecificationPCBTableInfo(const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return m_databaseController->getSpecificationPCBTableInfo(projectName);
|
||||
}
|
||||
|
||||
// Методы для работы со спецификацией материалов
|
||||
bool MainController::saveSpecificationTableToDatabase(const QByteArray &tableData, const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Если имя проекта не указано, получаем его из пути к файлу БД
|
||||
QString actualProjectName = projectName;
|
||||
if (actualProjectName.isEmpty()) {
|
||||
actualProjectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
}
|
||||
|
||||
bool success = m_databaseController->saveSpecificationTable(tableData, actualProjectName);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
QByteArray MainController::loadSpecificationTableFromDatabase(const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
// Если имя проекта не указано, получаем его из пути к файлу БД
|
||||
QString actualProjectName = projectName;
|
||||
if (actualProjectName.isEmpty()) {
|
||||
actualProjectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
}
|
||||
|
||||
QByteArray tableData = m_databaseController->loadSpecificationTable(actualProjectName);
|
||||
|
||||
return tableData;
|
||||
}
|
||||
|
||||
QString MainController::getSpecificationTableInfo(const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return m_databaseController->getSpecificationTableInfo(projectName);
|
||||
}
|
||||
|
||||
// Методы для работы с ведомостью покупных изделий
|
||||
bool MainController::saveVedomostTableToDatabase(const QByteArray &tableData, const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Если имя проекта не указано, получаем его из пути к файлу БД
|
||||
QString actualProjectName = projectName;
|
||||
if (actualProjectName.isEmpty()) {
|
||||
actualProjectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
}
|
||||
|
||||
bool success = m_databaseController->saveVedomostTable(tableData, actualProjectName);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
QByteArray MainController::loadVedomostTableFromDatabase(const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
// Если имя проекта не указано, получаем его из пути к файлу БД
|
||||
QString actualProjectName = projectName;
|
||||
if (actualProjectName.isEmpty()) {
|
||||
actualProjectName = QFileInfo(m_databaseController->getDatabasePath()).baseName();
|
||||
}
|
||||
|
||||
QByteArray tableData = m_databaseController->loadVedomostTable(actualProjectName);
|
||||
|
||||
return tableData;
|
||||
}
|
||||
|
||||
QString MainController::getVedomostTableInfo(const QString &projectName)
|
||||
{
|
||||
// Проверяем, открыта ли база данных проекта
|
||||
if (!m_databaseController->isDatabaseOpen()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
return m_databaseController->getVedomostTableInfo(projectName);
|
||||
}
|
||||
|
||||
bool MainController::exportSpecificationToPdf(const QString &filePath)
|
||||
{
|
||||
if (!m_pdfController) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_pdfController->exportSpecificationToPdf(filePath, this);
|
||||
}
|
||||
|
||||
bool MainController::exportVedomostToPdf(const QString &filePath)
|
||||
{
|
||||
if (!m_pdfController) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_pdfController->exportVedomostToPdf(filePath, this);
|
||||
}
|
||||
|
||||
bool MainController::exportPerechenToCsv(const QString &filePath)
|
||||
{
|
||||
if (!m_csvExporter || !m_perechenTableModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_csvExporter->exportPerechen(filePath, m_perechenTableModel);
|
||||
}
|
||||
|
||||
bool MainController::exportSpecificationPcbToCsv(const QString &filePath)
|
||||
{
|
||||
if (!m_csvExporter || !m_specificationPCBTableModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_csvExporter->exportSpecificationPCB(filePath, m_specificationPCBTableModel);
|
||||
}
|
||||
|
||||
bool MainController::exportSpecificationToCsv(const QString &filePath)
|
||||
{
|
||||
if (!m_csvExporter || !m_specificationTableModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_csvExporter->exportSpecification(filePath, m_specificationTableModel);
|
||||
}
|
||||
|
||||
bool MainController::exportVedomostToCsv(const QString &filePath)
|
||||
{
|
||||
if (!m_csvExporter || !m_vedomostTableModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_csvExporter->exportVedomost(filePath, m_vedomostTableModel);
|
||||
}
|
||||
|
||||
PDFController* MainController::pdfController() const
|
||||
{
|
||||
return m_pdfController;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
#ifndef MAINCONTROLLER_H
|
||||
#define MAINCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
#include "databasecontroller.h"
|
||||
#include "pdfcontroller.h"
|
||||
#include "csvexporter.h"
|
||||
|
||||
class ComponentTableModel;
|
||||
class ProjectParamTableModel;
|
||||
class ProjectSettingsModel;
|
||||
class DesignatorMappingModel;
|
||||
class PerechenTableModel;
|
||||
class PerechenTableController;
|
||||
class SpecificationPCBTableModel;
|
||||
class SpecificationPCBController;
|
||||
class SpecificationTableModel;
|
||||
class SpecificationController;
|
||||
class VedomostTableModel;
|
||||
class VedomostController;
|
||||
class TitleInscriptionsModel;
|
||||
class PCBMaterialModel;
|
||||
class AltiumParser;
|
||||
|
||||
class MainController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainController(QObject *parent = nullptr);
|
||||
~MainController();
|
||||
|
||||
// Доступ к моделям
|
||||
ComponentTableModel* componentTableModel() const;
|
||||
ProjectParamTableModel* projectParamTableModel() const;
|
||||
ProjectSettingsModel* projectSettingsModel() const;
|
||||
DesignatorMappingModel* designatorMappingModel() const;
|
||||
PerechenTableModel* perechenTableModel() const;
|
||||
PerechenTableController* perechenTableController() const;
|
||||
SpecificationPCBTableModel* specificationPCBTableModel() const;
|
||||
SpecificationPCBController* specificationPCBController() const;
|
||||
SpecificationTableModel* specificationTableModel() const;
|
||||
SpecificationController* specificationController() const;
|
||||
VedomostTableModel* vedomostTableModel() const;
|
||||
VedomostController* vedomostController() const;
|
||||
TitleInscriptionsModel* titleInscriptionsModel() const;
|
||||
PCBMaterialModel* pcbMaterialModel() const;
|
||||
|
||||
// Работа с БД
|
||||
bool initializeDatabase(const QString &dbPath = "components.db");
|
||||
bool initializeGlobalDatabase();
|
||||
bool isDatabaseOpen() const;
|
||||
QString lastError() const;
|
||||
|
||||
// Работа с данными
|
||||
void clearAllData();
|
||||
bool setCurrentVariant(const QString &variant);
|
||||
bool loadComponentsFromDatabase();
|
||||
bool saveComponentsToDatabase();
|
||||
bool loadProjectParamsFromDatabase();
|
||||
bool saveProjectParamsToDatabase();
|
||||
|
||||
// Работа с материалами платы
|
||||
bool loadPCBMaterialsFromDatabase();
|
||||
|
||||
// Работа с настройками проекта
|
||||
bool loadProjectSettingsFromDatabase();
|
||||
bool saveProjectSettingsToDatabase();
|
||||
|
||||
// Синхронизация настроек колонок с PerechenTableController
|
||||
void syncColumnMappingsWithPerechenController();
|
||||
void syncColumnMappingsWithSpecificationPCBController();
|
||||
void syncColumnMappingsWithSpecificationController();
|
||||
void syncColumnMappingsWithVedomostController();
|
||||
|
||||
// Работа с надписями титульного листа
|
||||
bool saveTitleInscriptionsToDatabase(const QMap<int, QString> &inscriptions);
|
||||
bool loadTitleInscriptionsFromDatabase(QMap<int, QString> &inscriptions);
|
||||
|
||||
// Работа с перечнем элементов
|
||||
bool savePerechenTableToDatabase(const QByteArray &tableData, const QString &projectName = QString());
|
||||
QByteArray loadPerechenTableFromDatabase(const QString &projectName = QString());
|
||||
QString getPerechenTableInfo(const QString &projectName = QString());
|
||||
|
||||
// Работа со спецификацией платы
|
||||
bool saveSpecificationPCBTableToDatabase(const QByteArray &tableData, const QString &projectName = QString());
|
||||
QByteArray loadSpecificationPCBTableFromDatabase(const QString &projectName = QString());
|
||||
QString getSpecificationPCBTableInfo(const QString &projectName = QString());
|
||||
|
||||
// Работа со спецификацией материалов
|
||||
bool saveSpecificationTableToDatabase(const QByteArray &tableData, const QString &projectName = QString());
|
||||
QByteArray loadSpecificationTableFromDatabase(const QString &projectName = QString());
|
||||
QString getSpecificationTableInfo(const QString &projectName = QString());
|
||||
|
||||
// Работа с ведомостью покупных изделий
|
||||
bool saveVedomostTableToDatabase(const QByteArray &tableData, const QString &projectName = QString());
|
||||
QByteArray loadVedomostTableFromDatabase(const QString &projectName = QString());
|
||||
QString getVedomostTableInfo(const QString &projectName = QString());
|
||||
|
||||
// Парсинг файлов
|
||||
bool parseFile(const QString &filePath);
|
||||
bool parseFileAsync(const QString &filePath);
|
||||
bool isParsingAsync() const;
|
||||
void cancelParsing();
|
||||
|
||||
bool exportPerechen();
|
||||
|
||||
// Метод для экспорта перечня элементов в PDF
|
||||
bool exportPerechenToPdf(const QString &filePath);
|
||||
|
||||
// Метод для экспорта спецификации PCB в PDF
|
||||
bool exportSpecificationPcbToPdf(const QString &filePath);
|
||||
|
||||
// Метод для экспорта спецификации материалов в PDF
|
||||
bool exportSpecificationToPdf(const QString &filePath);
|
||||
|
||||
// Метод для экспорта ведомости покупных изделий в PDF
|
||||
bool exportVedomostToPdf(const QString &filePath);
|
||||
|
||||
// Методы для экспорта в CSV
|
||||
bool exportPerechenToCsv(const QString &filePath);
|
||||
bool exportSpecificationPcbToCsv(const QString &filePath);
|
||||
bool exportSpecificationToCsv(const QString &filePath);
|
||||
bool exportVedomostToCsv(const QString &filePath);
|
||||
|
||||
// Метод для получения PDFController
|
||||
PDFController* pdfController() const;
|
||||
|
||||
signals:
|
||||
void parsingStarted();
|
||||
void parsingProgress(int percentage);
|
||||
void parsingFinished(bool success);
|
||||
void error(const QString &error);
|
||||
void databaseError(const QString &error);
|
||||
|
||||
private:
|
||||
ComponentTableModel* m_componentTableModel;
|
||||
ProjectParamTableModel* m_projectParamTableModel;
|
||||
ProjectSettingsModel* m_projectSettingsModel;
|
||||
DesignatorMappingModel* m_designatorMappingModel;
|
||||
PerechenTableModel* m_perechenTableModel;
|
||||
PerechenTableController* m_perechenTableController;
|
||||
SpecificationPCBTableModel* m_specificationPCBTableModel;
|
||||
SpecificationPCBController* m_specificationPCBController;
|
||||
SpecificationTableModel* m_specificationTableModel;
|
||||
SpecificationController* m_specificationController;
|
||||
VedomostTableModel* m_vedomostTableModel;
|
||||
VedomostController* m_vedomostController;
|
||||
TitleInscriptionsModel* m_titleInscriptionsModel;
|
||||
PCBMaterialModel* m_pcbMaterialModel;
|
||||
DataBaseController* m_databaseController;
|
||||
DataBaseController* m_globalDatabaseController;
|
||||
AltiumParser* m_altiumParser;
|
||||
QString m_currentVariant;
|
||||
PDFController* m_pdfController;
|
||||
CSVExporter* m_csvExporter;
|
||||
};
|
||||
|
||||
#endif // MAINCONTROLLER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
#ifndef PDFCONTROLLER_H
|
||||
#define PDFCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPainter>
|
||||
#include <QString>
|
||||
#include <QFont>
|
||||
#include <QList>
|
||||
#include <QModelIndex>
|
||||
#include "../model/pageinfo.h"
|
||||
#include "../model/perechentablemodel.h"
|
||||
|
||||
class MainController;
|
||||
class PerechenTableModel;
|
||||
class TitleInscriptionsModel;
|
||||
class ProjectParamTableModel;
|
||||
class SpecificationPCBTableModel;
|
||||
class SpecificationTableModel;
|
||||
class VedomostTableModel;
|
||||
|
||||
class PDFController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PDFController(QObject *parent = nullptr);
|
||||
|
||||
// Метод для экспорта перечня элементов в PDF
|
||||
bool exportPerechenToPdf(const QString &filePath, MainController *mainController);
|
||||
|
||||
// Метод для экспорта спецификации PCB в PDF
|
||||
bool exportSpecificationPcbToPdf(const QString &filePath, MainController *mainController);
|
||||
|
||||
// Метод для экспорта спецификации материалов в PDF
|
||||
bool exportSpecificationToPdf(const QString &filePath, MainController *mainController);
|
||||
|
||||
// Метод для экспорта ведомости покупных изделий в PDF
|
||||
bool exportVedomostToPdf(const QString &filePath, MainController *mainController);
|
||||
|
||||
// Новые методы для предварительного просмотра
|
||||
QList<PageInfo> getPerechenPagesInfo(MainController *mainController);
|
||||
QList<PageInfo> getSpecificationPcbPagesInfo(MainController *mainController);
|
||||
QList<PageInfo> getSpecificationPagesInfo(MainController *mainController);
|
||||
QList<PageInfo> getVedomostPagesInfo(MainController *mainController);
|
||||
|
||||
// Методы для рисования страниц на painter
|
||||
bool drawPerechenPage(QPainter &painter, const PageInfo &pageInfo, MainController *mainController);
|
||||
bool drawSpecificationPcbPage(QPainter &painter, const PageInfo &pageInfo, MainController *mainController);
|
||||
bool drawSpecificationPage(QPainter &painter, const PageInfo &pageInfo, MainController *mainController);
|
||||
bool drawVedomostPage(QPainter &painter, const PageInfo &pageInfo, MainController *mainController);
|
||||
|
||||
// Методы для генерации таблиц
|
||||
bool generateTableA4(const QString &filePath, MainController *mainController);
|
||||
bool generateTableA5(const QString &filePath, MainController *mainController);
|
||||
|
||||
// Методы для генерации штампов ГОСТ
|
||||
bool generateGostStampA4(const QString &filePath, MainController *mainController);
|
||||
|
||||
bool generateGostStampA5(const QString &filePath, MainController *mainController);
|
||||
|
||||
// Утилитарные функции для работы с шрифтом ГОСТ
|
||||
static QFont createGostFont(int pointSize, bool bold = false, bool italic = false, int stretch = 100);
|
||||
static void drawTextWithGostFont(QPainter &painter, const QRectF &rect,
|
||||
const QString &text, int pointSize,
|
||||
Qt::Alignment alignment = Qt::AlignLeft);
|
||||
static void drawTextWithAutoSize(QPainter &painter, const QRectF &rect,
|
||||
const QString &text, int maxPointSize = 20);
|
||||
static void drawTextMultiline(QPainter &painter, const QRectF &rect,
|
||||
const QString &text, const QFont &font,
|
||||
int maxLines = 3);
|
||||
|
||||
// Метод для получения значения надписи с учетом параметров проекта
|
||||
static QString getInscriptionValueWithProjectParams(const TitleInscriptionsModel* titleModel,
|
||||
const ProjectParamTableModel* projectParamModel,
|
||||
int inscriptionIndex);
|
||||
|
||||
private:
|
||||
// Вспомогательные методы для создания PDF
|
||||
bool createPdfDocument(const QString &filePath, const QString &title);
|
||||
bool addGostFrameA4FirstPage(QPainter &painter, const QRectF &pageRect, const TitleInscriptionsModel* model, const ProjectParamTableModel* projectParamModel, int currentPage, int totalPages , int docType);
|
||||
bool addGostFrameA4(QPainter &painter, const QRectF &pageRect, const TitleInscriptionsModel* model, const ProjectParamTableModel* projectParamModel, int currentPage, int totalPages, int docType);
|
||||
bool addGostFrameA3(QPainter &painter, const QRectF &pageRect, const TitleInscriptionsModel* model, const ProjectParamTableModel* projectParamModel, int currentPage, int totalPages);
|
||||
bool addTitleInscriptions(QPainter &painter, TitleInscriptionsModel *titleModel, const QRectF &stampRect);
|
||||
bool addPerechenTable(QPainter &painter, PerechenTableModel *perechenModel, const QRectF &tableRect, MainController *mainController = nullptr);
|
||||
bool addPerechenTableRange(QPainter &painter, PerechenTableModel *perechenModel, const QRectF &tableRect, int startRow, int rowCount, MainController *mainController = nullptr);
|
||||
bool addSpecificationPcbTableRange(QPainter &painter, SpecificationPCBTableModel *specificationModel, const QRectF &tableRect, int startRow, int rowCount, MainController *mainController = nullptr);
|
||||
bool addSpecificationTableRange(QPainter &painter, SpecificationTableModel *specificationModel, const QRectF &tableRect, int startRow, int rowCount, MainController *mainController = nullptr);
|
||||
bool addVedomostTableRange(QPainter &painter, VedomostTableModel *vedomostModel, const QRectF &tableRect, int startRow, int rowCount, MainController *mainController = nullptr);
|
||||
|
||||
bool addGostFrameA3FirstPage(QPainter &painter, const QRectF &pageRect, const TitleInscriptionsModel *model, const ProjectParamTableModel *projectParamModel, int currentPage, int totalPages);
|
||||
bool addListRegistrationTable(QPainter &painter,const QRectF &pageRect);
|
||||
|
||||
// Вспомогательная функция для получения поджима ячейки
|
||||
static int getCellStretch(const QModelIndex &index, int defaultStretch);
|
||||
|
||||
// Вспомогательная функция для получения флага подчеркивания ячейки
|
||||
static bool getCellUnderline(const QModelIndex &index, bool defaultUnderline = true);
|
||||
|
||||
// Вспомогательная функция для рисования ячейки с учетом поджима
|
||||
void drawCellWithStretch(QPainter &painter, const QModelIndex &index, const QRectF &rect,
|
||||
const QString &text, int fontSize, int defaultStretch,
|
||||
const QFont &baseFont, Qt::Alignment alignment, MainController *mainController = nullptr);
|
||||
signals:
|
||||
// Сигнал о переполнении ячейки при отрисовке в PDF
|
||||
void cellOverflowDetected(const QModelIndex &index, bool isOverflow);
|
||||
};
|
||||
|
||||
#endif // PDFCONTROLLER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
#ifndef PERECHENTABLECONTROLLER_H
|
||||
#define PERECHENTABLECONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
#include "../model/perechentablemodel.h"
|
||||
#include "../model/designatormappingmodel.h"
|
||||
#include "../model/projectsettingsmodel.h"
|
||||
|
||||
class ComponentModel;
|
||||
|
||||
class PerechenTableController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PerechenTableController(QObject *parent = nullptr);
|
||||
~PerechenTableController();
|
||||
|
||||
// Получение модели для отображения в UI
|
||||
PerechenTableModel* getTableModel() const { return m_tableModel; }
|
||||
PerechenTableModel* getModel() const { return m_tableModel; } // Алиас для совместимости
|
||||
|
||||
// Методы для работы с компонентами
|
||||
void setComponents(const QList<ComponentModel*> &components);
|
||||
void generateTableFromComponents();
|
||||
void updateTableFromComponents(); // Метод для обновления таблицы по кнопке
|
||||
|
||||
// Новые методы для управления строками
|
||||
void addEmptyRow();
|
||||
void addEmptyRowAt(int position);
|
||||
void insertEmptyRowAt(int position); // Вставка строки в определенную позицию
|
||||
void removeRow(int row);
|
||||
void clearTable();
|
||||
|
||||
// Методы для работы с настройками
|
||||
void setColumnMappings(const QStringList &mappings);
|
||||
QStringList getColumnMappings() const;
|
||||
QStringList getAvailableProperties() const;
|
||||
|
||||
// Метод для установки модели маппинга дезигнаторов
|
||||
void setDesignatorMappingModel(DesignatorMappingModel *mappingModel);
|
||||
|
||||
// Метод для установки модели таблицы (для интеграции с PerechenProcessor)
|
||||
void setModel(PerechenTableModel *model);
|
||||
|
||||
// Метод для установки модели настроек проекта
|
||||
void setProjectSettingsModel(ProjectSettingsModel *model);
|
||||
|
||||
// Метод для оптимизации разрывов страниц
|
||||
void optimizePageBreaks();
|
||||
|
||||
// Методы для работы с размером шрифта
|
||||
int getFontSize() const;
|
||||
void setFontSize(int fontSize);
|
||||
int getFontStretch() const;
|
||||
void setFontStretch(int stretch);
|
||||
|
||||
private:
|
||||
QString getComponentValue(ComponentModel *component, const QString &propertyName);
|
||||
QString parseExpression(ComponentModel *component, const QString &expression);
|
||||
QStringList collectPropertyNames();
|
||||
|
||||
|
||||
|
||||
// Методы для группировки
|
||||
QString getComponentType(ComponentModel *component);
|
||||
|
||||
// Метод для разделения десигнатора на буквенную и цифровую части
|
||||
QPair<QString, QString> splitDesignator(const QString &designator);
|
||||
|
||||
// Метод для разделения длинных наименований на несколько строк
|
||||
QList<QString> splitLongDesignation(const QString &designation, const QString originalString="",ComponentModel *component = nullptr , int maxLength = 60);
|
||||
|
||||
// Вспомогательный метод для разделения текста по пробелам
|
||||
QList<QString> splitBySpaces(const QString &text, int maxLength);
|
||||
|
||||
// Вспомогательный метод для разделения комплексной строки (с запятыми) по середине
|
||||
QList<QString> splitComplexStringByMiddle(const QString &text, int maxLength);
|
||||
|
||||
PerechenTableModel *m_tableModel;
|
||||
DesignatorMappingModel *m_designatorMappingModel;
|
||||
ProjectSettingsModel *m_projectSettingsModel;
|
||||
QList<ComponentModel*> m_components;
|
||||
QStringList m_columnMappings;
|
||||
QStringList m_propertyNames;
|
||||
};
|
||||
|
||||
#endif // PERECHENTABLECONTROLLER_H
|
||||
@@ -0,0 +1,842 @@
|
||||
#include "specificationcontroller.h"
|
||||
#include "../model/specificationtablemodel.h"
|
||||
#include "../model/designatormappingmodel.h"
|
||||
#include "../model/projectsettingsmodel.h"
|
||||
#include "../model/projectparamtablemodel.h"
|
||||
#include "../model/pcbmaterialmodel.h"
|
||||
#include "../controller/maincontroller.h"
|
||||
#include <QDebug>
|
||||
#include <QCollator>
|
||||
|
||||
SpecificationController::SpecificationController(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_tableModel(new SpecificationTableModel(this))
|
||||
, m_designatorMappingModel(nullptr)
|
||||
, m_projectSettingsModel(nullptr)
|
||||
, m_mainController(nullptr)
|
||||
, m_pcbMaterialModel(nullptr)
|
||||
{
|
||||
// Устанавливаем маппинг по умолчанию для спецификации
|
||||
m_columnMappings << "Format" << "Zone" << "Position" << "Designation" << "Name" << "Quantity" << "Note";
|
||||
}
|
||||
|
||||
SpecificationController::~SpecificationController()
|
||||
{
|
||||
// m_tableModel удалится автоматически, так как он является дочерним объектом
|
||||
}
|
||||
|
||||
void SpecificationController::setDesignatorMappingModel(DesignatorMappingModel *mappingModel)
|
||||
{
|
||||
m_designatorMappingModel = mappingModel;
|
||||
}
|
||||
|
||||
void SpecificationController::setModel(SpecificationTableModel *model)
|
||||
{
|
||||
if (m_tableModel != model) {
|
||||
qDebug() << "SpecificationController::setModel: Заменяем модель таблицы";
|
||||
m_tableModel = model;
|
||||
|
||||
// Если модель не пуста, загружаем из неё настройки колонок
|
||||
if (m_tableModel) {
|
||||
QStringList columnMappings = m_tableModel->columnMappings();
|
||||
if (!columnMappings.isEmpty()) {
|
||||
qDebug() << "SpecificationController::setModel: Загружаем настройки колонок из модели:" << columnMappings;
|
||||
m_columnMappings = columnMappings;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpecificationController::setProjectSettingsModel(ProjectSettingsModel *model)
|
||||
{
|
||||
m_projectSettingsModel = model;
|
||||
qDebug() << "SpecificationController::setProjectSettingsModel: Установлена модель настроек проекта";
|
||||
}
|
||||
|
||||
void SpecificationController::setMainController(MainController *controller)
|
||||
{
|
||||
m_mainController = controller;
|
||||
qDebug() << "SpecificationController::setMainController: Установлен главный контроллер";
|
||||
}
|
||||
|
||||
void SpecificationController::setMaterials(const QList<PCBMaterialModel*> &materials)
|
||||
{
|
||||
qDebug() << "SpecificationController::setMaterials: Устанавливаем" << materials.size() << "материалов";
|
||||
m_materials = materials;
|
||||
|
||||
// Собираем доступные свойства из материалов
|
||||
m_propertyNames = collectPropertyNames();
|
||||
qDebug() << "SpecificationController::setMaterials: Собрано свойств:" << m_propertyNames.size();
|
||||
qDebug() << "SpecificationController::setMaterials: Свойства:" << m_propertyNames;
|
||||
}
|
||||
|
||||
void SpecificationController::setPCBMaterialModel(PCBMaterialModel* model)
|
||||
{
|
||||
qDebug() << "SpecificationController::setPCBMaterialModel: Устанавливаем PCB модель материалов";
|
||||
m_pcbMaterialModel = model;
|
||||
|
||||
if (m_pcbMaterialModel) {
|
||||
qDebug() << "SpecificationController::setPCBMaterialModel: Материалов в модели:" << m_pcbMaterialModel->getMaterialCount();
|
||||
}
|
||||
}
|
||||
|
||||
void SpecificationController::generateTableFromMaterials()
|
||||
{
|
||||
if (!m_tableModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::generateTableFromMaterials: Начинаем генерацию таблицы";
|
||||
qDebug() << "SpecificationController::generateTableFromMaterials: Текущие настройки колонок:" << m_columnMappings;
|
||||
|
||||
// Очищаем таблицу
|
||||
m_tableModel->clear();
|
||||
|
||||
// Добавляем заголовок таблицы
|
||||
SpecificationRowData emptyRow;
|
||||
emptyRow.isEmpty = true;
|
||||
m_tableModel->addRow(emptyRow);
|
||||
|
||||
SpecificationRowData headerRow;
|
||||
headerRow.isHeader = true;
|
||||
headerRow.format = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow.zone = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow.position = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow.designation = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow.name = SpecificationCellData("Документаця", 0, 1, true, false, false, 100, true);
|
||||
headerRow.quantity = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow.note = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
m_tableModel->addRow(headerRow);
|
||||
|
||||
m_tableModel->addRow(emptyRow);
|
||||
|
||||
SpecificationRowData defaultRow1;
|
||||
defaultRow1.isHeader = false;
|
||||
defaultRow1.format = SpecificationCellData("A1", 0, 1, false, false, false, 100, false);
|
||||
defaultRow1.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
defaultRow1.position = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
defaultRow1.designation = SpecificationCellData(getDecimalNumberBoard() + "Э3 СБ", 0, 1, false, false, false, 100, false);
|
||||
defaultRow1.name = SpecificationCellData("Сборочный чертеж", 0, 1, false, false, false, 100, false);
|
||||
defaultRow1.quantity = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
defaultRow1.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
m_tableModel->addRow(defaultRow1);
|
||||
|
||||
SpecificationRowData defaultRow2;
|
||||
|
||||
defaultRow2.isHeader = false;
|
||||
defaultRow2.format = SpecificationCellData("*)", 0, 1, false, false, false, 100, false);
|
||||
defaultRow2.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
defaultRow2.position = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
defaultRow2.designation = SpecificationCellData(getDecimalNumberBoard() + " Э3 Т5М", 0, 1, false, false, false, 100, false);
|
||||
defaultRow2.name = SpecificationCellData("Данные проектирования", 0, 1, false, false, false, 100, false);
|
||||
defaultRow2.quantity = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
defaultRow2.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
m_tableModel->addRow(defaultRow2);
|
||||
|
||||
|
||||
m_tableModel->addRow(emptyRow);
|
||||
|
||||
SpecificationRowData headerRow2;
|
||||
headerRow2.isHeader = true;
|
||||
headerRow2.format = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow2.zone = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow2.position = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow2.designation = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow2.name = SpecificationCellData("Материалы", 0, 1, true, false, false, 100, true);
|
||||
headerRow2.quantity = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
headerRow2.note = SpecificationCellData("", 0, 1, true, false, false, 100, true);
|
||||
m_tableModel->addRow(headerRow2);
|
||||
|
||||
m_tableModel->addRow(emptyRow);
|
||||
|
||||
|
||||
if (!m_pcbMaterialModel || m_pcbMaterialModel->getMaterialCount() == 0) {
|
||||
qDebug() << "SpecificationController::generateTableFromMaterials: Нет материалов для генерации";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::generateTableFromMaterials: Материалов для обработки:" << m_pcbMaterialModel->getMaterialCount();
|
||||
|
||||
try {
|
||||
// Получаем список материалов из PCB модели
|
||||
QList<PCBMaterialData> materials = m_pcbMaterialModel->getMaterials();
|
||||
|
||||
// Сортируем материалы по номеру слоя
|
||||
std::sort(materials.begin(), materials.end(),
|
||||
[](const PCBMaterialData &a, const PCBMaterialData &b) {
|
||||
return a.layerNumber < b.layerNumber;
|
||||
});
|
||||
|
||||
// Группируем материалы по названию и типу
|
||||
QMap<QString, QList<PCBMaterialData>> groupedByName;
|
||||
for (const PCBMaterialData &material : materials) {
|
||||
QString materialName = material.name;
|
||||
groupedByName[materialName].append(material);
|
||||
}
|
||||
|
||||
// Подсчитываем количество ядер (dielType = 1 в модели PCB)
|
||||
int coreCount = 0;
|
||||
for (const PCBMaterialData &material : materials) {
|
||||
if (material.dielType == 1) {
|
||||
coreCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Подсчитываем общее количество слоев
|
||||
int totalLayers = m_pcbMaterialModel->getLayerCount();
|
||||
|
||||
// Рассчитываем количество фольги: (общее количество слоев - количество ядер)
|
||||
int foilCount = totalLayers - coreCount*2;
|
||||
|
||||
// Обрабатываем каждую группу материалов
|
||||
int pos = 1;
|
||||
for (auto it = groupedByName.begin(); it != groupedByName.end(); ++it) {
|
||||
QString materialName = it.key();
|
||||
QList<PCBMaterialData> materialsInGroup = it.value();
|
||||
|
||||
// Определяем тип материала и формируем название
|
||||
QString displayName;
|
||||
int quantity = 0;
|
||||
|
||||
if (materialName == "DielMaterial") {
|
||||
// Для диэлектрических материалов группируем по значению
|
||||
QMap<QString, QList<PCBMaterialData>> groupedByValue;
|
||||
for (const PCBMaterialData &material : materialsInGroup) {
|
||||
QString value = material.value;
|
||||
groupedByValue[value].append(material);
|
||||
}
|
||||
|
||||
// Обрабатываем каждое значение диэлектрика
|
||||
for (auto valueIt = groupedByValue.begin(); valueIt != groupedByValue.end(); ++valueIt) {
|
||||
QString value = valueIt.key();
|
||||
QList<PCBMaterialData> valueMaterials = valueIt.value();
|
||||
|
||||
// Определяем тип диэлектрика и формируем название
|
||||
QString dielTypeName;
|
||||
if (value == "FR4 PR") {
|
||||
dielTypeName = "Препрег FR4 PR";
|
||||
} else if (value == "FR4 Tg150") {
|
||||
dielTypeName = "Стеклотекстолит FR4 Tg150";
|
||||
} else if (value == "Solder Resist") {
|
||||
dielTypeName = "Паяльная маска";
|
||||
} else {
|
||||
dielTypeName = value;
|
||||
}
|
||||
|
||||
// Добавляем толщину к названию
|
||||
if (!valueMaterials.isEmpty()) {
|
||||
double thickness = valueMaterials.first().height;
|
||||
displayName = QString("%1 %2 мм").arg(dielTypeName).arg(QString::number(thickness, 'f', 3));
|
||||
}
|
||||
|
||||
quantity = valueMaterials.size();
|
||||
|
||||
// Добавляем строку в таблицу
|
||||
SpecificationRowData row;
|
||||
row.format = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
row.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
row.position = SpecificationCellData(QString::number(pos++), 0, 1, false, false, false, 100, false);
|
||||
row.designation = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
row.name = SpecificationCellData(displayName, 0, 1, false, false, false, 100, false);
|
||||
row.quantity = SpecificationCellData(QString::number(quantity), 0, 1, false, false, false, 100, false);
|
||||
row.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
|
||||
m_tableModel->addRow(row);
|
||||
}
|
||||
} else {
|
||||
// Для других материалов (например, фольга)
|
||||
displayName = materialName;
|
||||
quantity = materialsInGroup.size();
|
||||
|
||||
// Добавляем строку в таблицу
|
||||
SpecificationRowData row;
|
||||
row.format = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
row.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
row.position = SpecificationCellData(QString::number(pos++), 0, 1, false, false, false, 100, false);
|
||||
row.designation = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
row.name = SpecificationCellData(displayName, 0, 1, false, false, false, 100, false);
|
||||
row.quantity = SpecificationCellData(QString::number(quantity), 0, 1, false, false, false, 100, false);
|
||||
row.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
|
||||
m_tableModel->addRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем фольгу в конец, если она есть
|
||||
if (foilCount > 0) {
|
||||
SpecificationRowData foilRow;
|
||||
foilRow.format = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
foilRow.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
foilRow.position = SpecificationCellData(QString::number(pos++), 0, 1, false, false, false, 100, false);
|
||||
foilRow.designation = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
foilRow.name = SpecificationCellData("Фольга медная толщиной 18 мкм", 0, 1, false, false, false, 100, false);
|
||||
foilRow.quantity = SpecificationCellData(QString::number(foilCount), 0, 1, false, false, false, 100, false);
|
||||
foilRow.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
|
||||
|
||||
m_tableModel->addRow(foilRow);
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::generateTableFromMaterials: Таблица сгенерирована, строк:" << m_tableModel->rowCount();
|
||||
|
||||
// Оптимизируем разрывы страниц после генерации таблицы
|
||||
m_tableModel->optimizePageBreaks();
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
qDebug() << "SpecificationController::generateTableFromMaterials: Ошибка при генерации:" << e.what();
|
||||
} catch (...) {
|
||||
qDebug() << "SpecificationController::generateTableFromMaterials: Неизвестная ошибка при генерации";
|
||||
}
|
||||
}
|
||||
|
||||
void SpecificationController::updateTableFromMaterials()
|
||||
{
|
||||
if (!m_tableModel) {
|
||||
qDebug() << "SpecificationController::updateTableFromMaterials: m_tableModel is null";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::updateTableFromMaterials: Обновляем таблицу из" << m_materials.size() << "материалов";
|
||||
|
||||
if (m_materials.isEmpty()) {
|
||||
qDebug() << "SpecificationController::updateTableFromMaterials: Нет материалов для обновления";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Метод updateTableFromMaterials больше не используется в новой логике
|
||||
qDebug() << "SpecificationController::updateTableFromMaterials: Метод устарел";
|
||||
} catch (const std::exception &e) {
|
||||
qDebug() << "SpecificationController::updateTableFromMaterials: Ошибка при обновлении:" << e.what();
|
||||
} catch (...) {
|
||||
qDebug() << "SpecificationController::updateTableFromMaterials: Неизвестная ошибка при обновлении";
|
||||
}
|
||||
}
|
||||
|
||||
QString SpecificationController::getMaterialValue(PCBMaterialModel *material, const QString &propertyName)
|
||||
{
|
||||
if (!material) {
|
||||
return "";
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::getMaterialValue: propertyName =" << propertyName;
|
||||
|
||||
// Получаем значение свойства материала
|
||||
QString value;
|
||||
if (propertyName == "Name") {
|
||||
value = material->getMaterialName(0); // Получаем название первого материала
|
||||
qDebug() << "SpecificationController::getMaterialValue: Name =" << value;
|
||||
} else if (propertyName == "Value") {
|
||||
value = material->getMaterialValue(0);
|
||||
qDebug() << "SpecificationController::getMaterialValue: Value =" << value;
|
||||
} else if (propertyName == "Height") {
|
||||
value = material->formatHeight(material->getMaterialHeight(0));
|
||||
qDebug() << "SpecificationController::getMaterialValue: Height =" << value;
|
||||
} else if (propertyName == "DielType") {
|
||||
value = material->formatDielType(material->getMaterialDielType(0));
|
||||
qDebug() << "SpecificationController::getMaterialValue: DielType =" << value;
|
||||
} else if (propertyName == "LayerNumber") {
|
||||
value = QString::number(material->getMaterialLayerNumber(0));
|
||||
qDebug() << "SpecificationController::getMaterialValue: LayerNumber =" << value;
|
||||
} else {
|
||||
qDebug() << "SpecificationController::getMaterialValue: Неизвестное свойство" << propertyName;
|
||||
return "";
|
||||
}
|
||||
|
||||
// Проверяем, является ли значение свойства выражением
|
||||
if (value.startsWith("=")) {
|
||||
qDebug() << "SpecificationController::getMaterialValue: Значение свойства является выражением:" << value;
|
||||
return parseExpression(material, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
QString SpecificationController::formatDielType(int dielType)
|
||||
{
|
||||
switch (dielType) {
|
||||
case 0: return "Ядро";
|
||||
case 1: return "Препрег";
|
||||
default: return "Неизвестно";
|
||||
}
|
||||
}
|
||||
|
||||
QString SpecificationController::parseExpression(PCBMaterialModel *material, const QString &expression)
|
||||
{
|
||||
if (!material) {
|
||||
return "";
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::parseExpression: Обрабатываем выражение:" << expression;
|
||||
|
||||
QString result;
|
||||
QString expr;
|
||||
|
||||
// Определяем, как обрабатывать выражение
|
||||
if (expression.startsWith("=")) {
|
||||
expr = expression.mid(1); // Убираем начальный "="
|
||||
} else if (expression.startsWith("\"") && expression.endsWith("\"")) {
|
||||
// Если это просто значение в кавычках, возвращаем его без кавычек
|
||||
return expression.mid(1, expression.length() - 2);
|
||||
} else {
|
||||
// Если это не выражение, возвращаем как есть
|
||||
return expression;
|
||||
}
|
||||
|
||||
// Разбиваем выражение по операторам "+" с учетом кавычек
|
||||
QStringList parts;
|
||||
QString currentPart;
|
||||
bool inDoubleQuotes = false;
|
||||
bool inSingleQuotes = false;
|
||||
|
||||
for (int i = 0; i < expr.length(); ++i) {
|
||||
QChar ch = expr[i];
|
||||
|
||||
if (ch == '"' && !inSingleQuotes) {
|
||||
inDoubleQuotes = !inDoubleQuotes;
|
||||
currentPart += ch;
|
||||
} else if (ch == '\'' && !inDoubleQuotes) {
|
||||
inSingleQuotes = !inSingleQuotes;
|
||||
currentPart += ch;
|
||||
} else if (ch == '+' && !inDoubleQuotes && !inSingleQuotes) {
|
||||
// Это разделитель "+" вне кавычек
|
||||
if (!currentPart.trimmed().isEmpty()) {
|
||||
parts.append(currentPart.trimmed());
|
||||
}
|
||||
currentPart.clear();
|
||||
} else {
|
||||
currentPart += ch;
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем последнюю часть
|
||||
if (!currentPart.trimmed().isEmpty()) {
|
||||
parts.append(currentPart.trimmed());
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::parseExpression: Части выражения:" << parts;
|
||||
|
||||
for (const QString &part : parts) {
|
||||
QString trimmedPart = part.trimmed();
|
||||
qDebug() << "SpecificationController::parseExpression: Обрабатываем часть:" << trimmedPart;
|
||||
|
||||
// Если это не пустая строка, добавляем к результату
|
||||
if (!trimmedPart.isEmpty()) {
|
||||
QString value;
|
||||
|
||||
// Проверяем, является ли это литералом в одинарных кавычках
|
||||
if (trimmedPart.startsWith("'") && trimmedPart.endsWith("'")) {
|
||||
// Это литерал - убираем кавычки и используем как есть
|
||||
value = trimmedPart.mid(1, trimmedPart.length() - 2);
|
||||
qDebug() << "SpecificationController::parseExpression: Найден литерал в одинарных кавычках:" << value;
|
||||
}
|
||||
// Проверяем, является ли это именем свойства материала в двойных кавычках
|
||||
else if (trimmedPart.startsWith("\"") && trimmedPart.endsWith("\"")) {
|
||||
// Это свойство материала - убираем кавычки и ищем в свойствах
|
||||
QString propertyName = trimmedPart.mid(1, trimmedPart.length() - 2);
|
||||
qDebug() << "SpecificationController::parseExpression: Ищем свойство материала:" << propertyName;
|
||||
|
||||
value = getMaterialValue(material, propertyName);
|
||||
qDebug() << "SpecificationController::parseExpression: Найдено свойство" << propertyName << "=" << value;
|
||||
// Рекурсивно обрабатываем вложенные выражения (getMaterialValue уже обрабатывает первый уровень)
|
||||
// Но если значение само является выражением, нужно обработать его еще раз
|
||||
if (value.startsWith("=")) {
|
||||
qDebug() << "SpecificationController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
|
||||
value = parseExpression(material, value);
|
||||
}
|
||||
}
|
||||
// Проверяем, является ли это именем свойства материала без кавычек
|
||||
else {
|
||||
// Ищем в свойствах материала
|
||||
value = getMaterialValue(material, trimmedPart);
|
||||
qDebug() << "SpecificationController::parseExpression: Ищем свойство" << trimmedPart << "в материале, результат:" << value;
|
||||
// Рекурсивно обрабатываем вложенные выражения (getMaterialValue уже обрабатывает первый уровень)
|
||||
// Но если значение само является выражением, нужно обработать его еще раз
|
||||
if (value.startsWith("=")) {
|
||||
qDebug() << "SpecificationController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
|
||||
value = parseExpression(material, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем значение к результату
|
||||
if (!value.isEmpty()) {
|
||||
if (!result.isEmpty()) {
|
||||
result += value;
|
||||
} else {
|
||||
result = value;
|
||||
}
|
||||
qDebug() << "SpecificationController::parseExpression: Добавили к результату, текущий результат:" << result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::parseExpression: Финальный результат:" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList SpecificationController::collectPropertyNames()
|
||||
{
|
||||
QStringList propertyNames;
|
||||
|
||||
// Добавляем основные свойства материала
|
||||
propertyNames << "Name" << "Value" << "Height" << "DielType" << "LayerNumber";
|
||||
|
||||
// Если дополнительные свойства не найдены в материалах, добавляем стандартные
|
||||
if (propertyNames.size() <= 5) { // Только базовые свойства
|
||||
propertyNames << "Format" << "Zone" << "Position" << "Designation" << "Quantity" << "Note";
|
||||
qDebug() << "SpecificationController: Дополнительные свойства не найдены, используем стандартные:" << propertyNames;
|
||||
}
|
||||
|
||||
// Добавляем специальное свойство для количества материалов в группе
|
||||
propertyNames << "Quantity" << "Кол.";
|
||||
|
||||
return propertyNames;
|
||||
}
|
||||
|
||||
// Методы для работы с децимальными номерами
|
||||
QString SpecificationController::getDecimalNumberBoard() const
|
||||
{
|
||||
QStringList mappings = getColumnMappings();
|
||||
if (mappings.size() > 7) {
|
||||
QString fieldName = mappings[7];
|
||||
if (!fieldName.isEmpty()) {
|
||||
// Получаем значение из projectparamtable
|
||||
if (m_mainController) {
|
||||
ProjectParamTableModel *paramModel = m_mainController->projectParamTableModel();
|
||||
if (paramModel) {
|
||||
QMap<QString, QString> params = paramModel->getDataAsMap();
|
||||
if (params.contains(fieldName)) {
|
||||
return params[fieldName]; // Возвращаем значение, а не название поля
|
||||
}
|
||||
}
|
||||
}
|
||||
// Если не удалось получить значение из модели, возвращаем название поля
|
||||
return fieldName;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void SpecificationController::setDecimalNumberBoard(const QString &value)
|
||||
{
|
||||
QStringList mappings = getColumnMappings();
|
||||
while (mappings.size() <= 7) {
|
||||
mappings.append("");
|
||||
}
|
||||
mappings[7] = value;
|
||||
setColumnMappings(mappings);
|
||||
}
|
||||
|
||||
QString SpecificationController::getDecimalNumberDocument() const
|
||||
{
|
||||
QStringList mappings = getColumnMappings();
|
||||
if (mappings.size() > 8) {
|
||||
QString fieldName = mappings[8];
|
||||
if (!fieldName.isEmpty()) {
|
||||
// Получаем значение из projectparamtable
|
||||
if (m_mainController) {
|
||||
ProjectParamTableModel *paramModel = m_mainController->projectParamTableModel();
|
||||
if (paramModel) {
|
||||
QMap<QString, QString> params = paramModel->getDataAsMap();
|
||||
if (params.contains(fieldName)) {
|
||||
return params[fieldName]; // Возвращаем значение, а не название поля
|
||||
}
|
||||
}
|
||||
}
|
||||
// Если не удалось получить значение из модели, возвращаем название поля
|
||||
return fieldName;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void SpecificationController::setDecimalNumberDocument(const QString &value)
|
||||
{
|
||||
QStringList mappings = getColumnMappings();
|
||||
while (mappings.size() <= 8) {
|
||||
mappings.append("");
|
||||
}
|
||||
mappings[8] = value;
|
||||
setColumnMappings(mappings);
|
||||
}
|
||||
|
||||
void SpecificationController::setColumnMappings(const QStringList &mappings)
|
||||
{
|
||||
qDebug() << "SpecificationController::setColumnMappings: Устанавливаем новые настройки колонок:" << mappings;
|
||||
m_columnMappings = mappings;
|
||||
|
||||
// Сохраняем настройки в ProjectSettingsModel
|
||||
if (m_projectSettingsModel) {
|
||||
for (int i = 0; i < mappings.size(); ++i) {
|
||||
m_projectSettingsModel->setColumnMapping("Specification", i, mappings[i]);
|
||||
}
|
||||
qDebug() << "SpecificationController::setColumnMappings: Настройки сохранены в ProjectSettingsModel";
|
||||
}
|
||||
|
||||
// Обновляем настройки в модели
|
||||
if (m_tableModel) {
|
||||
m_tableModel->setColumnMappings(mappings);
|
||||
qDebug() << "SpecificationController::setColumnMappings: Настройки обновлены в модели";
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::setColumnMappings: Настройки колонок обновлены:" << m_columnMappings;
|
||||
}
|
||||
|
||||
QStringList SpecificationController::getColumnMappings() const
|
||||
{
|
||||
// Если есть ProjectSettingsModel, читаем настройки из него
|
||||
if (m_projectSettingsModel) {
|
||||
QStringList settings = m_projectSettingsModel->getColumnMappings("Specification");
|
||||
if (!settings.isEmpty()) {
|
||||
qDebug() << "SpecificationController::getColumnMappings: Получены настройки из ProjectSettingsModel:" << settings;
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: возвращаем локальные настройки
|
||||
qDebug() << "SpecificationController::getColumnMappings: Возвращаем локальные настройки:" << m_columnMappings;
|
||||
return m_columnMappings;
|
||||
}
|
||||
|
||||
QStringList SpecificationController::getAvailableProperties() const
|
||||
{
|
||||
QStringList properties = m_propertyNames;
|
||||
properties.prepend("<Пусто>");
|
||||
properties.prepend("<Авто>");
|
||||
return properties;
|
||||
}
|
||||
|
||||
QString SpecificationController::getMaterialType(PCBMaterialModel *material)
|
||||
{
|
||||
if (!material) return "";
|
||||
|
||||
// Получаем тип материала из свойств
|
||||
QString type = material->formatDielType(material->getMaterialDielType(0));
|
||||
if (!type.isEmpty()) {
|
||||
return type;
|
||||
}
|
||||
|
||||
// Если тип не найден, используем fallback
|
||||
return "Материал";
|
||||
}
|
||||
|
||||
QPair<QString, QString> SpecificationController::splitDesignator(const QString &designator)
|
||||
{
|
||||
if (designator.isEmpty()) {
|
||||
return QPair<QString, QString>("", "");
|
||||
}
|
||||
|
||||
// Используем регулярное выражение для разделения буквенной и цифровой части
|
||||
QRegExp regex("([A-Za-z]+)(\\d*)");
|
||||
if (regex.indexIn(designator) != -1) {
|
||||
QString letterPart = regex.cap(1);
|
||||
QString numberPart = regex.cap(2);
|
||||
return QPair<QString, QString>(letterPart, numberPart);
|
||||
}
|
||||
|
||||
// Fallback: если регулярное выражение не сработало,
|
||||
// ищем первую цифру и разделяем по ней
|
||||
for (int i = 0; i < designator.length(); ++i) {
|
||||
if (designator[i].isDigit()) {
|
||||
QString letterPart = designator.left(i);
|
||||
QString numberPart = designator.mid(i);
|
||||
return QPair<QString, QString>(letterPart, numberPart);
|
||||
}
|
||||
}
|
||||
|
||||
// Если цифр нет, возвращаем весь десигнатор как буквенную часть
|
||||
return QPair<QString, QString>(designator, "");
|
||||
}
|
||||
|
||||
// Новые методы для управления строками
|
||||
void SpecificationController::addEmptyRow()
|
||||
{
|
||||
if (m_tableModel) {
|
||||
m_tableModel->addEmptyRow();
|
||||
qDebug() << "SpecificationController::addEmptyRow: Добавлена пустая строка";
|
||||
|
||||
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
|
||||
// m_tableModel->optimizePageBreaks();
|
||||
}
|
||||
}
|
||||
|
||||
void SpecificationController::addEmptyRowAt(int position)
|
||||
{
|
||||
if (m_tableModel) {
|
||||
m_tableModel->addEmptyRowAt(position);
|
||||
qDebug() << "SpecificationController::addEmptyRowAt: Добавлена пустая строка в позицию" << position;
|
||||
|
||||
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
|
||||
// m_tableModel->optimizePageBreaks();
|
||||
}
|
||||
}
|
||||
|
||||
void SpecificationController::insertEmptyRowAt(int position)
|
||||
{
|
||||
if (m_tableModel) {
|
||||
m_tableModel->addEmptyRowAt(position);
|
||||
qDebug() << "SpecificationController::insertEmptyRowAt: Вставлена пустая строка в позицию" << position;
|
||||
|
||||
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
|
||||
// m_tableModel->optimizePageBreaks();
|
||||
}
|
||||
}
|
||||
|
||||
void SpecificationController::removeRow(int row)
|
||||
{
|
||||
if (m_tableModel) {
|
||||
m_tableModel->removeRow(row);
|
||||
qDebug() << "SpecificationController::removeRow: Удалена строка" << row;
|
||||
|
||||
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
|
||||
// m_tableModel->optimizePageBreaks();
|
||||
}
|
||||
}
|
||||
|
||||
void SpecificationController::clearTable()
|
||||
{
|
||||
if (m_tableModel) {
|
||||
m_tableModel->clear();
|
||||
qDebug() << "SpecificationController::clearTable: Таблица очищена";
|
||||
}
|
||||
}
|
||||
|
||||
void SpecificationController::optimizePageBreaks()
|
||||
{
|
||||
if (m_tableModel) {
|
||||
qDebug() << "SpecificationController::optimizePageBreaks: Оптимизируем разрывы страниц";
|
||||
m_tableModel->optimizePageBreaks();
|
||||
}
|
||||
}
|
||||
|
||||
int SpecificationController::getFontSize() const
|
||||
{
|
||||
if (m_projectSettingsModel) {
|
||||
return m_projectSettingsModel->getFontSize("Specification");
|
||||
}
|
||||
return 12; // По умолчанию
|
||||
}
|
||||
|
||||
void SpecificationController::setFontSize(int fontSize)
|
||||
{
|
||||
if (m_projectSettingsModel) {
|
||||
m_projectSettingsModel->setFontSize("Specification", fontSize);
|
||||
}
|
||||
}
|
||||
|
||||
int SpecificationController::getFontStretch() const
|
||||
{
|
||||
if (m_projectSettingsModel) {
|
||||
return m_projectSettingsModel->getFontStretch("Specification");
|
||||
}
|
||||
return 100; // По умолчанию (нормальный)
|
||||
}
|
||||
|
||||
void SpecificationController::setFontStretch(int stretch)
|
||||
{
|
||||
if (m_projectSettingsModel) {
|
||||
m_projectSettingsModel->setFontStretch("Specification", stretch);
|
||||
}
|
||||
}
|
||||
|
||||
QList<QString> SpecificationController::splitLongDesignation(const QString &designation, const QString originalString, PCBMaterialModel *material, int maxLength)
|
||||
{
|
||||
QList<QString> result;
|
||||
|
||||
if (designation.length() <= maxLength) {
|
||||
result.append(designation);
|
||||
return result;
|
||||
}
|
||||
|
||||
qDebug() << "SpecificationController::splitLongDesignation: Разделяем длинное наименование:" << designation;
|
||||
|
||||
// Обычный текст - разделяем по пробелам
|
||||
result = splitBySpaces(designation, maxLength);
|
||||
|
||||
qDebug() << "SpecificationController::splitLongDesignation: Результат разделения:" << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<QString> SpecificationController::splitBySpaces(const QString &text, int maxLength)
|
||||
{
|
||||
QList<QString> result;
|
||||
|
||||
if (text.length() <= maxLength) {
|
||||
result.append(text);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Ищем пробел, ближайший к середине строки
|
||||
int targetLength = maxLength;
|
||||
int bestSplitPos = -1;
|
||||
int minDifference = text.length(); // Минимальная разница с целевой длиной
|
||||
|
||||
// Ищем пробелы в тексте
|
||||
for (int i = 0; i < text.length(); ++i) {
|
||||
if (text[i] == ' ') {
|
||||
int leftLength = i;
|
||||
int rightLength = text.length() - i - 1;
|
||||
|
||||
// Вычисляем разницу с целевой длиной
|
||||
int leftDiff = abs(leftLength - targetLength);
|
||||
int rightDiff = abs(rightLength - targetLength);
|
||||
int totalDiff = leftDiff + rightDiff;
|
||||
|
||||
// Если эта позиция лучше предыдущей, запоминаем её
|
||||
if (totalDiff < minDifference) {
|
||||
minDifference = totalDiff;
|
||||
bestSplitPos = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если нашли подходящий пробел, разделяем по нему
|
||||
if (bestSplitPos != -1) {
|
||||
QString leftPart = text.left(bestSplitPos).trimmed();
|
||||
QString rightPart = text.mid(bestSplitPos + 1).trimmed();
|
||||
|
||||
// Рекурсивно обрабатываем обе части
|
||||
if (!leftPart.isEmpty()) {
|
||||
QList<QString> leftParts = splitBySpaces(leftPart, maxLength);
|
||||
result.append(leftParts);
|
||||
}
|
||||
|
||||
if (!rightPart.isEmpty()) {
|
||||
QList<QString> rightParts = splitBySpaces(rightPart, maxLength);
|
||||
result.append(rightParts);
|
||||
}
|
||||
} else {
|
||||
// Если пробелов нет или не удалось найти подходящий, разбиваем посимвольно
|
||||
// for (int i = 0; i < text.length(); i += maxLength) {
|
||||
// result.append(text.mid(i, maxLength));
|
||||
// }
|
||||
result.append(text);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString SpecificationController::getMaterialFormat(PCBMaterialModel *material)
|
||||
{
|
||||
if (!material) return "";
|
||||
|
||||
// Получаем формат из свойств материала
|
||||
// Для материалов платы обычно используется стандартный формат
|
||||
return "A4";
|
||||
}
|
||||
|
||||
QString SpecificationController::getMaterialZone(PCBMaterialModel *material)
|
||||
{
|
||||
if (!material) return "";
|
||||
|
||||
// Получаем зону из свойств материала
|
||||
// Для материалов платы зона обычно не указывается
|
||||
return "";
|
||||
}
|
||||
|
||||
QString SpecificationController::getMaterialPosition(PCBMaterialModel *material)
|
||||
{
|
||||
if (!material) return "";
|
||||
|
||||
// Для спецификации материалов позиция обычно совпадает с номером слоя
|
||||
return QString::number(material->getMaterialLayerNumber(0));
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#ifndef SPECIFICATIONCONTROLLER_H
|
||||
#define SPECIFICATIONCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
#include "../model/specificationtablemodel.h"
|
||||
#include "../model/designatormappingmodel.h"
|
||||
#include "../model/projectsettingsmodel.h"
|
||||
|
||||
class PCBMaterialModel;
|
||||
class MainController;
|
||||
|
||||
class SpecificationController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SpecificationController(QObject *parent = nullptr);
|
||||
~SpecificationController();
|
||||
|
||||
// Получение модели для отображения в UI
|
||||
SpecificationTableModel* getTableModel() const { return m_tableModel; }
|
||||
SpecificationTableModel* getModel() const { return m_tableModel; } // Алиас для совместимости
|
||||
|
||||
// Методы для работы с материалами
|
||||
void setMaterials(const QList<PCBMaterialModel*> &materials);
|
||||
void setPCBMaterialModel(PCBMaterialModel* model);
|
||||
void generateTableFromMaterials();
|
||||
void updateTableFromMaterials(); // Метод для обновления таблицы по кнопке
|
||||
|
||||
// Новые методы для управления строками
|
||||
void addEmptyRow();
|
||||
void addEmptyRowAt(int position);
|
||||
void insertEmptyRowAt(int position); // Вставка строки в определенную позицию
|
||||
void removeRow(int row);
|
||||
void clearTable();
|
||||
|
||||
// Методы для работы с настройками
|
||||
void setColumnMappings(const QStringList &mappings);
|
||||
QStringList getColumnMappings() const;
|
||||
QStringList getAvailableProperties() const;
|
||||
|
||||
// Метод для установки модели маппинга дезигнаторов
|
||||
void setDesignatorMappingModel(DesignatorMappingModel *mappingModel);
|
||||
|
||||
// Метод для установки модели таблицы (для интеграции с SpecificationProcessor)
|
||||
void setModel(SpecificationTableModel *model);
|
||||
|
||||
// Метод для установки модели настроек проекта
|
||||
void setProjectSettingsModel(ProjectSettingsModel *model);
|
||||
void setMainController(MainController *controller);
|
||||
|
||||
// Метод для оптимизации разрывов страниц
|
||||
void optimizePageBreaks();
|
||||
|
||||
// Методы для работы с размером шрифта
|
||||
int getFontSize() const;
|
||||
void setFontSize(int fontSize);
|
||||
int getFontStretch() const;
|
||||
void setFontStretch(int stretch);
|
||||
|
||||
// Методы для работы с децимальными номерами
|
||||
QString getDecimalNumberBoard() const;
|
||||
void setDecimalNumberBoard(const QString &value);
|
||||
QString getDecimalNumberDocument() const;
|
||||
void setDecimalNumberDocument(const QString &value);
|
||||
|
||||
private:
|
||||
QString getMaterialValue(PCBMaterialModel *material, const QString &propertyName);
|
||||
QString parseExpression(PCBMaterialModel *material, const QString &expression);
|
||||
QString formatDielType(int dielType);
|
||||
QStringList collectPropertyNames();
|
||||
|
||||
// Методы для группировки
|
||||
QString getMaterialType(PCBMaterialModel *material);
|
||||
|
||||
// Метод для разделения десигнатора на буквенную и цифровую части
|
||||
QPair<QString, QString> splitDesignator(const QString &designator);
|
||||
|
||||
// Метод для разделения длинных наименований на несколько строк
|
||||
QList<QString> splitLongDesignation(const QString &designation, const QString originalString="", PCBMaterialModel *material = nullptr, int maxLength = 60);
|
||||
|
||||
// Вспомогательный метод для разделения текста по пробелам
|
||||
QList<QString> splitBySpaces(const QString &text, int maxLength);
|
||||
|
||||
// Методы для специфичной логики спецификации
|
||||
QString getMaterialFormat(PCBMaterialModel *material);
|
||||
QString getMaterialZone(PCBMaterialModel *material);
|
||||
QString getMaterialPosition(PCBMaterialModel *material);
|
||||
|
||||
SpecificationTableModel *m_tableModel;
|
||||
DesignatorMappingModel *m_designatorMappingModel;
|
||||
ProjectSettingsModel *m_projectSettingsModel;
|
||||
MainController *m_mainController;
|
||||
QList<PCBMaterialModel*> m_materials;
|
||||
PCBMaterialModel *m_pcbMaterialModel;
|
||||
QStringList m_columnMappings;
|
||||
QStringList m_propertyNames;
|
||||
};
|
||||
|
||||
#endif // SPECIFICATIONCONTROLLER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,112 @@
|
||||
#ifndef SPECIFICATIONPCBCONTROLLER_H
|
||||
#define SPECIFICATIONPCBCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
#include "../model/specificationpcbtablemodel.h"
|
||||
#include "../model/designatormappingmodel.h"
|
||||
#include "../model/projectsettingsmodel.h"
|
||||
|
||||
class ComponentModel;
|
||||
class MainController;
|
||||
|
||||
class SpecificationPCBController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SpecificationPCBController(QObject *parent = nullptr);
|
||||
~SpecificationPCBController();
|
||||
|
||||
// Получение модели для отображения в UI
|
||||
SpecificationPCBTableModel* getTableModel() const { return m_tableModel; }
|
||||
SpecificationPCBTableModel* getModel() const { return m_tableModel; } // Алиас для совместимости
|
||||
|
||||
// Методы для работы с компонентами
|
||||
void setComponents(const QList<ComponentModel*> &components);
|
||||
void generateTableFromComponents();
|
||||
void updateTableFromComponents(); // Метод для обновления таблицы по кнопке
|
||||
|
||||
// Новые методы для управления строками
|
||||
void addEmptyRow();
|
||||
void addEmptyRowAt(int position);
|
||||
void insertEmptyRowAt(int position); // Вставка строки в определенную позицию
|
||||
void removeRow(int row);
|
||||
void clearTable();
|
||||
|
||||
// Методы для работы с настройками
|
||||
void setColumnMappings(const QStringList &mappings);
|
||||
QStringList getColumnMappings() const;
|
||||
QStringList getAvailableProperties() const;
|
||||
|
||||
// Метод для установки модели маппинга дезигнаторов
|
||||
void setDesignatorMappingModel(DesignatorMappingModel *mappingModel);
|
||||
|
||||
// Метод для установки модели таблицы (для интеграции с SpecificationPCBProcessor)
|
||||
void setModel(SpecificationPCBTableModel *model);
|
||||
|
||||
// Метод для установки модели настроек проекта
|
||||
void setProjectSettingsModel(ProjectSettingsModel *model);
|
||||
void setMainController(MainController *controller);
|
||||
|
||||
// Метод для оптимизации разрывов страниц
|
||||
void optimizePageBreaks();
|
||||
|
||||
// Метод для перерасчета позиций (начинает с последнего значения + 1)
|
||||
void recalculatePositions();
|
||||
|
||||
// Методы для работы с размером шрифта
|
||||
int getFontSize() const;
|
||||
void setFontSize(int fontSize);
|
||||
int getFontStretch() const;
|
||||
void setFontStretch(int stretch);
|
||||
|
||||
// Методы для работы с децимальными номерами
|
||||
QString getDecimalNumberBoard() const;
|
||||
void setDecimalNumberBoard(const QString &value);
|
||||
QString getDecimalNumberDocument() const;
|
||||
void setDecimalNumberDocument(const QString &value);
|
||||
|
||||
// Методы для работы с названием платы
|
||||
QString getBoardName() const;
|
||||
void setBoardName(const QString &value);
|
||||
|
||||
private:
|
||||
QString getComponentValue(ComponentModel *component, const QString &propertyName);
|
||||
QString parseExpression(ComponentModel *component, const QString &expression);
|
||||
QStringList collectPropertyNames();
|
||||
|
||||
// Методы для группировки
|
||||
QString getComponentType(ComponentModel *component);
|
||||
|
||||
// Метод для разделения десигнатора на буквенную и цифровую части
|
||||
QPair<QString, QString> splitDesignator(const QString &designator);
|
||||
|
||||
// Метод для разделения длинных наименований на несколько строк
|
||||
QList<QString> splitLongDesignation(const QString &designation, const QString originalString="", ComponentModel *component = nullptr, int maxLength = 34);
|
||||
|
||||
// Вспомогательный метод для разделения текста по пробелам
|
||||
QList<QString> splitBySpaces(const QString &text, int maxLength);
|
||||
|
||||
// Вспомогательный метод для разделения комплексной строки (с запятыми) по середине
|
||||
QList<QString> splitComplexStringByMiddle(const QString &text, int maxLength);
|
||||
|
||||
// Метод для разбиения длинных групп десигнаторов
|
||||
QStringList splitDesignatorGroups(const QStringList &designatorGroups, int maxLength = 30);
|
||||
|
||||
// Методы для специфичной логики спецификации платы
|
||||
QString getComponentFormat(ComponentModel *component);
|
||||
QString getComponentZone(ComponentModel *component);
|
||||
QString getComponentPosition(ComponentModel *component);
|
||||
|
||||
SpecificationPCBTableModel *m_tableModel;
|
||||
DesignatorMappingModel *m_designatorMappingModel;
|
||||
ProjectSettingsModel *m_projectSettingsModel;
|
||||
MainController *m_mainController;
|
||||
QList<ComponentModel*> m_components;
|
||||
QStringList m_columnMappings;
|
||||
QStringList m_propertyNames;
|
||||
};
|
||||
|
||||
#endif // SPECIFICATIONPCBCONTROLLER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,110 @@
|
||||
#ifndef VEDOMOSTCONTROLLER_H
|
||||
#define VEDOMOSTCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
#include "../model/vedomosttablemodel.h"
|
||||
#include "../model/designatormappingmodel.h"
|
||||
#include "../model/projectsettingsmodel.h"
|
||||
|
||||
class ComponentModel;
|
||||
class MainController;
|
||||
|
||||
class VedomostController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VedomostController(QObject *parent = nullptr);
|
||||
~VedomostController();
|
||||
|
||||
// Получение модели для отображения в UI
|
||||
VedomostTableModel* getTableModel() const { return m_tableModel; }
|
||||
VedomostTableModel* getModel() const { return m_tableModel; } // Алиас для совместимости
|
||||
|
||||
// Методы для работы с компонентами
|
||||
void setComponents(const QList<ComponentModel*> &components);
|
||||
void generateTableFromComponents();
|
||||
void updateTableFromComponents(); // Метод для обновления таблицы по кнопке
|
||||
|
||||
// Новые методы для управления строками
|
||||
void addEmptyRow();
|
||||
void addEmptyRowAt(int position);
|
||||
void insertEmptyRowAt(int position); // Вставка строки в определенную позицию
|
||||
void removeRow(int row);
|
||||
void clearTable();
|
||||
|
||||
// Методы для работы с настройками
|
||||
void setColumnMappings(const QStringList &mappings);
|
||||
QStringList getColumnMappings() const;
|
||||
QStringList getAvailableProperties() const;
|
||||
|
||||
// Метод для установки модели маппинга дезигнаторов
|
||||
void setDesignatorMappingModel(DesignatorMappingModel *mappingModel);
|
||||
|
||||
// Метод для установки модели таблицы (для интеграции с VedomostProcessor)
|
||||
void setModel(VedomostTableModel *model);
|
||||
|
||||
// Метод для установки модели настроек проекта
|
||||
void setProjectSettingsModel(ProjectSettingsModel *model);
|
||||
|
||||
// Метод для установки главного контроллера
|
||||
void setMainController(MainController *controller);
|
||||
|
||||
// Метод для оптимизации разрывов страниц
|
||||
void optimizePageBreaks();
|
||||
|
||||
// Методы для работы с размером шрифта
|
||||
int getFontSize() const;
|
||||
void setFontSize(int fontSize);
|
||||
int getFontStretch() const;
|
||||
void setFontStretch(int stretch);
|
||||
|
||||
private:
|
||||
QString getComponentValue(ComponentModel *component, const QString &propertyName);
|
||||
QString getComponentRawValue(ComponentModel *component, const QString &propertyName); // Получает сырое значение без вычисления выражений
|
||||
QString getMappedValue(ComponentModel *component, const QString &columnName);
|
||||
QString parseExpression(ComponentModel *component, const QString &expression);
|
||||
QStringList collectPropertyNames();
|
||||
|
||||
// Методы для группировки
|
||||
QString getComponentType(ComponentModel *component);
|
||||
QString getComponentTypeName(ComponentModel *component); // Название элемента в единственном числе
|
||||
|
||||
// Метод для разделения десигнатора на буквенную и цифровую части
|
||||
QPair<QString, QString> splitDesignator(const QString &designator);
|
||||
|
||||
// Метод для разделения длинных наименований на несколько строк
|
||||
QList<QString> splitLongDesignation(const QString &designation, const QString originalString="", ComponentModel *component = nullptr, int maxLength = 60);
|
||||
|
||||
// Вспомогательный метод для разделения текста по пробелам
|
||||
QList<QString> splitBySpaces(const QString &text, int maxLength);
|
||||
|
||||
// Вспомогательный метод для разделения текста по соединениям
|
||||
QList<QString> splitByConnectors(const QString &text, int maxLength);
|
||||
|
||||
// Вспомогательный метод для разделения комплексной строки (с запятыми) по середине
|
||||
QList<QString> splitComplexStringByMiddle(const QString &text, int maxLength);
|
||||
|
||||
// Метод для разбиения длинных групп десигнаторов
|
||||
QStringList splitDesignatorGroups(const QStringList &designatorGroups, int maxLength = 30);
|
||||
|
||||
// Метод для получения значения "Куда входит" из ProjectParamTable
|
||||
QString getWhereUsed() const;
|
||||
|
||||
private slots:
|
||||
// Слот для обработки изменений данных в строке (автоматический пересчет totalQuantity)
|
||||
void onRowDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
|
||||
|
||||
private:
|
||||
VedomostTableModel *m_tableModel;
|
||||
DesignatorMappingModel *m_designatorMappingModel;
|
||||
ProjectSettingsModel *m_projectSettingsModel;
|
||||
MainController *m_mainController;
|
||||
QList<ComponentModel*> m_components;
|
||||
QStringList m_columnMappings;
|
||||
QStringList m_propertyNames;
|
||||
};
|
||||
|
||||
#endif // VEDOMOSTCONTROLLER_H
|
||||
Reference in New Issue
Block a user