1537 lines
78 KiB
C++
1537 lines
78 KiB
C++
#include "specificationpcbcontroller.h"
|
||
#include "../model/specificationpcbtablemodel.h"
|
||
#include "../model/designatormappingmodel.h"
|
||
#include "../model/projectsettingsmodel.h"
|
||
#include "../model/projectparamtablemodel.h"
|
||
#include "../model/componenttablemodel.h"
|
||
#include "../controller/maincontroller.h"
|
||
#include <QDebug>
|
||
#include <QCollator>
|
||
|
||
SpecificationPCBController::SpecificationPCBController(QObject *parent)
|
||
: QObject(parent)
|
||
, m_tableModel(new SpecificationPCBTableModel(this))
|
||
, m_designatorMappingModel(nullptr)
|
||
, m_projectSettingsModel(nullptr)
|
||
, m_mainController(nullptr)
|
||
, m_pcbDocFileName("")
|
||
{
|
||
// Устанавливаем маппинг по умолчанию для спецификации платы
|
||
m_columnMappings << "Format" << "Zone" << "Position" << "Designator" << "Name" << "Quantity" << "Value";
|
||
}
|
||
|
||
SpecificationPCBController::~SpecificationPCBController()
|
||
{
|
||
// m_tableModel удалится автоматически, так как он является дочерним объектом
|
||
}
|
||
|
||
void SpecificationPCBController::setDesignatorMappingModel(DesignatorMappingModel *mappingModel)
|
||
{
|
||
m_designatorMappingModel = mappingModel;
|
||
}
|
||
|
||
void SpecificationPCBController::setModel(SpecificationPCBTableModel *model)
|
||
{
|
||
if (m_tableModel != model) {
|
||
qDebug() << "SpecificationPCBController::setModel: Заменяем модель таблицы";
|
||
m_tableModel = model;
|
||
|
||
// Если модель не пуста, загружаем из неё настройки колонок
|
||
if (m_tableModel) {
|
||
QStringList columnMappings = m_tableModel->columnMappings();
|
||
if (!columnMappings.isEmpty()) {
|
||
qDebug() << "SpecificationPCBController::setModel: Загружаем настройки колонок из модели:" << columnMappings;
|
||
m_columnMappings = columnMappings;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void SpecificationPCBController::setProjectSettingsModel(ProjectSettingsModel *model)
|
||
{
|
||
m_projectSettingsModel = model;
|
||
qDebug() << "SpecificationPCBController::setProjectSettingsModel: Установлена модель настроек проекта";
|
||
}
|
||
|
||
void SpecificationPCBController::setMainController(MainController *controller)
|
||
{
|
||
m_mainController = controller;
|
||
qDebug() << "SpecificationPCBController::setMainController: Установлен главный контроллер";
|
||
}
|
||
|
||
void SpecificationPCBController::setComponents(const QList<ComponentModel*> &components)
|
||
{
|
||
qDebug() << "SpecificationPCBController::setComponents: Устанавливаем" << components.size() << "компонентов";
|
||
m_components = components;
|
||
|
||
// Собираем доступные свойства из компонентов
|
||
m_propertyNames = collectPropertyNames();
|
||
qDebug() << "SpecificationPCBController::setComponents: Собрано свойств:" << m_propertyNames.size();
|
||
qDebug() << "SpecificationPCBController::setComponents: Свойства:" << m_propertyNames;
|
||
}
|
||
|
||
void SpecificationPCBController::generateTableFromComponents()
|
||
{
|
||
if (!m_tableModel) {
|
||
return;
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::generateTableFromComponents: Начинаем генерацию таблицы";
|
||
qDebug() << "SpecificationPCBController::generateTableFromComponents: Текущие настройки колонок:" << m_columnMappings;
|
||
qDebug() << "SpecificationPCBController::generateTableFromComponents: Количество компонентов:" << m_components.size();
|
||
|
||
// Очищаем таблицу
|
||
m_tableModel->clear();
|
||
SpecificationPCBRowData emptyRow;
|
||
emptyRow.isEmpty = true;
|
||
m_tableModel->addRow(emptyRow);
|
||
SpecificationPCBRowData headerRow;
|
||
headerRow.isHeader = true;
|
||
headerRow.format = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow.zone = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow.position = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow.designation = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow.name = SpecificationPCBCellData("Документация", 0, 1, true, false, false, 100, true);
|
||
headerRow.quantity = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow.note = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
|
||
|
||
m_tableModel->addRow(headerRow);
|
||
|
||
m_tableModel->addRow(emptyRow);
|
||
|
||
SpecificationPCBRowData defaultRow1;
|
||
defaultRow1.isHeader = false;
|
||
defaultRow1.format = SpecificationPCBCellData("A1", 0, 1, false, false, false, 100, false);
|
||
defaultRow1.zone = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow1.position = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow1.designation = SpecificationPCBCellData(getDecimalNumberBoard()+" СБ", 0, 1, false, false, false, 100, false);
|
||
defaultRow1.name = SpecificationPCBCellData("Сборочный чертеж", 0, 1, false, false, false, 100, false);
|
||
defaultRow1.quantity = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow1.note = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
m_tableModel->addRow(defaultRow1);
|
||
|
||
SpecificationPCBRowData defaultRow2;
|
||
defaultRow2.isHeader = false;
|
||
defaultRow2.format = SpecificationPCBCellData("A3", 0, 1, false, false, false, 100, false);
|
||
defaultRow2.zone = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow2.position = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow2.designation = SpecificationPCBCellData(getDecimalNumberBoard()+" Э3", 0, 1, false, false, false, 100, false);
|
||
defaultRow2.name = SpecificationPCBCellData("Схема электрическая принципиальная", 0, 1, false, false, false, 100, false);
|
||
m_tableModel->addRow(defaultRow2);
|
||
|
||
SpecificationPCBRowData defaultRow3;
|
||
defaultRow3.isHeader = false;
|
||
defaultRow3.format = SpecificationPCBCellData("A4", 0, 1, false, false, false, 100, false);
|
||
defaultRow3.zone = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow3.position = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow3.designation = SpecificationPCBCellData(getDecimalNumberBoard()+" ПЭ3", 0, 1, false, false, false, 100, false);
|
||
defaultRow3.name = SpecificationPCBCellData("Перечень элементов", 0, 1, false, false, false, 100, false);
|
||
defaultRow3.quantity = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow3.note = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
m_tableModel->addRow(defaultRow3);
|
||
|
||
SpecificationPCBRowData defaultRow4;
|
||
defaultRow4.isHeader = false;
|
||
defaultRow4.format = SpecificationPCBCellData("A3", 0, 1, false, false, false, 100, false);
|
||
defaultRow4.zone = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow4.position = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow4.designation = SpecificationPCBCellData(getDecimalNumberBoard()+" ВП", 0, 1, false, false, false, 100, false);
|
||
defaultRow4.name = SpecificationPCBCellData("Ведомость покупных изделий", 0, 1, false, false, false, 100, false);
|
||
defaultRow4.quantity = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
defaultRow4.note = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
m_tableModel->addRow(defaultRow4);
|
||
|
||
SpecificationPCBRowData defaultRow5;
|
||
defaultRow5.isHeader = false;
|
||
defaultRow5.format = SpecificationPCBCellData("*)", 0, 1, false);
|
||
defaultRow5.zone = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5.position = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5.designation = SpecificationPCBCellData(getDecimalNumberBoard()+" Д33", 0, 1, false);
|
||
defaultRow5.name = SpecificationPCBCellData("Данные результатов проектирования", 0, 1, false);
|
||
defaultRow5.quantity = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5.note = SpecificationPCBCellData("DVD диск", 0, 1, false);
|
||
m_tableModel->addRow(defaultRow5);
|
||
|
||
m_tableModel->addRow(emptyRow);
|
||
|
||
SpecificationPCBRowData defaultRow5_1;
|
||
defaultRow5_1.isHeader = false;
|
||
defaultRow5_1.format = SpecificationPCBCellData("А4", 0, 1, false);
|
||
defaultRow5_1.zone = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5_1.position = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5_1.designation = SpecificationPCBCellData(getDecimalNumberBoard()+" Д10-УЛ", 0, 1, false);
|
||
defaultRow5_1.name = SpecificationPCBCellData("Удостоверяющий лист", 0, 1, false);
|
||
defaultRow5_1.quantity = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5_1.note = SpecificationPCBCellData("Размножать", 0, 1, false);
|
||
m_tableModel->addRow(defaultRow5_1);
|
||
SpecificationPCBRowData defaultRow5_2;
|
||
defaultRow5_2.isHeader = false;
|
||
defaultRow5_2.format = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5_2.zone = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5_2.position = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5_2.designation = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5_2.name = SpecificationPCBCellData("Данные результатов проектирования", 0, 1, false);
|
||
defaultRow5_2.quantity = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow5_2.note = SpecificationPCBCellData("по указанию", 0, 1, false);
|
||
m_tableModel->addRow(defaultRow5_2);
|
||
m_tableModel->addRow(emptyRow);
|
||
SpecificationPCBRowData headerRow2_4;
|
||
headerRow2_4.isHeader = true;
|
||
headerRow2_4.format = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_4.zone = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_4.position = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_4.designation = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_4.name = SpecificationPCBCellData("Сборочные единицы", 0, 1, true, false, false, 100, true);
|
||
headerRow2_4.quantity = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_4.note = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
m_tableModel->addRow(headerRow2_4);
|
||
|
||
|
||
|
||
m_tableModel->addRow(emptyRow);
|
||
|
||
SpecificationPCBRowData pcbInfo;
|
||
pcbInfo.isHeader = false;
|
||
pcbInfo.format = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
pcbInfo.zone = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
pcbInfo.position = SpecificationPCBCellData("1", 0, 1, false, false, false, 100, false);
|
||
pcbInfo.designation = SpecificationPCBCellData(getDecimalNumberBoard()+" платы", 0, 1, false, false, false, 100, false);
|
||
pcbInfo.name = SpecificationPCBCellData(getBoardName(), 0, 1, false, false, false, 100, false);
|
||
pcbInfo.quantity = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
pcbInfo.note = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
m_tableModel->addRow(pcbInfo);
|
||
|
||
m_tableModel->addRow(emptyRow);
|
||
|
||
SpecificationPCBRowData headerRow2_1;
|
||
headerRow2_1.isHeader = true;
|
||
headerRow2_1.format = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_1.zone = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_1.position = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_1.designation = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_1.name = SpecificationPCBCellData("Стандартные изделия", 0, 1, true, false, false, 100, true);
|
||
headerRow2_1.quantity = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2_1.note = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
m_tableModel->addRow(headerRow2_1);
|
||
m_tableModel->addRow(emptyRow);
|
||
SpecificationPCBRowData headerRow2;
|
||
headerRow2.isHeader = true;
|
||
headerRow2.format = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2.zone = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2.position = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2.designation = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2.name = SpecificationPCBCellData("Детали", 0, 1, true, false, false, 100, true);
|
||
headerRow2.quantity = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow2.note = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
m_tableModel->addRow(headerRow2);
|
||
|
||
SpecificationPCBRowData headerRow3;
|
||
headerRow3.isHeader = true;
|
||
headerRow3.format = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow3.zone = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow3.position = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow3.designation = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow3.name = SpecificationPCBCellData("Прочие изделия", 0, 1, true, false, false, 100, true);
|
||
|
||
int pos1 = 2;
|
||
|
||
m_tableModel->addRow(headerRow3);
|
||
|
||
m_tableModel->addRow(emptyRow);
|
||
|
||
|
||
|
||
if (m_components.isEmpty()) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Сортируем компоненты по десигнатору
|
||
std::sort(m_components.begin(), m_components.end(),
|
||
[this](ComponentModel* a, ComponentModel* b) {
|
||
if (!a || !b) return false;
|
||
|
||
QString designatorA = a->designator();
|
||
QString designatorB = b->designator();
|
||
|
||
// Разделяем десигнаторы на буквенную и числовую части
|
||
QPair<QString, QString> partsA = SpecificationPCBController::splitDesignator(designatorA);
|
||
QPair<QString, QString> partsB = SpecificationPCBController::splitDesignator(designatorB);
|
||
|
||
QString letterA = partsA.first;
|
||
QString letterB = partsB.first;
|
||
QString numberA = partsA.second;
|
||
QString numberB = partsB.second;
|
||
|
||
// Сначала сравниваем буквенные части
|
||
if (letterA != letterB) {
|
||
return letterA < letterB;
|
||
}
|
||
|
||
// Если буквенные части одинаковые, сравниваем числовые части
|
||
bool okA, okB;
|
||
int numA = numberA.toInt(&okA);
|
||
int numB = numberB.toInt(&okB);
|
||
|
||
if (okA && okB) {
|
||
return numA < numB;
|
||
}
|
||
|
||
// Fallback: если не удалось преобразовать в числа, используем строковое сравнение
|
||
return numberA < numberB;
|
||
});
|
||
|
||
// Группируем компоненты по буквенной части десигнатора
|
||
QMap<QString, QList<ComponentModel*>> groupedByLetter;
|
||
for (ComponentModel *component : m_components) {
|
||
QPair<QString, QString> designatorParts = splitDesignator(component->designator());
|
||
QString desLetter = designatorParts.first;
|
||
groupedByLetter[desLetter].append(component);
|
||
}
|
||
|
||
// Обрабатываем каждую группу
|
||
for (auto it = groupedByLetter.begin(); it != groupedByLetter.end(); ++it) {
|
||
QString desLetter = it.key();
|
||
QList<ComponentModel*> componentsInGroup = it.value();
|
||
|
||
if (componentsInGroup.size() > 1) {
|
||
// Если компонентов больше одного, добавляем заголовок типа
|
||
SpecificationPCBRowData headerRow;
|
||
headerRow.isHeader = true;
|
||
headerRow.format = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow.zone = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow.position = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow.designation = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
// Заголовок с componentType не должен подчеркиваться
|
||
headerRow.name = SpecificationPCBCellData(getComponentType(componentsInGroup.first()), 0, 1, true, false, false, 100, false);
|
||
headerRow.quantity = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
headerRow.note = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true);
|
||
m_tableModel->addEmptyRow();
|
||
m_tableModel->addRow(headerRow);
|
||
m_tableModel->addEmptyRow();
|
||
// Сначала группируем компоненты по наименованию
|
||
QList<QPair<QString, QList<ComponentModel*>>> groupedByName;
|
||
for (ComponentModel *component : componentsInGroup) {
|
||
QString componentName = getComponentValue(component, "ManufacturerPartNumber");
|
||
|
||
// Ищем существующую группу
|
||
bool found = false;
|
||
for (auto &group : groupedByName) {
|
||
if (group.first == componentName) {
|
||
group.second.append(component);
|
||
found = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Если группа не найдена, создаем новую
|
||
if (!found) {
|
||
QList<ComponentModel*> newGroup;
|
||
newGroup.append(component);
|
||
groupedByName.append(qMakePair(componentName, newGroup));
|
||
}
|
||
}
|
||
|
||
// Теперь создаем строки для каждой группы по наименованию
|
||
for (const auto &nameGroup : groupedByName) {
|
||
QString componentName = nameGroup.first;
|
||
QList<ComponentModel*> componentsWithSameName = nameGroup.second;
|
||
|
||
// Подсчитываем общее количество компонентов
|
||
int totalQuantity = componentsWithSameName.size();
|
||
|
||
// Создаем строку для этой группы компонентов
|
||
ComponentModel *firstComponent = componentsWithSameName.first();
|
||
QMap<QString, QString> props = firstComponent->properties();
|
||
QString originalString = props.value("ManufacturerPartNumber", "");
|
||
QList<QString> designationParts = splitLongDesignation(componentName, originalString, firstComponent);
|
||
|
||
// Группируем десигнаторы только для компонентов с этим наименованием
|
||
// Сначала сортируем компоненты по десигнатору (численно)
|
||
std::sort(componentsWithSameName.begin(), componentsWithSameName.end(),
|
||
[this](ComponentModel* a, ComponentModel* b) {
|
||
if (!a || !b) return false;
|
||
|
||
QString designatorA = a->designator();
|
||
QString designatorB = b->designator();
|
||
|
||
// Разделяем десигнаторы на буквенную и числовую части
|
||
QPair<QString, QString> partsA = splitDesignator(designatorA);
|
||
QPair<QString, QString> partsB = splitDesignator(designatorB);
|
||
|
||
QString letterA = partsA.first;
|
||
QString letterB = partsB.first;
|
||
QString numberA = partsA.second;
|
||
QString numberB = partsB.second;
|
||
|
||
// Сначала сравниваем буквенные части
|
||
if (letterA != letterB) {
|
||
return letterA < letterB;
|
||
}
|
||
|
||
// Если буквенные части одинаковые, сравниваем числовые части
|
||
bool okA, okB;
|
||
int numA = numberA.toInt(&okA);
|
||
int numB = numberB.toInt(&okB);
|
||
|
||
if (okA && okB) {
|
||
return numA < numB;
|
||
}
|
||
|
||
// Fallback: если не удалось преобразовать в числа, используем строковое сравнение
|
||
return numberA < numberB;
|
||
});
|
||
|
||
QList<QString> designatorGroupsForThisName;
|
||
QString currentGroup = componentsWithSameName.first()->designator();
|
||
QString lastDesignator = currentGroup;
|
||
int groupCount = 1; // Счетчик элементов в текущей группе
|
||
|
||
for (int i = 1; i < componentsWithSameName.size(); ++i) {
|
||
QString currentDesignator = componentsWithSameName[i]->designator();
|
||
QPair<QString, QString> currentParts = splitDesignator(currentDesignator);
|
||
QPair<QString, QString> lastParts = splitDesignator(lastDesignator);
|
||
|
||
// Проверяем, является ли текущий десигнатор следующим по порядку
|
||
if (currentParts.first == lastParts.first) {
|
||
bool ok1, ok2;
|
||
int currentNum = currentParts.second.toInt(&ok1);
|
||
int lastNum = lastParts.second.toInt(&ok2);
|
||
|
||
if (ok1 && ok2 && currentNum == lastNum + 1) {
|
||
// Продолжаем группу
|
||
lastDesignator = currentDesignator;
|
||
groupCount++;
|
||
} else {
|
||
// Завершаем текущую группу и начинаем новую
|
||
if (currentGroup == lastDesignator) {
|
||
designatorGroupsForThisName.append(currentGroup);
|
||
} else {
|
||
// Если в группе 2 элемента - через запятую, иначе через дефис
|
||
if (groupCount == 2) {
|
||
designatorGroupsForThisName.append(currentGroup + ", " + lastDesignator);
|
||
} else {
|
||
designatorGroupsForThisName.append(currentGroup + "-" + lastDesignator);
|
||
}
|
||
}
|
||
currentGroup = currentDesignator;
|
||
lastDesignator = currentDesignator;
|
||
groupCount = 1;
|
||
}
|
||
} else {
|
||
// Завершаем текущую группу и начинаем новую
|
||
if (currentGroup == lastDesignator) {
|
||
designatorGroupsForThisName.append(currentGroup);
|
||
} else {
|
||
// Если в группе 2 элемента - через запятую, иначе через дефис
|
||
if (groupCount == 2) {
|
||
designatorGroupsForThisName.append(currentGroup + ", " + lastDesignator);
|
||
} else {
|
||
designatorGroupsForThisName.append(currentGroup + "-" + lastDesignator);
|
||
}
|
||
}
|
||
currentGroup = currentDesignator;
|
||
lastDesignator = currentDesignator;
|
||
groupCount = 1;
|
||
}
|
||
}
|
||
|
||
// Добавляем последнюю группу
|
||
if (currentGroup == lastDesignator) {
|
||
designatorGroupsForThisName.append(currentGroup);
|
||
} else {
|
||
// Если в группе 2 элемента - через запятую, иначе через дефис
|
||
if (groupCount == 2) {
|
||
designatorGroupsForThisName.append(currentGroup + ", " + lastDesignator);
|
||
} else {
|
||
designatorGroupsForThisName.append(currentGroup + "-" + lastDesignator);
|
||
}
|
||
}
|
||
|
||
// Разбиваем длинные группы десигнаторов (11 символов на строку)
|
||
QStringList designatorsSplit = splitDesignatorGroups(designatorGroupsForThisName, 11);
|
||
|
||
// Определяем максимальное количество строк для названия и десигнаторов
|
||
int maxRows = qMax(designationParts.size(), designatorsSplit.size());
|
||
|
||
for (int rowIndex = 0; rowIndex < maxRows; ++rowIndex) {
|
||
SpecificationPCBRowData row;
|
||
|
||
// Только в первой строке показываем позицию и количество
|
||
if (rowIndex == 0) {
|
||
row.position = SpecificationPCBCellData(QString::number(pos1++), 0, 1, false, false, false, 100, false);
|
||
row.quantity = SpecificationPCBCellData(QString::number(totalQuantity), 0, 1, false, false, false, 100, false);
|
||
} else {
|
||
// В последующих строках оставляем пустыми позицию и количество
|
||
row.position = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
row.quantity = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
}
|
||
|
||
// Заполняем название (если есть)
|
||
if (rowIndex < designationParts.size()) {
|
||
row.name = SpecificationPCBCellData(designationParts[rowIndex], 0, 1, false, false, false, 100, false);
|
||
} else {
|
||
row.name = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
}
|
||
|
||
// Заполняем десигнаторы (если есть)
|
||
if (rowIndex < designatorsSplit.size()) {
|
||
row.note = SpecificationPCBCellData(designatorsSplit[rowIndex], 0, 1, false, false, false, 100, false);
|
||
} else {
|
||
row.note = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
}
|
||
|
||
// Заполняем остальные поля согласно требованиям
|
||
row.format = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
row.zone = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
row.designation = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
|
||
m_tableModel->addRow(row);
|
||
}
|
||
}
|
||
} else {
|
||
// Если компонент один, добавляем его как отдельную строку
|
||
ComponentModel *component = componentsInGroup.first();
|
||
QString currentDesignation = getComponentValue(component, "ManufacturerPartNumber");
|
||
|
||
// Разделяем длинное наименование на несколько строк
|
||
QMap<QString, QString> props = component->properties();
|
||
QString originalString = props.value("ManufacturerPartNumber", "");
|
||
QList<QString> designationParts = splitLongDesignation(currentDesignation, originalString, component);
|
||
|
||
for (int partIndex = 0; partIndex < designationParts.size(); ++partIndex) {
|
||
SpecificationPCBRowData row;
|
||
|
||
// Только в первой строке показываем позицию и количество
|
||
if (partIndex == 0) {
|
||
row.position = SpecificationPCBCellData(QString::number(pos1++), 0, 1, false, false, false, 100, false);
|
||
row.quantity = SpecificationPCBCellData("1", 0, 1, false, false, false, 100, false);
|
||
row.note = SpecificationPCBCellData(component->designator(), 0, 1, false, false, false, 100, false);
|
||
} else {
|
||
// В последующих строках оставляем пустыми позицию и количество
|
||
row.position = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
row.quantity = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
row.note = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
}
|
||
|
||
// Заполняем остальные поля согласно требованиям
|
||
row.format = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
row.zone = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
row.designation = SpecificationPCBCellData("", 0, 1, false, false, false, 100, false);
|
||
row.name = SpecificationPCBCellData(designationParts[partIndex], 0, 1, false, false, false, 100, false);
|
||
|
||
m_tableModel->addRow(row);
|
||
}
|
||
}
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::generateTableFromComponents: Таблица сгенерирована, строк:" << m_tableModel->rowCount();
|
||
qDebug() << "SpecificationPCBController::generateTableFromComponents: Модель доступна:" << (m_tableModel ? "да" : "нет");
|
||
qDebug() << "SpecificationPCBController::generateTableFromComponents: Количество строк в модели:" << m_tableModel->rowCount();
|
||
qDebug() << "SpecificationPCBController::generateTableFromComponents: Количество колонок в модели:" << m_tableModel->columnCount();
|
||
|
||
// Оптимизируем разрывы страниц после генерации таблицы
|
||
m_tableModel->optimizePageBreaks();
|
||
|
||
} catch (const std::exception &e) {
|
||
qDebug() << "SpecificationPCBController::generateTableFromComponents: Ошибка при генерации:" << e.what();
|
||
} catch (...) {
|
||
qDebug() << "SpecificationPCBController::generateTableFromComponents: Неизвестная ошибка при генерации";
|
||
}
|
||
m_tableModel->addRow(emptyRow);
|
||
SpecificationPCBRowData defaultRow6;
|
||
defaultRow6.isHeader = false;
|
||
defaultRow6.format = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6.zone = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6.position = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6.designation = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6.name = SpecificationPCBCellData("Примечание", 0, 1, false);
|
||
defaultRow6.quantity = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6.note = SpecificationPCBCellData("", 0, 1, false);
|
||
m_tableModel->addRow(defaultRow6);
|
||
SpecificationPCBRowData defaultRow6_1;
|
||
defaultRow6_1.isHeader = false;
|
||
defaultRow6_1.format = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_1.zone = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_1.position = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_1.designation = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_1.name = SpecificationPCBCellData("Изготовить плату печатную", 0, 1, false);
|
||
defaultRow6_1.quantity = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_1.note = SpecificationPCBCellData("", 0, 1, false);
|
||
m_tableModel->addRow(defaultRow6_1);
|
||
SpecificationPCBRowData defaultRow6_2;
|
||
defaultRow6_2.isHeader = false;
|
||
defaultRow6_2.format = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_2.zone = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_2.position = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_2.designation = SpecificationPCBCellData("", 0, 1, false);
|
||
// Формируем строку "По файлу" с именем PcbDoc файла, если оно есть
|
||
QString fileText = "По файлу";
|
||
if (!m_pcbDocFileName.isEmpty()) {
|
||
QFileInfo fileInfo(m_pcbDocFileName);
|
||
fileText = "По файлу " + fileInfo.fileName();
|
||
}
|
||
defaultRow6_2.name = SpecificationPCBCellData(fileText, 0, 1, false);
|
||
defaultRow6_2.quantity = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_2.note = SpecificationPCBCellData("", 0, 1, false);
|
||
m_tableModel->addRow(defaultRow6_2);
|
||
SpecificationPCBRowData defaultRow6_3;
|
||
defaultRow6_3.isHeader = false;
|
||
defaultRow6_3.format = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_3.zone = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_3.position = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_3.designation = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_3.name = SpecificationPCBCellData("из состава"+getDecimalNumberBoard()+" Д10", 0, 1, false);
|
||
defaultRow6_3.quantity = SpecificationPCBCellData("", 0, 1, false);
|
||
defaultRow6_3.note = SpecificationPCBCellData("", 0, 1, false);
|
||
m_tableModel->addRow(defaultRow6_3);
|
||
}
|
||
|
||
void SpecificationPCBController::updateTableFromComponents()
|
||
{
|
||
if (!m_tableModel) {
|
||
qDebug() << "SpecificationPCBController::updateTableFromComponents: m_tableModel is null";
|
||
return;
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::updateTableFromComponents: Обновляем таблицу из" << m_components.size() << "компонентов";
|
||
|
||
if (m_components.isEmpty()) {
|
||
qDebug() << "SpecificationPCBController::updateTableFromComponents: Нет компонентов для обновления";
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Метод updateTableFromComponents больше не используется в новой логике
|
||
qDebug() << "SpecificationPCBController::updateTableFromComponents: Метод устарел";
|
||
} catch (const std::exception &e) {
|
||
qDebug() << "SpecificationPCBController::updateTableFromComponents: Ошибка при обновлении:" << e.what();
|
||
} catch (...) {
|
||
qDebug() << "SpecificationPCBController::updateTableFromComponents: Неизвестная ошибка при обновлении";
|
||
}
|
||
}
|
||
|
||
QString SpecificationPCBController::getComponentValue(ComponentModel *component, const QString &propertyName)
|
||
{
|
||
if (!component) {
|
||
return "";
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::getComponentValue: propertyName =" << propertyName;
|
||
|
||
// Получаем значение свойства компонента
|
||
QString value;
|
||
if (propertyName == "Designator") {
|
||
value = component->designator();
|
||
qDebug() << "SpecificationPCBController::getComponentValue: Designator =" << value;
|
||
} else {
|
||
QMap<QString, QString> props = component->properties();
|
||
value = props.value(propertyName, "");
|
||
qDebug() << "SpecificationPCBController::getComponentValue: Свойство" << propertyName << "=" << value;
|
||
}
|
||
|
||
// Проверяем, является ли значение свойства выражением
|
||
if (value.startsWith("=")) {
|
||
qDebug() << "SpecificationPCBController::getComponentValue: Значение свойства является выражением:" << value;
|
||
return parseExpression(component, value);
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
QString SpecificationPCBController::parseExpression(ComponentModel *component, const QString &expression)
|
||
{
|
||
if (!component) {
|
||
return "";
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::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() << "SpecificationPCBController::parseExpression: Части выражения:" << parts;
|
||
|
||
for (const QString &part : parts) {
|
||
QString trimmedPart = part.trimmed();
|
||
qDebug() << "SpecificationPCBController::parseExpression: Обрабатываем часть:" << trimmedPart;
|
||
|
||
// Если это не пустая строка, добавляем к результату
|
||
if (!trimmedPart.isEmpty()) {
|
||
QString value;
|
||
|
||
// Проверяем, является ли это литералом в одинарных кавычках
|
||
if (trimmedPart.startsWith("'") && trimmedPart.endsWith("'")) {
|
||
// Это литерал - убираем кавычки и используем как есть
|
||
value = trimmedPart.mid(1, trimmedPart.length() - 2);
|
||
qDebug() << "SpecificationPCBController::parseExpression: Найден литерал в одинарных кавычках:" << value;
|
||
}
|
||
// Проверяем, является ли это именем свойства компонента в двойных кавычках
|
||
else if (trimmedPart.startsWith("\"") && trimmedPart.endsWith("\"")) {
|
||
// Это свойство компонента - убираем кавычки и ищем в свойствах
|
||
QString propertyName = trimmedPart.mid(1, trimmedPart.length() - 2);
|
||
qDebug() << "SpecificationPCBController::parseExpression: Ищем свойство компонента:" << propertyName;
|
||
|
||
if (propertyName == "Designator") {
|
||
value = component->designator();
|
||
qDebug() << "SpecificationPCBController::parseExpression: Найдено свойство Designator =" << value;
|
||
} else {
|
||
// Ищем в свойствах компонента
|
||
QMap<QString, QString> props = component->properties();
|
||
value = props.value(propertyName, "");
|
||
qDebug() << "SpecificationPCBController::parseExpression: Ищем свойство" << propertyName << "в компоненте, результат:" << value;
|
||
// Рекурсивно обрабатываем вложенные выражения
|
||
if (value.startsWith("=")) {
|
||
qDebug() << "SpecificationPCBController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
|
||
value = parseExpression(component, value);
|
||
}
|
||
}
|
||
}
|
||
// Проверяем, является ли это именем свойства компонента без кавычек
|
||
else if (trimmedPart == "Designator") {
|
||
value = component->designator();
|
||
qDebug() << "SpecificationPCBController::parseExpression: Найдено свойство Designator =" << value;
|
||
} else {
|
||
// Ищем в свойствах компонента
|
||
QMap<QString, QString> props = component->properties();
|
||
value = props.value(trimmedPart, "");
|
||
qDebug() << "SpecificationPCBController::parseExpression: Ищем свойство" << trimmedPart << "в компоненте, результат:" << value;
|
||
// Рекурсивно обрабатываем вложенные выражения
|
||
if (value.startsWith("=")) {
|
||
qDebug() << "SpecificationPCBController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
|
||
value = parseExpression(component, value);
|
||
}
|
||
}
|
||
|
||
// Добавляем значение к результату
|
||
if (!value.isEmpty()) {
|
||
if (!result.isEmpty()) {
|
||
result += value;
|
||
} else {
|
||
result = value;
|
||
}
|
||
qDebug() << "SpecificationPCBController::parseExpression: Добавили к результату, текущий результат:" << result;
|
||
}
|
||
}
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::parseExpression: Финальный результат:" << result;
|
||
return result;
|
||
}
|
||
|
||
QStringList SpecificationPCBController::collectPropertyNames()
|
||
{
|
||
QStringList propertyNames;
|
||
|
||
// Добавляем основные свойства компонента
|
||
propertyNames << "Designator" << "Format" << "Zone" << "Position";
|
||
|
||
// Собираем дополнительные свойства из компонентов
|
||
for (ComponentModel *component : m_components) {
|
||
QMap<QString, QString> props = component->properties();
|
||
for (auto it = props.begin(); it != props.end(); ++it) {
|
||
if (!propertyNames.contains(it.key())) {
|
||
propertyNames.append(it.key());
|
||
}
|
||
}
|
||
}
|
||
|
||
// Если дополнительные свойства не найдены в компонентах, добавляем стандартные
|
||
if (propertyNames.size() <= 4) { // Только базовые свойства
|
||
propertyNames << "Name" << "Type" << "Value" << "Footprint" << "Description";
|
||
qDebug() << "SpecificationPCBController: Дополнительные свойства не найдены, используем стандартные:" << propertyNames;
|
||
}
|
||
|
||
// Добавляем специальное свойство для количества компонентов в группе
|
||
propertyNames << "Quantity" << "Кол.";
|
||
|
||
return propertyNames;
|
||
}
|
||
|
||
// Методы для работы с децимальными номерами
|
||
QString SpecificationPCBController::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 SpecificationPCBController::setDecimalNumberBoard(const QString &value)
|
||
{
|
||
QStringList mappings = getColumnMappings();
|
||
while (mappings.size() <= 7) {
|
||
mappings.append("");
|
||
}
|
||
mappings[7] = value;
|
||
setColumnMappings(mappings);
|
||
}
|
||
|
||
QString SpecificationPCBController::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 SpecificationPCBController::setDecimalNumberDocument(const QString &value)
|
||
{
|
||
QStringList mappings = getColumnMappings();
|
||
while (mappings.size() <= 8) {
|
||
mappings.append("");
|
||
}
|
||
mappings[8] = value;
|
||
setColumnMappings(mappings);
|
||
}
|
||
|
||
// Методы для работы с названием платы
|
||
QString SpecificationPCBController::getBoardName() const
|
||
{
|
||
QStringList mappings = getColumnMappings();
|
||
if (mappings.size() > 6) {
|
||
QString fieldName = mappings[6];
|
||
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 SpecificationPCBController::setBoardName(const QString &value)
|
||
{
|
||
QStringList mappings = getColumnMappings();
|
||
while (mappings.size() <= 6) {
|
||
mappings.append("");
|
||
}
|
||
mappings[6] = value;
|
||
setColumnMappings(mappings);
|
||
}
|
||
|
||
void SpecificationPCBController::setPcbDocFileName(const QString &fileName)
|
||
{
|
||
m_pcbDocFileName = fileName;
|
||
qDebug() << "SpecificationPCBController::setPcbDocFileName: Установлено имя файла:" << fileName;
|
||
}
|
||
|
||
QString SpecificationPCBController::getPcbDocFileName() const
|
||
{
|
||
return m_pcbDocFileName;
|
||
}
|
||
|
||
void SpecificationPCBController::setColumnMappings(const QStringList &mappings)
|
||
{
|
||
qDebug() << "SpecificationPCBController::setColumnMappings: Устанавливаем новые настройки колонок:" << mappings;
|
||
m_columnMappings = mappings;
|
||
|
||
// Сохраняем настройки в ProjectSettingsModel
|
||
if (m_projectSettingsModel) {
|
||
for (int i = 0; i < mappings.size(); ++i) {
|
||
m_projectSettingsModel->setColumnMapping("SpecificationPCB", i, mappings[i]);
|
||
}
|
||
qDebug() << "SpecificationPCBController::setColumnMappings: Настройки сохранены в ProjectSettingsModel";
|
||
}
|
||
|
||
// Обновляем настройки в модели
|
||
if (m_tableModel) {
|
||
m_tableModel->setColumnMappings(mappings);
|
||
qDebug() << "SpecificationPCBController::setColumnMappings: Настройки обновлены в модели";
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::setColumnMappings: Настройки колонок обновлены:" << m_columnMappings;
|
||
}
|
||
|
||
QStringList SpecificationPCBController::getColumnMappings() const
|
||
{
|
||
// Если есть ProjectSettingsModel, читаем настройки из него
|
||
if (m_projectSettingsModel) {
|
||
QStringList settings = m_projectSettingsModel->getColumnMappings("SpecificationPCB");
|
||
if (!settings.isEmpty()) {
|
||
qDebug() << "SpecificationPCBController::getColumnMappings: Получены настройки из ProjectSettingsModel:" << settings;
|
||
return settings;
|
||
}
|
||
}
|
||
|
||
// Fallback: возвращаем локальные настройки
|
||
qDebug() << "SpecificationPCBController::getColumnMappings: Возвращаем локальные настройки:" << m_columnMappings;
|
||
return m_columnMappings;
|
||
}
|
||
|
||
QStringList SpecificationPCBController::getAvailableProperties() const
|
||
{
|
||
QStringList properties = m_propertyNames;
|
||
properties.prepend("<Пусто>");
|
||
properties.prepend("<Авто>");
|
||
return properties;
|
||
}
|
||
|
||
QString SpecificationPCBController::getComponentType(ComponentModel *component)
|
||
{
|
||
if (!component) return "";
|
||
|
||
// Получаем тип компонента из маппинга дезигнаторов
|
||
if (m_designatorMappingModel) {
|
||
QString componentType = m_designatorMappingModel->getComponentType(component->designator(), true); // true для множественного числа
|
||
if (!componentType.isEmpty()) {
|
||
return componentType;
|
||
}
|
||
}
|
||
|
||
// Если маппинг не найден, используем тип из свойств компонента
|
||
QMap<QString, QString> props = component->properties();
|
||
QString type = props.value("Type", "");
|
||
if (!type.isEmpty()) {
|
||
return type;
|
||
}
|
||
|
||
// Если и тип не найден, используем designator как fallback
|
||
return component->designator();
|
||
}
|
||
|
||
QString SpecificationPCBController::getComponentFormat(ComponentModel *component)
|
||
{
|
||
if (!component) return "";
|
||
|
||
// Получаем формат из свойств компонента
|
||
QMap<QString, QString> props = component->properties();
|
||
QString format = props.value("Format", "");
|
||
if (!format.isEmpty()) {
|
||
return format;
|
||
}
|
||
|
||
// Если формат не найден, используем значение по умолчанию
|
||
return "A4";
|
||
}
|
||
|
||
QString SpecificationPCBController::getComponentZone(ComponentModel *component)
|
||
{
|
||
if (!component) return "";
|
||
|
||
// Получаем зону из свойств компонента
|
||
QMap<QString, QString> props = component->properties();
|
||
QString zone = props.value("Zone", "");
|
||
if (!zone.isEmpty()) {
|
||
return zone;
|
||
}
|
||
|
||
// Если зона не найдена, используем значение по умолчанию
|
||
return "1";
|
||
}
|
||
|
||
QString SpecificationPCBController::getComponentPosition(ComponentModel *component)
|
||
{
|
||
if (!component) return "";
|
||
|
||
// Для спецификации платы позиция обычно совпадает с дезигнатором
|
||
return component->designator();
|
||
}
|
||
|
||
QPair<QString, QString> SpecificationPCBController::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 SpecificationPCBController::addEmptyRow()
|
||
{
|
||
if (m_tableModel) {
|
||
m_tableModel->addEmptyRow();
|
||
qDebug() << "SpecificationPCBController::addEmptyRow: Добавлена пустая строка";
|
||
|
||
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
|
||
// m_tableModel->optimizePageBreaks();
|
||
}
|
||
}
|
||
|
||
void SpecificationPCBController::addEmptyRowAt(int position)
|
||
{
|
||
if (m_tableModel) {
|
||
m_tableModel->addEmptyRowAt(position);
|
||
qDebug() << "SpecificationPCBController::addEmptyRowAt: Добавлена пустая строка в позицию" << position;
|
||
|
||
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
|
||
// m_tableModel->optimizePageBreaks();
|
||
}
|
||
}
|
||
|
||
void SpecificationPCBController::insertEmptyRowAt(int position)
|
||
{
|
||
if (m_tableModel) {
|
||
m_tableModel->addEmptyRowAt(position);
|
||
qDebug() << "SpecificationPCBController::insertEmptyRowAt: Вставлена пустая строка в позицию" << position;
|
||
|
||
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
|
||
// m_tableModel->optimizePageBreaks();
|
||
}
|
||
}
|
||
|
||
void SpecificationPCBController::removeRow(int row)
|
||
{
|
||
if (m_tableModel) {
|
||
m_tableModel->removeRow(row);
|
||
qDebug() << "SpecificationPCBController::removeRow: Удалена строка" << row;
|
||
|
||
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
|
||
// m_tableModel->optimizePageBreaks();
|
||
}
|
||
}
|
||
|
||
void SpecificationPCBController::clearTable()
|
||
{
|
||
if (m_tableModel) {
|
||
m_tableModel->clear();
|
||
qDebug() << "SpecificationPCBController::clearTable: Таблица очищена";
|
||
}
|
||
}
|
||
|
||
void SpecificationPCBController::optimizePageBreaks()
|
||
{
|
||
if (m_tableModel) {
|
||
qDebug() << "SpecificationPCBController::optimizePageBreaks: Оптимизируем разрывы страниц";
|
||
m_tableModel->optimizePageBreaks();
|
||
// После оптимизации разрывов пересчитываем позиции
|
||
recalculatePositions();
|
||
}
|
||
}
|
||
|
||
void SpecificationPCBController::recalculatePositions()
|
||
{
|
||
if (!m_tableModel) {
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: m_tableModel is null, выходим";
|
||
return;
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Начинаем перерасчет позиций, строк в таблице:" << m_tableModel->rowCount();
|
||
|
||
const int POSITION_COLUMN = 2; // Индекс колонки "Поз."
|
||
int rowCount = m_tableModel->rowCount();
|
||
int currentPosition = 0;
|
||
int updatedCount = 0;
|
||
|
||
// Сначала собираем список строк, где позиция не пустая (пользователь ввел значение)
|
||
QList<int> rowsWithPosition;
|
||
|
||
for (int row = 0; row < rowCount; ++row) {
|
||
QModelIndex index = m_tableModel->index(row, POSITION_COLUMN);
|
||
if (!index.isValid()) {
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Строка" << row << "- невалидный индекс";
|
||
continue;
|
||
}
|
||
|
||
// Получаем значение позиции СНАЧАЛА, чтобы проверить, есть ли оно
|
||
QString positionValueRaw = m_tableModel->data(index, Qt::DisplayRole).toString();
|
||
QString positionValue = positionValueRaw.trimmed();
|
||
|
||
// Детальное логирование для диагностики
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Строка" << row
|
||
<< "- позиция (raw): '" << positionValueRaw << "'"
|
||
<< ", позиция (trimmed): '" << positionValue << "'"
|
||
<< ", isEmpty:" << positionValue.isEmpty();
|
||
|
||
// Если позиция пустая, пропускаем строку
|
||
if (positionValue.isEmpty()) {
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Строка" << row << "- позиция пустая, пропускаем";
|
||
continue;
|
||
}
|
||
|
||
// Проверяем, не является ли строка заголовком
|
||
QModelIndex firstColumnIndex = m_tableModel->index(row, 0);
|
||
QVariant headerVariant = m_tableModel->data(firstColumnIndex, Qt::UserRole);
|
||
bool isHeader = false;
|
||
|
||
if (headerVariant.isValid()) {
|
||
SpecificationPCBCellData cellData = headerVariant.value<SpecificationPCBCellData>();
|
||
isHeader = cellData.isHeader;
|
||
}
|
||
|
||
// Также проверяем через метод модели, если доступен
|
||
if (m_tableModel->isRowHeader(row)) {
|
||
isHeader = true;
|
||
}
|
||
|
||
// Пропускаем только заголовки (но не пустые строки, так как пользователь мог ввести позицию в пустую строку)
|
||
if (isHeader) {
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Строка" << row << "- заголовок, пропускаем (позиция:" << positionValue << ")";
|
||
continue;
|
||
}
|
||
|
||
// Если позиция не пустая и строка не заголовок, добавляем в список для пересчета
|
||
rowsWithPosition.append(row);
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Найдена строка" << row << "с позицией:" << positionValue << "(isHeader:" << isHeader << ")";
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Найдено строк с позициями:" << rowsWithPosition.size();
|
||
|
||
// Теперь пересчитываем позиции сквозно от 1 до n только для строк, где позиция была не пустая
|
||
// Всегда обновляем позиции, даже если они уже правильные, чтобы гарантировать последовательность
|
||
for (int row : rowsWithPosition) {
|
||
QModelIndex index = m_tableModel->index(row, POSITION_COLUMN);
|
||
if (!index.isValid()) {
|
||
continue;
|
||
}
|
||
|
||
// Получаем текущее значение позиции
|
||
QString positionValue = m_tableModel->data(index, Qt::DisplayRole).toString().trimmed();
|
||
|
||
// Увеличиваем счетчик позиции и устанавливаем новое значение
|
||
currentPosition++;
|
||
QString newPosition = QString::number(currentPosition);
|
||
|
||
// Всегда обновляем позицию, чтобы гарантировать последовательность
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Обновляем позицию в строке" << row
|
||
<< "с '" << positionValue << "' на '" << newPosition << "'";
|
||
bool success = m_tableModel->setData(index, newPosition, Qt::EditRole);
|
||
if (success) {
|
||
updatedCount++;
|
||
// Проверяем, что значение действительно обновилось
|
||
QString updatedValue = m_tableModel->data(index, Qt::DisplayRole).toString().trimmed();
|
||
if (updatedValue != newPosition) {
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: ВНИМАНИЕ! Позиция в строке" << row
|
||
<< "не обновилась! Ожидалось:" << newPosition << ", получено:" << updatedValue;
|
||
} else {
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Позиция в строке" << row
|
||
<< "успешно обновлена на" << newPosition;
|
||
}
|
||
} else {
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Ошибка при обновлении позиции в строке" << row
|
||
<< "- setData вернул false";
|
||
}
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::recalculatePositions: Перерасчет позиций завершен, обновлено строк:" << updatedCount << "из" << currentPosition;
|
||
}
|
||
|
||
int SpecificationPCBController::getFontSize() const
|
||
{
|
||
if (m_projectSettingsModel) {
|
||
return m_projectSettingsModel->getFontSize("SpecificationPCB");
|
||
}
|
||
return 12; // По умолчанию
|
||
}
|
||
|
||
void SpecificationPCBController::setFontSize(int fontSize)
|
||
{
|
||
if (m_projectSettingsModel) {
|
||
m_projectSettingsModel->setFontSize("SpecificationPCB", fontSize);
|
||
}
|
||
}
|
||
|
||
int SpecificationPCBController::getFontStretch() const
|
||
{
|
||
if (m_projectSettingsModel) {
|
||
return m_projectSettingsModel->getFontStretch("SpecificationPCB");
|
||
}
|
||
return 100; // По умолчанию (нормальный)
|
||
}
|
||
|
||
void SpecificationPCBController::setFontStretch(int stretch)
|
||
{
|
||
if (m_projectSettingsModel) {
|
||
m_projectSettingsModel->setFontStretch("SpecificationPCB", stretch);
|
||
}
|
||
}
|
||
|
||
QList<QString> SpecificationPCBController::splitLongDesignation(const QString &designation, const QString originalString, ComponentModel *component, int maxLength)
|
||
{
|
||
QList<QString> result;
|
||
|
||
if (designation.length() <= maxLength) {
|
||
result.append(designation);
|
||
return result;
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::splitLongDesignation: Разделяем длинное наименование:" << designation;
|
||
|
||
// Проверяем, является ли наименование выражением с частями
|
||
if (originalString.startsWith("=") && component) {
|
||
// Это выражение - разделяем по частям
|
||
QString expr = originalString.mid(1); // Убираем начальный "="
|
||
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() << "SpecificationPCBController::splitLongDesignation: Части выражения:" << parts;
|
||
|
||
// Сначала собираем все части в одну строку для комплексных строк
|
||
QString fullString;
|
||
|
||
for (int i = 0; i < parts.size(); ++i) {
|
||
QString trimmedPart = parts[i].trimmed();
|
||
if (!trimmedPart.isEmpty()) {
|
||
QString displayPart;
|
||
|
||
// Проверяем, является ли это литералом в одинарных кавычках
|
||
if (trimmedPart.startsWith("'") && trimmedPart.endsWith("'")) {
|
||
// Это литерал (запятая, пробел и т.д.)
|
||
displayPart = trimmedPart.mid(1, trimmedPart.length() - 2);
|
||
} else {
|
||
// Это имя свойства - получаем значение из компонента
|
||
QMap<QString, QString> props = component->properties();
|
||
qDebug() << "Обрабатываем свойство:" << trimmedPart;
|
||
|
||
if (trimmedPart == "Designator") {
|
||
displayPart = component->designator();
|
||
} else {
|
||
QString propertyName = trimmedPart.startsWith("\"") && trimmedPart.endsWith("\"")
|
||
? trimmedPart.mid(1, trimmedPart.length() - 2)
|
||
: trimmedPart;
|
||
displayPart = props.value(propertyName, "");
|
||
// Рекурсивно обрабатываем вложенные выражения
|
||
if (displayPart.startsWith("=")) {
|
||
qDebug() << "SpecificationPCBController::splitLongDesignation: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
|
||
displayPart = parseExpression(component, displayPart);
|
||
}
|
||
}
|
||
}
|
||
|
||
fullString += displayPart;
|
||
}
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::splitLongDesignation: Собранная полная строка:" << fullString << ", длина:" << fullString.length();
|
||
|
||
// Проверяем, содержит ли строка запятые (комплексная строка)
|
||
bool isComplexString = fullString.contains(',');
|
||
|
||
if (isComplexString && fullString.length() > maxLength) {
|
||
qDebug() << "SpecificationPCBController::splitLongDesignation: Комплексная строка с запятыми, делим по середине";
|
||
// Для комплексной строки делим по середине, а не по началу
|
||
result = splitComplexStringByMiddle(fullString, maxLength);
|
||
} else if (fullString.length() > maxLength) {
|
||
qDebug() << "SpecificationPCBController::splitLongDesignation: Строка длинная, разделяем по пробелам";
|
||
// Обычная длинная строка - разделяем по пробелам
|
||
result = splitBySpaces(fullString, maxLength);
|
||
} else {
|
||
qDebug() << "SpecificationPCBController::splitLongDesignation: Строка короткая, возвращаем как есть";
|
||
result.append(fullString);
|
||
}
|
||
} else {
|
||
// Обычный текст - разделяем по пробелам
|
||
result = splitBySpaces(designation, maxLength);
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::splitLongDesignation: Результат разделения:" << result;
|
||
return result;
|
||
}
|
||
|
||
QList<QString> SpecificationPCBController::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;
|
||
}
|
||
|
||
QList<QString> SpecificationPCBController::splitComplexStringByMiddle(const QString &text, int maxLength)
|
||
{
|
||
QList<QString> result;
|
||
|
||
if (text.length() <= maxLength) {
|
||
result.append(text);
|
||
return result;
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::splitComplexStringByMiddle: Разделяем комплексную строку:" << text;
|
||
|
||
// Ищем запятые в тексте
|
||
QList<int> commaPositions;
|
||
for (int i = 0; i < text.length(); ++i) {
|
||
if (text[i] == ',') {
|
||
commaPositions.append(i);
|
||
}
|
||
}
|
||
|
||
if (commaPositions.isEmpty()) {
|
||
// Если запятых нет, используем обычное разделение по пробелам
|
||
qDebug() << "SpecificationPCBController::splitComplexStringByMiddle: Запятых не найдено, используем splitBySpaces";
|
||
return splitBySpaces(text, maxLength);
|
||
}
|
||
|
||
// Ищем запятую, ближайшую к середине строки
|
||
int targetLength = maxLength;
|
||
int bestSplitPos = -1;
|
||
int minDifference = text.length();
|
||
|
||
for (int pos : commaPositions) {
|
||
int leftLength = pos + 1; // Включаем запятую в левую часть
|
||
int rightLength = text.length() - pos - 1;
|
||
|
||
// Вычисляем разницу с целевой длиной
|
||
int leftDiff = abs(leftLength - targetLength);
|
||
int rightDiff = abs(rightLength - targetLength);
|
||
int totalDiff = leftDiff + rightDiff;
|
||
|
||
// Если эта позиция лучше предыдущей, запоминаем её
|
||
if (totalDiff < minDifference) {
|
||
minDifference = totalDiff;
|
||
bestSplitPos = pos;
|
||
}
|
||
}
|
||
|
||
// Если нашли подходящую запятую, разделяем по ней
|
||
if (bestSplitPos != -1) {
|
||
QString leftPart = text.left(bestSplitPos + 1).trimmed(); // Включаем запятую
|
||
QString rightPart = text.mid(bestSplitPos + 1).trimmed();
|
||
|
||
qDebug() << "SpecificationPCBController::splitComplexStringByMiddle: Найдена запятая на позиции" << bestSplitPos;
|
||
qDebug() << "SpecificationPCBController::splitComplexStringByMiddle: Левая часть:" << leftPart;
|
||
qDebug() << "SpecificationPCBController::splitComplexStringByMiddle: Правая часть:" << rightPart;
|
||
|
||
// Рекурсивно обрабатываем обе части
|
||
if (!leftPart.isEmpty()) {
|
||
QList<QString> leftParts = splitComplexStringByMiddle(leftPart, maxLength);
|
||
result.append(leftParts);
|
||
}
|
||
|
||
if (!rightPart.isEmpty()) {
|
||
QList<QString> rightParts = splitComplexStringByMiddle(rightPart, maxLength);
|
||
result.append(rightParts);
|
||
}
|
||
} else {
|
||
// Если не удалось найти подходящую запятую, используем обычное разделение
|
||
qDebug() << "SpecificationPCBController::splitComplexStringByMiddle: Не удалось найти подходящую запятую, используем splitBySpaces";
|
||
result = splitBySpaces(text, maxLength);
|
||
}
|
||
|
||
qDebug() << "SpecificationPCBController::splitComplexStringByMiddle: Результат:" << result;
|
||
return result;
|
||
}
|
||
|
||
QStringList SpecificationPCBController::splitDesignatorGroups(const QStringList &designatorGroups, int maxLength)
|
||
{
|
||
QStringList result;
|
||
QString currentLine;
|
||
|
||
for (const QString &group : designatorGroups) {
|
||
QString testLine = currentLine.isEmpty() ? group : currentLine + ", " + group;
|
||
|
||
if (testLine.length() <= maxLength) {
|
||
currentLine = testLine;
|
||
} else {
|
||
if (!currentLine.isEmpty()) {
|
||
result.append(currentLine +",");
|
||
}
|
||
currentLine = group;
|
||
}
|
||
}
|
||
|
||
if (!currentLine.isEmpty()) {
|
||
result.append(currentLine);
|
||
}
|
||
|
||
// Теперь разбиваем каждую строку, если она длиннее maxLength
|
||
QStringList finalResult;
|
||
for (const QString &line : result) {
|
||
if (line.length() <= maxLength) {
|
||
finalResult.append(line);
|
||
} else {
|
||
// Разбиваем длинную строку посимвольно, но стараемся разбивать по запятым
|
||
QStringList parts = line.split(", ");
|
||
QString currentPart = "";
|
||
|
||
for (const QString &part : parts) {
|
||
QString testPart = currentPart.isEmpty() ? part : currentPart + ", " + part;
|
||
|
||
if (testPart.length() <= maxLength) {
|
||
currentPart = testPart;
|
||
} else {
|
||
if (!currentPart.isEmpty()) {
|
||
finalResult.append(currentPart);
|
||
}
|
||
currentPart = part;
|
||
}
|
||
}
|
||
|
||
if (!currentPart.isEmpty()) {
|
||
finalResult.append(currentPart);
|
||
}
|
||
}
|
||
}
|
||
|
||
return finalResult;
|
||
}
|