Files
GostGenerator/controller/perechentablecontroller.cpp
T

1078 lines
53 KiB
C++

#include "perechentablecontroller.h"
#include "../model/componentmodel.h"
#include "../model/designatormappingmodel.h"
#include <QDebug>
#include <QCollator>
PerechenTableController::PerechenTableController(QObject *parent)
: QObject(parent)
, m_tableModel(new PerechenTableModel(this))
, m_designatorMappingModel(nullptr)
, m_projectSettingsModel(nullptr)
{
// Устанавливаем маппинг по умолчанию для группировки
// Эти настройки будут переопределены в MainController
m_columnMappings << "Designator" << "Name" << "Quantity" << "Note";
}
PerechenTableController::~PerechenTableController()
{
// m_tableModel удалится автоматически, так как он является дочерним объектом
}
void PerechenTableController::setDesignatorMappingModel(DesignatorMappingModel *mappingModel)
{
m_designatorMappingModel = mappingModel;
}
void PerechenTableController::setModel(PerechenTableModel *model)
{
if (m_tableModel != model) {
qDebug() << "PerechenTableController::setModel: Заменяем модель таблицы";
m_tableModel = model;
// Если модель не пуста, загружаем из неё настройки колонок
if (m_tableModel) {
QStringList columnMappings = m_tableModel->columnMappings();
if (!columnMappings.isEmpty()) {
qDebug() << "PerechenTableController::setModel: Загружаем настройки колонок из модели:" << columnMappings;
m_columnMappings = columnMappings;
}
}
}
}
void PerechenTableController::setProjectSettingsModel(ProjectSettingsModel *model)
{
m_projectSettingsModel = model;
qDebug() << "PerechenTableController::setProjectSettingsModel: Установлена модель настроек проекта";
}
void PerechenTableController::setComponents(const QList<ComponentModel*> &components)
{
m_components = components;
// Собираем доступные свойства из компонентов
m_propertyNames = collectPropertyNames();
}
void PerechenTableController::generateTableFromComponents()
{
if (!m_tableModel) {
return;
}
qDebug() << "PerechenTableController::generateTableFromComponents: Начинаем генерацию таблицы";
qDebug() << "PerechenTableController::generateTableFromComponents: Текущие настройки колонок:" << m_columnMappings;
// Дополнительная проверка настроек колонок
if (m_tableModel) {
QStringList modelMappings = m_tableModel->columnMappings();
qDebug() << "PerechenTableController::generateTableFromComponents: Настройки колонок в модели:" << modelMappings;
// Если настройки в модели отличаются от локальных, синхронизируем их
if (modelMappings != m_columnMappings) {
qDebug() << "PerechenTableController::generateTableFromComponents: Синхронизируем настройки колонок";
m_columnMappings = modelMappings;
}
}
qDebug() << "PerechenTableController::generateTableFromComponents: Количество компонентов:" << m_components.size();
// Очищаем таблицу
m_tableModel->clear();
if (m_components.isEmpty()) {
return;
}
try {
// Группируем компоненты по типу
// QList<ComponentGroup> groups = groupComponentsByType(m_components);
// Добавляем заголовок таблицы
PerechenRowData emptyRow;
emptyRow.isEmpty = true;
// Добавляем группы компонентов с группировкой по типу
int rowNumber = 1;
QString currentType;
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 = PerechenTableController::splitDesignator(designatorA);
QPair<QString, QString> partsB = PerechenTableController::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;
});
QString complesDesignatorFront = "";
QString complesDesignatorBack = "";
// Группируем компоненты по буквенной части десигнатора
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) {
// Если компонентов больше одного, добавляем заголовок типа
PerechenRowData headerRow;
m_tableModel->addRow(emptyRow);
headerRow.isHeader = true;
headerRow.designation = PerechenCellData(getComponentType(componentsInGroup.first()), 0, 1, true, false, false, 100, true);
m_tableModel->addRow(headerRow);
m_tableModel->addRow(emptyRow);
// Обрабатываем компоненты последовательно, группируя по currentDesignation
QString prevDesignation = "";
QString prevOriginalString = "";
ComponentModel *prevComponent = nullptr;
QString groupStartDesignator = "";
QString groupLastDesignator = "";
int groupCount = 0;
for (int i = 0; i < componentsInGroup.size(); ++i) {
ComponentModel *component = componentsInGroup[i];
QString currentDesignation = getComponentValue(component, m_columnMappings.value(0, "<Пусто>"));
if (i == 0 || currentDesignation != prevDesignation) {
// Добавляем предыдущую группу, если она есть
if (i > 0 && groupCount > 0) {
// Разделяем длинное наименование на несколько строк
// Используем исходное значение для правильного разделения по частям
QList<QString> designationParts = splitLongDesignation(prevDesignation, prevOriginalString, prevComponent);
for (int partIndex = 0; partIndex < designationParts.size(); ++partIndex) {
PerechenRowData row;
// Только в первой строке показываем позицию и количество
if (partIndex == 0) {
QString positionText;
if (groupCount == 1) {
positionText = groupStartDesignator;
} else if (groupCount == 2) {
// Если в группе 2 элемента - через запятую
positionText = groupStartDesignator + ", " + groupLastDesignator;
} else {
// Если в группе 3 и более элементов - через дефис
positionText = groupStartDesignator + "-" + groupLastDesignator;
}
row.position = PerechenCellData(positionText, 0, 1, false, false, false, 100, false);
row.quantity = PerechenCellData(QString::number(groupCount), 0, 1, false, false, false, 100, false);
} else {
// В последующих строках оставляем пустыми позицию и количество
row.position = PerechenCellData("", 0, 1, false, false, false, 100, false);
row.quantity = PerechenCellData("", 0, 1, false, false, false, 100, false);
}
row.designation = PerechenCellData(designationParts[partIndex], 0, 1, false, false, false, 100, false);
row.note = PerechenCellData("", 0, 1, false, false, false, 100, false);
m_tableModel->addRow(row);
}
}
// Начинаем новую группу
groupStartDesignator = component->designator();
groupLastDesignator = component->designator();
groupCount = 1;
prevDesignation = currentDesignation;
// Сохраняем исходное значение и компонент для правильного разделения
QMap<QString, QString> props = component->properties();
prevOriginalString = props.value(m_columnMappings.value(0, "<Пусто>"), "");
prevComponent = component;
} else {
// Продолжаем текущую группу - обновляем последний десигнатор
groupLastDesignator = component->designator();
groupCount++;
}
}
// Добавляем последнюю группу
if (groupCount > 0) {
// Разделяем длинное наименование на несколько строк
// Используем сохраненные значения для правильного разделения
QList<QString> designationParts = splitLongDesignation(prevDesignation, prevOriginalString, prevComponent);
for (int partIndex = 0; partIndex < designationParts.size(); ++partIndex) {
PerechenRowData row;
// Только в первой строке показываем позицию и количество
if (partIndex == 0) {
QString positionText;
if (groupCount == 1) {
positionText = groupStartDesignator;
} else if (groupCount == 2) {
// Если в группе 2 элемента - через запятую
positionText = groupStartDesignator + ", " + groupLastDesignator;
} else {
// Если в группе 3 и более элементов - через дефис
positionText = groupStartDesignator + "-" + groupLastDesignator;
}
row.position = PerechenCellData(positionText, 0, 1, false, false, false, 100, false);
row.quantity = PerechenCellData(QString::number(groupCount), 0, 1, false, false, false, 100, false);
} else {
// В последующих строках оставляем пустыми позицию и количество
row.position = PerechenCellData("", 0, 1, false, false, false, 100, false);
row.quantity = PerechenCellData("", 0, 1, false, false, false, 100, false);
}
row.designation = PerechenCellData(designationParts[partIndex], 0, 1, false, false, false, 100, false);
row.note = PerechenCellData("", 0, 1, false, false, false, 100, false);
m_tableModel->addRow(row);
}
}
} else {
// Если компонент один, объединяем тип и обозначение
ComponentModel *component = componentsInGroup.first();
QString componentType = getComponentType(component);
QString currentDesignation = getComponentValue(component, m_columnMappings.value(0, "<Пусто>"));
QString fullDesignation = componentType + " " + currentDesignation;
// Разделяем длинное наименование на несколько строк
// Нужно получить исходное значение для правильного разделения
QMap<QString, QString> props = component->properties();
QString originalString = props.value(m_columnMappings.value(0, "<Пусто>"), "");
QList<QString> designationParts = splitLongDesignation(fullDesignation, originalString, component);
m_tableModel->addRow(emptyRow);
for (int partIndex = 0; partIndex < designationParts.size(); ++partIndex) {
PerechenRowData row;
// Только в первой строке показываем позицию и количество
if (partIndex == 0) {
row.position = PerechenCellData(component->designator(), 0, 1, false, false, false, 100, false);
row.quantity = PerechenCellData("1", 0, 1, false, false, false, 100, false);
} else {
// В последующих строках оставляем пустыми позицию и количество
row.position = PerechenCellData("", 0, 1, false, false, false, 100, false);
row.quantity = PerechenCellData("", 0, 1, false, false, false, 100, false);
}
row.designation = PerechenCellData(designationParts[partIndex], 0, 1, false, false, false, 100, false);
row.note = PerechenCellData("", 0, 1, false, false, false, 100, false);
m_tableModel->addRow(row);
}
}
}
// for (const ComponentGroup &group : groups) {
// if (group.components.isEmpty()) {
// continue;
// }
// // Добавляем пустую строку между разными типами компонентов
// if (currentType != group.componentType && !currentType.isEmpty()) {
// PerechenRowData emptyRow;
// emptyRow.isEmpty = true;
// m_tableModel->addRow(emptyRow);
// }
// // Добавляем заголовок типа компонента, если он изменился
// if (currentType != group.componentType) {
// PerechenRowData typeHeaderRow;
// typeHeaderRow.isHeader = true;
// typeHeaderRow.designation = PerechenCellData(group.componentType, 0, 1, true);
// m_tableModel->addRow(typeHeaderRow);
// currentType = group.componentType;
// }
// // Если в группе один элемент, объединяем тип и наименование
// if (group.components.size() == 1) {
// PerechenRowData row;
// // Заполняем данные в зависимости от маппинга
// for (int col = 0; col < 4; ++col) {
// QString mapping = m_columnMappings.value(col, "<Пусто>");
// QString value;
// bool isAuto = false;
// if (mapping == "<Авто>") {
// value = QString::number(rowNumber);
// isAuto = true;
// } else if (mapping == "<Пусто>") {
// value = "";
// } else if (mapping == "Designator") {
// // Для колонки Designator используем дезигнатор компонента
// value = group.components.first()->designator();
// } else if (mapping == "Quantity" || mapping == "Кол.") {
// // Для колонки количества используем количество компонентов в группе
// value = QString::number(group.components.size());
// } else if (mapping == "Name" || mapping == "Наименование") {
// // Для наименования используем название группы (это то, что возвращает getComponentDesignation)
// value = group.name;
// } else {
// // Для остальных свойств берем значение из компонента
// ComponentModel *component = group.components.first();
// value = getComponentValue(component, mapping);
// }
// PerechenCellData cellData(value, rowNumber, 1, false, isAuto, value.isEmpty());
// switch (col) {
// case 0: row.position = cellData; break;
// case 1: row.designation = cellData; break;
// case 2: row.quantity = cellData; break;
// case 3: row.note = cellData; break;
// }
// }
// row.rowNumber = rowNumber++;
// m_tableModel->addRow(row);
// } else {
// // Если в группе несколько элементов, добавляем строку с диапазоном
// PerechenRowData row;
// // Заполняем данные в зависимости от маппинга
// for (int col = 0; col < 4; ++col) {
// QString mapping = m_columnMappings.value(col, "<Пусто>");
// QString value;
// bool isAuto = false;
// if (mapping == "<Авто>") {
// value = QString::number(rowNumber);
// isAuto = true;
// } else if (mapping == "<Пусто>") {
// value = "";
// } else if (mapping == "Designator") {
// // Для колонки Designator используем диапазон обозначений группы
// value = group.designatorRange;
// } else if (mapping == "Quantity" || mapping == "Кол.") {
// // Для колонки количества используем количество компонентов в группе
// value = QString::number(group.components.size());
// } else if (mapping == "Name" || mapping == "Наименование") {
// // Для наименования используем название группы (это то, что возвращает getComponentDesignation)
// value = group.name;
// } else {
// // Для остальных свойств берем значение из первого компонента группы
// ComponentModel *firstComponent = group.components.first();
// value = getComponentValue(firstComponent, mapping);
// }
// PerechenCellData cellData(value, rowNumber, 1, false, isAuto, value.isEmpty());
// switch (col) {
// case 0: row.position = cellData; break;
// case 1: row.designation = cellData; break;
// case 2: row.quantity = cellData; break;
// case 3: row.note = cellData; break;
// }
// }
// row.rowNumber = rowNumber++;
// m_tableModel->addRow(row);
// }
// }
qDebug() << "PerechenTableController::generateTableFromComponents: Таблица сгенерирована, строк:" << m_tableModel->rowCount();
// Оптимизируем разрывы страниц после генерации таблицы
m_tableModel->optimizePageBreaks();
} catch (const std::exception &e) {
qDebug() << "PerechenTableController::generateTableFromComponents: Ошибка при генерации:" << e.what();
} catch (...) {
qDebug() << "PerechenTableController::generateTableFromComponents: Неизвестная ошибка при генерации";
}
}
void PerechenTableController::updateTableFromComponents()
{
if (!m_tableModel) {
qDebug() << "PerechenTableController::updateTableFromComponents: m_tableModel is null";
return;
}
qDebug() << "PerechenTableController::updateTableFromComponents: Обновляем таблицу из" << m_components.size() << "компонентов";
if (m_components.isEmpty()) {
qDebug() << "PerechenTableController::updateTableFromComponents: Нет компонентов для обновления";
return;
}
try {
// Метод updateTableFromComponents больше не используется в новой логике
qDebug() << "PerechenTableController::updateTableFromComponents: Метод устарел";
} catch (const std::exception &e) {
qDebug() << "PerechenTableController::updateTableFromComponents: Ошибка при обновлении:" << e.what();
} catch (...) {
qDebug() << "PerechenTableController::updateTableFromComponents: Неизвестная ошибка при обновлении";
}
}
QString PerechenTableController::getComponentValue(ComponentModel *component, const QString &propertyName)
{
if (!component) {
return "";
}
qDebug() << "PerechenTableController::getComponentValue: propertyName =" << propertyName;
qDebug() << "PerechenTableController::getComponentValue: Текущие настройки колонок:" << m_columnMappings;
// Получаем значение свойства компонента
QString value;
if (propertyName == "Designator") {
value = component->designator();
qDebug() << "PerechenTableController::getComponentValue: Designator =" << value;
} else {
QMap<QString, QString> props = component->properties();
value = props.value(propertyName, "");
qDebug() << "PerechenTableController::getComponentValue: Свойство" << propertyName << "=" << value;
}
// Проверяем, является ли значение свойства выражением
if (value.startsWith("=")) {
qDebug() << "PerechenTableController::getComponentValue: Значение свойства является выражением:" << value;
return parseExpression(component, value);
}
return value;
}
QString PerechenTableController::parseExpression(ComponentModel *component, const QString &expression)
{
if (!component) {
return "";
}
qDebug() << "PerechenTableController::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() << "PerechenTableController::parseExpression: Части выражения:" << parts;
for (const QString &part : parts) {
QString trimmedPart = part.trimmed();
qDebug() << "PerechenTableController::parseExpression: Обрабатываем часть:" << trimmedPart;
// Если это не пустая строка, добавляем к результату
if (!trimmedPart.isEmpty()) {
QString value;
// Проверяем, является ли это литералом в одинарных кавычках
if (trimmedPart.startsWith("'") && trimmedPart.endsWith("'")) {
// Это литерал - убираем кавычки и используем как есть
value = trimmedPart.mid(1, trimmedPart.length() - 2);
qDebug() << "PerechenTableController::parseExpression: Найден литерал в одинарных кавычках:" << value;
}
// Проверяем, является ли это именем свойства компонента в двойных кавычках
else if (trimmedPart.startsWith("\"") && trimmedPart.endsWith("\"")) {
// Это свойство компонента - убираем кавычки и ищем в свойствах
QString propertyName = trimmedPart.mid(1, trimmedPart.length() - 2);
qDebug() << "PerechenTableController::parseExpression: Ищем свойство компонента:" << propertyName;
if (propertyName == "Designator") {
value = component->designator();
qDebug() << "PerechenTableController::parseExpression: Найдено свойство Designator =" << value;
} else {
// Ищем в свойствах компонента
QMap<QString, QString> props = component->properties();
value = props.value(propertyName, "");
qDebug() << "PerechenTableController::parseExpression: Ищем свойство" << propertyName << "в компоненте, результат:" << value;
// Рекурсивно обрабатываем вложенные выражения
if (value.startsWith("=")) {
qDebug() << "PerechenTableController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
value = parseExpression(component, value);
}
}
}
// Проверяем, является ли это именем свойства компонента без кавычек
else if (trimmedPart == "Designator") {
value = component->designator();
qDebug() << "PerechenTableController::parseExpression: Найдено свойство Designator =" << value;
} else {
// Ищем в свойствах компонента
QMap<QString, QString> props = component->properties();
value = props.value(trimmedPart, "");
qDebug() << "PerechenTableController::parseExpression: Ищем свойство" << trimmedPart << "в компоненте, результат:" << value;
// Рекурсивно обрабатываем вложенные выражения
if (value.startsWith("=")) {
qDebug() << "PerechenTableController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
value = parseExpression(component, value);
}
}
// Добавляем значение к результату
if (!value.isEmpty()) {
if (!result.isEmpty()) {
result += value;
} else {
result = value;
}
qDebug() << "PerechenTableController::parseExpression: Добавили к результату, текущий результат:" << result;
}
}
}
qDebug() << "PerechenTableController::parseExpression: Финальный результат:" << result;
return result;
}
QList<QString> PerechenTableController::splitComplexStringByMiddle(const QString &text, int maxLength)
{
QList<QString> result;
if (text.length() <= maxLength) {
result.append(text);
return result;
}
qDebug() << "PerechenTableController::splitComplexStringByMiddle: Разделяем комплексную строку:" << text;
// Ищем запятые в тексте
QList<int> commaPositions;
for (int i = 0; i < text.length(); ++i) {
if (text[i] == ',') {
commaPositions.append(i);
}
}
if (commaPositions.isEmpty()) {
// Если запятых нет, используем обычное разделение по пробелам
qDebug() << "PerechenTableController::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() << "PerechenTableController::splitComplexStringByMiddle: Найдена запятая на позиции" << bestSplitPos;
qDebug() << "PerechenTableController::splitComplexStringByMiddle: Левая часть:" << leftPart;
qDebug() << "PerechenTableController::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() << "PerechenTableController::splitComplexStringByMiddle: Не удалось найти подходящую запятую, используем splitBySpaces";
result = splitBySpaces(text, maxLength);
}
qDebug() << "PerechenTableController::splitComplexStringByMiddle: Результат:" << result;
return result;
}
QStringList PerechenTableController::collectPropertyNames()
{
QStringList propertyNames;
// Добавляем основные свойства компонента
propertyNames << "Designator";
// Собираем дополнительные свойства из компонентов
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() == 1) { // Только Designator
propertyNames << "Name" << "Type" << "Value" << "Footprint" << "Description";
qDebug() << "PerechenTableController: Дополнительные свойства не найдены, используем стандартные:" << propertyNames;
}
// Добавляем специальное свойство для количества компонентов в группе
propertyNames << "Quantity" << "Кол.";
return propertyNames;
}
void PerechenTableController::setColumnMappings(const QStringList &mappings)
{
qDebug() << "PerechenTableController::setColumnMappings: Устанавливаем новые настройки колонок:" << mappings;
m_columnMappings = mappings;
// Сохраняем настройки в ProjectSettingsModel
if (m_projectSettingsModel) {
for (int i = 0; i < mappings.size(); ++i) {
m_projectSettingsModel->setColumnMapping("Perechen", i, mappings[i]);
}
qDebug() << "PerechenTableController::setColumnMappings: Настройки сохранены в ProjectSettingsModel";
}
// Обновляем настройки в модели
if (m_tableModel) {
m_tableModel->setColumnMappings(mappings);
qDebug() << "PerechenTableController::setColumnMappings: Настройки обновлены в модели";
// Проверяем, что настройки действительно применились
QStringList appliedMappings = m_tableModel->columnMappings();
qDebug() << "PerechenTableController::setColumnMappings: Проверка - настройки в модели:" << appliedMappings;
}
qDebug() << "PerechenTableController::setColumnMappings: Настройки колонок обновлены:" << m_columnMappings;
}
QStringList PerechenTableController::getColumnMappings() const
{
// Если есть ProjectSettingsModel, читаем настройки из него
if (m_projectSettingsModel) {
QStringList settings = m_projectSettingsModel->getColumnMappings("Perechen");
if (!settings.isEmpty()) {
qDebug() << "PerechenTableController::getColumnMappings: Получены настройки из ProjectSettingsModel:" << settings;
return settings;
}
}
// Fallback: возвращаем локальные настройки
qDebug() << "PerechenTableController::getColumnMappings: Возвращаем локальные настройки:" << m_columnMappings;
return m_columnMappings;
}
QStringList PerechenTableController::getAvailableProperties() const
{
QStringList properties = m_propertyNames;
properties.prepend("<Пусто>");
properties.prepend("<Авто>");
return properties;
}
QString PerechenTableController::getComponentType(ComponentModel *component)
{
if (!component) return "";
// Получаем тип компонента из маппинга дезигнаторов
if (m_designatorMappingModel) {
// Сначала пытаемся найти по полному дезигнатору (две буквы)
QString componentType = m_designatorMappingModel->getComponentType(component->designator(), true); // true для множественного числа
if (!componentType.isEmpty()) {
return componentType;
}
// Если не найдено по двум буквам, пытаемся найти по первой букве
QString designator = component->designator();
if (designator.length() >= 1) {
QString firstLetter = designator.left(1);
componentType = m_designatorMappingModel->getComponentType(firstLetter, 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();
}
QPair<QString, QString> PerechenTableController::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 PerechenTableController::addEmptyRow()
{
if (m_tableModel) {
m_tableModel->addEmptyRow();
qDebug() << "PerechenTableController::addEmptyRow: Добавлена пустая строка";
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
// m_tableModel->optimizePageBreaks();
}
}
void PerechenTableController::addEmptyRowAt(int position)
{
if (m_tableModel) {
m_tableModel->addEmptyRowAt(position);
qDebug() << "PerechenTableController::addEmptyRowAt: Добавлена пустая строка в позицию" << position;
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
// m_tableModel->optimizePageBreaks();
}
}
void PerechenTableController::insertEmptyRowAt(int position)
{
if (m_tableModel) {
m_tableModel->addEmptyRowAt(position);
qDebug() << "PerechenTableController::insertEmptyRowAt: Вставлена пустая строка в позицию" << position;
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
// m_tableModel->optimizePageBreaks();
}
}
void PerechenTableController::removeRow(int row)
{
if (m_tableModel) {
m_tableModel->removeRow(row);
qDebug() << "PerechenTableController::removeRow: Удалена строка" << row;
// Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
// m_tableModel->optimizePageBreaks();
}
}
void PerechenTableController::clearTable()
{
if (m_tableModel) {
m_tableModel->clear();
qDebug() << "PerechenTableController::clearTable: Таблица очищена";
}
}
void PerechenTableController::optimizePageBreaks()
{
if (m_tableModel) {
qDebug() << "PerechenTableController::optimizePageBreaks: Оптимизируем разрывы страниц";
m_tableModel->optimizePageBreaks();
}
}
int PerechenTableController::getFontSize() const
{
if (m_projectSettingsModel) {
return m_projectSettingsModel->getFontSize("Perechen");
}
return 12; // По умолчанию
}
void PerechenTableController::setFontSize(int fontSize)
{
if (m_projectSettingsModel) {
m_projectSettingsModel->setFontSize("Perechen", fontSize);
}
}
int PerechenTableController::getFontStretch() const
{
if (m_projectSettingsModel) {
return m_projectSettingsModel->getFontStretch("Perechen");
}
return 100; // По умолчанию (нормальный)
}
void PerechenTableController::setFontStretch(int stretch)
{
if (m_projectSettingsModel) {
m_projectSettingsModel->setFontStretch("Perechen", stretch);
}
}
QList<QString> PerechenTableController::splitLongDesignation(const QString &designation, const QString originalString, ComponentModel *component, int maxLength)
{
QList<QString> result;
if (designation.length() <= maxLength) {
result.append(designation);
return result;
}
qDebug() << "PerechenTableController::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() << "PerechenTableController::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() << "PerechenTableController::splitLongDesignation: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
displayPart = parseExpression(component, displayPart);
}
}
}
fullString += displayPart;
}
}
qDebug() << "PerechenTableController::splitLongDesignation: Собранная полная строка:" << fullString << ", длина:" << fullString.length();
// Проверяем, содержит ли строка запятые (комплексная строка)
bool isComplexString = fullString.contains(',');
if (isComplexString && fullString.length() > maxLength) {
qDebug() << "PerechenTableController::splitLongDesignation: Комплексная строка с запятыми, делим по середине";
// Для комплексной строки делим по середине, а не по началу
result = splitComplexStringByMiddle(fullString, maxLength);
} else if (fullString.length() > maxLength) {
qDebug() << "PerechenTableController::splitLongDesignation: Строка длинная, разделяем по пробелам";
// Обычная длинная строка - разделяем по пробелам
result = splitBySpaces(fullString, maxLength);
} else {
qDebug() << "PerechenTableController::splitLongDesignation: Строка короткая, возвращаем как есть";
result.append(fullString);
}
} else {
// Обычный текст - разделяем по пробелам
result = splitBySpaces(designation, maxLength);
}
qDebug() << "PerechenTableController::splitLongDesignation: Результат разделения:" << result;
return result;
}
QList<QString> PerechenTableController::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;
}