diff --git a/app_icon.rc b/app_icon.rc index f2cdf59..c133b1c 100644 --- a/app_icon.rc +++ b/app_icon.rc @@ -5,3 +5,9 @@ IDI_ICON1 ICON DISCARDABLE "assets/icon2.ico" + + + + + + diff --git a/controller/databasecontroller.cpp b/controller/databasecontroller.cpp index 721d6b7..50c3b72 100644 --- a/controller/databasecontroller.cpp +++ b/controller/databasecontroller.cpp @@ -2585,7 +2585,7 @@ QString DataBaseController::getSpecificationTableInfo(const QString &projectName query.addBindValue(projectName); if (!query.exec() || !query.next()) { - setLastError("Ошибка получения информации о спецификации материалов: " + query.lastError().text()); + setLastError("Ошибка получения информации о спецификации: " + query.lastError().text()); return QString(); } @@ -2595,7 +2595,7 @@ QString DataBaseController::getSpecificationTableInfo(const QString &projectName int minOrder = query.value(3).toInt(); int maxOrder = query.value(4).toInt(); - QString info = QString("Спецификация материалов для проекта '%1':\n" + QString info = QString("Спецификация для проекта '%1':\n" "Всего строк: %2\n" "Заголовков: %3\n" "Пустых строк: %4\n" diff --git a/controller/pdfcontroller.cpp b/controller/pdfcontroller.cpp index 556981b..eee483e 100644 --- a/controller/pdfcontroller.cpp +++ b/controller/pdfcontroller.cpp @@ -113,7 +113,7 @@ bool PDFController::exportPerechenToPdf(const QString &filePath, MainController int pageNumber = 1; // Вычисляем общее количество страниц заранее - int totalPages = 2; + int totalPages = 1; int tempRow = 0; while (tempRow < totalRows) { int rowsOnThisPage = (totalPages == 1) ? rowsOnFirstPage : rowsOnOtherPages; @@ -988,7 +988,18 @@ painter.drawText(mainTableRect.left()+165*mmToPixels, mainTableRect.top()+20*mmT painter.drawText(60*mmToPixels,0, 60*mmToPixels, 5*mmToPixels, Qt::AlignCenter,"Перв. примен."); painter.drawText(0,5*mmToPixels, 60*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 24)); - painter.drawText(60*mmToPixels,5*mmToPixels, 60*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 25)); + // Определяем номер поля "Первичное применение" в зависимости от типа документа + int primaryApplicationField = 25; // По умолчанию + if (docType == 1) { + primaryApplicationField = 251; // Перечень + } else if (docType == 2) { + primaryApplicationField = 252; // Спецификация ПП + } else if (docType == 3) { + primaryApplicationField = 253; // Спецификация материалов + } else if (docType == 4) { + primaryApplicationField = 254; // Ведомость + } + painter.drawText(60*mmToPixels,5*mmToPixels, 60*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, primaryApplicationField)); painter.restore(); @@ -1351,7 +1362,8 @@ bool PDFController::addGostFrameA3FirstPage(QPainter &painter, const QRectF &pag painter.drawText(60*mmToPixels,0, 60*mmToPixels, 5*mmToPixels, Qt::AlignCenter,"Перв. примен."); painter.drawText(0,5*mmToPixels, 60*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 24)); - painter.drawText(60*mmToPixels,5*mmToPixels, 60*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 25)); + // A3 формат используется только для ведомости, поэтому используем поле 254 + painter.drawText(60*mmToPixels,5*mmToPixels, 60*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 254)); painter.restore(); diff --git a/controller/specificationpcbcontroller.cpp b/controller/specificationpcbcontroller.cpp index 387c401..9421fcb 100644 --- a/controller/specificationpcbcontroller.cpp +++ b/controller/specificationpcbcontroller.cpp @@ -203,7 +203,17 @@ void SpecificationPCBController::generateTableFromComponents() m_tableModel->addRow(pcbInfo); m_tableModel->addRow(emptyRow); - + SpecificationPCBRowData headerRow2; + headerRow2.isHeader = true; + headerRow2.format = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); + headerRow2.zone = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); + headerRow2.position = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); + headerRow2.designation = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); + headerRow2.name = SpecificationPCBCellData("Детали", 0, 1, true, false, false, 100, true); + headerRow2.quantity = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); + headerRow2.note = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); + m_tableModel->addRow(headerRow2); + m_tableModel->addRow(emptyRow); SpecificationPCBRowData headerRow2_1; headerRow2_1.isHeader = true; headerRow2_1.format = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); @@ -215,16 +225,7 @@ void SpecificationPCBController::generateTableFromComponents() headerRow2_1.note = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); m_tableModel->addRow(headerRow2_1); m_tableModel->addRow(emptyRow); - SpecificationPCBRowData headerRow2; - headerRow2.isHeader = true; - headerRow2.format = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); - headerRow2.zone = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); - headerRow2.position = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); - headerRow2.designation = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); - headerRow2.name = SpecificationPCBCellData("Детали", 0, 1, true, false, false, 100, true); - headerRow2.quantity = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); - headerRow2.note = SpecificationPCBCellData("", 0, 1, true, false, false, 100, true); - m_tableModel->addRow(headerRow2); + SpecificationPCBRowData headerRow3; headerRow3.isHeader = true; diff --git a/model/specificationpcbtablemodel.cpp b/model/specificationpcbtablemodel.cpp index f7f29a1..617a53c 100644 --- a/model/specificationpcbtablemodel.cpp +++ b/model/specificationpcbtablemodel.cpp @@ -1018,10 +1018,14 @@ void SpecificationPCBTableModel::updatePageNumbers() int currentRow = 0; int currentPage = 1; int rowsOnCurrentPage = 0; + bool pageNumbersChanged = false; for (int i = 0; i < m_rows.size(); ++i) { SpecificationPCBRowData &row = m_rows[i]; + // Сохраняем старый номер страницы для проверки изменений + int oldPageNumber = row.pageNumber; + // Определяем, сколько строк помещается на текущей странице int maxRowsOnPage = (currentPage == 1) ? ROWS_PER_FIRST_PAGE : ROWS_PER_OTHER_PAGE; @@ -1032,6 +1036,11 @@ void SpecificationPCBTableModel::updatePageNumbers() maxRowsOnPage = ROWS_PER_OTHER_PAGE; // Начиная со второй страницы } + // Проверяем, изменился ли номер страницы + if (oldPageNumber != currentPage) { + pageNumbersChanged = true; + } + // Устанавливаем номер страницы для строки row.pageNumber = currentPage; row.format.pageNumber = currentPage; @@ -1052,8 +1061,9 @@ void SpecificationPCBTableModel::updatePageNumbers() qDebug() << "SpecificationPCBTableModel::updatePageNumbers: Обновление завершено, всего страниц:" << currentPage; - // Уведомляем UI об изменении данных для обновления отображения страниц - if (!m_rows.isEmpty()) { + // Уведомляем UI об изменении данных ТОЛЬКО если номера страниц действительно изменились + // Это критично для производительности при редактировании больших таблиц + if (pageNumbersChanged && !m_rows.isEmpty()) { emit dataChanged(index(0, 0), index(m_rows.size() - 1, COLUMN_COUNT - 1), QVector() << Qt::BackgroundRole); emit headerDataChanged(Qt::Vertical, 0, m_rows.size() - 1); @@ -1264,11 +1274,27 @@ void SpecificationPCBTableModel::updatePageDisplay() { qDebug() << "SpecificationPCBTableModel::updatePageDisplay: Обновляем отображение страниц в UI"; + // Сохраняем старые номера страниц для проверки изменений + QList oldPageNumbers; + for (const SpecificationPCBRowData &row : m_rows) { + oldPageNumbers.append(row.pageNumber); + } + // Обновляем номера страниц updatePageNumbers(); - // Уведомляем UI об изменении всех данных для обновления отображения - if (!m_rows.isEmpty()) { + // Проверяем, изменились ли номера страниц + bool pageNumbersChanged = false; + for (int i = 0; i < m_rows.size() && i < oldPageNumbers.size(); ++i) { + if (m_rows[i].pageNumber != oldPageNumbers[i]) { + pageNumbersChanged = true; + break; + } + } + + // Уведомляем UI об изменении данных ТОЛЬКО если номера страниц действительно изменились + // Это критично для производительности при редактировании больших таблиц + if (pageNumbersChanged && !m_rows.isEmpty()) { emit dataChanged(index(0, 0), index(m_rows.size() - 1, COLUMN_COUNT - 1), QVector() << Qt::BackgroundRole); diff --git a/view/documentprocessor.cpp b/view/documentprocessor.cpp index d0ff474..d162d11 100644 --- a/view/documentprocessor.cpp +++ b/view/documentprocessor.cpp @@ -1339,6 +1339,29 @@ void DocumentEditWidget::onRemoveRow() return; } + // Проверяем, является ли процессор SpecificationProcessor + SpecificationProcessor *specProcessor = qobject_cast(m_processor); + if (specProcessor) { + // Проверяем, можно ли удалить эту строку + if (m_controller && m_controller->specificationTableModel()) { + if (!m_controller->specificationTableModel()->canEditRow(row)) { + qDebug() << "DocumentEditWidget::onRemoveRow: Строка" << row << "не может быть удалена (заголовок или автоматически сгенерированная)"; + return; + } + } + + qDebug() << "DocumentEditWidget::onRemoveRow: Удаляем строку" << row; + + // Получаем контроллер и удаляем строку + if (m_controller && m_controller->specificationController()) { + m_controller->specificationController()->removeRow(row); + qDebug() << "DocumentEditWidget::onRemoveRow: Строка удалена через SpecificationController"; + } else { + qDebug() << "DocumentEditWidget::onRemoveRow: SpecificationController недоступен"; + } + return; + } + // Проверяем, является ли процессор VedomostProcessor VedomostProcessor *vedomostProcessor = qobject_cast(m_processor); if (vedomostProcessor) { diff --git a/view/documentsettingsdialog.cpp b/view/documentsettingsdialog.cpp index df14c10..7cb2697 100644 --- a/view/documentsettingsdialog.cpp +++ b/view/documentsettingsdialog.cpp @@ -45,6 +45,10 @@ void DocumentSettingsDialog::initializeFieldData() s_fieldNames[22] = "Инв. номер дубликата"; s_fieldNames[24] = "Обозначение документа (взамен) / Справ. №"; s_fieldNames[25] = "Обозначение соответствующего документа / Перв. примен."; + s_fieldNames[251] = "Первичное применение (Перечень)"; + s_fieldNames[252] = "Первичное применение (Спецификация ПП)"; + s_fieldNames[253] = "Первичное применение (Спецификация)"; + s_fieldNames[254] = "Первичное применение (Ведомость)"; s_fieldNames[301]= "Наименование документа"; s_fieldNames[1002] = "Название документа"; @@ -77,6 +81,8 @@ DocumentSettingsDialog::DocumentSettingsDialog(DocumentType docType, MainControl , m_controller(controller) , m_projectParamModel(nullptr) , m_titleInscriptionsModel(nullptr) + , m_primaryApplicationComboBox(nullptr) + , m_primaryApplicationFieldNumber(0) { qDebug() << "DocumentSettingsDialog: Конструктор для типа документа:" << static_cast(docType); @@ -118,6 +124,9 @@ void DocumentSettingsDialog::setUp() loadDecimalNumberSettings(); } + // Загружаем настройки "Первичное применение" для всех типов документов + loadPrimaryApplicationSettings(); + qDebug() << "DocumentSettingsDialog::setUp: Настройка диалога завершена"; } @@ -166,6 +175,9 @@ void DocumentSettingsDialog::createTableSettingsTab() createDecimalNumberFields(); } + // Создаем поле "Первичное применение" для всех типов документов + createPrimaryApplicationField(); + // Создаем поле "Куда входит" для ведомости if (m_documentType == DocumentType::Vedomost) { createWhereUsedField(); @@ -551,6 +563,95 @@ void DocumentSettingsDialog::createWhereUsedField() qDebug() << "DocumentSettingsDialog::createWhereUsedField: Поле 'Куда входит' создано"; } +void DocumentSettingsDialog::createPrimaryApplicationField() +{ + qDebug() << "DocumentSettingsDialog::createPrimaryApplicationField: Создаем поле 'Первичное применение'"; + + // Определяем номер поля в зависимости от типа документа + int fieldNumber = 0; + QString fieldLabelText; + switch (m_documentType) { + case DocumentType::Perechen: + fieldNumber = 251; + fieldLabelText = "Первичное применение (Перечень):"; + break; + case DocumentType::SpecificationPCB: + fieldNumber = 252; + fieldLabelText = "Первичное применение (Спецификация ПП):"; + break; + case DocumentType::Specification: + fieldNumber = 253; + fieldLabelText = "Первичное применение (Спецификация):"; + break; + case DocumentType::Vedomost: + fieldNumber = 254; + fieldLabelText = "Первичное применение (Ведомость):"; + break; + default: + return; + } + + // Создаем группу для поля "Первичное применение" + QGroupBox *primaryAppGroup = new QGroupBox("Первичное применение", m_tableScrollContent); + QGridLayout *primaryAppLayout = new QGridLayout(primaryAppGroup); + + // Поле "Первичное применение" + QLabel *primaryAppLabel = new QLabel(fieldLabelText, primaryAppGroup); + primaryAppLayout->addWidget(primaryAppLabel, 0, 0); + + QComboBox *primaryAppComboBox = new QComboBox(primaryAppGroup); + primaryAppComboBox->setEditable(true); + primaryAppComboBox->addItem("-- Не выбрано --", ""); + + // Добавляем параметры проекта в комбобокс + if (m_projectParamModel) { + QMap projectParams = m_projectParamModel->getDataAsMap(); + for (auto it = projectParams.begin(); it != projectParams.end(); ++it) { + QString paramName = it.key(); + QString paramValue = it.value(); + + // Формируем отображаемый текст: "Название (значение)" если значение не пустое + QString displayText = paramName; + if (!paramValue.isEmpty()) { + displayText += QString(" (%1)").arg(paramValue); + } + + primaryAppComboBox->addItem(displayText, paramName); + } + } + + // Соединяем сигнал изменения + connect(primaryAppComboBox, QOverload::of(&QComboBox::currentTextChanged), + [this, fieldNumber](const QString &value) { + onPrimaryApplicationComboBoxChanged(fieldNumber, value); + }); + + // Добавляем комбобокс в компоновку + primaryAppLayout->addWidget(primaryAppComboBox, 0, 1); + + // Сохраняем ссылку на комбобокс + m_primaryApplicationComboBox = primaryAppComboBox; + m_primaryApplicationFieldNumber = fieldNumber; + + // Добавляем группу в основную компоновку таблицы + QGridLayout *mainGridLayout = qobject_cast(m_tableScrollContent->layout()); + if (mainGridLayout) { + int row = mainGridLayout->rowCount(); + mainGridLayout->addWidget(primaryAppGroup, row, 0, 1, 2); + } else { + // Если основная компоновка не является QGridLayout, создаем новую + QVBoxLayout *mainLayout = qobject_cast(m_tableScrollContent->layout()); + if (mainLayout) { + mainLayout->addWidget(primaryAppGroup); + } else { + QVBoxLayout *newLayout = new QVBoxLayout(m_tableScrollContent); + newLayout->addWidget(primaryAppGroup); + } + } + + qDebug() << "DocumentSettingsDialog::createPrimaryApplicationField: Поле 'Первичное применение' создано для поля" << fieldNumber; +} + void DocumentSettingsDialog::createFontSettingsFields() { qDebug() << "DocumentSettingsDialog::createFontSettingsFields: Создаем поля настроек шрифта"; @@ -816,7 +917,8 @@ QStringList DocumentSettingsDialog::getDefaultTableMappings() const QList DocumentSettingsDialog::getRequiredInscriptionFields() const { // Общие обязательные поля для всех документов - return {1, 2, 4, 9, 10, 11, 111, 112, 113, 114, 25}; + // Поле 25 (Первичное применение) теперь находится в настройках таблицы как 251-254 + return {1, 2, 4, 9, 10, 11, 111, 112, 113, 114}; } QList DocumentSettingsDialog::getOptionalInscriptionFields() const @@ -1146,22 +1248,24 @@ void DocumentSettingsDialog::saveInscriptionSettings() qDebug() << "DocumentSettingsDialog::saveInscriptionSettings: Сохраняем настройки надписей"; if (m_titleInscriptionsModel) { - QMap values; - + // Обновляем только поля из таба основных надписей, не заменяя все поля + // Это важно, чтобы не потерять поля 251-254 (Первичное применение) for (auto it = m_inscriptionFields.begin(); it != m_inscriptionFields.end(); ++it) { int fieldNumber = it.key(); const TitleInscriptionFieldExtended &field = it.value(); if (!field.currentValue.isEmpty()) { - values[fieldNumber] = field.currentValue; + m_titleInscriptionsModel->setInscriptionValue(fieldNumber, field.currentValue); + } else { + m_titleInscriptionsModel->setInscriptionValue(fieldNumber, ""); } } - m_titleInscriptionsModel->setAllInscriptions(values); - // Сохраняем в базу данных через контроллер + // Сохраняем все надписи из модели, как это делают остальные поля if (m_controller) { - m_controller->saveTitleInscriptionsToDatabase(values); + QMap allInscriptions = m_titleInscriptionsModel->getAllInscriptions(); + m_controller->saveTitleInscriptionsToDatabase(allInscriptions); } } @@ -1264,6 +1368,9 @@ void DocumentSettingsDialog::onAccept() saveDecimalNumberSettings(); } + // Сохраняем настройки "Первичное применение" для всех типов документов + savePrimaryApplicationSettings(); + accept(); } @@ -1617,6 +1724,118 @@ void DocumentSettingsDialog::saveDecimalNumberSettings() } } +void DocumentSettingsDialog::loadPrimaryApplicationSettings() +{ + qDebug() << "DocumentSettingsDialog::loadPrimaryApplicationSettings: Загружаем настройки 'Первичное применение'"; + + if (!m_primaryApplicationComboBox || m_primaryApplicationFieldNumber == 0) { + qDebug() << "DocumentSettingsDialog::loadPrimaryApplicationSettings: Поле 'Первичное применение' не создано"; + return; + } + + // Загружаем значение из titleInscriptionsModel + if (m_titleInscriptionsModel) { + QString value = m_titleInscriptionsModel->getInscriptionValue(m_primaryApplicationFieldNumber); + if (!value.isEmpty()) { + // Пытаемся найти значение в списке по itemData (название поля) + int index = m_primaryApplicationComboBox->findData(value); + if (index >= 0) { + m_primaryApplicationComboBox->setCurrentIndex(index); + } else { + // Если не найдено в списке, устанавливаем как кастомный текст + m_primaryApplicationComboBox->setCurrentText(value); + } + qDebug() << "DocumentSettingsDialog::loadPrimaryApplicationSettings: Загружено значение из поля" << m_primaryApplicationFieldNumber << ":" << value; + } else { + // Если значение пустое, устанавливаем "-- Не выбрано --" + m_primaryApplicationComboBox->setCurrentIndex(0); + } + } +} + +void DocumentSettingsDialog::savePrimaryApplicationSettings() +{ + qDebug() << "DocumentSettingsDialog::savePrimaryApplicationSettings: Сохраняем настройки 'Первичное применение'"; + + if (!m_primaryApplicationComboBox || m_primaryApplicationFieldNumber == 0) { + qDebug() << "DocumentSettingsDialog::savePrimaryApplicationSettings: Поле 'Первичное применение' не создано"; + return; + } + + QString value = m_primaryApplicationComboBox->currentText(); + + // Если выбрано "-- Не выбрано --", очищаем поле + if (value == "-- Не выбрано --" || value.isEmpty()) { + if (m_titleInscriptionsModel) { + m_titleInscriptionsModel->setInscriptionValue(m_primaryApplicationFieldNumber, ""); + } + qDebug() << "DocumentSettingsDialog::savePrimaryApplicationSettings: Очищено поле" << m_primaryApplicationFieldNumber; + } else { + // Получаем значение: если это предустановленное значение, берем itemData, иначе текст + int index = m_primaryApplicationComboBox->findText(value); + if (index >= 0) { + QString fieldName = m_primaryApplicationComboBox->itemData(index).toString(); + if (!fieldName.isEmpty()) { + // Это предустановленное значение - сохраняем название поля + if (m_titleInscriptionsModel) { + m_titleInscriptionsModel->setInscriptionValue(m_primaryApplicationFieldNumber, fieldName); + } + qDebug() << "DocumentSettingsDialog::savePrimaryApplicationSettings: Сохранено предустановленное значение в поле" << m_primaryApplicationFieldNumber << ":" << fieldName; + } else { + // Это кастомный ввод - сохраняем текст + if (m_titleInscriptionsModel) { + m_titleInscriptionsModel->setInscriptionValue(m_primaryApplicationFieldNumber, value); + } + qDebug() << "DocumentSettingsDialog::savePrimaryApplicationSettings: Сохранено кастомное значение в поле" << m_primaryApplicationFieldNumber << ":" << value; + } + } else { + // Кастомный ввод - сохраняем текст + if (m_titleInscriptionsModel) { + m_titleInscriptionsModel->setInscriptionValue(m_primaryApplicationFieldNumber, value); + } + qDebug() << "DocumentSettingsDialog::savePrimaryApplicationSettings: Сохранено кастомное значение в поле" << m_primaryApplicationFieldNumber << ":" << value; + } + + // Сохраняем в базу данных через контроллер + // Сохраняем все надписи из модели, как это делают остальные поля + if (m_controller && m_titleInscriptionsModel) { + QMap allInscriptions = m_titleInscriptionsModel->getAllInscriptions(); + m_controller->saveTitleInscriptionsToDatabase(allInscriptions); + qDebug() << "DocumentSettingsDialog::savePrimaryApplicationSettings: Сохранены все надписи из модели, включая поле" << m_primaryApplicationFieldNumber; + } + } +} + +void DocumentSettingsDialog::onPrimaryApplicationComboBoxChanged(int fieldNumber, const QString &value) +{ + qDebug() << "DocumentSettingsDialog::onPrimaryApplicationComboBoxChanged: Изменено значение поля" << fieldNumber << "на" << value; + + // Обновляем значение в модели (но не сохраняем в базу данных до нажатия ОК) + if (m_titleInscriptionsModel) { + if (value == "-- Не выбрано --" || value.isEmpty()) { + m_titleInscriptionsModel->setInscriptionValue(fieldNumber, ""); + } else { + // Получаем значение: если это предустановленное значение, берем itemData, иначе текст + if (m_primaryApplicationComboBox) { + int index = m_primaryApplicationComboBox->findText(value); + if (index >= 0) { + QString fieldName = m_primaryApplicationComboBox->itemData(index).toString(); + if (!fieldName.isEmpty()) { + // Это предустановленное значение - сохраняем название поля + m_titleInscriptionsModel->setInscriptionValue(fieldNumber, fieldName); + } else { + // Это кастомный ввод - сохраняем текст + m_titleInscriptionsModel->setInscriptionValue(fieldNumber, value); + } + } else { + // Кастомный ввод - сохраняем текст + m_titleInscriptionsModel->setInscriptionValue(fieldNumber, value); + } + } + } + } +} + // Публичные методы QStringList DocumentSettingsDialog::getTableColumnMappings() const { diff --git a/view/documentsettingsdialog.h b/view/documentsettingsdialog.h index d11dc8a..8ed353c 100644 --- a/view/documentsettingsdialog.h +++ b/view/documentsettingsdialog.h @@ -133,6 +133,10 @@ private: QMap m_decimalNumberComboBoxes; QMap m_decimalNumberValues; + // Поля для "Первичное применение" + QComboBox *m_primaryApplicationComboBox; + int m_primaryApplicationFieldNumber; + // Статические данные о графах ГОСТ static QMap s_fieldNames; static QMap s_fieldDescriptions; @@ -146,6 +150,12 @@ private: void onDecimalNumberComboBoxChanged(const QString &fieldName, const QString &value); void updateDecimalNumberFieldValue(const QString &type, const QString &value); + // Методы для работы с полем "Первичное применение" + void createPrimaryApplicationField(); + void loadPrimaryApplicationSettings(); + void savePrimaryApplicationSettings(); + void onPrimaryApplicationComboBoxChanged(int fieldNumber, const QString &value); + // Методы для работы с настройками шрифта void createFontSettingsFields(); void loadFontSettings(); diff --git a/view/editpdfwidget.cpp b/view/editpdfwidget.cpp index 2ef78cc..e68b767 100644 --- a/view/editpdfwidget.cpp +++ b/view/editpdfwidget.cpp @@ -140,7 +140,7 @@ void EditPDFWidget::setUpConnections(){ QString documentType; switch (index) { case 0: // Спецификация - documentType = "Спецификация материалов"; + documentType = "Спецификация"; break; case 1: // Спецификация ПП documentType = "Спецификация PCB"; diff --git a/view/mainwindow.cpp b/view/mainwindow.cpp index 573f803..290a6c9 100644 --- a/view/mainwindow.cpp +++ b/view/mainwindow.cpp @@ -752,25 +752,25 @@ void MainWindow::onExportSpecification(){ QString defaultPath = QCoreApplication::applicationDirPath() + "/" + fileNameBase + ".pdf"; QString fileName = QFileDialog::getSaveFileName( this, - tr("Экспорт спецификации материалов"), + tr("Экспорт спецификации"), defaultPath, tr("PDF файлы (*.pdf)") ); if (!fileName.isEmpty()) { - m_statusBar->showMessage(tr("Экспорт спецификации материалов: %1").arg(fileName)); + m_statusBar->showMessage(tr("Экспорт спецификации: %1").arg(fileName)); // Экспортируем в PDF через MainController if (m_controller->exportSpecificationToPdf(fileName)) { - m_statusBar->showMessage(tr("Спецификация материалов успешно экспортирована: %1").arg(fileName)); + m_statusBar->showMessage(tr("Спецификация успешно экспортирована: %1").arg(fileName)); // Автоматически открываем созданный PDF файл QUrl fileUrl = QUrl::fromLocalFile(fileName); QDesktopServices::openUrl(fileUrl); } else { - m_statusBar->showMessage(tr("Ошибка экспорта спецификации материалов")); + m_statusBar->showMessage(tr("Ошибка экспорта спецификации")); QMessageBox::critical(this, tr("Ошибка"), - tr("Не удалось экспортировать спецификацию материалов")); + tr("Не удалось экспортировать спецификацию")); } } } @@ -982,23 +982,23 @@ void MainWindow::onExportSpecificationToCsv() QString defaultPath = QCoreApplication::applicationDirPath() + "/Спецификация.csv"; QString fileName = QFileDialog::getSaveFileName( this, - tr("Экспорт спецификации материалов в CSV"), + tr("Экспорт спецификации в CSV"), defaultPath, tr("CSV файлы (*.csv);;Все файлы (*)") ); if (!fileName.isEmpty()) { - m_statusBar->showMessage(tr("Экспорт спецификации материалов в CSV: %1").arg(fileName)); + m_statusBar->showMessage(tr("Экспорт спецификации в CSV: %1").arg(fileName)); // Экспортируем в CSV через MainController if (m_controller->exportSpecificationToCsv(fileName)) { - m_statusBar->showMessage(tr("Спецификация материалов успешно экспортирована в CSV: %1").arg(fileName)); + m_statusBar->showMessage(tr("Спецификация успешно экспортирована в CSV: %1").arg(fileName)); QMessageBox::information(this, tr("Успех"), - tr("Спецификация материалов успешно экспортирована в CSV:\n%1").arg(fileName)); + tr("Спецификация успешно экспортирована в CSV:\n%1").arg(fileName)); } else { - m_statusBar->showMessage(tr("Ошибка экспорта спецификации материалов в CSV")); + m_statusBar->showMessage(tr("Ошибка экспорта спецификации в CSV")); QMessageBox::critical(this, tr("Ошибка"), - tr("Не удалось экспортировать спецификацию материалов в CSV")); + tr("Не удалось экспортировать спецификацию в CSV")); } } } diff --git a/view/previewpdfwidget.cpp b/view/previewpdfwidget.cpp index a9b238c..b63cdb0 100644 --- a/view/previewpdfwidget.cpp +++ b/view/previewpdfwidget.cpp @@ -10,11 +10,10 @@ #include #include #include // Added for qDebug -#include // Константы const int PreviewPdfWidget::ZOOM_LEVELS[] = {25, 50, 75, 100, 125, 150, 200}; -const QStringList PreviewPdfWidget::DOCUMENT_TYPES = {"Перечень элементов", "Спецификация PCB", "Спецификация материалов", "Ведомость покупных изделий"}; +const QStringList PreviewPdfWidget::DOCUMENT_TYPES = {"Перечень элементов", "Спецификация PCB", "Спецификация", "Ведомость покупных изделий"}; // Дополнительные константы для мелкого масштабирования const int PreviewPdfWidget::FINE_ZOOM_STEP = 5; // Шаг для Ctrl+колесико (5%) @@ -44,16 +43,10 @@ PreviewPdfWidget::PreviewPdfWidget(QWidget *parent) : QWidget{parent} , m_mainController(nullptr) , m_pdfController(nullptr) - , m_updateTimer(new QTimer(this)) , m_currentPage(0) , m_currentZoom(100) , m_currentDocumentType("Перечень элементов") { - // Настраиваем таймер для отложенного обновления (500 мс задержка) - m_updateTimer->setSingleShot(true); - m_updateTimer->setInterval(500); - connect(m_updateTimer, &QTimer::timeout, this, &PreviewPdfWidget::updatePreview); - setUp(); } @@ -78,6 +71,7 @@ void PreviewPdfWidget::setWidgets(){ m_prevPageBtn = new QPushButton("←", this); m_nextPageBtn = new QPushButton("→", this); + m_refreshBtn = new QPushButton("Обновить", this); m_pageInfoLabel = new QLabel("Страница 1 из 1", this); // Создаем область прокрутки для страниц @@ -119,6 +113,9 @@ void PreviewPdfWidget::setUpLayout(){ m_controlsLayout->addWidget(m_nextPageBtn); m_controlsLayout->addWidget(m_pageInfoLabel); + m_controlsLayout->addSpacing(20); + m_controlsLayout->addWidget(m_refreshBtn); + m_controlsLayout->addStretch(); // Добавляем все в основной layout @@ -154,6 +151,7 @@ void PreviewPdfWidget::setUpConnections(){ renderPage(m_currentPage); } }); + connect(m_refreshBtn, &QPushButton::clicked, this, &PreviewPdfWidget::updatePreview); // Подключаем сигнал масштабирования от ZoomableScrollArea connect(m_scrollArea, &ZoomableScrollArea::zoomRequested, @@ -180,59 +178,11 @@ void PreviewPdfWidget::setMainController(MainController *mainController) if (m_mainController) { m_pdfController = m_mainController->pdfController(); qDebug() << "PreviewPdfWidget::setMainController: PDFController получен из MainController:" << m_pdfController; - - // Подключаемся к сигналам изменения данных (используем отложенное обновление) - connect(reinterpret_cast(m_mainController->perechenTableModel()), &QAbstractItemModel::dataChanged, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->perechenTableModel()), &QAbstractItemModel::modelReset, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->perechenTableModel()), &QAbstractItemModel::rowsInserted, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->perechenTableModel()), &QAbstractItemModel::rowsRemoved, - this, [this]() { m_updateTimer->start(); }); - - connect(reinterpret_cast(m_mainController->specificationPCBTableModel()), &QAbstractItemModel::dataChanged, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->specificationPCBTableModel()), &QAbstractItemModel::modelReset, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->specificationPCBTableModel()), &QAbstractItemModel::rowsInserted, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->specificationPCBTableModel()), &QAbstractItemModel::rowsRemoved, - this, [this]() { m_updateTimer->start(); }); - - connect(reinterpret_cast(m_mainController->specificationTableModel()), &QAbstractItemModel::dataChanged, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->specificationTableModel()), &QAbstractItemModel::modelReset, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->specificationTableModel()), &QAbstractItemModel::rowsInserted, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->specificationTableModel()), &QAbstractItemModel::rowsRemoved, - this, [this]() { m_updateTimer->start(); }); - - connect(reinterpret_cast(m_mainController->vedomostTableModel()), &QAbstractItemModel::dataChanged, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->vedomostTableModel()), &QAbstractItemModel::modelReset, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->vedomostTableModel()), &QAbstractItemModel::rowsInserted, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->vedomostTableModel()), &QAbstractItemModel::rowsRemoved, - this, [this]() { m_updateTimer->start(); }); - - // Подключаемся к сигналам изменения данных TitleInscriptionsModel - connect(m_mainController->titleInscriptionsModel(), &TitleInscriptionsModel::dataChanged, - this, [this]() { - qDebug() << "PreviewPdfWidget: Получен сигнал dataChanged от TitleInscriptionsModel"; - m_updateTimer->start(); - }); - - connect(reinterpret_cast(m_mainController->projectParamTableModel()), &QAbstractItemModel::dataChanged, - this, [this]() { m_updateTimer->start(); }); - connect(reinterpret_cast(m_mainController->projectParamTableModel()), &QAbstractItemModel::modelReset, - this, [this]() { m_updateTimer->start(); }); } else { m_pdfController = nullptr; } + // Обновляем превью при первой установке контроллера updatePreview(); } @@ -261,7 +211,7 @@ void PreviewPdfWidget::updatePreview() qDebug() << "PreviewPdfWidget::updatePreview: Количество строк в спецификации PCB:" << m_mainController->specificationPCBTableModel()->rowCount(); } if (m_mainController->specificationTableModel()) { - qDebug() << "PreviewPdfWidget::updatePreview: Количество строк в спецификации материалов:" << m_mainController->specificationTableModel()->rowCount(); + qDebug() << "PreviewPdfWidget::updatePreview: Количество строк в спецификации:" << m_mainController->specificationTableModel()->rowCount(); } if (m_mainController->vedomostTableModel()) { qDebug() << "PreviewPdfWidget::updatePreview: Количество строк в ведомости покупных изделий:" << m_mainController->vedomostTableModel()->rowCount(); @@ -320,10 +270,10 @@ void PreviewPdfWidget::generatePages() qDebug() << "PreviewPdfWidget::generatePages: Вызываем getSpecificationPcbPagesInfo"; m_pagesInfo = m_pdfController->getSpecificationPcbPagesInfo(m_mainController); qDebug() << "PreviewPdfWidget::generatePages: Получено страниц спецификации PCB:" << m_pagesInfo.size(); - } else if (m_currentDocumentType == "Спецификация материалов") { + } else if (m_currentDocumentType == "Спецификация") { qDebug() << "PreviewPdfWidget::generatePages: Вызываем getSpecificationPagesInfo"; m_pagesInfo = m_pdfController->getSpecificationPagesInfo(m_mainController); - qDebug() << "PreviewPdfWidget::generatePages: Получено страниц спецификации материалов:" << m_pagesInfo.size(); + qDebug() << "PreviewPdfWidget::generatePages: Получено страниц спецификации:" << m_pagesInfo.size(); } else if (m_currentDocumentType == "Ведомость покупных изделий") { qDebug() << "PreviewPdfWidget::generatePages: Вызываем getVedomostPagesInfo"; m_pagesInfo = m_pdfController->getVedomostPagesInfo(m_mainController); @@ -384,9 +334,9 @@ QPixmap PreviewPdfWidget::createPagePixmap(const PageInfo &pageInfo) } else if (m_currentDocumentType == "Спецификация PCB") { success = m_pdfController->drawSpecificationPcbPage(painter, pageInfo, m_mainController); qDebug() << "PreviewPdfWidget::createPagePixmap: Результат рисования спецификации PCB:" << success; - } else if (m_currentDocumentType == "Спецификация материалов") { + } else if (m_currentDocumentType == "Спецификация") { success = m_pdfController->drawSpecificationPage(painter, pageInfo, m_mainController); - qDebug() << "PreviewPdfWidget::createPagePixmap: Результат рисования спецификации материалов:" << success; + qDebug() << "PreviewPdfWidget::createPagePixmap: Результат рисования спецификации:" << success; } else if (m_currentDocumentType == "Ведомость покупных изделий") { success = m_pdfController->drawVedomostPage(painter, pageInfo, m_mainController); qDebug() << "PreviewPdfWidget::createPagePixmap: Результат рисования ведомости:" << success; diff --git a/view/previewpdfwidget.h b/view/previewpdfwidget.h index 5a355d2..fa2eeef 100644 --- a/view/previewpdfwidget.h +++ b/view/previewpdfwidget.h @@ -16,7 +16,6 @@ #include #include #include -#include // Включаем структуру PageInfo #include "../model/pageinfo.h" @@ -88,15 +87,13 @@ private: QComboBox* m_pageCombo; QPushButton* m_prevPageBtn; QPushButton* m_nextPageBtn; + QPushButton* m_refreshBtn; QLabel* m_pageInfoLabel; // Контроллеры MainController* m_mainController; PDFController* m_pdfController; - // Таймер для отложенного обновления (чтобы избежать множественных обновлений при массовых изменениях) - QTimer* m_updateTimer; - // Данные QList m_pagesInfo; QList m_pagePixmaps;