843 lines
38 KiB
C++
843 lines
38 KiB
C++
#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));
|
||
}
|