Files
GostGenerator/controller/vedomostcontroller.cpp
T

1486 lines
77 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "vedomostcontroller.h"
#include "../model/componentmodel.h"
#include "../model/projectparamtablemodel.h"
#include "../model/titleinscriptionsmodel.h"
#include "../controller/maincontroller.h"
#include <QDebug>
#include <QCollator>
VedomostController::VedomostController(QObject *parent)
: QObject(parent)
, m_tableModel(new VedomostTableModel(this))
, m_designatorMappingModel(nullptr)
, m_projectSettingsModel(nullptr)
, m_mainController(nullptr)
{
// Устанавливаем маппинг по умолчанию для ведомости покупных изделий
// Только поля, которые можно маппить на свойства компонентов
m_columnMappings << "Name" << "ProductCode" << "DocumentCode" << "Supplier"
<< "WhereUsed" << "Note";
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
// connect(m_tableModel, &VedomostTableModel::dataChanged,
// this, &VedomostController::onRowDataChanged);
}
VedomostController::~VedomostController()
{
// m_tableModel удалится автоматически, так как он является дочерним объектом
}
void VedomostController::setDesignatorMappingModel(DesignatorMappingModel *mappingModel)
{
m_designatorMappingModel = mappingModel;
}
void VedomostController::setModel(VedomostTableModel *model)
{
if (m_tableModel != model) {
qDebug() << "VedomostController::setModel: Заменяем модель таблицы";
m_tableModel = model;
// Если модель не пуста, загружаем из неё настройки колонок
if (m_tableModel) {
QStringList columnMappings = m_tableModel->columnMappings();
if (!columnMappings.isEmpty()) {
qDebug() << "VedomostController::setModel: Загружаем настройки колонок из модели:" << columnMappings;
m_columnMappings = columnMappings;
}
}
}
}
void VedomostController::setProjectSettingsModel(ProjectSettingsModel *model)
{
m_projectSettingsModel = model;
qDebug() << "VedomostController::setProjectSettingsModel: Установлена модель настроек проекта";
}
void VedomostController::setMainController(MainController *controller)
{
m_mainController = controller;
qDebug() << "VedomostController::setMainController: Установлен главный контроллер";
}
void VedomostController::setComponents(const QList<ComponentModel*> &components)
{
qDebug() << "VedomostController::setComponents: Устанавливаем" << components.size() << "компонентов";
m_components = components;
// Собираем доступные свойства из компонентов
m_propertyNames = collectPropertyNames();
qDebug() << "VedomostController::setComponents: Собрано свойств:" << m_propertyNames.size();
qDebug() << "VedomostController::setComponents: Свойства:" << m_propertyNames;
}
void VedomostController::generateTableFromComponents()
{
if (!m_tableModel) {
return;
}
qDebug() << "VedomostController::generateTableFromComponents: Начинаем генерацию таблицы";
qDebug() << "VedomostController::generateTableFromComponents: Текущие настройки колонок:" << m_columnMappings;
qDebug() << "VedomostController::generateTableFromComponents: Количество компонентов:" << m_components.size();
// Очищаем таблицу
m_tableModel->clear();
// Добавляем заголовок таблицы
// VedomostRowData headerRow;
// headerRow.isHeader = true;
// headerRow.name = VedomostCellData("Наименование", 0, 1, true);
// headerRow.productCode = VedomostCellData("Код продукции", 0, 1, true);
// headerRow.documentCode = VedomostCellData("Обозначение документа на поставку", 0, 1, true);
// headerRow.supplier = VedomostCellData("Поставщик", 0, 1, true);
// headerRow.whereUsed = VedomostCellData("Куда входит (обозначение)", 0, 1, true);
// headerRow.quantityPerItem = VedomostCellData("Количество на изделие", 0, 1, true);
// headerRow.quantityInSet = VedomostCellData("Количество в комплекте", 0, 1, true);
// headerRow.quantityForReg = VedomostCellData("Количество на регулир", 0, 1, true);
// headerRow.totalQuantity = VedomostCellData("Количество всего", 0, 1, true);
// headerRow.note = VedomostCellData("Примечание", 0, 1, true);
// m_tableModel->addRow(headerRow);
// // Добавляем пустую строку после заголовка
// m_tableModel->addEmptyRow();
if (m_components.isEmpty()) {
qDebug() << "VedomostController::generateTableFromComponents: Нет компонентов для генерации";
return;
}
try {
// Сортируем компоненты по десигнатору
std::sort(m_components.begin(), m_components.end(),
[this](ComponentModel* a, ComponentModel* b) {
if (!a || !b) return false;
return a->designator() < b->designator();
});
// Группируем компоненты по буквенной части десигнатора
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) {
// Если компонентов больше одного, группируем компоненты по наименованию
QList<QPair<QString, QList<ComponentModel*>>> groupedByName;
for (ComponentModel *component : componentsInGroup) {
QString componentName = getMappedValue(component, "Name");
// Ищем существующую группу
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));
}
}
// Если несколько разных названий в группе - добавляем заголовок типа
if (groupedByName.size() > 1) {
// Добавляем заголовок типа (множественное число)
QString componentTypeHeader = getComponentType(componentsInGroup.first());
if (!componentTypeHeader.isEmpty()) {
VedomostRowData headerRow;
// Заголовок должен иметь isHeader=true и isUnderline=true для центрирования и подчеркивания в PDF
headerRow.name = VedomostCellData(componentTypeHeader, 0, 1, true, true, false, 100, true);
headerRow.productCode = VedomostCellData("", 0, 1, false, true, false, 100, false);
headerRow.documentCode = VedomostCellData("", 0, 1, false, true, false, 100, false);
headerRow.supplier = VedomostCellData("", 0, 1, false, true, false, 100, false);
headerRow.whereUsed = VedomostCellData("", 0, 1, false, true, false, 100, false);
headerRow.quantityPerItem = VedomostCellData("", 0, 1, false, true, false, 100, false);
headerRow.quantityInSet = VedomostCellData("", 0, 1, false, true, false, 100, false);
headerRow.quantityForReg = VedomostCellData("", 0, 1, false, true, false, 100, false);
headerRow.totalQuantity = VedomostCellData("", 0, 1, false, true, false, 100, false);
headerRow.note = VedomostCellData("", 0, 1, false, true, false, 100, false);
headerRow.isHeader = true; // Помечаем всю строку как заголовок
m_tableModel->addRow(headerRow);
}
// Добавляем пустую строку
m_tableModel->addEmptyRow();
}
// Теперь создаем строки для каждой группы по наименованию
for (const auto &nameGroup : groupedByName) {
QString componentName = nameGroup.first;
QList<ComponentModel*> componentsWithSameName = nameGroup.second;
// Подсчитываем общее количество компонентов
int totalQuantity = componentsWithSameName.size();
// Создаем строку для этой группы компонентов
ComponentModel *firstComponent = componentsWithSameName.first();
// Получаем оригинальные строки для правильной обработки выражений
QStringList mappings = getColumnMappings();
QString nameProperty = mappings.size() > 0 ? mappings[0] : "Name";
QString productCodeProperty = mappings.size() > 1 ? mappings[1] : "ProductCode";
QString documentCodeProperty = mappings.size() > 2 ? mappings[2] : "DocumentCode";
QString supplierProperty = mappings.size() > 3 ? mappings[3] : "Supplier";
// Получаем СЫРЫЕ значения свойств БЕЗ вычисления выражений для правильного разделения
QString nameOriginalString = getComponentRawValue(firstComponent, nameProperty);
QString productCodeOriginalString = getComponentRawValue(firstComponent, productCodeProperty);
QString documentCodeOriginalString = getComponentRawValue(firstComponent, documentCodeProperty);
QString supplierOriginalString = getComponentRawValue(firstComponent, supplierProperty);
// Получаем данные с разделением длинных строк
QString nameValue = getMappedValue(firstComponent, "Name");
// Определяем, нужно ли добавлять название элемента
// Если несколько разных названий в группе - только название без типа
// Если несколько одинаковых элементов - множественное число + название
// Если один элемент - единственное число + название
bool addComponentType = false;
QString componentTypeName;
if (groupedByName.size() > 1) {
// Несколько разных названий - только название без типа
addComponentType = false;
} else if (totalQuantity > 1) {
// Несколько одинаковых элементов - множественное число
componentTypeName = getComponentType(firstComponent);
addComponentType = true;
} else {
// Один элемент - единственное число
componentTypeName = getComponentTypeName(firstComponent);
addComponentType = true;
}
QString productCodeValue = getMappedValue(firstComponent, "ProductCode");
QString documentCodeValue = getMappedValue(firstComponent, "DocumentCode");
QString supplierValue = getMappedValue(firstComponent, "Supplier");
QString whereUsedValue = getWhereUsed(); // Получаем из titleInscriptionsModel или ProjectParamTable
QString noteValue = getMappedValue(firstComponent, "Note");
qDebug() << "[SPLIT_CALL] ========== ВЫЗОВ splitLongDesignation для Name ==========";
qDebug() << "[SPLIT_CALL] nameValue:" << nameValue;
qDebug() << "[SPLIT_CALL] nameOriginalString:" << nameOriginalString;
qDebug() << "[SPLIT_CALL] component:" << (firstComponent ? "не nullptr" : "nullptr");
qDebug() << "[SPLIT_CALL] maxLength: 32";
// Разделяем длинные строки (используем оригинальные строки для обработки выражений)
// ВАЖНО: сначала разделяем, потом добавляем название элемента к первой части
QList<QString> nameParts = splitLongDesignation(nameValue, nameOriginalString, firstComponent, 32);
qDebug() << "[SPLIT_CALL] Результат nameParts:" << nameParts;
// Добавляем название элемента к первой части, если нужно
if (addComponentType && !componentTypeName.isEmpty() && !nameParts.isEmpty()) {
if (!nameParts.first().isEmpty()) {
nameParts.first() = componentTypeName + " " + nameParts.first();
} else {
nameParts.first() = componentTypeName;
}
}
QList<QString> productCodeParts = splitLongDesignation(productCodeValue, productCodeOriginalString, firstComponent, 25);
QList<QString> documentCodeParts = splitLongDesignation(documentCodeValue, documentCodeOriginalString, firstComponent, 35);
QList<QString> supplierParts = splitLongDesignation(supplierValue, supplierOriginalString, firstComponent, 25);
QList<QString> whereUsedParts = splitLongDesignation(whereUsedValue, whereUsedValue, firstComponent, 35);
QList<QString> noteParts = splitLongDesignation(noteValue, noteValue, firstComponent, 16);
// Группируем десигнаторы только для компонентов с этим наименованием
// Сначала сортируем компоненты по десигнатору (численно)
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;
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;
} else {
// Завершаем текущую группу и начинаем новую
if (currentGroup == lastDesignator) {
designatorGroupsForThisName.append(currentGroup);
} else {
designatorGroupsForThisName.append(currentGroup + "-" + lastDesignator);
}
currentGroup = currentDesignator;
lastDesignator = currentDesignator;
}
} else {
// Завершаем текущую группу и начинаем новую
if (currentGroup == lastDesignator) {
designatorGroupsForThisName.append(currentGroup);
} else {
designatorGroupsForThisName.append(currentGroup + "-" + lastDesignator);
}
currentGroup = currentDesignator;
lastDesignator = currentDesignator;
}
}
// Добавляем последнюю группу
if (currentGroup == lastDesignator) {
designatorGroupsForThisName.append(currentGroup);
} else {
designatorGroupsForThisName.append(currentGroup + "-" + lastDesignator);
}
// Разбиваем длинные группы десигнаторов (35 символов на строку для whereUsed)
QStringList designatorsSplit = splitDesignatorGroups(designatorGroupsForThisName, 35);
// Если несколько одинаковых элементов или один элемент - добавляем пустую строку перед
if (groupedByName.size() == 1) {
m_tableModel->addEmptyRow();
}
// Определяем максимальное количество строк для всех полей
int maxRows = qMax(qMax(qMax(nameParts.size(), productCodeParts.size()),
qMax(documentCodeParts.size(), supplierParts.size())),
qMax(qMax(whereUsedParts.size(), noteParts.size()), designatorsSplit.size()));
// Создаем строки для каждой части
for (int i = 0; i < maxRows; ++i) {
VedomostRowData row;
// Заполняем данные с учетом разделения
row.name = VedomostCellData(i < nameParts.size() ? nameParts[i] : "", 0, 1, false, true, false, 100, false);
row.productCode = VedomostCellData(i < productCodeParts.size() ? productCodeParts[i] : "", 0, 1, false, true, false, 100, false);
row.documentCode = VedomostCellData(i < documentCodeParts.size() ? documentCodeParts[i] : "", 0, 1, false, true, false, 100, false);
row.supplier = VedomostCellData(i < supplierParts.size() ? supplierParts[i] : "", 0, 1, false, true, false, 100, false);
// В whereUsed показываем значение из titleInscriptionsModel или ProjectParamTable
if (i < whereUsedParts.size()) {
row.whereUsed = VedomostCellData(whereUsedParts[i], 0, 1, false, true, false, 100, false);
} else {
row.whereUsed = VedomostCellData("", 0, 1, false, true, false, 100, false);
}
// Количества только в первой строке
if (i == 0) {
row.quantityPerItem = VedomostCellData(QString::number(totalQuantity), 0, 1, false, true, false, 100, false);
row.quantityInSet = VedomostCellData("", 0, 1, false, true, false, 100, false);
row.quantityForReg = VedomostCellData("", 0, 1, false, true, false, 100, false);
// totalQuantity должен быть автоматически сгенерирован для автоматического пересчета
row.totalQuantity = VedomostCellData(QString::number(totalQuantity), 0, 1, false, true, true, 100, false);
} else {
row.quantityPerItem = VedomostCellData("", 0, 1, false, true, false, 100, false);
row.quantityInSet = VedomostCellData("", 0, 1, false, true, false, 100, false);
row.quantityForReg = VedomostCellData("", 0, 1, false, true, false, 100, false);
row.totalQuantity = VedomostCellData("", 0, 1, false, true, false, 100, false);
}
row.note = VedomostCellData(i < noteParts.size() ? noteParts[i] : "", 0, 1, false, true, false, 100, false);
m_tableModel->addRow(row);
}
// Если несколько одинаковых элементов или один элемент - добавляем пустую строку после
if (groupedByName.size() == 1) {
m_tableModel->addEmptyRow();
}
}
} else {
// Если компонент один, добавляем его как отдельную строку
ComponentModel *component = componentsInGroup.first();
// Получаем оригинальные строки для правильной обработки выражений
QStringList mappings = getColumnMappings();
QString nameProperty = mappings.size() > 0 ? mappings[0] : "Name";
QString productCodeProperty = mappings.size() > 1 ? mappings[1] : "ProductCode";
QString documentCodeProperty = mappings.size() > 2 ? mappings[2] : "DocumentCode";
QString supplierProperty = mappings.size() > 3 ? mappings[3] : "Supplier";
// Получаем СЫРЫЕ значения свойств БЕЗ вычисления выражений для правильного разделения
QString nameOriginalString = getComponentRawValue(component, nameProperty);
QString productCodeOriginalString = getComponentRawValue(component, productCodeProperty);
QString documentCodeOriginalString = getComponentRawValue(component, documentCodeProperty);
QString supplierOriginalString = getComponentRawValue(component, supplierProperty);
// Получаем данные с разделением длинных строк
QString nameValue = getMappedValue(component, "Name");
// Для одного элемента: единственное число + название
QString componentTypeName = getComponentTypeName(component);
// Добавляем пустую строку перед
m_tableModel->addEmptyRow();
QString productCodeValue = getMappedValue(component, "ProductCode");
QString documentCodeValue = getMappedValue(component, "DocumentCode");
QString supplierValue = getMappedValue(component, "Supplier");
QString whereUsedValue = getWhereUsed(); // Получаем из titleInscriptionsModel или ProjectParamTable
QString noteValue = getMappedValue(component, "Note");
qDebug() << "[SPLIT_CALL] ========== ВЫЗОВ splitLongDesignation для Name (один элемент) ==========";
qDebug() << "[SPLIT_CALL] nameValue:" << nameValue;
qDebug() << "[SPLIT_CALL] nameOriginalString:" << nameOriginalString;
qDebug() << "[SPLIT_CALL] component:" << (component ? "не nullptr" : "nullptr");
qDebug() << "[SPLIT_CALL] maxLength: 32";
// Разделяем длинные строки (используем оригинальные строки для обработки выражений)
// ВАЖНО: сначала разделяем, потом добавляем название элемента к первой части
QList<QString> nameParts = splitLongDesignation(nameValue, nameOriginalString, component, 32);
qDebug() << "[SPLIT_CALL] Результат nameParts:" << nameParts;
// Добавляем название элемента к первой части, если нужно
if (!componentTypeName.isEmpty() && !nameParts.isEmpty()) {
if (!nameParts.first().isEmpty()) {
nameParts.first() = componentTypeName + " " + nameParts.first();
} else {
nameParts.first() = componentTypeName;
}
}
QList<QString> productCodeParts = splitLongDesignation(productCodeValue, productCodeOriginalString, component, 25);
QList<QString> documentCodeParts = splitLongDesignation(documentCodeValue, documentCodeOriginalString, component, 35);
QList<QString> supplierParts = splitLongDesignation(supplierValue, supplierOriginalString, component, 25);
QList<QString> whereUsedParts = splitLongDesignation(whereUsedValue, whereUsedValue, component, 35);
QList<QString> noteParts = splitLongDesignation(noteValue, noteValue, component, 16);
// Определяем максимальное количество строк
int maxRows = qMax(qMax(qMax(nameParts.size(), productCodeParts.size()),
qMax(documentCodeParts.size(), supplierParts.size())),
qMax(whereUsedParts.size(), noteParts.size()));
// Создаем строки для каждой части
for (int i = 0; i < maxRows; ++i) {
VedomostRowData row;
// Заполняем данные с учетом разделения
row.name = VedomostCellData(i < nameParts.size() ? nameParts[i] : "", 0, 1, false, true, false, 100, false);
row.productCode = VedomostCellData(i < productCodeParts.size() ? productCodeParts[i] : "", 0, 1, false, true, false, 100, false);
row.documentCode = VedomostCellData(i < documentCodeParts.size() ? documentCodeParts[i] : "", 0, 1, false, true, false, 100, false);
row.supplier = VedomostCellData(i < supplierParts.size() ? supplierParts[i] : "", 0, 1, false, true, false, 100, false);
// В whereUsed показываем значение из titleInscriptionsModel или ProjectParamTable
if (i < whereUsedParts.size()) {
row.whereUsed = VedomostCellData(whereUsedParts[i], 0, 1, false, true, false, 100, false);
} else {
row.whereUsed = VedomostCellData("", 0, 1, false, true, false, 100, false);
}
// Количества только в первой строке
if (i == 0) {
row.quantityPerItem = VedomostCellData("1", 0, 1, false, true, false, 100, false);
row.quantityInSet = VedomostCellData("", 0, 1, false, true, false, 100, false);
row.quantityForReg = VedomostCellData("", 0, 1, false, true, false, 100, false);
// totalQuantity должен быть автоматически сгенерирован для автоматического пересчета
row.totalQuantity = VedomostCellData("1", 0, 1, false, true, true, 100, false);
} else {
row.quantityPerItem = VedomostCellData("", 0, 1, false, true, false, 100, false);
row.quantityInSet = VedomostCellData("", 0, 1, false, true, false, 100, false);
row.quantityForReg = VedomostCellData("", 0, 1, false, true, false, 100, false);
row.totalQuantity = VedomostCellData("", 0, 1, false, true, false, 100, false);
}
row.note = VedomostCellData(i < noteParts.size() ? noteParts[i] : "", 0, 1, false, true, false, 100, false);
m_tableModel->addRow(row);
}
// Добавляем пустую строку после
m_tableModel->addEmptyRow();
}
}
qDebug() << "VedomostController::generateTableFromComponents: Таблица сгенерирована, строк:" << m_tableModel->rowCount();
// Оптимизируем разрывы страниц после генерации таблицы
m_tableModel->optimizePageBreaks();
} catch (const std::exception &e) {
qDebug() << "VedomostController::generateTableFromComponents: Ошибка при генерации:" << e.what();
} catch (...) {
qDebug() << "VedomostController::generateTableFromComponents: Неизвестная ошибка при генерации";
}
}
void VedomostController::updateTableFromComponents()
{
if (!m_tableModel) {
qDebug() << "VedomostController::updateTableFromComponents: m_tableModel is null";
return;
}
qDebug() << "VedomostController::updateTableFromComponents: Обновляем таблицу из" << m_components.size() << "компонентов";
if (m_components.isEmpty()) {
qDebug() << "VedomostController::updateTableFromComponents: Нет компонентов для обновления";
return;
}
try {
// Метод updateTableFromComponents больше не используется в новой логике
qDebug() << "VedomostController::updateTableFromComponents: Метод устарел";
} catch (const std::exception &e) {
qDebug() << "VedomostController::updateTableFromComponents: Ошибка при обновлении:" << e.what();
} catch (...) {
qDebug() << "VedomostController::updateTableFromComponents: Неизвестная ошибка при обновлении";
}
}
QString VedomostController::getComponentValue(ComponentModel *component, const QString &propertyName)
{
if (!component) {
return "";
}
qDebug() << "VedomostController::getComponentValue: propertyName =" << propertyName;
// Получаем значение свойства компонента
QString value;
if (propertyName == "Designator") {
value = component->designator();
qDebug() << "VedomostController::getComponentValue: Designator =" << value;
} else {
QMap<QString, QString> props = component->properties();
value = props.value(propertyName, "");
qDebug() << "VedomostController::getComponentValue: Свойство" << propertyName << "=" << value;
}
// Проверяем, является ли значение свойства выражением
if (value.startsWith("=")) {
qDebug() << "VedomostController::getComponentValue: Значение свойства является выражением:" << value;
return parseExpression(component, value);
}
return value;
}
QString VedomostController::getComponentRawValue(ComponentModel *component, const QString &propertyName)
{
if (!component) {
return "";
}
qDebug() << "[RAW_VALUE] VedomostController::getComponentRawValue: propertyName =" << propertyName;
// Получаем сырое значение свойства компонента БЕЗ вычисления выражений
QString value;
if (propertyName == "Designator") {
value = component->designator();
qDebug() << "[RAW_VALUE] Designator =" << value;
} else {
QMap<QString, QString> props = component->properties();
value = props.value(propertyName, "");
qDebug() << "[RAW_VALUE] Свойство" << propertyName << "=" << value;
}
// Возвращаем сырое значение без вычисления
return value;
}
QString VedomostController::getMappedValue(ComponentModel *component, const QString &columnName)
{
if (!component) {
return "";
}
qDebug() << "VedomostController::getMappedValue: columnName =" << columnName;
// Определяем индекс колонки в маппинге
int columnIndex = -1;
if (columnName == "Name") columnIndex = 0;
else if (columnName == "ProductCode") columnIndex = 1;
else if (columnName == "DocumentCode") columnIndex = 2;
else if (columnName == "Supplier") columnIndex = 3;
else if (columnName == "WhereUsed") columnIndex = 4;
else if (columnName == "Note") columnIndex = 5;
if (columnIndex < 0 || columnIndex >= m_columnMappings.size()) {
qDebug() << "VedomostController::getMappedValue: Неизвестная колонка или индекс вне диапазона:" << columnName;
return "";
}
// Получаем маппинг для этой колонки
QString mappedProperty = m_columnMappings[columnIndex];
// Если маппинг пустой или "Не выбрано", возвращаем пустую строку
if (mappedProperty.isEmpty() || mappedProperty == "-- Не выбрано --") {
qDebug() << "VedomostController::getMappedValue: Маппинг пустой для колонки" << columnName;
return "";
}
qDebug() << "VedomostController::getMappedValue: Маппинг" << columnName << "->" << mappedProperty;
// Для колонки "WhereUsed" значение получается из ProjectParamTable, а не из компонента
if (columnName == "WhereUsed") {
return getWhereUsed();
}
// Получаем значение из компонента
QString value = getComponentValue(component, mappedProperty);
return value;
}
QString VedomostController::parseExpression(ComponentModel *component, const QString &expression)
{
if (!component) {
return "";
}
qDebug() << "VedomostController::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() << "VedomostController::parseExpression: Части выражения:" << parts;
for (const QString &part : parts) {
QString trimmedPart = part.trimmed();
qDebug() << "VedomostController::parseExpression: Обрабатываем часть:" << trimmedPart;
// Если это не пустая строка, добавляем к результату
if (!trimmedPart.isEmpty()) {
QString value;
// Проверяем, является ли это литералом в одинарных кавычках
if (trimmedPart.startsWith("'") && trimmedPart.endsWith("'")) {
// Это литерал - убираем кавычки и используем как есть
value = trimmedPart.mid(1, trimmedPart.length() - 2);
qDebug() << "VedomostController::parseExpression: Найден литерал в одинарных кавычках:" << value;
}
// Проверяем, является ли это именем свойства компонента в двойных кавычках
else if (trimmedPart.startsWith("\"") && trimmedPart.endsWith("\"")) {
// Это свойство компонента - убираем кавычки и ищем в свойствах
QString propertyName = trimmedPart.mid(1, trimmedPart.length() - 2);
qDebug() << "VedomostController::parseExpression: Ищем свойство компонента:" << propertyName;
if (propertyName == "Designator") {
value = component->designator();
qDebug() << "VedomostController::parseExpression: Найдено свойство Designator =" << value;
} else {
// Ищем в свойствах компонента
QMap<QString, QString> props = component->properties();
value = props.value(propertyName, "");
qDebug() << "VedomostController::parseExpression: Ищем свойство" << propertyName << "в компоненте, результат:" << value;
// Рекурсивно обрабатываем вложенные выражения
if (value.startsWith("=")) {
qDebug() << "VedomostController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
value = parseExpression(component, value);
}
}
}
// Проверяем, является ли это именем свойства компонента без кавычек
else if (trimmedPart == "Designator") {
value = component->designator();
qDebug() << "VedomostController::parseExpression: Найдено свойство Designator =" << value;
} else {
// Ищем в свойствах компонента
QMap<QString, QString> props = component->properties();
value = props.value(trimmedPart, "");
qDebug() << "VedomostController::parseExpression: Ищем свойство" << trimmedPart << "в компоненте, результат:" << value;
// Рекурсивно обрабатываем вложенные выражения
if (value.startsWith("=")) {
qDebug() << "VedomostController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
value = parseExpression(component, value);
}
}
// Добавляем значение к результату
if (!value.isEmpty()) {
if (!result.isEmpty()) {
result += value;
} else {
result = value;
}
qDebug() << "VedomostController::parseExpression: Добавили к результату, текущий результат:" << result;
}
}
}
qDebug() << "VedomostController::parseExpression: Финальный результат:" << result;
return result;
}
QList<QString> VedomostController::splitByConnectors(const QString &text, int maxLength)
{
QList<QString> result;
if (text.length() <= maxLength) {
result.append(text);
return result;
}
// Ищем соединения (тире, дефисы, точки)
QStringList connectors = {" - ", "", "", "", "", " / ", " \\ ", " + ", " = "};
// Ищем ближайший к середине строки разделитель
int targetLength = maxLength;
int bestSplitPos = -1;
int minDifference = text.length();
for (const QString &connector : connectors) {
int pos = text.indexOf(connector);
while (pos != -1) {
int leftLength = pos;
int rightLength = text.length() - pos - connector.length();
// Вычисляем разницу с целевой длиной
int leftDiff = abs(leftLength - targetLength);
int rightDiff = abs(rightLength - targetLength);
int totalDiff = leftDiff + rightDiff;
// Если эта позиция лучше предыдущей, запоминаем её
if (totalDiff < minDifference) {
minDifference = totalDiff;
bestSplitPos = pos;
}
pos = text.indexOf(connector, pos + 1);
}
}
// Если нашли подходящий разделитель, разделяем по нему
if (bestSplitPos != -1) {
// Определяем длину разделителя
int connectorLength = 0;
for (const QString &connector : connectors) {
if (text.mid(bestSplitPos, connector.length()) == connector) {
connectorLength = connector.length();
break;
}
}
QString leftPart = text.left(bestSplitPos).trimmed();
QString rightPart = text.mid(bestSplitPos + connectorLength).trimmed();
// Рекурсивно обрабатываем обе части
if (!leftPart.isEmpty()) {
QList<QString> leftParts = splitByConnectors(leftPart, maxLength);
result.append(leftParts);
}
if (!rightPart.isEmpty()) {
QList<QString> rightParts = splitByConnectors(rightPart, maxLength);
result.append(rightParts);
}
}
// Если разделители не найдены или не подходят, возвращаем исходный текст
if (result.isEmpty()) {
result.append(text);
}
return result;
}
QList<QString> VedomostController::splitComplexStringByMiddle(const QString &text, int maxLength)
{
QList<QString> result;
if (text.length() <= maxLength) {
result.append(text);
return result;
}
qDebug() << "[SPLIT_DEBUG] splitComplexStringByMiddle: Разделяем комплексную строку:" << text;
// Ищем запятые в тексте
QList<int> commaPositions;
for (int i = 0; i < text.length(); ++i) {
if (text[i] == ',') {
commaPositions.append(i);
}
}
if (commaPositions.isEmpty()) {
// Если запятых нет, используем обычное разделение по пробелам
qDebug() << "[SPLIT_DEBUG] 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() << "[SPLIT_DEBUG] splitComplexStringByMiddle: Найдена запятая на позиции" << bestSplitPos;
qDebug() << "[SPLIT_DEBUG] splitComplexStringByMiddle: Левая часть:" << leftPart;
qDebug() << "[SPLIT_DEBUG] 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() << "[SPLIT_DEBUG] splitComplexStringByMiddle: Не удалось найти подходящую запятую, используем splitBySpaces";
result = splitBySpaces(text, maxLength);
}
qDebug() << "[SPLIT_DEBUG] splitComplexStringByMiddle: Результат:" << result;
return result;
}
QStringList VedomostController::collectPropertyNames()
{
QStringList propertyNames;
// Добавляем основные свойства компонента
propertyNames << "Designator" << "Name" << "ProductCode" << "DocumentCode" << "Supplier";
// Собираем дополнительные свойства из компонентов
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() <= 5) { // Только базовые свойства
propertyNames << "Type" << "Value" << "Footprint" << "Description" << "ManufacturerPartNumber";
qDebug() << "VedomostController: Дополнительные свойства не найдены, используем стандартные:" << propertyNames;
}
// Добавляем специальные свойства для ведомости
propertyNames << "WhereUsed" << "QuantityPerItem" << "QuantityInSet" << "QuantityForReg" << "TotalQuantity" << "Note";
return propertyNames;
}
void VedomostController::setColumnMappings(const QStringList &mappings)
{
qDebug() << "VedomostController::setColumnMappings: Устанавливаем новые настройки колонок:" << mappings;
m_columnMappings = mappings;
// Сохраняем настройки в ProjectSettingsModel
if (m_projectSettingsModel) {
for (int i = 0; i < mappings.size(); ++i) {
m_projectSettingsModel->setColumnMapping("Vedomost", i, mappings[i]);
}
qDebug() << "VedomostController::setColumnMappings: Настройки сохранены в ProjectSettingsModel";
}
// Обновляем настройки в модели
if (m_tableModel) {
m_tableModel->setColumnMappings(mappings);
qDebug() << "VedomostController::setColumnMappings: Настройки обновлены в модели";
}
qDebug() << "VedomostController::setColumnMappings: Настройки колонок обновлены:" << m_columnMappings;
}
QStringList VedomostController::getColumnMappings() const
{
// Если есть ProjectSettingsModel, читаем настройки из него
if (m_projectSettingsModel) {
QStringList settings = m_projectSettingsModel->getColumnMappings("Vedomost");
if (!settings.isEmpty()) {
qDebug() << "VedomostController::getColumnMappings: Получены настройки из ProjectSettingsModel:" << settings;
return settings;
}
}
// Fallback: возвращаем локальные настройки
qDebug() << "VedomostController::getColumnMappings: Возвращаем локальные настройки:" << m_columnMappings;
return m_columnMappings;
}
QStringList VedomostController::getAvailableProperties() const
{
QStringList properties = m_propertyNames;
// Убираем специальные значения, оставляем только реальные свойства компонентов
return properties;
}
QString VedomostController::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 VedomostController::getComponentTypeName(ComponentModel *component)
{
if (!component) return "";
// Получаем название элемента по десигнатору в единственном числе
if (m_designatorMappingModel) {
QString componentType = m_designatorMappingModel->getComponentType(component->designator(), false); // false для единственного числа
if (!componentType.isEmpty()) {
return componentType;
}
}
// Если маппинг не найден, используем тип из свойств компонента
QMap<QString, QString> props = component->properties();
QString type = props.value("Type", "");
if (!type.isEmpty()) {
return type;
}
// Если и тип не найден, возвращаем пустую строку
return QString();
}
QPair<QString, QString> VedomostController::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 VedomostController::addEmptyRow()
{
if (m_tableModel) {
m_tableModel->addEmptyRow();
qDebug() << "VedomostController::addEmptyRow: Добавлена пустая строка";
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
// m_tableModel->optimizePageBreaks();
}
}
void VedomostController::addEmptyRowAt(int position)
{
if (m_tableModel) {
m_tableModel->addEmptyRowAt(position);
qDebug() << "VedomostController::addEmptyRowAt: Добавлена пустая строка в позицию" << position;
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
// m_tableModel->optimizePageBreaks();
}
}
void VedomostController::insertEmptyRowAt(int position)
{
if (m_tableModel) {
m_tableModel->addEmptyRowAt(position);
qDebug() << "VedomostController::insertEmptyRowAt: Вставлена пустая строка в позицию" << position;
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
// m_tableModel->optimizePageBreaks();
}
}
void VedomostController::removeRow(int row)
{
if (m_tableModel) {
m_tableModel->removeRow(row);
qDebug() << "VedomostController::removeRow: Удалена строка" << row;
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
// m_tableModel->optimizePageBreaks();
}
}
void VedomostController::clearTable()
{
if (m_tableModel) {
m_tableModel->clear();
qDebug() << "VedomostController::clearTable: Таблица очищена";
}
}
void VedomostController::optimizePageBreaks()
{
if (m_tableModel) {
qDebug() << "VedomostController::optimizePageBreaks: Оптимизируем разрывы страниц";
m_tableModel->optimizePageBreaks();
}
}
int VedomostController::getFontSize() const
{
if (m_projectSettingsModel) {
return m_projectSettingsModel->getFontSize("Vedomost");
}
return 12; // По умолчанию
}
void VedomostController::setFontSize(int fontSize)
{
if (m_projectSettingsModel) {
m_projectSettingsModel->setFontSize("Vedomost", fontSize);
}
}
int VedomostController::getFontStretch() const
{
if (m_projectSettingsModel) {
return m_projectSettingsModel->getFontStretch("Vedomost");
}
return 100; // По умолчанию (нормальный)
}
void VedomostController::setFontStretch(int stretch)
{
if (m_projectSettingsModel) {
m_projectSettingsModel->setFontStretch("Vedomost", stretch);
}
}
QString VedomostController::getWhereUsed() const
{
// Сначала пытаемся получить значение из titleInscriptionsModel (поля 101 или 1001)
if (m_mainController) {
TitleInscriptionsModel *titleModel = m_mainController->titleInscriptionsModel();
ProjectParamTableModel *paramModel = m_mainController->projectParamTableModel();
if (titleModel) {
// Пробуем сначала поле 101, затем 1001
QString inscriptionValue;
int fieldNumber = -1;
if (!titleModel->getInscriptionValue(101).isEmpty()) {
inscriptionValue = titleModel->getInscriptionValue(101);
fieldNumber = 101;
} else if (!titleModel->getInscriptionValue(1001).isEmpty()) {
inscriptionValue = titleModel->getInscriptionValue(1001);
fieldNumber = 1001;
}
if (!inscriptionValue.isEmpty() && inscriptionValue != "-- Не выбрано --") {
// Если значение - это название поля из ProjectParamTable, получаем реальное значение
if (paramModel) {
QMap<QString, QString> params = paramModel->getDataAsMap();
if (params.contains(inscriptionValue)) {
QString projectParamValue = params[inscriptionValue];
if (!projectParamValue.isEmpty()) {
return projectParamValue;
}
}
}
// Если сопоставления нет или значение параметра пустое, возвращаем значение надписи
return inscriptionValue;
}
}
}
// Fallback: используем старую логику из columnMappings
QStringList mappings = getColumnMappings();
// Поле "WhereUsed" находится в позиции 4 в columnMappings
if (mappings.size() > 4) {
QString fieldName = mappings[4];
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();
}
QList<QString> VedomostController::splitLongDesignation(const QString &designation, const QString originalString, ComponentModel *component, int maxLength)
{
QList<QString> result;
qDebug() << "[SPLIT_DEBUG] ========== splitLongDesignation START ==========";
qDebug() << "[SPLIT_DEBUG] designation:" << designation;
qDebug() << "[SPLIT_DEBUG] designation.length():" << designation.length();
qDebug() << "[SPLIT_DEBUG] originalString:" << originalString;
qDebug() << "[SPLIT_DEBUG] originalString.startsWith('='):" << originalString.startsWith("=");
qDebug() << "[SPLIT_DEBUG] component:" << (component ? "не nullptr" : "nullptr");
qDebug() << "[SPLIT_DEBUG] maxLength:" << maxLength;
if (designation.length() <= maxLength) {
qDebug() << "[SPLIT_DEBUG] Строка короткая, возвращаем как есть";
result.append(designation);
qDebug() << "[SPLIT_DEBUG] ========== splitLongDesignation END (короткая строка) ==========";
return result;
}
// Проверяем, является ли наименование выражением с частями
if (originalString.startsWith("=") && component) {
qDebug() << "[SPLIT_DEBUG] >>> ВЕТКА: Это выражение, разделяем по плюсам";
// Это выражение - разделяем по частям
QString expr = originalString.mid(1); // Убираем начальный "="
qDebug() << "[SPLIT_DEBUG] Выражение без '=':" << expr;
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) {
// Это разделитель "+" вне кавычек
qDebug() << "[SPLIT_DEBUG] Найден разделитель '+' на позиции" << i << ", текущая часть:" << currentPart;
if (!currentPart.trimmed().isEmpty()) {
parts.append(currentPart.trimmed());
qDebug() << "[SPLIT_DEBUG] Добавлена часть в список:" << currentPart.trimmed();
}
currentPart.clear();
} else {
currentPart += ch;
}
}
// Добавляем последнюю часть
if (!currentPart.trimmed().isEmpty()) {
parts.append(currentPart.trimmed());
qDebug() << "[SPLIT_DEBUG] Добавлена последняя часть:" << currentPart.trimmed();
}
qDebug() << "[SPLIT_DEBUG] Всего частей выражения:" << parts.size();
qDebug() << "[SPLIT_DEBUG] Части выражения:" << 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() << "[SPLIT_DEBUG] Обрабатываем свойство:" << trimmedPart;
if (trimmedPart == "Designator") {
displayPart = component->designator();
qDebug() << "[SPLIT_DEBUG] Свойство Designator, значение:" << displayPart;
} else if (trimmedPart.startsWith("\"") && trimmedPart.endsWith("\"")) {
QString propertyName = trimmedPart.mid(1, trimmedPart.length() - 2);
displayPart = props.value(propertyName, "");
qDebug() << "[SPLIT_DEBUG] Свойство в кавычках:" << propertyName << ", значение:" << displayPart;
// Рекурсивно обрабатываем вложенные выражения
if (displayPart.startsWith("=")) {
qDebug() << "[SPLIT_DEBUG] Значение свойства является вложенным выражением, рекурсивно обрабатываем";
displayPart = parseExpression(component, displayPart);
}
} else {
displayPart = props.value(trimmedPart, "");
qDebug() << "[SPLIT_DEBUG] Свойство без кавычек:" << trimmedPart << ", значение:" << displayPart;
// Рекурсивно обрабатываем вложенные выражения
if (displayPart.startsWith("=")) {
qDebug() << "[SPLIT_DEBUG] Значение свойства является вложенным выражением, рекурсивно обрабатываем";
displayPart = parseExpression(component, displayPart);
}
}
}
fullString += displayPart;
}
}
qDebug() << "[SPLIT_DEBUG] Собранная полная строка:" << fullString << ", длина:" << fullString.length();
// Проверяем, содержит ли строка запятые (комплексная строка)
bool isComplexString = fullString.contains(',');
if (isComplexString && fullString.length() > maxLength) {
qDebug() << "[SPLIT_DEBUG] Комплексная строка с запятыми, делим по середине";
// Для комплексной строки делим по середине, а не по началу
result = splitComplexStringByMiddle(fullString, maxLength);
} else if (fullString.length() > maxLength) {
qDebug() << "[SPLIT_DEBUG] Строка длинная, разделяем по пробелам";
// Обычная длинная строка - разделяем по пробелам
result = splitBySpaces(fullString, maxLength);
} else {
qDebug() << "[SPLIT_DEBUG] Строка короткая, возвращаем как есть";
result.append(fullString);
}
} else {
qDebug() << "[SPLIT_DEBUG] >>> ВЕТКА: Обычный текст (не выражение)";
qDebug() << "[SPLIT_DEBUG] Причина: originalString.startsWith('=') =" << originalString.startsWith("=") << ", component =" << (component ? "не nullptr" : "nullptr");
// Обычный текст - сначала пытаемся разделить по соединениям (тире, дефисы)
qDebug() << "[SPLIT_DEBUG] Пытаемся разделить по соединениям (тире, дефисы)";
result = splitByConnectors(designation, maxLength);
qDebug() << "[SPLIT_DEBUG] Результат разделения по соединениям:" << result << ", размер:" << result.size();
// Если разделение по соединениям не дало результата, разделяем по пробелам
if (result.size() <= 1) {
qDebug() << "[SPLIT_DEBUG] Разделение по соединениям не дало результата, разделяем по пробелам";
result = splitBySpaces(designation, maxLength);
qDebug() << "[SPLIT_DEBUG] Результат разделения по пробелам:" << result;
}
}
qDebug() << "[SPLIT_DEBUG] ФИНАЛЬНЫЙ результат разделения:" << result;
qDebug() << "[SPLIT_DEBUG] ========== splitLongDesignation END ==========";
return result;
}
QList<QString> VedomostController::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;
}
QStringList VedomostController::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;
}
void VedomostController::onRowDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
Q_UNUSED(roles);
if (!m_tableModel) {
return;
}
// Обрабатываем каждую измененную строку
for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
// Проверяем, изменились ли колонки с количествами (5, 6, 7)
int startCol = topLeft.column();
int endCol = bottomRight.column();
bool quantityChanged = false;
for (int col = startCol; col <= endCol; ++col) {
if (col == 5 || col == 6 || col == 7) { // quantityPerItem, quantityInSet, quantityForReg
quantityChanged = true;
break;
}
}
if (quantityChanged) {
// Проверяем, что totalQuantity автоматически сгенерировано (не редактировалось вручную)
// Используем прямой вызов метода модели для проверки и обновления
m_tableModel->updateTotalQuantity(row);
}
}
}