#include "documentprocessor.h" #include "../model/perechentablemodel.h" #include "../model/specificationpcbtablemodel.h" #include "../model/specificationtablemodel.h" #include "../model/vedomosttablemodel.h" #include "../model/pcbmaterialmodel.h" #include "columnsettingsdialog.h" #include "cellsettingsdialog.h" #include "../controller/maincontroller.h" #include #include // Регистрируем метатипы для работы с QVariant // Примечание: SpecificationPCBCellData уже объявлен в specificationpcbtablemodel.h Q_DECLARE_METATYPE(PerechenCellData) Q_DECLARE_METATYPE(SpecificationCellData) Q_DECLARE_METATYPE(VedomostCellData) #include #include #include #include #include #include #include // DocumentProcessor DocumentProcessor::DocumentProcessor(QObject *parent) : QObject(parent) { } // PerechenProcessor PerechenProcessor::PerechenProcessor(QObject *parent) : DocumentProcessor(parent) , m_controller(new PerechenTableController(this)) { } PerechenProcessor::~PerechenProcessor() { // m_controller удалится автоматически, так как он является дочерним объектом } void PerechenProcessor::processComponents(const QList &components) { qDebug() << "PerechenProcessor::processComponents: Получено" << components.size() << "компонентов"; // Передаем компоненты в контроллер if (m_controller) { m_controller->setComponents(components); } } void PerechenProcessor::processProjectParams(const QMap ¶ms) { qDebug() << "PerechenProcessor::processProjectParams: Получено" << params.size() << "параметров"; // Пока не используем параметры проекта для Perechen } QTableView* PerechenProcessor::createTableView() { QTableView *tableView = new QTableView(); if (m_controller) { // НЕ генерируем таблицу автоматически - только отображаем существующую модель qDebug() << "PerechenProcessor::createTableView: Отображаем существующую модель без генерации"; tableView->setModel(m_controller->getTableModel()); // Настройка растягивания столбцов для заполнения всего виджета QHeaderView *horizontalHeader = tableView->horizontalHeader(); // Отключаем автоматическое изменение размера по содержимому horizontalHeader->setStretchLastSection(false); // Устанавливаем режимы для каждого столбца - все интерактивные (изменяемые по ширине) horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Поз.обозначение horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Кол. horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Примечание // Устанавливаем начальные размеры для столбцов horizontalHeader->resizeSection(0, 100); // Поз.обозначение - 100px horizontalHeader->resizeSection(1, 200); // Наименование - 200px horizontalHeader->resizeSection(2, 60); // Кол. - 60px horizontalHeader->resizeSection(3, 150); // Примечание - 150px // Настройка вертикального заголовка QHeaderView *verticalHeader = tableView->verticalHeader(); verticalHeader->setDefaultSectionSize(25); // Устанавливаем высоту строки verticalHeader->setSectionResizeMode(QHeaderView::Fixed); // Принудительно обновляем размеры столбцов //horizontalHeader->resizeSections(); qDebug() << "PerechenProcessor::createTableView: Настроено растягивание столбцов"; } else { // Если контроллер не установлен, создаем временную модель для корректной настройки заголовков QStandardItemModel *tempModel = new QStandardItemModel(tableView); QStringList headers; headers << "Поз.обозначение" << "Наименование" << "Кол." << "Примечание"; tempModel->setHorizontalHeaderLabels(headers); // Устанавливаем временную модель для корректной настройки заголовков tableView->setModel(tempModel); // Настройка растягивания столбцов для заполнения всего виджета QHeaderView *horizontalHeader = tableView->horizontalHeader(); // Отключаем автоматическое изменение размера по содержимому horizontalHeader->setStretchLastSection(false); // Устанавливаем режимы для каждого столбца - все интерактивные (изменяемые по ширине) horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Поз.обозначение horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Кол. horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Примечание // Устанавливаем начальные размеры для столбцов horizontalHeader->resizeSection(0, 100); // Поз.обозначение - 100px horizontalHeader->resizeSection(1, 200); // Наименование - 200px horizontalHeader->resizeSection(2, 60); // Кол. - 60px horizontalHeader->resizeSection(3, 150); // Примечание - 150px // Настройка вертикального заголовка QHeaderView *verticalHeader = tableView->verticalHeader(); verticalHeader->setDefaultSectionSize(25); // Устанавливаем высоту строки verticalHeader->setSectionResizeMode(QHeaderView::Fixed); qDebug() << "PerechenProcessor::createTableView: Создана временная модель для настройки заголовков"; } return tableView; } void PerechenProcessor::setColumnMappings(const QStringList &mappings) { if (m_controller) { m_controller->setColumnMappings(mappings); } } QStringList PerechenProcessor::getColumnMappings() const { if (m_controller) { return m_controller->getColumnMappings(); } return QStringList(); } QStringList PerechenProcessor::getAvailableProperties() const { if (m_controller) { return m_controller->getAvailableProperties(); } return QStringList(); } void PerechenProcessor::updateTable() { qDebug() << "PerechenProcessor::updateTable: Обновляем таблицу по кнопке"; if (m_controller) { m_controller->updateTableFromComponents(); } } void PerechenProcessor::setController(PerechenTableController *controller) { if (m_controller != controller) { qDebug() << "PerechenProcessor::setController: Заменяем контроллер"; m_controller = controller; } } void PerechenProcessor::setModel(PerechenTableModel *model) { if (m_controller && model) { qDebug() << "PerechenProcessor::setModel: Устанавливаем модель в контроллер"; m_controller->setModel(model); } } // SpecificationProcessor SpecificationProcessor::SpecificationProcessor(QObject *parent) : DocumentProcessor(parent) , m_controller(new SpecificationController(this)) { } void SpecificationProcessor::processComponents(const QList &components) { qDebug() << "SpecificationProcessor::processComponents: Получено" << components.size() << "компонентов"; // Для спецификации материалов компоненты не используются } void SpecificationProcessor::processProjectParams(const QMap ¶ms) { qDebug() << "SpecificationProcessor::processProjectParams: Получено" << params.size() << "параметров"; // Пока не используем параметры проекта для Specification } QTableView* SpecificationProcessor::createTableView() { QTableView *tableView = new QTableView(); if (m_controller) { // НЕ генерируем таблицу автоматически - только отображаем существующую модель qDebug() << "SpecificationProcessor::createTableView: Отображаем существующую модель без генерации"; tableView->setModel(m_controller->getTableModel()); // Настройка растягивания столбцов для заполнения всего виджета QHeaderView *horizontalHeader = tableView->horizontalHeader(); // Отключаем автоматическое изменение размера по содержимому horizontalHeader->setStretchLastSection(false); // Устанавливаем режимы для каждого столбца - все интерактивные (изменяемые по ширине) horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Формат horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Зона horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Поз. horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Обозначение horizontalHeader->setSectionResizeMode(4, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(5, QHeaderView::Interactive); // Кол. horizontalHeader->setSectionResizeMode(6, QHeaderView::Interactive); // Примечание // Устанавливаем начальные размеры для столбцов horizontalHeader->resizeSection(0, 60); // Формат - 60px horizontalHeader->resizeSection(1, 50); // Зона - 50px horizontalHeader->resizeSection(2, 80); // Поз. - 80px horizontalHeader->resizeSection(3, 150); // Обозначение - 150px horizontalHeader->resizeSection(4, 200); // Наименование - 200px horizontalHeader->resizeSection(5, 60); // Кол. - 60px horizontalHeader->resizeSection(6, 150); // Примечание - 150px // Столбец 4 (Наименование) в режиме Stretch займет оставшееся пространство // Настройка вертикального заголовка QHeaderView *verticalHeader = tableView->verticalHeader(); verticalHeader->setDefaultSectionSize(25); // Устанавливаем высоту строки verticalHeader->setSectionResizeMode(QHeaderView::Fixed); qDebug() << "SpecificationProcessor::createTableView: Настроено растягивание столбцов"; } else { // Если контроллер не установлен, создаем временную модель для корректной настройки заголовков QStandardItemModel *tempModel = new QStandardItemModel(tableView); QStringList headers; headers << "Формат" << "Зона" << "Позиция" << "Обозначение" << "Наименование" << "Кол." << "Примечание"; tempModel->setHorizontalHeaderLabels(headers); // Устанавливаем временную модель для корректной настройки заголовков tableView->setModel(tempModel); // Настройка растягивания столбцов для заполнения всего виджета QHeaderView *horizontalHeader = tableView->horizontalHeader(); // Отключаем автоматическое изменение размера по содержимому horizontalHeader->setStretchLastSection(false); // Устанавливаем режимы для каждого столбца - все интерактивные (изменяемые по ширине) horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Формат horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Зона horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Позиция horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Обозначение horizontalHeader->setSectionResizeMode(4, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(5, QHeaderView::Interactive); // Кол. horizontalHeader->setSectionResizeMode(6, QHeaderView::Interactive); // Примечание // Устанавливаем начальные размеры для столбцов horizontalHeader->resizeSection(0, 60); // Формат - 60px horizontalHeader->resizeSection(1, 50); // Зона - 50px horizontalHeader->resizeSection(2, 80); // Позиция - 80px horizontalHeader->resizeSection(3, 120); // Обозначение - 120px horizontalHeader->resizeSection(4, 200); // Наименование - 200px horizontalHeader->resizeSection(5, 60); // Кол. - 60px horizontalHeader->resizeSection(6, 150); // Примечание - 150px qDebug() << "SpecificationProcessor::createTableView: Создана временная модель для настройки заголовков"; } return tableView; } void SpecificationProcessor::setColumnMappings(const QStringList &mappings) { if (m_controller) { m_controller->setColumnMappings(mappings); } } QStringList SpecificationProcessor::getColumnMappings() const { if (m_controller) { return m_controller->getColumnMappings(); } return QStringList(); } QStringList SpecificationProcessor::getAvailableProperties() const { if (m_controller) { return m_controller->getAvailableProperties(); } return QStringList(); } void SpecificationProcessor::updateTable() { if (m_controller) { m_controller->updateTableFromMaterials(); } } void SpecificationProcessor::setController(SpecificationController *controller) { if (m_controller != controller) { m_controller = controller; qDebug() << "SpecificationProcessor::setController: Контроллер заменен"; } } void SpecificationProcessor::setModel(SpecificationTableModel *model) { if (m_controller) { m_controller->setModel(model); } } // SpecificationPCBProcessor SpecificationPCBProcessor::SpecificationPCBProcessor(QObject *parent) : DocumentProcessor(parent) , m_controller(nullptr) { } SpecificationPCBProcessor::~SpecificationPCBProcessor() { // m_controller удалится автоматически, так как он является дочерним объектом } void SpecificationPCBProcessor::processComponents(const QList &components) { qDebug() << "SpecificationPCBProcessor::processComponents: Получено" << components.size() << "компонентов"; // Компоненты будут обрабатываться через главный контроллер } void SpecificationPCBProcessor::processProjectParams(const QMap ¶ms) { qDebug() << "SpecificationPCBProcessor::processProjectParams: Получено" << params.size() << "параметров"; // Пока не используем параметры проекта для SpecificationPCB } QTableView* SpecificationPCBProcessor::createTableView() { QTableView *tableView = new QTableView(); qDebug() << "SpecificationPCBProcessor::createTableView: Контроллер доступен:" << (m_controller ? "да" : "нет"); if (m_controller) { qDebug() << "SpecificationPCBProcessor::createTableView: Модель в контроллере доступна:" << (m_controller->getTableModel() ? "да" : "нет"); if (m_controller->getTableModel()) { qDebug() << "SpecificationPCBProcessor::createTableView: Количество строк в модели:" << m_controller->getTableModel()->rowCount(); qDebug() << "SpecificationPCBProcessor::createTableView: Количество колонок в модели:" << m_controller->getTableModel()->columnCount(); } } // Если контроллер доступен, используем его модель if (m_controller && m_controller->getTableModel()) { tableView->setModel(m_controller->getTableModel()); qDebug() << "SpecificationPCBProcessor::createTableView: Используем модель из контроллера"; } else { // Создаем временную модель с 7 столбцами для корректной настройки заголовков QStandardItemModel *tempModel = new QStandardItemModel(tableView); QStringList headers; headers << "Формат" << "Зона" << "Поз." << "Обозначение" << "Наименование" << "Кол." << "Примечание"; tempModel->setHorizontalHeaderLabels(headers); // Устанавливаем временную модель для корректной настройки заголовков tableView->setModel(tempModel); qDebug() << "SpecificationPCBProcessor::createTableView: Создана временная модель для настройки заголовков"; } // Настройка растягивания столбцов для заполнения всего виджета QHeaderView *horizontalHeader = tableView->horizontalHeader(); // Отключаем автоматическое изменение размера по содержимому horizontalHeader->setStretchLastSection(false); // Устанавливаем режимы для каждого столбца - все интерактивные (изменяемые по ширине) horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Формат horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Зона horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Поз. horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Обозначение horizontalHeader->setSectionResizeMode(4, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(5, QHeaderView::Interactive); // Кол. horizontalHeader->setSectionResizeMode(6, QHeaderView::Interactive); // Примечание // Устанавливаем начальные размеры для столбцов horizontalHeader->resizeSection(0, 60); // Формат - 60px horizontalHeader->resizeSection(1, 50); // Зона - 50px horizontalHeader->resizeSection(2, 80); // Поз. - 80px horizontalHeader->resizeSection(3, 150); // Обозначение - 150px horizontalHeader->resizeSection(4, 200); // Наименование - 200px horizontalHeader->resizeSection(5, 60); // Кол. - 60px horizontalHeader->resizeSection(6, 150); // Примечание - 150px // Настройка вертикального заголовка QHeaderView *verticalHeader = tableView->verticalHeader(); verticalHeader->setDefaultSectionSize(25); // Устанавливаем высоту строки verticalHeader->setSectionResizeMode(QHeaderView::Fixed); qDebug() << "SpecificationPCBProcessor::createTableView: Настроено растягивание столбцов"; return tableView; } void SpecificationPCBProcessor::setColumnMappings(const QStringList &mappings) { qDebug() << "SpecificationPCBProcessor::setColumnMappings: Настройки колонок обновлены:" << mappings; } QStringList SpecificationPCBProcessor::getColumnMappings() const { return QStringList(); } QStringList SpecificationPCBProcessor::getAvailableProperties() const { return QStringList(); } void SpecificationPCBProcessor::updateTable() { qDebug() << "SpecificationPCBProcessor::updateTable: Обновляем таблицу по кнопке"; } void SpecificationPCBProcessor::setController(SpecificationPCBController *controller) { qDebug() << "SpecificationPCBProcessor::setController: Устанавливаем контроллер"; m_controller = controller; if (m_controller) { qDebug() << "SpecificationPCBProcessor::setController: Контроллер установлен"; } else { qDebug() << "SpecificationPCBProcessor::setController: Контроллер сброшен"; } } void SpecificationPCBProcessor::setModel(SpecificationPCBTableModel *model) { qDebug() << "SpecificationPCBProcessor::setModel: Модель установлена в контроллер"; if (m_controller) { m_controller->setModel(model); qDebug() << "SpecificationPCBProcessor::setModel: Модель передана в контроллер"; } else { qDebug() << "SpecificationPCBProcessor::setModel: Контроллер недоступен"; } } // VedomostProcessor VedomostProcessor::VedomostProcessor(QObject *parent) : DocumentProcessor(parent) , m_controller(nullptr) { } VedomostProcessor::~VedomostProcessor() { // m_controller удалится автоматически, так как он является дочерним объектом } void VedomostProcessor::processComponents(const QList &components) { qDebug() << "VedomostProcessor::processComponents: Получено" << components.size() << "компонентов"; // Только передаем компоненты в контроллер, но не генерируем таблицу if (m_controller) { m_controller->setComponents(components); qDebug() << "VedomostProcessor::processComponents: Компоненты переданы в контроллер"; } else { qDebug() << "VedomostProcessor::processComponents: Контроллер недоступен"; } } void VedomostProcessor::processProjectParams(const QMap ¶ms) { qDebug() << "VedomostProcessor::processProjectParams: Получено" << params.size() << "параметров"; // Пока не используем параметры проекта для Vedomost } QTableView* VedomostProcessor::createTableView() { QTableView *tableView = new QTableView(); qDebug() << "VedomostProcessor::createTableView: Контроллер доступен:" << (m_controller ? "да" : "нет"); if (m_controller) { qDebug() << "VedomostProcessor::createTableView: Модель в контроллере доступна:" << (m_controller->getTableModel() ? "да" : "нет"); if (m_controller->getTableModel()) { qDebug() << "VedomostProcessor::createTableView: Количество строк в модели:" << m_controller->getTableModel()->rowCount(); qDebug() << "VedomostProcessor::createTableView: Количество колонок в модели:" << m_controller->getTableModel()->columnCount(); } } // Если контроллер доступен, используем его модель if (m_controller && m_controller->getTableModel()) { tableView->setModel(m_controller->getTableModel()); qDebug() << "VedomostProcessor::createTableView: Используем модель из контроллера"; } else { // Создаем временную модель с 10 столбцами для корректной настройки заголовков QStandardItemModel *tempModel = new QStandardItemModel(tableView); QStringList headers; headers << "Наименование" << "Код продукции" << "Обозначение документа на поставку" << "Поставщик" << "Куда входит (обозначение)" << "Количество на изделие" << "Количество в комплекте" << "Количество на регулир" << "Количество всего" << "Примечание"; tempModel->setHorizontalHeaderLabels(headers); // Устанавливаем временную модель для корректной настройки заголовков tableView->setModel(tempModel); qDebug() << "VedomostProcessor::createTableView: Создана временная модель для настройки заголовков"; } // Настройка растягивания столбцов для заполнения всего виджета QHeaderView *horizontalHeader = tableView->horizontalHeader(); // Отключаем автоматическое изменение размера по содержимому horizontalHeader->setStretchLastSection(false); // Устанавливаем режимы для каждого столбца - все интерактивные (изменяемые по ширине) horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Код продукции horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Обозначение документа на поставку horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Поставщик horizontalHeader->setSectionResizeMode(4, QHeaderView::Interactive); // Куда входит (обозначение) horizontalHeader->setSectionResizeMode(5, QHeaderView::Interactive); // Количество на изделие horizontalHeader->setSectionResizeMode(6, QHeaderView::Interactive); // Количество в комплекте horizontalHeader->setSectionResizeMode(7, QHeaderView::Interactive); // Количество на регулир horizontalHeader->setSectionResizeMode(8, QHeaderView::Interactive); // Количество всего horizontalHeader->setSectionResizeMode(9, QHeaderView::Interactive); // Примечание // Устанавливаем начальные размеры для столбцов horizontalHeader->resizeSection(0, 200); // Наименование - 200px horizontalHeader->resizeSection(1, 120); // Код продукции - 120px horizontalHeader->resizeSection(2, 150); // Обозначение документа на поставку - 150px horizontalHeader->resizeSection(3, 100); // Поставщик - 100px horizontalHeader->resizeSection(4, 120); // Куда входит (обозначение) - 120px horizontalHeader->resizeSection(5, 100); // Количество на изделие - 100px horizontalHeader->resizeSection(6, 100); // Количество в комплекте - 100px horizontalHeader->resizeSection(7, 100); // Количество на регулир - 100px horizontalHeader->resizeSection(8, 100); // Количество всего - 100px horizontalHeader->resizeSection(9, 150); // Примечание - 150px // Настройка вертикального заголовка QHeaderView *verticalHeader = tableView->verticalHeader(); verticalHeader->setDefaultSectionSize(25); // Устанавливаем высоту строки verticalHeader->setSectionResizeMode(QHeaderView::Fixed); qDebug() << "VedomostProcessor::createTableView: Настроено растягивание столбцов"; return tableView; } void VedomostProcessor::setColumnMappings(const QStringList &mappings) { qDebug() << "VedomostProcessor::setColumnMappings: Настройки колонок обновлены:" << mappings; if (m_controller) { m_controller->setColumnMappings(mappings); qDebug() << "VedomostProcessor::setColumnMappings: Настройки переданы в контроллер"; } else { qDebug() << "VedomostProcessor::setColumnMappings: Контроллер недоступен"; } } QStringList VedomostProcessor::getColumnMappings() const { if (m_controller) { return m_controller->getColumnMappings(); } return QStringList(); } QStringList VedomostProcessor::getAvailableProperties() const { if (m_controller) { return m_controller->getAvailableProperties(); } return QStringList(); } void VedomostProcessor::updateTable() { qDebug() << "VedomostProcessor::updateTable: Обновляем таблицу по кнопке"; if (m_controller) { m_controller->updateTableFromComponents(); qDebug() << "VedomostProcessor::updateTable: Таблица обновлена через контроллер"; } else { qDebug() << "VedomostProcessor::updateTable: Контроллер недоступен"; } } void VedomostProcessor::setController(VedomostController *controller) { qDebug() << "VedomostProcessor::setController: Устанавливаем контроллер"; m_controller = controller; if (m_controller) { qDebug() << "VedomostProcessor::setController: Контроллер установлен"; } else { qDebug() << "VedomostProcessor::setController: Контроллер сброшен"; } } void VedomostProcessor::setModel(VedomostTableModel *model) { qDebug() << "VedomostProcessor::setModel: Модель установлена в контроллер"; if (m_controller) { m_controller->setModel(model); qDebug() << "VedomostProcessor::setModel: Модель передана в контроллер"; } else { qDebug() << "VedomostProcessor::setModel: Контроллер недоступен"; } } // DocumentEditWidget DocumentEditWidget::DocumentEditWidget(DocumentProcessor *processor, QWidget *parent) : QWidget(parent) , m_processor(processor) , m_componentModel(nullptr) , m_projectParamModel(nullptr) , m_controller(nullptr) , m_titleInscriptionsModel(nullptr) { qDebug() << "DocumentEditWidget: Конструктор без контроллера, processor:" << (processor ? "доступен" : "nullptr"); setUp(); } DocumentEditWidget::DocumentEditWidget(DocumentProcessor *processor, MainController *controller, QWidget *parent) : QWidget(parent) , m_processor(processor) , m_componentModel(nullptr) , m_projectParamModel(nullptr) , m_controller(controller) , m_titleInscriptionsModel(nullptr) { qDebug() << "DocumentEditWidget: Конструктор с контроллером, processor:" << (processor ? "доступен" : "nullptr") << "controller:" << (controller ? "доступен" : "nullptr"); setUp(); } void DocumentEditWidget::setUp() { qDebug() << "DocumentEditWidget::setUp: Начинаем настройку виджета"; setWidgets(); setUpLayout(); setUpConnections(); // Инициализируем состояние кнопок m_insertRowButton->setEnabled(false); // Кнопка вставки неактивна по умолчанию m_removeRowButton->setEnabled(false); // Кнопка удаления неактивна по умолчанию // Применяем настройки растягивания столбцов к пустой таблице applyColumnStretching(); qDebug() << "DocumentEditWidget::setUp: Настройка виджета завершена"; } void DocumentEditWidget::setWidgets() { qDebug() << "DocumentEditWidget::setWidgets: Создаем виджеты"; m_openSettingsButton = new QPushButton("Настройки документа", this); m_generateTableButton = new QPushButton("Генерация таблицы", this); m_recalculateTableButton = new QPushButton("Пересчет таблицы", this); // Новые кнопки для управления строками m_addRowButton = new QPushButton("+ Добавить строку", this); m_insertRowButton = new QPushButton("+ Вставить строку", this); m_removeRowButton = new QPushButton("- Удалить строку", this); m_tableView = new QTableView(this); // Настраиваем таблицу для растягивания на весь виджет m_tableView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_tableView->horizontalHeader()->setStretchLastSection(false); // Включаем контекстное меню m_tableView->setContextMenuPolicy(Qt::CustomContextMenu); // Устанавливаем режим множественного выбора строк m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows); m_tableView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_settingsGroupBox = new QGroupBox("Настройки", this); qDebug() << "DocumentEditWidget::setWidgets: Виджеты созданы"; } void DocumentEditWidget::setUpLayout() { qDebug() << "DocumentEditWidget::setUpLayout: Настраиваем компоновку"; // Настраиваем политику размера для всего виджета setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QVBoxLayout* mainLayout = new QVBoxLayout(this); // Группа настроек QHBoxLayout* groupBoxLayout = new QHBoxLayout(m_settingsGroupBox); // Левая группа кнопок groupBoxLayout->addWidget(m_openSettingsButton); // Растягивающийся элемент для разделения groupBoxLayout->addStretch(); // Средняя группа кнопок для управления строками groupBoxLayout->addWidget(m_addRowButton); groupBoxLayout->addWidget(m_insertRowButton); groupBoxLayout->addWidget(m_removeRowButton); // Растягивающийся элемент для разделения groupBoxLayout->addStretch(); // Правая группа кнопок groupBoxLayout->addWidget(m_generateTableButton); groupBoxLayout->addWidget(m_recalculateTableButton); mainLayout->addWidget(m_settingsGroupBox); mainLayout->addWidget(m_tableView, 1); // Растягиваем таблицу на все доступное пространство qDebug() << "DocumentEditWidget::setUpLayout: Компоновка настроена"; } void DocumentEditWidget::setUpConnections() { qDebug() << "DocumentEditWidget::setUpConnections: Настраиваем соединения сигналов"; connect(m_generateTableButton, &QPushButton::clicked, this, &DocumentEditWidget::onGenerateTable); connect(m_recalculateTableButton, &QPushButton::clicked, this, &DocumentEditWidget::onRecalculateTable); connect(m_openSettingsButton, &QPushButton::clicked, this, &DocumentEditWidget::onOpenColumnSettings); // Соединения для новых кнопок управления строками connect(m_addRowButton, &QPushButton::clicked, this, &DocumentEditWidget::onAddRow); connect(m_insertRowButton, &QPushButton::clicked, this, &DocumentEditWidget::onInsertRow); connect(m_removeRowButton, &QPushButton::clicked, this, &DocumentEditWidget::onRemoveRow); // Соединение для контекстного меню connect(m_tableView, &QTableView::customContextMenuRequested, this, &DocumentEditWidget::onContextMenuRequested); // Соединение для обновления состояния кнопок при изменении выбора // Будем устанавливать это соединение после того, как таблица получит модель // connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged, // this, &DocumentEditWidget::onSelectionChanged); qDebug() << "DocumentEditWidget::setUpConnections: Соединения сигналов настроены"; } void DocumentEditWidget::onOpenColumnSettings() { qDebug() << "DocumentEditWidget::onOpenColumnSettings: Нажата кнопка настроек колонок"; // Определяем тип документа DocumentType docType = DocumentType::Perechen; // По умолчанию if (qobject_cast(m_processor)) { docType = DocumentType::Perechen; } else if (qobject_cast(m_processor)) { docType = DocumentType::SpecificationPCB; } else if (qobject_cast(m_processor)) { docType = DocumentType::Specification; } else if (qobject_cast(m_processor)) { docType = DocumentType::Vedomost; } else { qDebug() << "DocumentEditWidget::onOpenColumnSettings: Процессор не поддерживает настройки"; return; } // Создаем универсальный диалог настроек DocumentSettingsDialog dialog(docType, m_controller, this); if (dialog.exec() == QDialog::Accepted) { QStringList newTableMappings = dialog.getTableColumnMappings(); QMap newInscriptionValues = dialog.getTitleInscriptionValues(); qDebug() << "DocumentEditWidget::onOpenColumnSettings: Получены настройки таблицы:" << newTableMappings; qDebug() << "DocumentEditWidget::onOpenColumnSettings: Получены настройки надписей:" << newInscriptionValues; // Настройки таблицы и надписей уже сохранены в диалоге qDebug() << "DocumentEditWidget::onOpenColumnSettings: Настройки обновлены, но таблица не генерируется автоматически"; } else { qDebug() << "DocumentEditWidget::onOpenColumnSettings: Диалог настроек отменен"; } } void DocumentEditWidget::onGenerateTable() { qDebug() << "DocumentEditWidget::onGenerateTable: Нажата кнопка генерации таблицы"; // Проверяем, является ли процессор PerechenProcessor PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor) { if (m_controller && m_controller->perechenTableController()) { qDebug() << "DocumentEditWidget::onGenerateTable: Генерируем таблицу через PerechenTableController"; m_controller->perechenTableController()->generateTableFromComponents(); // Устанавливаем модель из контроллера if (m_controller->perechenTableModel()) { m_tableView->setModel(m_controller->perechenTableModel()); applyColumnStretching(); setupSelectionConnection(); qDebug() << "DocumentEditWidget::onGenerateTable: Модель PerechenTableModel установлена"; } } else { qDebug() << "DocumentEditWidget::onGenerateTable: PerechenTableController недоступен"; } } else { // Проверяем, является ли процессор SpecificationPCBProcessor SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor) { if (m_controller && m_controller->specificationPCBController()) { qDebug() << "DocumentEditWidget::onGenerateTable: Генерируем таблицу через SpecificationPCBController"; qDebug() << "DocumentEditWidget::onGenerateTable: Компонентов в модели:" << m_componentModel->getComponents().size(); // Передаем компоненты в контроллер m_controller->specificationPCBController()->setComponents(m_componentModel->getComponents()); m_controller->specificationPCBController()->generateTableFromComponents(); // Устанавливаем модель из контроллера if (m_controller->specificationPCBTableModel()) { m_tableView->setModel(m_controller->specificationPCBTableModel()); applyColumnStretching(); setupSelectionConnection(); qDebug() << "DocumentEditWidget::onGenerateTable: Модель SpecificationPCBTableModel установлена"; qDebug() << "DocumentEditWidget::onGenerateTable: Количество строк в модели:" << m_controller->specificationPCBTableModel()->rowCount(); } } else { qDebug() << "DocumentEditWidget::onGenerateTable: SpecificationPCBController недоступен"; } } else { // Проверяем, является ли процессор SpecificationProcessor SpecificationProcessor *specProcessor = qobject_cast(m_processor); if (specProcessor) { if (m_controller && m_controller->specificationController()) { qDebug() << "DocumentEditWidget::onGenerateTable: Генерируем таблицу через SpecificationController"; // Получаем PCB модель материалов PCBMaterialModel* pcbMaterialModel = m_controller->pcbMaterialModel(); if (pcbMaterialModel) { qDebug() << "DocumentEditWidget::onGenerateTable: PCB модель материалов доступна, материалов:" << pcbMaterialModel->getMaterialCount(); // Передаем PCB модель в контроллер m_controller->specificationController()->setPCBMaterialModel(pcbMaterialModel); } else { qDebug() << "DocumentEditWidget::onGenerateTable: PCB модель материалов недоступна"; // Передаем nullptr m_controller->specificationController()->setPCBMaterialModel(nullptr); } m_controller->specificationController()->generateTableFromMaterials(); // Устанавливаем модель из контроллера if (m_controller->specificationTableModel()) { m_tableView->setModel(m_controller->specificationTableModel()); applyColumnStretching(); setupSelectionConnection(); qDebug() << "DocumentEditWidget::onGenerateTable: Модель SpecificationTableModel установлена"; qDebug() << "DocumentEditWidget::onGenerateTable: Количество строк в модели:" << m_controller->specificationTableModel()->rowCount(); } } else { qDebug() << "DocumentEditWidget::onGenerateTable: SpecificationController недоступен"; } } else { // Проверяем, является ли процессор VedomostProcessor VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor) { if (m_controller && m_controller->vedomostController()) { qDebug() << "DocumentEditWidget::onGenerateTable: Генерируем таблицу через VedomostController"; qDebug() << "DocumentEditWidget::onGenerateTable: Компонентов в модели:" << m_componentModel->getComponents().size(); // Передаем компоненты в контроллер m_controller->vedomostController()->setComponents(m_componentModel->getComponents()); m_controller->vedomostController()->generateTableFromComponents(); // Устанавливаем модель из контроллера if (m_controller->vedomostTableModel()) { m_tableView->setModel(m_controller->vedomostTableModel()); applyColumnStretching(); setupSelectionConnection(); qDebug() << "DocumentEditWidget::onGenerateTable: Модель VedomostTableModel установлена"; qDebug() << "DocumentEditWidget::onGenerateTable: Количество строк в модели:" << m_controller->vedomostTableModel()->rowCount(); } } else { qDebug() << "DocumentEditWidget::onGenerateTable: VedomostController недоступен"; } } else { qDebug() << "DocumentEditWidget::onGenerateTable: Процессор не является PerechenProcessor, SpecificationPCBProcessor, SpecificationProcessor или VedomostProcessor"; } } } } } void DocumentEditWidget::onRecalculateTable() { qDebug() << "DocumentEditWidget::onRecalculateTable: Нажата кнопка пересчета таблицы"; // Проверяем, является ли процессор PerechenProcessor PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor) { if (m_controller && m_controller->perechenTableModel()) { qDebug() << "DocumentEditWidget::onRecalculateTable: Пересчитываем таблицу PerechenTableModel"; PerechenTableModel *model = m_controller->perechenTableModel(); model->updateRowNumbers(); model->updatePageNumbers(); // updatePageNumbers уже уведомляет об изменениях qDebug() << "DocumentEditWidget::onRecalculateTable: Пересчет PerechenTableModel завершен"; } else { qDebug() << "DocumentEditWidget::onRecalculateTable: PerechenTableModel недоступна"; } return; } // Проверяем, является ли процессор SpecificationPCBProcessor SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor) { if (m_controller && m_controller->specificationPCBTableModel()) { qDebug() << "DocumentEditWidget::onRecalculateTable: Пересчитываем таблицу SpecificationPCBTableModel"; SpecificationPCBTableModel *model = m_controller->specificationPCBTableModel(); model->updateRowNumbers(); model->updatePageNumbers(); // updatePageNumbers уже уведомляет об изменениях // Вызываем optimizePageBreaks через контроллер, который также пересчитывает позиции if (m_controller->specificationPCBController()) { qDebug() << "DocumentEditWidget::onRecalculateTable: Вызываем optimizePageBreaks для пересчета позиций"; m_controller->specificationPCBController()->optimizePageBreaks(); } qDebug() << "DocumentEditWidget::onRecalculateTable: Пересчет SpecificationPCBTableModel завершен"; } else { qDebug() << "DocumentEditWidget::onRecalculateTable: SpecificationPCBTableModel недоступна"; } return; } // Проверяем, является ли процессор SpecificationProcessor SpecificationProcessor *specProcessor = qobject_cast(m_processor); if (specProcessor) { if (m_controller && m_controller->specificationTableModel()) { qDebug() << "DocumentEditWidget::onRecalculateTable: Пересчитываем таблицу SpecificationTableModel"; SpecificationTableModel *model = m_controller->specificationTableModel(); model->updateRowNumbers(); model->updatePageNumbers(); // updatePageNumbers уже уведомляет об изменениях qDebug() << "DocumentEditWidget::onRecalculateTable: Пересчет SpecificationTableModel завершен"; } else { qDebug() << "DocumentEditWidget::onRecalculateTable: SpecificationTableModel недоступна"; } return; } // Проверяем, является ли процессор VedomostProcessor VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor) { if (m_controller && m_controller->vedomostTableModel()) { qDebug() << "DocumentEditWidget::onRecalculateTable: Пересчитываем таблицу VedomostTableModel"; VedomostTableModel *model = m_controller->vedomostTableModel(); model->updateRowNumbers(); model->updatePageNumbers(); // Пересчитываем totalQuantity для всех строк // updateTotalQuantity уже уведомляет об изменениях через emit dataChanged for (int row = 0; row < model->rowCount(); ++row) { model->updateTotalQuantity(row); } qDebug() << "DocumentEditWidget::onRecalculateTable: Пересчет VedomostTableModel завершен"; } else { qDebug() << "DocumentEditWidget::onRecalculateTable: VedomostTableModel недоступна"; } return; } qDebug() << "DocumentEditWidget::onRecalculateTable: Процессор не является PerechenProcessor, SpecificationPCBProcessor, SpecificationProcessor или VedomostProcessor"; } void DocumentEditWidget::setData(ComponentTableModel *componentModel, ProjectParamTableModel *projectParamModel) { qDebug() << "DocumentEditWidget::setData: Устанавливаем данные, componentModel:" << (componentModel ? "доступен" : "nullptr") << "projectParamModel:" << (projectParamModel ? "доступен" : "nullptr"); m_componentModel = componentModel; m_projectParamModel = projectParamModel; // Передаем DesignatorMappingModel в PerechenTableController, если это PerechenProcessor PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor && m_controller) { // Получаем контроллер из PerechenProcessor PerechenTableController *perecheController = perechenProcessor->getController(); if (perecheController) { // Передаем модель маппинга дезигнаторов perecheController->setDesignatorMappingModel(m_controller->designatorMappingModel()); qDebug() << "DocumentEditWidget::setData: DesignatorMappingModel передан в PerechenTableController"; } } // Передаем DesignatorMappingModel в SpecificationPCBController, если это SpecificationPCBProcessor SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor && m_controller) { // Получаем контроллер из SpecificationPCBProcessor SpecificationPCBController *specPCBController = specPCBProcessor->getController(); if (specPCBController) { // Передаем модель маппинга дезигнаторов specPCBController->setDesignatorMappingModel(m_controller->designatorMappingModel()); qDebug() << "DocumentEditWidget::setData: DesignatorMappingModel передан в SpecificationPCBController"; } } // Передаем DesignatorMappingModel в VedomostController, если это VedomostProcessor VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor && m_controller) { // Получаем контроллер из VedomostProcessor VedomostController *vedomostController = vedomostProcessor->getController(); if (vedomostController) { // Передаем модель маппинга дезигнаторов vedomostController->setDesignatorMappingModel(m_controller->designatorMappingModel()); qDebug() << "DocumentEditWidget::setData: DesignatorMappingModel передан в VedomostController"; } } // Не вызываем updateView() автоматически - таблица будет генерироваться только по нажатию кнопки qDebug() << "DocumentEditWidget::setData: Данные установлены"; } void DocumentEditWidget::updateView() { //qDebug() << "DocumentEditWidget::updateView: Начинаем обновление представления для типа документа:" << m_processor->getDocumentType(); if (!m_processor || !m_componentModel || !m_projectParamModel) { qDebug() << "DocumentEditWidget::updateView: Один из указателей null - processor:" << (m_processor ? "доступен" : "nullptr") << "componentModel:" << (m_componentModel ? "доступен" : "nullptr") << "projectParamModel:" << (m_projectParamModel ? "доступен" : "nullptr"); return; } qDebug() << "DocumentEditWidget::updateView: Компонентов в модели:" << m_componentModel->getComponents().size(); // Проверяем, является ли процессор VedomostProcessor VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor) { // Для ведомости только передаем компоненты в контроллер, но не генерируем таблицу qDebug() << "DocumentEditWidget::updateView: VedomostProcessor - только передаем компоненты в контроллер"; if (vedomostProcessor->getController()) { vedomostProcessor->getController()->setComponents(m_componentModel->getComponents()); } } else { // Для других процессоров обрабатываем данные и генерируем таблицу m_processor->processComponents(m_componentModel->getComponents()); m_processor->processProjectParams(m_projectParamModel->getDataAsMap()); } // Создаем новую таблицу QTableView *newTableView = m_processor->createTableView(); if (!newTableView || !newTableView->model()) { qDebug() << "DocumentEditWidget::updateView: Не удалось создать таблицу или модель"; delete newTableView; return; } // Безопасно заменяем модель QAbstractItemModel *oldModel = m_tableView->model(); m_tableView->setModel(newTableView->model()); // Удаляем старую модель только после успешной установки новой if (oldModel && oldModel != newTableView->model()) { oldModel->deleteLater(); } // Удаляем временную таблицу, но не её модель delete newTableView; // Применяем настройки растягивания столбцов к основной таблице applyColumnStretching(); // Устанавливаем соединение для сигнала selectionChanged после установки модели setupSelectionConnection(); qDebug() << "DocumentEditWidget::updateView: Таблица обновлена успешно"; } TitleInscriptionsModel* DocumentEditWidget::getTitleInscriptionsModel() const { // Возвращаем модель надписей из MainController if (m_controller) { TitleInscriptionsModel *titleModel = m_controller->titleInscriptionsModel(); qDebug() << "DocumentEditWidget::getTitleInscriptionsModel: Возвращаем модель надписей из MainController:" << (titleModel ? "доступна" : "nullptr"); return titleModel; } qDebug() << "DocumentEditWidget::getTitleInscriptionsModel: Контроллер недоступен, возвращаем nullptr"; return nullptr; } PerechenTableModel* DocumentEditWidget::getPerechenTableModel() const { qDebug() << "DocumentEditWidget::getPerechenTableModel: Проверяем доступность PerechenProcessor"; // Проверяем, является ли текущий процессор PerechenProcessor PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor) { if (m_controller && m_controller->perechenTableModel()) { qDebug() << "DocumentEditWidget::getPerechenTableModel: Возвращаем модель перечня:" << (m_controller->perechenTableModel() ? "доступна" : "nullptr"); return m_controller->perechenTableModel(); } } qDebug() << "DocumentEditWidget::getPerechenTableModel: PerechenProcessor недоступен, возвращаем nullptr"; return nullptr; } SpecificationPCBTableModel* DocumentEditWidget::getSpecificationPCBTableModel() const { qDebug() << "DocumentEditWidget::getSpecificationPCBTableModel: Проверяем доступность SpecificationPCBProcessor"; // Проверяем, является ли текущий процессор SpecificationPCBProcessor SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor) { if (m_controller && m_controller->specificationPCBTableModel()) { qDebug() << "DocumentEditWidget::getSpecificationPCBTableModel: Возвращаем модель спецификации платы:" << (m_controller->specificationPCBTableModel() ? "доступна" : "nullptr"); return m_controller->specificationPCBTableModel(); } } qDebug() << "DocumentEditWidget::getSpecificationPCBTableModel: SpecificationPCBProcessor недоступен, возвращаем nullptr"; return nullptr; } SpecificationTableModel* DocumentEditWidget::getSpecificationTableModel() const { qDebug() << "DocumentEditWidget::getSpecificationTableModel: Проверяем доступность SpecificationProcessor"; // Проверяем, является ли текущий процессор SpecificationProcessor SpecificationProcessor *specProcessor = qobject_cast(m_processor); if (specProcessor) { if (m_controller && m_controller->specificationTableModel()) { qDebug() << "DocumentEditWidget::getSpecificationTableModel: Возвращаем модель спецификации:" << (m_controller->specificationTableModel() ? "доступна" : "nullptr"); return m_controller->specificationTableModel(); } } qDebug() << "DocumentEditWidget::getSpecificationTableModel: SpecificationProcessor недоступен, возвращаем nullptr"; return nullptr; } VedomostTableModel* DocumentEditWidget::getVedomostTableModel() const { qDebug() << "DocumentEditWidget::getVedomostTableModel: Проверяем доступность VedomostProcessor"; // Проверяем, является ли текущий процессор VedomostProcessor VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor) { if (m_controller && m_controller->vedomostTableModel()) { qDebug() << "DocumentEditWidget::getVedomostTableModel: Возвращаем модель ведомости:" << (m_controller->vedomostTableModel() ? "доступна" : "nullptr"); return m_controller->vedomostTableModel(); } } qDebug() << "DocumentEditWidget::getVedomostTableModel: VedomostProcessor недоступен, возвращаем nullptr"; return nullptr; } // Новые слоты для управления строками void DocumentEditWidget::onAddRow() { qDebug() << "DocumentEditWidget::onAddRow: Нажата кнопка добавления строки"; // Проверяем, является ли процессор PerechenProcessor PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor) { if (m_controller && m_controller->perechenTableController()) { m_controller->perechenTableController()->addEmptyRow(); qDebug() << "DocumentEditWidget::onAddRow: Пустая строка добавлена через PerechenTableController"; } else { qDebug() << "DocumentEditWidget::onAddRow: PerechenTableController недоступен"; } return; } // Проверяем, является ли процессор SpecificationPCBProcessor SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor) { if (m_controller && m_controller->specificationPCBController()) { m_controller->specificationPCBController()->addEmptyRow(); qDebug() << "DocumentEditWidget::onAddRow: Пустая строка добавлена через SpecificationPCBController"; } else { qDebug() << "DocumentEditWidget::onAddRow: SpecificationPCBController недоступен"; } return; } // Проверяем, является ли процессор VedomostProcessor VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor) { if (m_controller && m_controller->vedomostController()) { m_controller->vedomostController()->addEmptyRow(); qDebug() << "DocumentEditWidget::onAddRow: Пустая строка добавлена через VedomostController"; } else { qDebug() << "DocumentEditWidget::onAddRow: VedomostController недоступен"; } return; } qDebug() << "DocumentEditWidget::onAddRow: Процессор не поддерживает добавление строк"; } void DocumentEditWidget::onInsertRow() { qDebug() << "DocumentEditWidget::onInsertRow: Нажата кнопка вставки строки"; // Получаем текущую выбранную строку int selectedRow = getCurrentSelectedRow(); if (selectedRow == -1) { qDebug() << "DocumentEditWidget::onInsertRow: Нет выбранной строки"; return; } // Проверяем, является ли процессор PerechenProcessor PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor) { // Проверяем, можно ли вставить строку в эту позицию if (m_controller && m_controller->perechenTableModel()) { if (!m_controller->perechenTableModel()->canEditRow(selectedRow)) { qDebug() << "DocumentEditWidget::onInsertRow: Нельзя вставить строку перед строкой" << selectedRow << "(заголовок или автоматически сгенерированная)"; return; } } qDebug() << "DocumentEditWidget::onInsertRow: Вставляем строку перед строкой" << selectedRow; // Получаем контроллер и вставляем пустую строку перед текущей if (m_controller && m_controller->perechenTableController()) { m_controller->perechenTableController()->insertEmptyRowAt(selectedRow); qDebug() << "DocumentEditWidget::onInsertRow: Пустая строка вставлена через PerechenTableController"; } else { qDebug() << "DocumentEditWidget::onInsertRow: PerechenTableController недоступен"; } return; } // Проверяем, является ли процессор SpecificationPCBProcessor SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor) { // Проверяем, можно ли вставить строку в эту позицию if (m_controller && m_controller->specificationPCBTableModel()) { if (!m_controller->specificationPCBTableModel()->canEditRow(selectedRow)) { qDebug() << "DocumentEditWidget::onInsertRow: Нельзя вставить строку перед строкой" << selectedRow << "(заголовок или автоматически сгенерированная)"; return; } } qDebug() << "DocumentEditWidget::onInsertRow: Вставляем строку перед строкой" << selectedRow; // Получаем контроллер и вставляем пустую строку перед текущей if (m_controller && m_controller->specificationPCBController()) { m_controller->specificationPCBController()->insertEmptyRowAt(selectedRow); qDebug() << "DocumentEditWidget::onInsertRow: Пустая строка вставлена через SpecificationPCBController"; } else { qDebug() << "DocumentEditWidget::onInsertRow: SpecificationPCBController недоступен"; } return; } // Проверяем, является ли процессор VedomostProcessor VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor) { // Проверяем, можно ли вставить строку в эту позицию if (m_controller && m_controller->vedomostTableModel()) { if (!m_controller->vedomostTableModel()->canEditRow(selectedRow)) { qDebug() << "DocumentEditWidget::onInsertRow: Нельзя вставить строку перед строкой" << selectedRow << "(заголовок или автоматически сгенерированная)"; return; } } qDebug() << "DocumentEditWidget::onInsertRow: Вставляем строку перед строкой" << selectedRow; // Получаем контроллер и вставляем пустую строку перед текущей if (m_controller && m_controller->vedomostController()) { m_controller->vedomostController()->insertEmptyRowAt(selectedRow); qDebug() << "DocumentEditWidget::onInsertRow: Пустая строка вставлена через VedomostController"; } else { qDebug() << "DocumentEditWidget::onInsertRow: VedomostController недоступен"; } return; } qDebug() << "DocumentEditWidget::onInsertRow: Процессор не поддерживает вставку строк"; } void DocumentEditWidget::onRemoveRow() { qDebug() << "DocumentEditWidget::onRemoveRow: Нажата кнопка удаления строки"; // Получаем текущую выбранную строку int row = getCurrentSelectedRow(); if (row == -1) { qDebug() << "DocumentEditWidget::onRemoveRow: Нет выбранной строки"; return; } // Проверяем, является ли процессор PerechenProcessor PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor) { // Проверяем, можно ли удалить эту строку if (m_controller && m_controller->perechenTableModel()) { if (!m_controller->perechenTableModel()->canEditRow(row)) { qDebug() << "DocumentEditWidget::onRemoveRow: Строка" << row << "не может быть удалена (заголовок или автоматически сгенерированная)"; return; } } qDebug() << "DocumentEditWidget::onRemoveRow: Удаляем строку" << row; // Получаем контроллер и удаляем строку if (m_controller && m_controller->perechenTableController()) { m_controller->perechenTableController()->removeRow(row); qDebug() << "DocumentEditWidget::onRemoveRow: Строка удалена через PerechenTableController"; } else { qDebug() << "DocumentEditWidget::onRemoveRow: PerechenTableController недоступен"; } return; } // Проверяем, является ли процессор SpecificationPCBProcessor SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor) { // Проверяем, можно ли удалить эту строку if (m_controller && m_controller->specificationPCBTableModel()) { if (!m_controller->specificationPCBTableModel()->canEditRow(row)) { qDebug() << "DocumentEditWidget::onRemoveRow: Строка" << row << "не может быть удалена (заголовок или автоматически сгенерированная)"; return; } } qDebug() << "DocumentEditWidget::onRemoveRow: Удаляем строку" << row; // Получаем контроллер и удаляем строку if (m_controller && m_controller->specificationPCBController()) { m_controller->specificationPCBController()->removeRow(row); qDebug() << "DocumentEditWidget::onRemoveRow: Строка удалена через SpecificationPCBController"; } else { qDebug() << "DocumentEditWidget::onRemoveRow: SpecificationPCBController недоступен"; } return; } // Проверяем, является ли процессор VedomostProcessor VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor) { // Проверяем, можно ли удалить эту строку if (m_controller && m_controller->vedomostTableModel()) { if (!m_controller->vedomostTableModel()->canEditRow(row)) { qDebug() << "DocumentEditWidget::onRemoveRow: Строка" << row << "не может быть удалена (заголовок или автоматически сгенерированная)"; return; } } qDebug() << "DocumentEditWidget::onRemoveRow: Удаляем строку" << row; // Получаем контроллер и удаляем строку if (m_controller && m_controller->vedomostController()) { m_controller->vedomostController()->removeRow(row); qDebug() << "DocumentEditWidget::onRemoveRow: Строка удалена через VedomostController"; } else { qDebug() << "DocumentEditWidget::onRemoveRow: VedomostController недоступен"; } return; } qDebug() << "DocumentEditWidget::onRemoveRow: Процессор не поддерживает удаление строк"; } // Слот для обновления состояния кнопок void DocumentEditWidget::onSelectionChanged() { int selectedRow = getCurrentSelectedRow(); bool hasSelection = selectedRow != -1; // Кнопки активны только когда есть выбранная строка m_insertRowButton->setEnabled(hasSelection); m_removeRowButton->setEnabled(hasSelection); qDebug() << "DocumentEditWidget::onSelectionChanged: Выбрана строка" << selectedRow << "кнопки вставки и удаления" << (hasSelection ? "активны" : "неактивны"); } // Вспомогательные методы int DocumentEditWidget::getCurrentSelectedRow() const { QModelIndex currentIndex = m_tableView->currentIndex(); if (currentIndex.isValid()) { return currentIndex.row(); } return -1; // Нет выбранной строки } void DocumentEditWidget::setupSelectionConnection() { // Отключаем предыдущее соединение, если оно есть disconnect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DocumentEditWidget::onSelectionChanged); // Устанавливаем новое соединение if (m_tableView->selectionModel()) { connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DocumentEditWidget::onSelectionChanged); qDebug() << "DocumentEditWidget::setupSelectionConnection: Соединение selectionChanged установлено"; // Обновляем состояние кнопок сразу после установки соединения onSelectionChanged(); } else { qDebug() << "DocumentEditWidget::setupSelectionConnection: selectionModel недоступен"; } } void DocumentEditWidget::applyColumnStretching() { qDebug() << "DocumentEditWidget::applyColumnStretching: Применяем настройки растягивания столбцов"; if (!m_tableView || !m_tableView->model()) { qDebug() << "DocumentEditWidget::applyColumnStretching: Таблица или модель недоступны"; return; } // Проверяем тип процессора и применяем соответствующие настройки PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor) { // Настройки для Perechen (Перечень элементов) QHeaderView *horizontalHeader = m_tableView->horizontalHeader(); // Отключаем автоматическое изменение размера по содержимому horizontalHeader->setStretchLastSection(false); // Устанавливаем режимы для каждого столбца - все интерактивные (изменяемые по ширине) horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Поз.обозначение horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Кол. horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Примечание // Устанавливаем начальные размеры для столбцов horizontalHeader->resizeSection(0, 100); // Поз.обозначение - 100px horizontalHeader->resizeSection(1, 200); // Наименование - 200px horizontalHeader->resizeSection(2, 60); // Кол. - 60px horizontalHeader->resizeSection(3, 150); // Примечание - 150px // Принудительно обновляем размеры столбцов //horizontalHeader->resizeSections(); qDebug() << "DocumentEditWidget::applyColumnStretching: Настройки для Perechen применены"; return; } SpecificationProcessor *specProcessor = qobject_cast(m_processor); if (specProcessor) { // Настройки для Specification (Спецификация) QHeaderView *horizontalHeader = m_tableView->horizontalHeader(); horizontalHeader->setStretchLastSection(false); horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Формат horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Зона horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Поз. horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Обозначение horizontalHeader->setSectionResizeMode(4, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(5, QHeaderView::Interactive); // Количество horizontalHeader->setSectionResizeMode(6, QHeaderView::Interactive); // Примечание horizontalHeader->resizeSection(0, 60); // Формат - 60px horizontalHeader->resizeSection(1, 50); // Зона - 50px horizontalHeader->resizeSection(2, 80); // Поз. - 80px horizontalHeader->resizeSection(3, 150); // Обозначение - 150px horizontalHeader->resizeSection(4, 200); // Наименование - 200px horizontalHeader->resizeSection(5, 60); // Количество - 60px horizontalHeader->resizeSection(6, 150); // Примечание - 150px // horizontalHeader->resizeSections(); qDebug() << "DocumentEditWidget::applyColumnStretching: Настройки для Specification применены"; return; } SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor) { // Настройки для SpecificationPCB (Спецификация ПП) QHeaderView *horizontalHeader = m_tableView->horizontalHeader(); horizontalHeader->setStretchLastSection(false); horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Формат horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Зона horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Поз. horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Обозначение horizontalHeader->setSectionResizeMode(4, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(5, QHeaderView::Interactive); // Количество horizontalHeader->setSectionResizeMode(6, QHeaderView::Interactive); // Примечание horizontalHeader->resizeSection(0, 60); // Формат - 60px horizontalHeader->resizeSection(1, 50); // Зона - 50px horizontalHeader->resizeSection(2, 80); // Поз. - 80px horizontalHeader->resizeSection(3, 150); // Обозначение - 150px horizontalHeader->resizeSection(4, 200); // Наименование - 200px horizontalHeader->resizeSection(5, 60); // Количество - 60px horizontalHeader->resizeSection(6, 150); // Примечание - 150px //horizontalHeader->resizeSections(); qDebug() << "DocumentEditWidget::applyColumnStretching: Настройки для SpecificationPCB применены"; return; } VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor) { // Настройки для Vedomost (Ведомость покупных изделий) - 10 колонок QHeaderView *horizontalHeader = m_tableView->horizontalHeader(); horizontalHeader->setStretchLastSection(false); horizontalHeader->setSectionResizeMode(0, QHeaderView::Interactive); // Наименование horizontalHeader->setSectionResizeMode(1, QHeaderView::Interactive); // Код продукции horizontalHeader->setSectionResizeMode(2, QHeaderView::Interactive); // Обозначение документа на поставку horizontalHeader->setSectionResizeMode(3, QHeaderView::Interactive); // Поставщик horizontalHeader->setSectionResizeMode(4, QHeaderView::Interactive); // Куда входит (обозначение) horizontalHeader->setSectionResizeMode(5, QHeaderView::Interactive); // Количество на изделие horizontalHeader->setSectionResizeMode(6, QHeaderView::Interactive); // Количество в комплекте horizontalHeader->setSectionResizeMode(7, QHeaderView::Interactive); // Количество на регулир horizontalHeader->setSectionResizeMode(8, QHeaderView::Interactive); // Количество всего horizontalHeader->setSectionResizeMode(9, QHeaderView::Interactive); // Примечание horizontalHeader->resizeSection(0, 200); // Наименование - 200px horizontalHeader->resizeSection(1, 120); // Код продукции - 120px horizontalHeader->resizeSection(2, 150); // Обозначение документа на поставку - 150px horizontalHeader->resizeSection(3, 100); // Поставщик - 100px horizontalHeader->resizeSection(4, 120); // Куда входит (обозначение) - 120px horizontalHeader->resizeSection(5, 100); // Количество на изделие - 100px horizontalHeader->resizeSection(6, 100); // Количество в комплекте - 100px horizontalHeader->resizeSection(7, 100); // Количество на регулир - 100px horizontalHeader->resizeSection(8, 100); // Количество всего - 100px horizontalHeader->resizeSection(9, 150); // Примечание - 150px qDebug() << "DocumentEditWidget::applyColumnStretching: Настройки для Vedomost применены"; return; } qDebug() << "DocumentEditWidget::applyColumnStretching: Неизвестный тип процессора"; } void DocumentEditWidget::onContextMenuRequested(const QPoint &pos) { QModelIndex index = m_tableView->indexAt(pos); if (!index.isValid()) { return; } int row = index.row(); // Получаем выделенные строки QItemSelectionModel *selectionModel = m_tableView->selectionModel(); QModelIndexList selectedRows = selectionModel->selectedRows(); int selectedCount = selectedRows.size(); QMenu contextMenu(this); QAction *addRowAction = contextMenu.addAction("Добавить пустую строку"); connect(addRowAction, &QAction::triggered, this, &DocumentEditWidget::onContextMenuAddRow); // Показываем либо "Удалить строку", либо "Удалить n строк" в зависимости от количества выделенных QAction *removeRowAction; if (selectedCount > 1) { removeRowAction = contextMenu.addAction(QString("Удалить %1 строк").arg(selectedCount)); connect(removeRowAction, &QAction::triggered, this, &DocumentEditWidget::onContextMenuRemoveSelectedRows); } else { removeRowAction = contextMenu.addAction("Удалить строку"); connect(removeRowAction, &QAction::triggered, this, &DocumentEditWidget::onContextMenuRemoveRow); } // Добавляем подменю "Объединить" если выбрано несколько строк if (selectedCount > 1) { contextMenu.addSeparator(); QMenu *mergeMenu = contextMenu.addMenu(QString("Объединить %1 строк").arg(selectedCount)); QAction *mergeAllAction = mergeMenu->addAction("Объединить все"); connect(mergeAllAction, &QAction::triggered, this, &DocumentEditWidget::onContextMenuMergeRows); // Получаем столбец, на котором был клик int clickedColumn = index.column(); QString columnName = m_tableView->model()->headerData(clickedColumn, Qt::Horizontal, Qt::DisplayRole).toString(); if (columnName.isEmpty()) { columnName = QString("Столбец %1").arg(clickedColumn + 1); } QAction *mergeColumnAction = mergeMenu->addAction(QString("Объединить только \"%1\"").arg(columnName)); // Сохраняем номер столбца в данных действия для использования в слоте mergeColumnAction->setData(clickedColumn); connect(mergeColumnAction, &QAction::triggered, this, &DocumentEditWidget::onContextMenuMergeColumn); } contextMenu.addSeparator(); QAction *cellSettingsAction = contextMenu.addAction("Настройка ячейки..."); connect(cellSettingsAction, &QAction::triggered, this, &DocumentEditWidget::onContextMenuCellSettings); contextMenu.exec(m_tableView->viewport()->mapToGlobal(pos)); } void DocumentEditWidget::onContextMenuAddRow() { QModelIndex index = m_tableView->currentIndex(); if (!index.isValid()) { return; } int row = index.row(); // Добавляем пустую строку после текущей PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor && m_controller && m_controller->perechenTableController()) { m_controller->perechenTableController()->addEmptyRowAt(row + 1); } SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor && m_controller && m_controller->specificationPCBController()) { m_controller->specificationPCBController()->addEmptyRowAt(row + 1); } SpecificationProcessor *specProcessor = qobject_cast(m_processor); if (specProcessor && m_controller && m_controller->specificationController()) { m_controller->specificationController()->addEmptyRowAt(row + 1); } VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor && m_controller && m_controller->vedomostController()) { m_controller->vedomostController()->addEmptyRowAt(row + 1); } } void DocumentEditWidget::onContextMenuRemoveRow() { QModelIndex index = m_tableView->currentIndex(); if (!index.isValid()) { return; } int row = index.row(); onRemoveRow(); } void DocumentEditWidget::onContextMenuRemoveSelectedRows() { // Получаем выделенные строки QItemSelectionModel *selectionModel = m_tableView->selectionModel(); QModelIndexList selectedRows = selectionModel->selectedRows(); if (selectedRows.isEmpty()) { return; } // Собираем номера строк и сортируем в обратном порядке (для корректного удаления) QList rowsToDelete; for (const QModelIndex &index : selectedRows) { if (index.isValid()) { rowsToDelete.append(index.row()); } } // Удаляем дубликаты и сортируем в обратном порядке std::sort(rowsToDelete.begin(), rowsToDelete.end()); rowsToDelete.erase(std::unique(rowsToDelete.begin(), rowsToDelete.end()), rowsToDelete.end()); std::reverse(rowsToDelete.begin(), rowsToDelete.end()); int count = rowsToDelete.size(); // Запрашиваем подтверждение QMessageBox::StandardButton reply = QMessageBox::question( this, tr("Подтверждение удаления"), tr("Вы уверены, что хотите удалить %1 строк?").arg(count), QMessageBox::Yes | QMessageBox::No ); if (reply != QMessageBox::Yes) { return; } // Удаляем строки в обратном порядке (чтобы индексы не сбивались) for (int row : rowsToDelete) { // Проверяем, можно ли удалить эту строку bool canDelete = true; // Проверяем для каждого типа процессора PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor && m_controller && m_controller->perechenTableModel()) { canDelete = m_controller->perechenTableModel()->canEditRow(row); } SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor && m_controller && m_controller->specificationPCBTableModel()) { canDelete = m_controller->specificationPCBTableModel()->canEditRow(row); } SpecificationProcessor *specProcessor = qobject_cast(m_processor); if (specProcessor && m_controller && m_controller->specificationTableModel()) { canDelete = m_controller->specificationTableModel()->canEditRow(row); } VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor && m_controller && m_controller->vedomostTableModel()) { canDelete = m_controller->vedomostTableModel()->canEditRow(row); } if (!canDelete) { qDebug() << "DocumentEditWidget::onContextMenuRemoveSelectedRows: Строка" << row << "не может быть удалена (заголовок или автоматически сгенерированная)"; continue; } // Удаляем строку через соответствующий контроллер if (perechenProcessor && m_controller && m_controller->perechenTableController()) { m_controller->perechenTableController()->removeRow(row); } else if (specPCBProcessor && m_controller && m_controller->specificationPCBController()) { m_controller->specificationPCBController()->removeRow(row); } else if (specProcessor && m_controller && m_controller->specificationController()) { m_controller->specificationController()->removeRow(row); } else if (vedomostProcessor && m_controller && m_controller->vedomostController()) { m_controller->vedomostController()->removeRow(row); } } qDebug() << "DocumentEditWidget::onContextMenuRemoveSelectedRows: Удалено строк:" << count; } void DocumentEditWidget::onContextMenuMergeRows() { // Получаем выделенные строки QItemSelectionModel *selectionModel = m_tableView->selectionModel(); QModelIndexList selectedRows = selectionModel->selectedRows(); if (selectedRows.size() < 2) { return; // Нужно минимум 2 строки для объединения } // Собираем номера строк и сортируем QList rowsToMerge; for (const QModelIndex &index : selectedRows) { if (index.isValid()) { rowsToMerge.append(index.row()); } } // Удаляем дубликаты и сортируем std::sort(rowsToMerge.begin(), rowsToMerge.end()); rowsToMerge.erase(std::unique(rowsToMerge.begin(), rowsToMerge.end()), rowsToMerge.end()); if (rowsToMerge.size() < 2) { return; } int firstRow = rowsToMerge.first(); int columnCount = m_tableView->model()->columnCount(); // Объединяем содержимое ячеек для каждой колонки for (int col = 0; col < columnCount; ++col) { QStringList mergedValues; // Собираем значения из всех выбранных строк for (int row : rowsToMerge) { QModelIndex cellIndex = m_tableView->model()->index(row, col); if (cellIndex.isValid()) { QString cellValue = m_tableView->model()->data(cellIndex, Qt::DisplayRole).toString().trimmed(); if (!cellValue.isEmpty()) { mergedValues.append(cellValue); } } } // Объединяем значения через пробел QString mergedValue = mergedValues.join(" "); // Записываем объединенное значение в первую строку QModelIndex firstCellIndex = m_tableView->model()->index(firstRow, col); if (firstCellIndex.isValid()) { // Сохраняем CellData из первой строки (если есть) QVariant originalCellData = m_tableView->model()->data(firstCellIndex, Qt::UserRole); // Устанавливаем новое значение m_tableView->model()->setData(firstCellIndex, mergedValue, Qt::EditRole); // Если была структура CellData, обновляем значение в ней if (originalCellData.isValid()) { if (originalCellData.canConvert()) { PerechenCellData cell = originalCellData.value(); cell.value = mergedValue; m_tableView->model()->setData(firstCellIndex, QVariant::fromValue(cell), Qt::UserRole); } else if (originalCellData.canConvert()) { SpecificationPCBCellData cell = originalCellData.value(); cell.value = mergedValue; m_tableView->model()->setData(firstCellIndex, QVariant::fromValue(cell), Qt::UserRole); } else if (originalCellData.canConvert()) { SpecificationCellData cell = originalCellData.value(); cell.value = mergedValue; m_tableView->model()->setData(firstCellIndex, QVariant::fromValue(cell), Qt::UserRole); } else if (originalCellData.canConvert()) { VedomostCellData cell = originalCellData.value(); cell.value = mergedValue; m_tableView->model()->setData(firstCellIndex, QVariant::fromValue(cell), Qt::UserRole); } } } } // Удаляем остальные строки в обратном порядке (чтобы индексы не сбивались) QList rowsToDelete = rowsToMerge; rowsToDelete.removeFirst(); // Не удаляем первую строку std::reverse(rowsToDelete.begin(), rowsToDelete.end()); // Удаляем строки через соответствующий контроллер for (int row : rowsToDelete) { // Проверяем, можно ли удалить эту строку bool canDelete = true; PerechenProcessor *perechenProcessor = qobject_cast(m_processor); if (perechenProcessor && m_controller && m_controller->perechenTableModel()) { canDelete = m_controller->perechenTableModel()->canEditRow(row); } SpecificationPCBProcessor *specPCBProcessor = qobject_cast(m_processor); if (specPCBProcessor && m_controller && m_controller->specificationPCBTableModel()) { canDelete = m_controller->specificationPCBTableModel()->canEditRow(row); } SpecificationProcessor *specProcessor = qobject_cast(m_processor); if (specProcessor && m_controller && m_controller->specificationTableModel()) { canDelete = m_controller->specificationTableModel()->canEditRow(row); } VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor && m_controller && m_controller->vedomostTableModel()) { canDelete = m_controller->vedomostTableModel()->canEditRow(row); } if (!canDelete) { qDebug() << "DocumentEditWidget::onContextMenuMergeRows: Строка" << row << "не может быть удалена (заголовок или автоматически сгенерированная)"; continue; } // Удаляем строку через соответствующий контроллер if (perechenProcessor && m_controller && m_controller->perechenTableController()) { m_controller->perechenTableController()->removeRow(row); } else if (specPCBProcessor && m_controller && m_controller->specificationPCBController()) { m_controller->specificationPCBController()->removeRow(row); } else if (specProcessor && m_controller && m_controller->specificationController()) { m_controller->specificationController()->removeRow(row); } else if (vedomostProcessor && m_controller && m_controller->vedomostController()) { m_controller->vedomostController()->removeRow(row); } } qDebug() << "DocumentEditWidget::onContextMenuMergeRows: Объединено строк:" << rowsToMerge.size() << "в строку" << firstRow; } void DocumentEditWidget::onContextMenuMergeColumn() { // Получаем выделенные строки QItemSelectionModel *selectionModel = m_tableView->selectionModel(); QModelIndexList selectedRows = selectionModel->selectedRows(); if (selectedRows.size() < 2) { return; // Нужно минимум 2 строки для объединения } // Получаем столбец из действия, которое вызвало слот QAction *action = qobject_cast(sender()); if (!action) { return; } int targetColumn = action->data().toInt(); if (targetColumn < 0) { return; } // Собираем номера строк и сортируем QList rowsToMerge; for (const QModelIndex &index : selectedRows) { if (index.isValid()) { rowsToMerge.append(index.row()); } } // Удаляем дубликаты и сортируем std::sort(rowsToMerge.begin(), rowsToMerge.end()); rowsToMerge.erase(std::unique(rowsToMerge.begin(), rowsToMerge.end()), rowsToMerge.end()); if (rowsToMerge.size() < 2) { return; } int firstRow = rowsToMerge.first(); // Объединяем содержимое ячеек только для выбранного столбца QStringList mergedValues; // Собираем значения из всех выбранных строк для выбранного столбца for (int row : rowsToMerge) { QModelIndex cellIndex = m_tableView->model()->index(row, targetColumn); if (cellIndex.isValid()) { QString cellValue = m_tableView->model()->data(cellIndex, Qt::DisplayRole).toString().trimmed(); if (!cellValue.isEmpty()) { mergedValues.append(cellValue); } } } // Объединяем значения через пробел QString mergedValue = mergedValues.join(" "); // Записываем объединенное значение в первую строку QModelIndex firstCellIndex = m_tableView->model()->index(firstRow, targetColumn); if (firstCellIndex.isValid()) { // Сохраняем CellData из первой строки (если есть) QVariant originalCellData = m_tableView->model()->data(firstCellIndex, Qt::UserRole); // Устанавливаем новое значение m_tableView->model()->setData(firstCellIndex, mergedValue, Qt::EditRole); // Если была структура CellData, обновляем значение в ней if (originalCellData.isValid()) { if (originalCellData.canConvert()) { PerechenCellData cell = originalCellData.value(); cell.value = mergedValue; m_tableView->model()->setData(firstCellIndex, QVariant::fromValue(cell), Qt::UserRole); } else if (originalCellData.canConvert()) { SpecificationPCBCellData cell = originalCellData.value(); cell.value = mergedValue; m_tableView->model()->setData(firstCellIndex, QVariant::fromValue(cell), Qt::UserRole); } else if (originalCellData.canConvert()) { SpecificationCellData cell = originalCellData.value(); cell.value = mergedValue; m_tableView->model()->setData(firstCellIndex, QVariant::fromValue(cell), Qt::UserRole); } else if (originalCellData.canConvert()) { VedomostCellData cell = originalCellData.value(); cell.value = mergedValue; m_tableView->model()->setData(firstCellIndex, QVariant::fromValue(cell), Qt::UserRole); } } } // Очищаем значения в остальных строках для выбранного столбца QList rowsToClear = rowsToMerge; rowsToClear.removeFirst(); // Не очищаем первую строку for (int row : rowsToClear) { QModelIndex cellIndex = m_tableView->model()->index(row, targetColumn); if (cellIndex.isValid()) { // Очищаем значение, но сохраняем структуру CellData QVariant originalCellData = m_tableView->model()->data(cellIndex, Qt::UserRole); m_tableView->model()->setData(cellIndex, "", Qt::EditRole); // Обновляем значение в CellData, если оно есть if (originalCellData.isValid()) { if (originalCellData.canConvert()) { PerechenCellData cell = originalCellData.value(); cell.value = ""; m_tableView->model()->setData(cellIndex, QVariant::fromValue(cell), Qt::UserRole); } else if (originalCellData.canConvert()) { SpecificationPCBCellData cell = originalCellData.value(); cell.value = ""; m_tableView->model()->setData(cellIndex, QVariant::fromValue(cell), Qt::UserRole); } else if (originalCellData.canConvert()) { SpecificationCellData cell = originalCellData.value(); cell.value = ""; m_tableView->model()->setData(cellIndex, QVariant::fromValue(cell), Qt::UserRole); } else if (originalCellData.canConvert()) { VedomostCellData cell = originalCellData.value(); cell.value = ""; m_tableView->model()->setData(cellIndex, QVariant::fromValue(cell), Qt::UserRole); } } } } qDebug() << "DocumentEditWidget::onContextMenuMergeColumn: Объединен столбец" << targetColumn << "для строк:" << rowsToMerge.size() << "в строку" << firstRow; } void DocumentEditWidget::onContextMenuCellSettings() { QModelIndex index = m_tableView->currentIndex(); if (!index.isValid()) { return; } int row = index.row(); int column = index.column(); // Получаем название ячейки из заголовка QString cellName = m_tableView->model()->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString(); if (cellName.isEmpty()) { cellName = QString("Колонка %1").arg(column + 1); } // Получаем текущие значения из модели int currentStretch = 100; bool currentIsHeader = false; bool currentIsUnderline = true; QVariant cellData = m_tableView->model()->data(index, Qt::UserRole); if (cellData.isValid()) { // Извлекаем значения из CellData if (cellData.canConvert()) { PerechenCellData cell = cellData.value(); currentStretch = cell.stretch; currentIsHeader = cell.isHeader; currentIsUnderline = cell.isUnderline; } else if (cellData.canConvert()) { SpecificationPCBCellData cell = cellData.value(); currentStretch = cell.stretch; currentIsHeader = cell.isHeader; currentIsUnderline = cell.isUnderline; } else if (cellData.canConvert()) { SpecificationCellData cell = cellData.value(); currentStretch = cell.stretch; currentIsHeader = cell.isHeader; currentIsUnderline = cell.isUnderline; } else if (cellData.canConvert()) { VedomostCellData cell = cellData.value(); currentStretch = cell.stretch; currentIsHeader = cell.isHeader; currentIsUnderline = cell.isUnderline; } } // Создаем диалог настройки ячейки CellSettingsDialog dialog(row, column, cellName, currentStretch, currentIsHeader, currentIsUnderline, this); if (dialog.exec() == QDialog::Accepted) { int newStretch = dialog.getStretch(); bool newIsHeader = dialog.isHeader(); bool newIsUnderline = dialog.isUnderline(); qDebug() << "DocumentEditWidget::onContextMenuCellSettings: Установлены настройки для ячейки row=" << row << "column=" << column << "stretch=" << newStretch << "isHeader=" << newIsHeader << "isUnderline=" << newIsUnderline; // Обновляем настройки в соответствующей модели bool success = false; PerechenTableModel *perechenModel = getPerechenTableModel(); if (perechenModel) { // Вызываем все три метода независимо - они вернут true, если значение изменилось perechenModel->setCellStretch(row, column, newStretch); perechenModel->setCellHeader(row, column, newIsHeader); perechenModel->setCellUnderline(row, column, newIsUnderline); success = true; // Всегда успех, если модель доступна } else { SpecificationPCBTableModel *specPCBModel = getSpecificationPCBTableModel(); if (specPCBModel) { // Вызываем все три метода независимо - они вернут true, если значение изменилось specPCBModel->setCellStretch(row, column, newStretch); specPCBModel->setCellHeader(row, column, newIsHeader); specPCBModel->setCellUnderline(row, column, newIsUnderline); success = true; // Всегда успех, если модель доступна } else { SpecificationTableModel *specModel = getSpecificationTableModel(); if (specModel) { // Вызываем все три метода независимо - они вернут true, если значение изменилось specModel->setCellStretch(row, column, newStretch); specModel->setCellHeader(row, column, newIsHeader); specModel->setCellUnderline(row, column, newIsUnderline); success = true; // Всегда успех, если модель доступна } else { VedomostTableModel *vedomostModel = getVedomostTableModel(); if (vedomostModel) { // Вызываем все три метода независимо - они вернут true, если значение изменилось vedomostModel->setCellStretch(row, column, newStretch); vedomostModel->setCellHeader(row, column, newIsHeader); vedomostModel->setCellUnderline(row, column, newIsUnderline); success = true; // Всегда успех, если модель доступна } } } } if (success) { qDebug() << "DocumentEditWidget::onContextMenuCellSettings: Настройки успешно сохранены в модель"; } else { qDebug() << "DocumentEditWidget::onContextMenuCellSettings: Ошибка при сохранении настроек в модель - модель не найдена"; } } }