#include "pdfcontroller.h" #include "maincontroller.h" #include "perechentablecontroller.h" #include "specificationpcbcontroller.h" #include "specificationcontroller.h" #include "vedomostcontroller.h" #include "../model/perechentablemodel.h" #include "../model/specificationpcbtablemodel.h" #include "../model/titleinscriptionsmodel.h" #include "../model/projectparamtablemodel.h" #include "../model/specificationtablemodel.h" #include "../model/vedomosttablemodel.h" #include "../model/specificationpcbtablemodel.h" #include "../model/pageinfo.h" #include #include // Регистрируем метатипы для работы с QVariant в PDFController // Примечание: SpecificationPCBCellData уже объявлен в specificationpcbtablemodel.h // Эти объявления должны быть после включения заголовков, где определены структуры Q_DECLARE_METATYPE(PerechenCellData) Q_DECLARE_METATYPE(SpecificationCellData) Q_DECLARE_METATYPE(VedomostCellData) #include #include #include #include #include #include #include #include #include #include // Вспомогательная функция для получения правильного разрешения устройства // Для QPdfWriter использует resolution(), для других устройств - logicalDpiX() static qreal getDeviceResolution(QPaintDevice *device) { if (!device) { return 96.0; // Значение по умолчанию } // QPdfWriter наследуется от QPaintDevice // Используем dynamic_cast (QPaintDevice имеет виртуальные функции в Qt) QPdfWriter *pdfWriter = dynamic_cast(device); if (pdfWriter) { return pdfWriter->resolution(); } // Если dynamic_cast не сработал, используем logicalDpiX() return device->logicalDpiX(); } PDFController::PDFController(QObject *parent) : QObject{parent} {} bool PDFController::exportPerechenToPdf(const QString &filePath, MainController *mainController) { if (!mainController) { qDebug() << "PDFController::exportPerechenToPdf: MainController не передан"; return false; } // Получаем модель перечня элементов из MainController PerechenTableModel *perechenModel = mainController->perechenTableModel(); if (!perechenModel) { qDebug() << "PDFController::exportPerechenToPdf: Модель перечня элементов недоступна"; return false; } // Получаем модель надписей титульного листа из MainController TitleInscriptionsModel *titleModel = mainController->titleInscriptionsModel(); if (!titleModel) { qDebug() << "PDFController::exportPerechenToPdf: Модель надписей титульного листа недоступна"; return false; } // Получаем модель параметров проекта из MainController ProjectParamTableModel *projectParamModel = mainController->projectParamTableModel(); if (!projectParamModel) { qDebug() << "PDFController::exportPerechenToPdf: Модель параметров проекта недоступна"; return false; } qDebug() << "PDFController::exportPerechenToPdf: Начинаем экспорт перечня в PDF:" << filePath; qDebug() << "PDFController::exportPerechenToPdf: Количество строк в модели:" << perechenModel->rowCount(); qDebug() << "PDFController::exportPerechenToPdf: Количество полей надписей:" << titleModel->getFieldCount(); // Создаем PDF документ формата А4 QPdfWriter writer(filePath); writer.setPageSize(QPageSize(QPageSize::A4)); writer.setPageMargins(QMarginsF(0, 0, 0, 0)); QPainter painter(&writer); if (!painter.isActive()) { qDebug() << "PDFController::exportPerechenToPdf: Не удалось создать painter"; return false; } // Получаем размеры страницы QRectF pageRect = writer.pageLayout().paintRectPixels(writer.resolution()); // Конвертируем миллиметры в пиксели qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // Константы для количества строк на страницах const int rowsOnFirstPage = 25; // На первой странице 23 строки const int rowsOnOtherPages = 32; // На последующих страницах 29 строк int totalRows = perechenModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Вычисляем общее количество страниц заранее int totalPages = 1; int tempRow = 0; while (tempRow < totalRows) { int rowsOnThisPage = (totalPages == 1) ? rowsOnFirstPage : rowsOnOtherPages; tempRow += rowsOnThisPage; if (tempRow < totalRows) { totalPages++; } } while (currentRow < totalRows) { // Определяем количество строк для текущей страницы int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; // Проверяем, является ли это последней страницей bool isLastPage = (currentRow + rowsOnThisPage >= totalRows); // Если это последняя страница, добавляем пустые строки до конца страницы if (isLastPage) { int remainingRows = totalRows - currentRow; int emptyRowsToAdd = rowsOnThisPage - remainingRows; rowsOnThisPage = remainingRows + emptyRowsToAdd; } // Добавляем новую страницу (кроме первой) if (pageNumber > 1) { writer.newPage(); } // Добавляем рамку ГОСТ в зависимости от номера страницы if (pageNumber == 1) { addGostFrameA4FirstPage(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,1); } else { addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,1); } // Вычисляем область для таблицы QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -5*mmToPixels); // Добавляем таблицу с указанным диапазоном строк (включая пустые строки на последней странице) addPerechenTableRange(painter, perechenModel, tableRect, currentRow, rowsOnThisPage, mainController); currentRow += (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; pageNumber++; } writer.newPage(); addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,1); QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -20*mmToPixels); addListRegistrationTable(painter, tableRect); painter.end(); qDebug() << "PDFController::exportPerechenToPdf: Экспорт завершен успешно. Создано страниц:" << (pageNumber - 1); return true; } bool PDFController::exportSpecificationPcbToPdf(const QString &filePath, MainController *mainController) { if (!mainController) { qDebug() << "PDFController::exportSpecificationPcbToPdf: MainController не передан"; return false; } // Получаем модель спецификации PCB из MainController SpecificationPCBTableModel *specificationModel = mainController->specificationPCBTableModel(); if (!specificationModel) { qDebug() << "PDFController::exportSpecificationPcbToPdf: Модель спецификации PCB недоступна"; return false; } // Получаем модель надписей титульного листа из MainController TitleInscriptionsModel *titleModel = mainController->titleInscriptionsModel(); if (!titleModel) { qDebug() << "PDFController::exportSpecificationPcbToPdf: Модель надписей титульного листа недоступна"; return false; } // Получаем модель параметров проекта из MainController ProjectParamTableModel *projectParamModel = mainController->projectParamTableModel(); if (!projectParamModel) { qDebug() << "PDFController::exportSpecificationPcbToPdf: Модель параметров проекта недоступна"; return false; } qDebug() << "PDFController::exportSpecificationPcbToPdf: Начинаем экспорт спецификации PCB в PDF:" << filePath; qDebug() << "PDFController::exportSpecificationPcbToPdf: Количество строк в модели:" << specificationModel->rowCount(); qDebug() << "PDFController::exportSpecificationPcbToPdf: Количество полей надписей:" << titleModel->getFieldCount(); // Создаем PDF документ формата А4 QPdfWriter writer(filePath); writer.setPageSize(QPageSize(QPageSize::A4)); writer.setPageMargins(QMarginsF(0, 0, 0, 0)); QPainter painter(&writer); if (!painter.isActive()) { qDebug() << "PDFController::exportSpecificationPcbToPdf: Не удалось создать painter"; return false; } // Получаем размеры страницы QRectF pageRect = writer.pageLayout().paintRectPixels(writer.resolution()); // Конвертируем миллиметры в пиксели qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // Константы для количества строк на страницах (аналогично перечню) const int rowsOnFirstPage = 26; // На первой странице 27 строк const int rowsOnOtherPages = 32; // На последующих страницах 33 строки int totalRows = specificationModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Вычисляем общее количество страниц заранее int totalPages = 1; int tempRow = 0; while (tempRow < totalRows) { int rowsOnThisPage = (totalPages == 1) ? rowsOnFirstPage : rowsOnOtherPages; tempRow += rowsOnThisPage; if (tempRow < totalRows) { totalPages++; } } while (currentRow < totalRows) { // Определяем количество строк для текущей страницы int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; // Проверяем, является ли это последней страницей bool isLastPage = (currentRow + rowsOnThisPage >= totalRows); // Если это последняя страница, добавляем пустые строки до конца страницы if (isLastPage) { int remainingRows = totalRows - currentRow; int emptyRowsToAdd = rowsOnThisPage - remainingRows; rowsOnThisPage = remainingRows + emptyRowsToAdd; } // Добавляем новую страницу (кроме первой) if (pageNumber > 1) { writer.newPage(); } // Добавляем рамку ГОСТ в зависимости от номера страницы if (pageNumber == 1) { addGostFrameA4FirstPage(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,2); } else { addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,2); } // Вычисляем область для таблицы QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -5*mmToPixels); // Добавляем таблицу спецификации с указанным диапазоном строк (включая пустые строки на последней странице) addSpecificationPcbTableRange(painter, specificationModel, tableRect, currentRow, rowsOnThisPage, mainController); currentRow += (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; pageNumber++; } writer.newPage(); addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,2); QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -20*mmToPixels); addListRegistrationTable(painter, tableRect); painter.end(); qDebug() << "PDFController::exportSpecificationPcbToPdf: Экспорт завершен успешно. Создано страниц:" << (pageNumber - 1); return true; } bool PDFController::exportSpecificationToPdf(const QString &filePath, MainController *mainController) { if (!mainController) { qDebug() << "PDFController::exportSpecificationToPdf: MainController не передан"; return false; } // Получаем модель спецификации материалов из MainController SpecificationTableModel *specificationModel = mainController->specificationTableModel(); if (!specificationModel) { qDebug() << "PDFController::exportSpecificationToPdf: Модель спецификации материалов недоступна"; return false; } // Получаем модель надписей титульного листа из MainController TitleInscriptionsModel *titleModel = mainController->titleInscriptionsModel(); if (!titleModel) { qDebug() << "PDFController::exportSpecificationToPdf: Модель надписей титульного листа недоступна"; return false; } // Получаем модель параметров проекта из MainController ProjectParamTableModel *projectParamModel = mainController->projectParamTableModel(); if (!projectParamModel) { qDebug() << "PDFController::exportSpecificationToPdf: Модель параметров проекта недоступна"; return false; } qDebug() << "PDFController::exportSpecificationToPdf: Начинаем экспорт спецификации материалов в PDF:" << filePath; qDebug() << "PDFController::exportSpecificationToPdf: Количество строк в модели:" << specificationModel->rowCount(); qDebug() << "PDFController::exportSpecificationToPdf: Количество полей надписей:" << titleModel->getFieldCount(); // Создаем PDF документ формата А4 QPdfWriter writer(filePath); writer.setPageSize(QPageSize(QPageSize::A4)); writer.setPageMargins(QMarginsF(0, 0, 0, 0)); QPainter painter(&writer); if (!painter.isActive()) { qDebug() << "PDFController::exportSpecificationToPdf: Не удалось создать painter"; return false; } // Получаем размеры страницы QRectF pageRect = writer.pageLayout().paintRectPixels(writer.resolution()); // Конвертируем миллиметры в пиксели qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // Константы для количества строк на страницах (аналогично перечню) const int rowsOnFirstPage = 26; // На первой странице 27 строк const int rowsOnOtherPages = 32; // На последующих страницах 33 строки int totalRows = specificationModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Вычисляем общее количество страниц заранее int totalPages = 1; int tempRow = 0; while (tempRow < totalRows) { int rowsOnThisPage = (totalPages == 1) ? rowsOnFirstPage : rowsOnOtherPages; tempRow += rowsOnThisPage; if (tempRow < totalRows) { totalPages++; } } while (currentRow < totalRows) { // Определяем количество строк для текущей страницы int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; // Проверяем, является ли это последней страницей bool isLastPage = (currentRow + rowsOnThisPage >= totalRows); // Если это последняя страница, добавляем пустые строки до конца страницы if (isLastPage) { int remainingRows = totalRows - currentRow; int emptyRowsToAdd = rowsOnThisPage - remainingRows; rowsOnThisPage = remainingRows + emptyRowsToAdd; } // Добавляем новую страницу (кроме первой) if (pageNumber > 1) { writer.newPage(); } // Добавляем рамку ГОСТ в зависимости от номера страницы if (pageNumber == 1) { addGostFrameA4FirstPage(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,3); // painter.drawText(pageRect.left()+65*mmToPixels, pageRect.top(), 120*mmToPixels, 15*mmToPixels, Qt::AlignCenter, "ХУй"); } else { addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,3); } // Вычисляем область для таблицы QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -5*mmToPixels); // Добавляем таблицу спецификации с указанным диапазоном строк (включая пустые строки на последней странице) addSpecificationTableRange(painter, specificationModel, tableRect, currentRow, rowsOnThisPage, mainController); currentRow += (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; pageNumber++; } writer.newPage(); addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,3); QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -20*mmToPixels); addListRegistrationTable(painter, tableRect); painter.end(); qDebug() << "PDFController::exportSpecificationToPdf: Экспорт завершен успешно. Создано страниц:" << (pageNumber - 1); return true; } bool PDFController::exportVedomostToPdf(const QString &filePath, MainController *mainController) { if (!mainController) { qDebug() << "PDFController::exportVedomostToPdf: MainController не передан"; return false; } // Получаем модель ведомости покупных изделий из MainController VedomostTableModel *vedomostModel = mainController->vedomostTableModel(); if (!vedomostModel) { qDebug() << "PDFController::exportVedomostToPdf: Модель ведомости покупных изделий недоступна"; return false; } // Получаем модель надписей титульного листа из MainController TitleInscriptionsModel *titleModel = mainController->titleInscriptionsModel(); if (!titleModel) { qDebug() << "PDFController::exportVedomostToPdf: Модель надписей титульного листа недоступна"; return false; } // Получаем модель параметров проекта из MainController ProjectParamTableModel *projectParamModel = mainController->projectParamTableModel(); if (!projectParamModel) { qDebug() << "PDFController::exportVedomostToPdf: Модель параметров проекта недоступна"; return false; } qDebug() << "PDFController::exportVedomostToPdf: Начинаем экспорт ведомости покупных изделий в PDF:" << filePath; qDebug() << "PDFController::exportVedomostToPdf: Количество строк в модели:" << vedomostModel->rowCount(); // Создаем PDF документ формата А5 QPdfWriter writer(filePath); writer.setPageSize(QPageSize(QPageSize::A3)); writer.setPageMargins(QMarginsF(0, 0, 0, 0)); writer.setPageOrientation(QPageLayout::Landscape); QPainter painter(&writer); if (!painter.isActive()) { qDebug() << "PDFController::exportVedomostToPdf: Не удалось создать painter"; return false; } // Получаем размеры страницы QRectF pageRect = writer.pageLayout().paintRectPixels(writer.resolution()); // Конвертируем миллиметры в пиксели qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // Константы для количества строк на страницах (для А5 формата) const int rowsOnFirstPage = 24; // На первой странице 20 строк const int rowsOnOtherPages = 29; // На последующих страницах 25 строк int totalRows = vedomostModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Вычисляем общее количество страниц заранее int totalPages = 1; int tempRow = 0; while (tempRow < totalRows) { int rowsOnThisPage = (totalPages == 1) ? rowsOnFirstPage : rowsOnOtherPages; tempRow += rowsOnThisPage; if (tempRow < totalRows) { totalPages++; } } while (currentRow < totalRows) { // Определяем количество строк для текущей страницы int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; // Проверяем, является ли это последней страницей bool isLastPage = (currentRow + rowsOnThisPage >= totalRows); // Если это последняя страница, добавляем пустые строки до конца страницы if (isLastPage) { int remainingRows = totalRows - currentRow; int emptyRowsToAdd = rowsOnThisPage - remainingRows; rowsOnThisPage = remainingRows + emptyRowsToAdd; } // Добавляем новую страницу (кроме первой) if (pageNumber > 1) { writer.newPage(); } // Добавляем рамку ГОСТ A5 if(pageNumber==1){ addGostFrameA4FirstPage(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,4); }else{ addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageNumber, totalPages,4); } // Вычисляем область для таблицы (A5 формат) QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -5*mmToPixels); // Добавляем таблицу ведомости с указанным диапазоном строк addVedomostTableRange(painter, vedomostModel, tableRect, currentRow, rowsOnThisPage, mainController); currentRow += (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; pageNumber++; } // Устанавливаем размер и ориентацию страницы ДО создания новой страницы writer.setPageSize(QPageSize(QPageSize::A4)); writer.setPageOrientation(QPageLayout::Portrait); writer.setPageMargins(QMarginsF(0, 0, 0, 0)); // Создаем новую страницу с новыми настройками writer.newPage(); // Обновляем pageRect для A4 формата после изменения размера и ориентации страницы QRectF pageRectA4 = writer.pageLayout().paintRectPixels(writer.resolution()); addGostFrameA4(painter, pageRectA4, titleModel, projectParamModel, pageNumber, totalPages,4); QRectF tableRect = pageRectA4.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -20*mmToPixels); addListRegistrationTable(painter, tableRect); painter.end(); qDebug() << "PDFController::exportVedomostToPdf: Экспорт завершен успешно. Создано страниц:" << (pageNumber - 1); return true; } bool PDFController::generateTableA4(const QString &filePath, MainController *mainController) { if (!mainController) { qDebug() << "PDFController::generateTableA4: MainController не передан"; return false; } PerechenTableModel *perechenModel = mainController->perechenTableModel(); if (!perechenModel) { qDebug() << "PDFController::generateTableA4: Модель перечня элементов недоступна"; return false; } qDebug() << "PDFController::generateTableA4: Начинаем генерацию таблицы А4:" << filePath; // Создаем PDF документ QPdfWriter writer(filePath); writer.setPageSize(QPageSize(QPageSize::A4)); writer.setPageMargins(QMarginsF(20, 20, 20, 20)); QPainter painter(&writer); if (!painter.isActive()) { qDebug() << "PDFController::generateTableA4: Не удалось создать painter"; return false; } // Получаем размеры страницы QRectF pageRect = writer.pageLayout().paintRectPixels(writer.resolution()); // Добавляем рамку ГОСТ //addGostFrameA4(painter, pageRect, nullptr, 1, 1); // Добавляем заголовок QFont titleFont("Arial", 14, QFont::Bold); painter.setFont(titleFont); painter.drawText(QRectF(pageRect.x() + 50, pageRect.y() + 50, pageRect.width() - 100, 50), "ПЕРЕЧЕНЬ ЭЛЕМЕНТОВ", QTextOption(Qt::AlignCenter)); // Добавляем таблицу перечня QRectF tableRect(pageRect.x() + 50, pageRect.y() + 120, pageRect.width() - 100, pageRect.height() - 170); addPerechenTable(painter, perechenModel, tableRect, mainController); painter.end(); qDebug() << "PDFController::generateTableA4: Таблица А4 сгенерирована успешно"; return true; } bool PDFController::generateTableA5(const QString &filePath, MainController *mainController) { qDebug() << "PDFController::generateTableA5: Заглушка для А5 формата - пока не реализовано"; // TODO: Реализовать генерацию таблицы А5 return false; } bool PDFController::generateGostStampA4(const QString &filePath, MainController *mainController) { if (!mainController) { qDebug() << "PDFController::generateGostStampA4: MainController не передан"; return false; } TitleInscriptionsModel *titleModel = mainController->titleInscriptionsModel(); if (!titleModel) { qDebug() << "PDFController::generateGostStampA4: Модель надписей титульного листа недоступна"; return false; } qDebug() << "PDFController::generateGostStampA4: Начинаем генерацию штампа ГОСТ А4:" << filePath; // Создаем PDF документ QPdfWriter writer(filePath); writer.setPageSize(QPageSize(QPageSize::A4)); writer.setPageMargins(QMarginsF(20, 20, 20, 20)); QPainter painter(&writer); if (!painter.isActive()) { qDebug() << "PDFController::generateGostStampA4: Не удалось создать painter"; return false; } // Получаем размеры страницы QRectF pageRect = writer.pageLayout().paintRectPixels(writer.resolution()); // Добавляем рамку ГОСТ addGostFrameA4(painter, pageRect, titleModel, nullptr, 1, 1,0); // Добавляем штамп ГОСТ в правом нижнем углу QRectF stampRect(pageRect.width() - 200, pageRect.height() - 100, 180, 80); addTitleInscriptions(painter, titleModel, stampRect); painter.end(); qDebug() << "PDFController::generateGostStampA4: Штамп ГОСТ А4 сгенерирован успешно"; return true; } bool PDFController::generateGostStampA5(const QString &filePath, MainController *mainController) { qDebug() << "PDFController::generateGostStampA5: Заглушка для А5 формата - пока не реализовано"; // TODO: Реализовать генерацию штампа ГОСТ А5 return false; } bool PDFController::createPdfDocument(const QString &filePath, const QString &title) { QPdfWriter writer(filePath); writer.setPageSize(QPageSize(QPageSize::A4)); writer.setPageMargins(QMarginsF(20, 20, 20, 20)); QPainter painter(&writer); if (!painter.isActive()) { return false; } // Добавляем заголовок QFont titleFont("Arial", 16, QFont::Bold); painter.setFont(titleFont); QRectF pageRect = writer.pageLayout().paintRectPixels(writer.resolution()); painter.drawText(QRectF(pageRect.x(), pageRect.y(), pageRect.width(), 100), title, QTextOption(Qt::AlignCenter)); painter.end(); return true; } bool PDFController::addListRegistrationTable(QPainter &painter, const QRectF &pageRect) { // Используем правильное разрешение для PDF qreal resolution = getDeviceResolution(painter.device()); qreal mmToPixels = resolution / 25.4; // Используем физические единицы для PDF (0.5 мм для рамок) QPen framePen(Qt::black, 0.5 * mmToPixels); framePen.setCosmetic(false); // Важно для PDF - использовать физические единицы painter.setPen(framePen); // Конвертируем миллиметры в пиксели float rowHeight = 8.175; int rowCount = 29; // Создаем QTextOption с правильными настройками для переноса строк QTextOption textOption; textOption.setAlignment(Qt::AlignCenter); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); QRectF nameRect = QRectF(pageRect.left(), pageRect.top(),185*mmToPixels, 10*mmToPixels); painter.drawLine(nameRect.bottomLeft(),nameRect.bottomRight()); painter.drawText(nameRect, "Лист регистрации изменений", textOption); painter.drawLine(pageRect.left()+8*mmToPixels,pageRect.top()+16*mmToPixels,pageRect.left()+88*mmToPixels,pageRect.top()+16*mmToPixels); painter.drawText(QRectF(pageRect.left()+8*mmToPixels,pageRect.top()+10*mmToPixels,80*mmToPixels, 6*mmToPixels), "Номера листов (страниц)", textOption); painter.drawLine(pageRect.left(),pageRect.top()+35*mmToPixels,pageRect.left()+185*mmToPixels, pageRect.top()+35*mmToPixels); painter.drawLine(pageRect.left()+8*mmToPixels,pageRect.top()+10*mmToPixels,pageRect.left()+8*mmToPixels,pageRect.top()+35*mmToPixels+(rowCount)*rowHeight*mmToPixels); painter.drawLine(pageRect.left()+28*mmToPixels,pageRect.top()+16*mmToPixels,pageRect.left()+28*mmToPixels,pageRect.bottom()); painter.drawLine(pageRect.left()+48*mmToPixels,pageRect.top()+16*mmToPixels,pageRect.left()+48*mmToPixels,pageRect.bottom()); painter.drawLine(pageRect.left()+68*mmToPixels,pageRect.top()+16*mmToPixels,pageRect.left()+68*mmToPixels,pageRect.bottom()); painter.drawLine(pageRect.left()+88*mmToPixels,pageRect.top()+10*mmToPixels,pageRect.left()+88*mmToPixels,pageRect.bottom()); painter.drawLine(pageRect.left()+108*mmToPixels,pageRect.top()+10*mmToPixels,pageRect.left()+108*mmToPixels,pageRect.bottom()); painter.drawLine(pageRect.left()+133*mmToPixels,pageRect.top()+10*mmToPixels,pageRect.left()+133*mmToPixels,pageRect.bottom()); painter.drawLine(pageRect.left()+158*mmToPixels,pageRect.top()+10*mmToPixels,pageRect.left()+158*mmToPixels,pageRect.bottom()); painter.drawLine(pageRect.left()+173*mmToPixels,pageRect.top()+10*mmToPixels,pageRect.left()+173*mmToPixels,pageRect.bottom()); painter.drawText(QRectF(pageRect.left(),pageRect.top()+10*mmToPixels, 8*mmToPixels, 25*mmToPixels), "Изм.", textOption); painter.drawText(QRectF(pageRect.left()+8*mmToPixels,pageRect.top()+16*mmToPixels, 20*mmToPixels, 19*mmToPixels), "измененных", textOption); painter.drawText(QRectF(pageRect.left()+28*mmToPixels,pageRect.top()+16*mmToPixels, 20*mmToPixels, 19*mmToPixels), "замененных", textOption); painter.drawText(QRectF(pageRect.left()+48*mmToPixels,pageRect.top()+16*mmToPixels, 20*mmToPixels, 19*mmToPixels), "новых", textOption); painter.drawText(QRectF(pageRect.left()+68*mmToPixels,pageRect.top()+16*mmToPixels, 20*mmToPixels, 19*mmToPixels), "аннулиро-ванных", textOption); painter.drawText(QRectF(pageRect.left()+88*mmToPixels,pageRect.top()+10*mmToPixels, 20*mmToPixels, 25*mmToPixels), "Всего листов (страниц) в документе", textOption); painter.drawText(QRectF(pageRect.left()+108*mmToPixels,pageRect.top()+10*mmToPixels, 25*mmToPixels, 25*mmToPixels), "Номер документа", textOption); painter.drawText(QRectF(pageRect.left()+133*mmToPixels,pageRect.top()+10*mmToPixels, 25*mmToPixels, 25*mmToPixels), "Входящий номер сопроводительного документа и дата", textOption); painter.drawText(QRectF(pageRect.left()+158*mmToPixels,pageRect.top()+10*mmToPixels, 15*mmToPixels, 25*mmToPixels), "Подпись", textOption); painter.drawText(QRectF(pageRect.left()+173*mmToPixels,pageRect.top()+10*mmToPixels, 12*mmToPixels, 25*mmToPixels), "Дата", textOption); for(int i =1; i<=rowCount;i++){ painter.drawLine(pageRect.left(), pageRect.top()+35*mmToPixels+i*rowHeight*mmToPixels, pageRect.left()+ 185*mmToPixels,pageRect.top()+35*mmToPixels+i*rowHeight*mmToPixels); } return true; } bool PDFController::addGostFrameA4FirstPage(QPainter &painter, const QRectF &pageRect, const TitleInscriptionsModel* model, const ProjectParamTableModel* projectParamModel, int currentPage, int totalPages, int docType) { // Загружаем TTF шрифт из QRC ресурсов totalPages++; QString fontPath = ":/assets/GOST_A.TTF"; int fontId = QFontDatabase::addApplicationFont(fontPath); if (fontId == -1) { qDebug() << "PDFController::addGostFrameA4: Не удалось загрузить шрифт из ресурсов:/assets/GOST_A.TTF"; // Используем стандартный шрифт как fallback QFont fallbackFont("Arial", 12); painter.setFont(fallbackFont); } else { // Получаем имя семейства шрифта QStringList fontFamilies = QFontDatabase::applicationFontFamilies(fontId); if (!fontFamilies.isEmpty()) { QString fontFamily = fontFamilies.first(); qDebug() << "PDFController::addGostFrameA4: Загружен шрифт из ресурсов:" << fontFamily; // Создаем шрифт с нужным кеглем (размером) QFont gostFont(fontFamily, 12); // кегль 12 пунктов painter.setFont(gostFont); } } // Рисуем только внутреннюю рамку ГОСТ с отступами: // Слева: 20мм, Сверху: 5мм, Справа: 5мм, Снизу: 5мм // Используем правильное разрешение для PDF qreal resolution = getDeviceResolution(painter.device()); qreal mmToPixels = resolution / 25.4; // 25.4 мм = 1 дюйм // Используем физические единицы для PDF (0.5 мм для рамок ГОСТ) QPen framePen(Qt::black, 0.5 * mmToPixels); framePen.setCosmetic(false); // Важно для PDF - использовать физические единицы painter.setPen(framePen); // Вычисляем отступы в пикселях qreal leftMargin = 20 * mmToPixels; // 20мм слева qreal topMargin = 5 * mmToPixels; // 5мм сверху qreal rightMargin = 5 * mmToPixels; // 5мм справа qreal bottomMargin = 5 * mmToPixels; // 5мм снизу // Внутренняя рамка с указанными отступами в пикселях QRectF innerRect = pageRect.adjusted(leftMargin, topMargin, -rightMargin, -bottomMargin); painter.drawRect(innerRect); // Пример использования шрифта для текста // Получаем текущий шрифт QFont currentFont = painter.font(); // Устанавливаем разные кегли для разных элементов // Угловые маркеры для фальцовки // qreal markerSize = 5.0; // painter.drawLine(innerRect.left(), innerRect.top() - markerSize, // innerRect.left(), innerRect.top() + markerSize); // painter.drawLine(innerRect.left() - markerSize, innerRect.top(), // innerRect.left() + markerSize, innerRect.top()); // painter.drawLine(innerRect.right(), innerRect.top() - markerSize, // innerRect.right(), innerRect.top() + markerSize); // painter.drawLine(innerRect.right() - markerSize, innerRect.top(), // innerRect.right() + markerSize, innerRect.top()); // Уменьшаем шрифт для лучшего размещения текста QRectF lowTableRect = QRectF(innerRect.left(), innerRect.bottom(), -12*mmToPixels, -(25+35+25+25+35)*mmToPixels); // Сначала рисуем всё в обычном прямоугольнике painter.drawRect(lowTableRect); // Рисуем повернутый прямоугольник с тем же содержимым painter.drawLine(lowTableRect.right()+5*mmToPixels, lowTableRect.top(), lowTableRect.right()+5*mmToPixels, lowTableRect.bottom()); painter.drawLine(lowTableRect.right(), lowTableRect.top()-25*mmToPixels, lowTableRect.left(), lowTableRect.top()-25*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25+25)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25+25)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25+25+35)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25+25+35)*mmToPixels); QRectF topTableRect = QRectF(innerRect.left(), innerRect.top(), -12*mmToPixels, 120*mmToPixels); painter.drawRect(topTableRect); painter.drawLine(topTableRect.right()+5*mmToPixels, topTableRect.top(), topTableRect.right()+5*mmToPixels, topTableRect.bottom()); painter.drawLine(topTableRect.right(), topTableRect.top()+60*mmToPixels, topTableRect.left(),topTableRect.top()+60*mmToPixels); QRectF mainTableRect = QRect(innerRect.right()-185*mmToPixels,innerRect.bottom()-40*mmToPixels,185*mmToPixels, 40*mmToPixels); painter.drawRect(mainTableRect); painter.drawLine(mainTableRect.left(), mainTableRect.top()+5*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+5*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+10*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+10*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+15*mmToPixels,mainTableRect.right(), mainTableRect.top()+15*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+20*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+20*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+25*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+30*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+30*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+35*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+35*mmToPixels); painter.drawLine(mainTableRect.right()-50*mmToPixels, mainTableRect.top()+20*mmToPixels,mainTableRect.right(), mainTableRect.top()+20*mmToPixels); painter.drawLine(mainTableRect.right()-50*mmToPixels, mainTableRect.top()+25*mmToPixels,mainTableRect.right(), mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.left()+65*mmToPixels, mainTableRect.top(),mainTableRect.left()+65*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+55*mmToPixels, mainTableRect.top(),mainTableRect.left()+55*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+40*mmToPixels, mainTableRect.top(),mainTableRect.left()+40*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+17*mmToPixels, mainTableRect.top(),mainTableRect.left()+17*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+7*mmToPixels, mainTableRect.top(),mainTableRect.left()+7*mmToPixels, mainTableRect.top()+15*mmToPixels); painter.drawLine(mainTableRect.right()-50*mmToPixels, mainTableRect.top()+15*mmToPixels,mainTableRect.right()-50*mmToPixels,mainTableRect.bottom()); painter.drawLine(mainTableRect.right()-45*mmToPixels, mainTableRect.top()+20*mmToPixels,mainTableRect.right()-45*mmToPixels,mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.right()-40*mmToPixels, mainTableRect.top()+20*mmToPixels,mainTableRect.right()-40*mmToPixels,mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.right()-35*mmToPixels, mainTableRect.top()+15*mmToPixels,mainTableRect.right()-35*mmToPixels,mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.right()-20*mmToPixels, mainTableRect.top()+15*mmToPixels,mainTableRect.right()-20*mmToPixels,mainTableRect.top()+25*mmToPixels); QRectF idkTableRect = QRectF(mainTableRect.right()-120*mmToPixels,mainTableRect.top()-22*mmToPixels, 120*mmToPixels, 22*mmToPixels); // painter.drawRect(idkTableRect); painter.drawLine(idkTableRect.topLeft(), idkTableRect.bottomLeft()); painter.drawLine(idkTableRect.topRight(), idkTableRect.bottomRight()); painter.drawLine(idkTableRect.topRight(), idkTableRect.topLeft()); painter.drawLine(idkTableRect.left(),idkTableRect.top()+14*mmToPixels, idkTableRect.right(),idkTableRect.top()+14*mmToPixels); painter.drawLine(idkTableRect.left()+14*mmToPixels,idkTableRect.top(), idkTableRect.left()+14*mmToPixels,idkTableRect.top()+14*mmToPixels); painter.drawLine(idkTableRect.left()+67*mmToPixels, idkTableRect.top(), idkTableRect.left()+67*mmToPixels, idkTableRect.top()+14*mmToPixels); painter.setFont(createGostFont(12, false, true)); painter.drawText(mainTableRect.left(),mainTableRect.top()+5*mmToPixels, 7*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 14)); painter.drawText(mainTableRect.left()+7*mmToPixels,mainTableRect.top()+5*mmToPixels, 10*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 15)); painter.drawText(mainTableRect.left()+17*mmToPixels,mainTableRect.top()+5*mmToPixels, 23*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 16)); painter.drawText(mainTableRect.left()+40*mmToPixels,mainTableRect.top()+5*mmToPixels, 15*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 17)); painter.drawText(mainTableRect.left()+55*mmToPixels,mainTableRect.top()+5*mmToPixels, 10*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 18)); painter.drawText(mainTableRect.left(),mainTableRect.top()+10*mmToPixels, 7*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Изм."); painter.drawText(mainTableRect.left()+7*mmToPixels,mainTableRect.top()+10*mmToPixels, 10*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Лист"); painter.drawText(mainTableRect.left()+17*mmToPixels,mainTableRect.top()+10*mmToPixels, 23*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"№ докум."); painter.drawText(mainTableRect.left()+40*mmToPixels,mainTableRect.top()+10*mmToPixels, 15*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Подп."); painter.drawText(mainTableRect.left()+55*mmToPixels,mainTableRect.top()+10*mmToPixels, 10*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Дата"); painter.drawText(mainTableRect.left()+1*mmToPixels,mainTableRect.top()+15*mmToPixels, 17*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,"Разраб."); painter.drawText(mainTableRect.left()+1*mmToPixels,mainTableRect.top()+20*mmToPixels, 17*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,"Пров."); painter.drawText(mainTableRect.left()+1*mmToPixels,mainTableRect.top()+25*mmToPixels, 17*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 10)); painter.drawText(mainTableRect.left()+17*mmToPixels+1*mmToPixels,mainTableRect.top()+25*mmToPixels, 23*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 11)); painter.drawText(mainTableRect.left()+17*mmToPixels+1*mmToPixels,mainTableRect.top()+15*mmToPixels, 23*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 111)); painter.drawText(mainTableRect.left()+17*mmToPixels+1*mmToPixels,mainTableRect.top()+20*mmToPixels, 23*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 112)); painter.drawText(mainTableRect.left()+17*mmToPixels+1*mmToPixels,mainTableRect.top()+30*mmToPixels, 23*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 113)); painter.drawText(mainTableRect.left()+17*mmToPixels+1*mmToPixels,mainTableRect.top()+35*mmToPixels, 23*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 114)); painter.drawText(mainTableRect.left()+40*mmToPixels+1*mmToPixels,mainTableRect.top()+25*mmToPixels, 15*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 12)); painter.drawText(mainTableRect.left()+55*mmToPixels+1*mmToPixels,mainTableRect.top()+25*mmToPixels, 10*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 13)); painter.drawText(mainTableRect.left()+1*mmToPixels,mainTableRect.top()+30*mmToPixels, 17*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,"Н. контр."); painter.drawText(mainTableRect.left()+1*mmToPixels,mainTableRect.top()+35*mmToPixels, 17*mmToPixels-1*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter,"Утв."); if(docType!=4){ QFont nameFont = createGostFont(18, false, true); QString nameText = getInscriptionValueWithProjectParams(model, projectParamModel, 1); if(docType==3){ nameText = getInscriptionValueWithProjectParams(model, projectParamModel, 1002); } QRectF nameRect(mainTableRect.left()+65*mmToPixels, mainTableRect.top()+15*mmToPixels, 70*mmToPixels, 25*mmToPixels); drawTextMultiline(painter, nameRect, nameText, nameFont, 3); painter.setFont(createGostFont(12, false, true)); if(docType==1){ painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top()+15*mmToPixels,70*mmToPixels, 25*mmToPixels,Qt::AlignHCenter|Qt::AlignBottom, "Перечень элементов"); } } else{ QFont nameFont = createGostFont(18, false, true); QString nameText = getInscriptionValueWithProjectParams(model, projectParamModel, 1); QRectF nameRect(mainTableRect.left()+65*mmToPixels, mainTableRect.top()+15*mmToPixels, 70*mmToPixels, 20*mmToPixels); drawTextMultiline(painter, nameRect, nameText, nameFont, 3); painter.setFont(createGostFont(12, false, true)); painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top()+35*mmToPixels,70*mmToPixels, 5*mmToPixels,Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 301)); painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.bottom()-20*mmToPixels,70*mmToPixels, 20*mmToPixels,Qt::AlignHCenter|Qt::AlignBottom, "Ведомость покупных изделий"); } painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.bottom(),70*mmToPixels, 5*mmToPixels,Qt::AlignLeft|Qt::AlignVCenter, "Копировал"); // if(docType==4){ // painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top(), 120*mmToPixels, 10*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 2)); // painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top()+10*mmToPixels, 120*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 301)); // } // else{ painter.setFont(createGostFont(18, false, true)); QString titleText = getInscriptionValueWithProjectParams(model, projectParamModel, 2); if(docType==1){ titleText += " ПЭ3"; } else if(docType == 4){ titleText += " ВП"; } else if(docType == 3){ // Для спецификации используем значение из поля 1001 вместо стандартного titleText = getInscriptionValueWithProjectParams(model, projectParamModel, 1001); } painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top(), 120*mmToPixels, 15*mmToPixels, Qt::AlignCenter, titleText); // } painter.setFont(createGostFont(12, false, true)); painter.drawText(mainTableRect.left()+135*mmToPixels, mainTableRect.top()+15*mmToPixels, 15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Лит."); painter.drawText(mainTableRect.left()+150*mmToPixels, mainTableRect.top()+15*mmToPixels, 15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Лист"); painter.drawText(mainTableRect.left()+165*mmToPixels, mainTableRect.top()+15*mmToPixels, 20*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Листов"); QString littera = getInscriptionValueWithProjectParams(model, projectParamModel, 4); for(int litI = 0 ; litI<3; litI++){ if(littera.size()>litI) painter.drawText(mainTableRect.left()+135*mmToPixels+5*mmToPixels*litI, mainTableRect.top()+20*mmToPixels, 5*mmToPixels, 5*mmToPixels, Qt::AlignCenter, littera.at(litI)); } if(totalPages>1){ painter.drawText(mainTableRect.left()+150*mmToPixels, mainTableRect.top()+20*mmToPixels, 15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, QString::number(currentPage)); } painter.drawText(mainTableRect.left()+165*mmToPixels, mainTableRect.top()+20*mmToPixels, 20*mmToPixels, 5*mmToPixels, Qt::AlignCenter, QString::number(totalPages)); painter.drawText(mainTableRect.left()+135*mmToPixels, mainTableRect.top()+25*mmToPixels, 50*mmToPixels, 15*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 9)); if(docType==4){ painter.drawText(mainTableRect.left()+135*mmToPixels, mainTableRect.bottom(), 50*mmToPixels, 5*mmToPixels, Qt::AlignLeft|Qt::AlignVCenter, "Формат А3"); } else{ painter.drawText(mainTableRect.left()+135*mmToPixels, mainTableRect.bottom(), 50*mmToPixels, 5*mmToPixels, Qt::AlignLeft|Qt::AlignVCenter, "Формат А4"); } painter.drawText(idkTableRect.left(), idkTableRect.top(), 14*mmToPixels, 14*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 27)); painter.drawText(idkTableRect.left()+14*mmToPixels, idkTableRect.top(), 53*mmToPixels, 14*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 28)); painter.drawText(idkTableRect.left()+67*mmToPixels, idkTableRect.top(), 53*mmToPixels, 14*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 29)); painter.drawText(idkTableRect.left(), idkTableRect.top()+14*mmToPixels,120*mmToPixels, 8*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 30)); painter.save(); // Создаем трансформацию для поворота текста на 90 градусов QTransform transform; transform.translate(lowTableRect.right(), lowTableRect.top()); transform.rotate(-90); painter.setTransform(transform); // Рисуем повернутый текст painter.drawText(0, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Инв. № подл"); painter.drawText(25*mmToPixels, 0, 35*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп. и дата"); painter.drawText(60*mmToPixels, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Взам. инв. №"); painter.drawText(85*mmToPixels, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Инв. № дубл"); painter.drawText(110*mmToPixels, 0, 35*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп. и дата"); painter.drawText(0, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 19)); painter.drawText(25*mmToPixels, 5*mmToPixels, 35*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 20)); painter.drawText(60*mmToPixels, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 21)); painter.drawText(85*mmToPixels, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 22)); painter.drawText(110*mmToPixels, 5*mmToPixels, 35*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 23)); // painter.drawRect(0, 0, 145*mmToPixels, 12*mmToPixels); // Восстанавливаем трансформацию painter.restore(); painter.save(); QTransform transformTop; transformTop.translate(topTableRect.right(), topTableRect.bottom()); transformTop.rotate(-90); painter.setTransform(transformTop); painter.drawText(0,0, 60*mmToPixels, 5*mmToPixels, Qt::AlignCenter,"Справ. №"); 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)); // Определяем номер поля "Первичное применение" в зависимости от типа документа 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(); return true; } bool PDFController::addGostFrameA4(QPainter &painter, const QRectF &pageRect, const TitleInscriptionsModel* model, const ProjectParamTableModel* projectParamModel, int currentPage, int totalPages, int docType) { totalPages++; // Рисуем только внутреннюю рамку ГОСТ с отступами: // Слева: 20мм, Сверху: 5мм, Справа: 5мм, Снизу: 5мм qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // 25.4 мм = 1 дюйм // Используем физические единицы для PDF (0.5 мм для рамок ГОСТ) QPen framePen(Qt::black, 0.5 * mmToPixels); framePen.setCosmetic(false); // Важно для PDF - использовать физические единицы painter.setPen(framePen); // Вычисляем отступы в пикселях qreal leftMargin = 20 * mmToPixels; // 20мм слева qreal topMargin = 5 * mmToPixels; // 5мм сверху qreal rightMargin = 5 * mmToPixels; // 5мм справа qreal bottomMargin = 5 * mmToPixels; // 5мм снизу // Внутренняя рамка с указанными отступами в пикселях QRectF innerRect = pageRect.adjusted(leftMargin, topMargin, -rightMargin, -bottomMargin); painter.drawRect(innerRect); // Пример использования шрифта для текста // Получаем текущий шрифт QFont currentFont = painter.font(); QRectF lowTableRect = QRectF(innerRect.left(), innerRect.bottom(), -12*mmToPixels, -(25+35+25+25+35)*mmToPixels); // Сначала рисуем всё в обычном прямоугольнике painter.drawRect(lowTableRect); // Рисуем повернутый прямоугольник с тем же содержимым painter.drawLine(lowTableRect.right()+5*mmToPixels, lowTableRect.top(), lowTableRect.right()+5*mmToPixels, lowTableRect.bottom()); painter.drawLine(lowTableRect.right(), lowTableRect.top()-25*mmToPixels, lowTableRect.left(), lowTableRect.top()-25*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25+25)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25+25)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25+25+35)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25+25+35)*mmToPixels); QRectF mainTableRect = QRect(innerRect.right()-185*mmToPixels,innerRect.bottom()-15*mmToPixels,185*mmToPixels, 15*mmToPixels); painter.drawRect(mainTableRect); painter.drawLine(mainTableRect.left()+7*mmToPixels, mainTableRect.top(),mainTableRect.left()+7*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+17*mmToPixels, mainTableRect.top(),mainTableRect.left()+17*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+40*mmToPixels, mainTableRect.top(),mainTableRect.left()+40*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+55*mmToPixels, mainTableRect.top(),mainTableRect.left()+55*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+65*mmToPixels, mainTableRect.top(),mainTableRect.left()+65*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+175*mmToPixels, mainTableRect.top(),mainTableRect.left()+175*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left(),mainTableRect.top()+5*mmToPixels,mainTableRect.left()+65*mmToPixels, mainTableRect.top()+5*mmToPixels); painter.drawLine(mainTableRect.left(),mainTableRect.top()+10*mmToPixels,mainTableRect.left()+65*mmToPixels, mainTableRect.top()+10*mmToPixels); painter.drawLine(mainTableRect.right()-10*mmToPixels,mainTableRect.top()+7*mmToPixels,mainTableRect.right(), mainTableRect.top()+7*mmToPixels); painter.setFont(createGostFont(12, false, true)); painter.drawText(mainTableRect.left(),mainTableRect.bottom()-5*mmToPixels,7*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Изм."); painter.drawText(mainTableRect.left()+7*mmToPixels,mainTableRect.bottom()-5*mmToPixels,10*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Лист"); painter.drawText(mainTableRect.left()+17*mmToPixels,mainTableRect.bottom()-5*mmToPixels,23*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "№ докум"); painter.drawText(mainTableRect.left()+40*mmToPixels,mainTableRect.bottom()-5*mmToPixels,15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп."); painter.drawText(mainTableRect.left()+55*mmToPixels,mainTableRect.bottom()-5*mmToPixels,10*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Дата"); painter.drawText(mainTableRect.left(),mainTableRect.bottom()-10*mmToPixels,7*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 14)); painter.drawText(mainTableRect.left()+7*mmToPixels,mainTableRect.bottom()-10*mmToPixels,10*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 15)); painter.drawText(mainTableRect.left()+17*mmToPixels,mainTableRect.bottom()-10*mmToPixels,23*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 16)); painter.drawText(mainTableRect.left()+40*mmToPixels,mainTableRect.bottom()-10*mmToPixels,15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 17)); painter.drawText(mainTableRect.left()+55*mmToPixels,mainTableRect.bottom()-10*mmToPixels,10*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 18)); // if(docType==4){ // painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top(), 110*mmToPixels, 10*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 2)); // painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top()+10*mmToPixels, 110*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 301)); // } // else{ // painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top(), 110*mmToPixels, 15*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 2)); // } painter.setFont(createGostFont(24, false, true)); QString titleText = getInscriptionValueWithProjectParams(model, projectParamModel, 2); if(docType==1){ titleText += " ПЭ3"; } else if(docType == 4){ titleText += " ВП"; } else if(docType == 3){ // Для спецификации используем значение из поля 1001 вместо стандартного titleText = getInscriptionValueWithProjectParams(model, projectParamModel, 1001); } painter.drawText(mainTableRect.left()+65*mmToPixels,mainTableRect.top(),110*mmToPixels, 15*mmToPixels, Qt::AlignCenter,titleText); painter.setFont(createGostFont(12, false, true)); painter.drawText(mainTableRect.left()+65*mmToPixels,mainTableRect.bottom(),110*mmToPixels, 5*mmToPixels, Qt::AlignLeft|Qt::AlignVCenter, "Копировал"); if(docType==4){ painter.drawText(mainTableRect.left()+65*mmToPixels,mainTableRect.bottom(),110*mmToPixels, 5*mmToPixels, Qt::AlignRight|Qt::AlignVCenter, "Формат А3"); } else{ painter.drawText(mainTableRect.left()+65*mmToPixels,mainTableRect.bottom(),110*mmToPixels, 5*mmToPixels, Qt::AlignRight|Qt::AlignVCenter, "Формат А4"); } painter.drawText(mainTableRect.right()-10*mmToPixels,mainTableRect.top(),10*mmToPixels, 7*mmToPixels, Qt::AlignCenter, "Лист"); painter.drawText(mainTableRect.right()-10*mmToPixels,mainTableRect.top()+7*mmToPixels,10*mmToPixels, 8*mmToPixels, Qt::AlignCenter, QString::number(currentPage)); painter.save(); // Создаем трансформацию для поворота текста на 90 градусов QTransform transform; transform.translate(lowTableRect.right(), lowTableRect.top()); transform.rotate(-90); painter.setTransform(transform); // Рисуем повернутый текст painter.drawText(0, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Инв. № подл"); painter.drawText(25*mmToPixels, 0, 35*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп. и дата"); painter.drawText(60*mmToPixels, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Взам. инв. №"); painter.drawText(85*mmToPixels, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Инв. № дубл"); painter.drawText(110*mmToPixels, 0, 35*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп. и дата"); painter.drawText(0, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 19)); painter.drawText(25*mmToPixels, 5*mmToPixels, 35*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 20)); painter.drawText(60*mmToPixels, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 21)); painter.drawText(85*mmToPixels, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 22)); painter.drawText(110*mmToPixels, 5*mmToPixels, 35*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 23)); painter.restore(); return true; } bool PDFController::addGostFrameA3FirstPage(QPainter &painter, const QRectF &pageRect, const TitleInscriptionsModel *model, const ProjectParamTableModel *projectParamModel, int currentPage, int totalPages) { QString fontPath = ":/assets/GOST_A.TTF"; int fontId = QFontDatabase::addApplicationFont(fontPath); if (fontId == -1) { qDebug() << "PDFController::addGostFrameA4: Не удалось загрузить шрифт из ресурсов:/assets/GOST_A.TTF"; // Используем стандартный шрифт как fallback QFont fallbackFont("Arial", 6); painter.setFont(fallbackFont); } else { // Получаем имя семейства шрифта QStringList fontFamilies = QFontDatabase::applicationFontFamilies(fontId); if (!fontFamilies.isEmpty()) { QString fontFamily = fontFamilies.first(); qDebug() << "PDFController::addGostFrameA4: Загружен шрифт из ресурсов:" << fontFamily; // Создаем шрифт с нужным кеглем (размером) QFont gostFont(fontFamily, 12); // кегль 12 пунктов painter.setFont(gostFont); } } // Рисуем только внутреннюю рамку ГОСТ с отступами: // Слева: 20мм, Сверху: 5мм, Справа: 5мм, Снизу: 5мм // Используем правильное разрешение для PDF qreal resolution = getDeviceResolution(painter.device()); qreal mmToPixels = resolution / 25.4; // 25.4 мм = 1 дюйм // Используем физические единицы для PDF (0.5 мм для рамок ГОСТ) QPen framePen(Qt::black, 0.5 * mmToPixels); framePen.setCosmetic(false); // Важно для PDF - использовать физические единицы painter.setPen(framePen); // Вычисляем отступы в пикселях qreal leftMargin = 20 * mmToPixels; // 20мм слева qreal topMargin = 5 * mmToPixels; // 5мм сверху qreal rightMargin = 5 * mmToPixels; // 5мм справа qreal bottomMargin = 5 * mmToPixels; // 5мм снизу QRectF innerRect = pageRect.adjusted(leftMargin, topMargin, -rightMargin, -bottomMargin); painter.drawRect(innerRect); QFont currentFont = painter.font(); QRectF lowTableRect = QRectF(innerRect.left(), innerRect.bottom(), -12*mmToPixels, -(25+35+25+25+35)*mmToPixels); // Сначала рисуем всё в обычном прямоугольнике painter.drawRect(lowTableRect); // Рисуем повернутый прямоугольник с тем же содержимым painter.drawLine(lowTableRect.right()+5*mmToPixels, lowTableRect.top(), lowTableRect.right()+5*mmToPixels, lowTableRect.bottom()); painter.drawLine(lowTableRect.right(), lowTableRect.top()-25*mmToPixels, lowTableRect.left(), lowTableRect.top()-25*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25+25)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25+25)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25+25+35)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25+25+35)*mmToPixels); QRectF topTableRect = QRectF(innerRect.left(), innerRect.top(), -12*mmToPixels, 120*mmToPixels); painter.drawRect(topTableRect); painter.drawLine(topTableRect.right()+5*mmToPixels, topTableRect.top(), topTableRect.right()+5*mmToPixels, topTableRect.bottom()); painter.drawLine(topTableRect.right(), topTableRect.top()+60*mmToPixels, topTableRect.left(),topTableRect.top()+60*mmToPixels); QRectF mainTableRect = QRect(innerRect.right()-185*mmToPixels,innerRect.bottom()-40*mmToPixels,185*mmToPixels, 40*mmToPixels); painter.drawRect(mainTableRect); painter.drawLine(mainTableRect.left(), mainTableRect.top()+5*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+5*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+10*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+10*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+15*mmToPixels,mainTableRect.right(), mainTableRect.top()+15*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+20*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+20*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+25*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+30*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+30*mmToPixels); painter.drawLine(mainTableRect.left(), mainTableRect.top()+35*mmToPixels,mainTableRect.left()+(7+10+23+15+10)*mmToPixels, mainTableRect.top()+35*mmToPixels); painter.drawLine(mainTableRect.right()-50*mmToPixels, mainTableRect.top()+20*mmToPixels,mainTableRect.right(), mainTableRect.top()+20*mmToPixels); painter.drawLine(mainTableRect.right()-50*mmToPixels, mainTableRect.top()+25*mmToPixels,mainTableRect.right(), mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.left()+65*mmToPixels, mainTableRect.top(),mainTableRect.left()+65*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+55*mmToPixels, mainTableRect.top(),mainTableRect.left()+55*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+40*mmToPixels, mainTableRect.top(),mainTableRect.left()+40*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+17*mmToPixels, mainTableRect.top(),mainTableRect.left()+17*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+7*mmToPixels, mainTableRect.top(),mainTableRect.left()+7*mmToPixels, mainTableRect.top()+15*mmToPixels); painter.drawLine(mainTableRect.right()-50*mmToPixels, mainTableRect.top()+15*mmToPixels,mainTableRect.right()-50*mmToPixels,mainTableRect.bottom()); painter.drawLine(mainTableRect.right()-45*mmToPixels, mainTableRect.top()+20*mmToPixels,mainTableRect.right()-45*mmToPixels,mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.right()-40*mmToPixels, mainTableRect.top()+20*mmToPixels,mainTableRect.right()-40*mmToPixels,mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.right()-35*mmToPixels, mainTableRect.top()+15*mmToPixels,mainTableRect.right()-35*mmToPixels,mainTableRect.top()+25*mmToPixels); painter.drawLine(mainTableRect.right()-20*mmToPixels, mainTableRect.top()+15*mmToPixels,mainTableRect.right()-20*mmToPixels,mainTableRect.top()+25*mmToPixels); QRectF idkTableRect = QRectF(mainTableRect.right()-120*mmToPixels,mainTableRect.top()-22*mmToPixels, 120*mmToPixels, 22*mmToPixels); // painter.drawRect(idkTableRect); painter.drawLine(idkTableRect.topLeft(), idkTableRect.bottomLeft()); painter.drawLine(idkTableRect.topRight(), idkTableRect.bottomRight()); painter.drawLine(idkTableRect.topRight(), idkTableRect.topLeft()); painter.drawLine(idkTableRect.left(),idkTableRect.top()+14*mmToPixels, idkTableRect.right(),idkTableRect.top()+14*mmToPixels); painter.drawLine(idkTableRect.left()+14*mmToPixels,idkTableRect.top(), idkTableRect.left()+14*mmToPixels,idkTableRect.top()+14*mmToPixels); painter.drawLine(idkTableRect.left()+67*mmToPixels, idkTableRect.top(), idkTableRect.left()+67*mmToPixels, idkTableRect.top()+14*mmToPixels); painter.setFont(createGostFont(12, false, true)); painter.drawText(mainTableRect.left(),mainTableRect.top()+5*mmToPixels, 7*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 14)); painter.drawText(mainTableRect.left()+7*mmToPixels,mainTableRect.top()+5*mmToPixels, 10*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 15)); painter.drawText(mainTableRect.left()+17*mmToPixels,mainTableRect.top()+5*mmToPixels, 23*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 16)); painter.drawText(mainTableRect.left()+40*mmToPixels,mainTableRect.top()+5*mmToPixels, 15*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 17)); painter.drawText(mainTableRect.left()+55*mmToPixels,mainTableRect.top()+5*mmToPixels, 10*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 18)); painter.drawText(mainTableRect.left(),mainTableRect.top()+10*mmToPixels, 7*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Изм."); painter.drawText(mainTableRect.left()+7*mmToPixels,mainTableRect.top()+10*mmToPixels, 10*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Лист"); painter.drawText(mainTableRect.left()+17*mmToPixels,mainTableRect.top()+10*mmToPixels, 23*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"№ докум."); painter.drawText(mainTableRect.left()+40*mmToPixels,mainTableRect.top()+10*mmToPixels, 15*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Подп."); painter.drawText(mainTableRect.left()+55*mmToPixels,mainTableRect.top()+10*mmToPixels, 10*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Дата"); painter.drawText(mainTableRect.left(),mainTableRect.top()+15*mmToPixels, 17*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Разраб."); painter.drawText(mainTableRect.left(),mainTableRect.top()+20*mmToPixels, 17*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Пров."); painter.drawText(mainTableRect.left(),mainTableRect.top()+25*mmToPixels, 17*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 10)); painter.drawText(mainTableRect.left()+17*mmToPixels,mainTableRect.top()+25*mmToPixels, 23*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 11)); painter.drawText(mainTableRect.left()+40*mmToPixels,mainTableRect.top()+25*mmToPixels, 15*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 12)); painter.drawText(mainTableRect.left()+55*mmToPixels,mainTableRect.top()+25*mmToPixels, 10*mmToPixels, 5*mmToPixels,Qt::AlignCenter,getInscriptionValueWithProjectParams(model, projectParamModel, 13)); painter.drawText(mainTableRect.left(),mainTableRect.top()+30*mmToPixels, 17*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Н. контр."); painter.drawText(mainTableRect.left(),mainTableRect.top()+35*mmToPixels, 17*mmToPixels, 5*mmToPixels,Qt::AlignCenter,"Утв."); painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top()+15*mmToPixels,70*mmToPixels, 25*mmToPixels,Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 1)); painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.top(), 120*mmToPixels, 15*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 2)); painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.bottom()+5*mmToPixels, 120*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 301)); painter.drawText(mainTableRect.left()+135*mmToPixels, mainTableRect.top()+15*mmToPixels, 15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Лит."); painter.drawText(mainTableRect.left()+150*mmToPixels, mainTableRect.top()+15*mmToPixels, 15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Лист"); painter.drawText(mainTableRect.left()+165*mmToPixels, mainTableRect.top()+15*mmToPixels, 20*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Листов"); painter.drawText(mainTableRect.left()+140*mmToPixels, mainTableRect.top()+20*mmToPixels, 5*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 4)); painter.drawText(mainTableRect.left()+150*mmToPixels, mainTableRect.top()+20*mmToPixels, 15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, QString::number(currentPage)); painter.drawText(mainTableRect.left()+165*mmToPixels, mainTableRect.top()+20*mmToPixels, 20*mmToPixels, 5*mmToPixels, Qt::AlignCenter, QString::number(totalPages)); painter.drawText(mainTableRect.left()+135*mmToPixels, mainTableRect.top()+25*mmToPixels, 50*mmToPixels, 15*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 9)); painter.drawText(idkTableRect.left(), idkTableRect.top(), 14*mmToPixels, 14*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 27)); painter.drawText(idkTableRect.left()+14*mmToPixels, idkTableRect.top(), 53*mmToPixels, 14*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 28)); painter.drawText(idkTableRect.left()+67*mmToPixels, idkTableRect.top(), 53*mmToPixels, 14*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 29)); painter.drawText(idkTableRect.left(), idkTableRect.top()+14*mmToPixels,120*mmToPixels, 8*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 30)); painter.save(); // Создаем трансформацию для поворота текста на 90 градусов QTransform transform; transform.translate(lowTableRect.right(), lowTableRect.top()); transform.rotate(-90); painter.setTransform(transform); // Рисуем повернутый текст painter.drawText(0, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Инв. № подл"); painter.drawText(25*mmToPixels, 0, 35*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп. и дата"); painter.drawText(60*mmToPixels, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Взам. инв. №"); painter.drawText(85*mmToPixels, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Инв. № дубл"); painter.drawText(110*mmToPixels, 0, 35*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп. и дата"); painter.drawText(0, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 19)); painter.drawText(25*mmToPixels, 5*mmToPixels, 35*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 20)); painter.drawText(60*mmToPixels, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 21)); painter.drawText(85*mmToPixels, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 22)); painter.drawText(110*mmToPixels, 5*mmToPixels, 35*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 23)); // painter.drawRect(0, 0, 145*mmToPixels, 12*mmToPixels); // Восстанавливаем трансформацию painter.restore(); painter.save(); QTransform transformTop; transformTop.translate(topTableRect.right(), topTableRect.bottom()); transformTop.rotate(-90); painter.setTransform(transformTop); painter.drawText(0,0, 60*mmToPixels, 5*mmToPixels, Qt::AlignCenter,"Справ. №"); 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)); // A3 формат используется только для ведомости, поэтому используем поле 254 painter.drawText(60*mmToPixels,5*mmToPixels, 60*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 254)); painter.restore(); return true; } bool PDFController::addGostFrameA3(QPainter &painter, const QRectF &pageRect, const TitleInscriptionsModel *model, const ProjectParamTableModel *projectParamModel, int currentPage, int totalPages) { // Рисуем только внутреннюю рамку ГОСТ с отступами: // Слева: 20мм, Сверху: 5мм, Справа: 5мм, Снизу: 5мм qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // Используем физические единицы для PDF (0.5 мм для рамок ГОСТ) QPen framePen(Qt::black, 0.5 * mmToPixels); framePen.setCosmetic(false); // Важно для PDF - использовать физические единицы painter.setPen(framePen); // Вычисляем отступы в пикселях qreal leftMargin = 20 * mmToPixels; // 20мм слева qreal topMargin = 5 * mmToPixels; // 5мм сверху qreal rightMargin = 5 * mmToPixels; // 5мм справа qreal bottomMargin = 5 * mmToPixels; // 5мм снизу // Внутренняя рамка с указанными отступами в пикселях QRectF innerRect = pageRect.adjusted(leftMargin, topMargin, -rightMargin, -bottomMargin); painter.drawRect(innerRect); // Пример использования шрифта для текста // Получаем текущий шрифт QFont currentFont = painter.font(); QRectF lowTableRect = QRectF(innerRect.left(), innerRect.bottom(), -12*mmToPixels, -(25+35+25+25+35)*mmToPixels); // Сначала рисуем всё в обычном прямоугольнике painter.drawRect(lowTableRect); // Рисуем повернутый прямоугольник с тем же содержимым painter.drawLine(lowTableRect.right()+5*mmToPixels, lowTableRect.top(), lowTableRect.right()+5*mmToPixels, lowTableRect.bottom()); painter.drawLine(lowTableRect.right(), lowTableRect.top()-25*mmToPixels, lowTableRect.left(), lowTableRect.top()-25*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25+25)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25+25)*mmToPixels); painter.drawLine(lowTableRect.right(), lowTableRect.top()-(25+35+25+25+35)*mmToPixels, lowTableRect.left(), lowTableRect.top()-(25+35+25+25+35)*mmToPixels); QRectF mainTableRect = QRect(innerRect.right()-185*mmToPixels,innerRect.bottom()-15*mmToPixels,185*mmToPixels, 15*mmToPixels); painter.drawRect(mainTableRect); painter.drawLine(mainTableRect.left()+7*mmToPixels, mainTableRect.top(),mainTableRect.left()+7*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+17*mmToPixels, mainTableRect.top(),mainTableRect.left()+17*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+40*mmToPixels, mainTableRect.top(),mainTableRect.left()+40*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+55*mmToPixels, mainTableRect.top(),mainTableRect.left()+55*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+65*mmToPixels, mainTableRect.top(),mainTableRect.left()+65*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left()+175*mmToPixels, mainTableRect.top(),mainTableRect.left()+175*mmToPixels, mainTableRect.bottom()); painter.drawLine(mainTableRect.left(),mainTableRect.top()+5*mmToPixels,mainTableRect.left()+65*mmToPixels, mainTableRect.top()+5*mmToPixels); painter.drawLine(mainTableRect.left(),mainTableRect.top()+10*mmToPixels,mainTableRect.left()+65*mmToPixels, mainTableRect.top()+10*mmToPixels); painter.drawLine(mainTableRect.right()-10*mmToPixels,mainTableRect.top()+7*mmToPixels,mainTableRect.right(), mainTableRect.top()+7*mmToPixels); painter.setFont(createGostFont(12, false, true)); painter.drawText(mainTableRect.left(),mainTableRect.bottom()-5*mmToPixels,7*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Изм."); painter.drawText(mainTableRect.left()+7*mmToPixels,mainTableRect.bottom()-5*mmToPixels,10*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Лист"); painter.drawText(mainTableRect.left()+17*mmToPixels,mainTableRect.bottom()-5*mmToPixels,23*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "№ докум"); painter.drawText(mainTableRect.left()+40*mmToPixels,mainTableRect.bottom()-5*mmToPixels,15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп."); painter.drawText(mainTableRect.left()+55*mmToPixels,mainTableRect.bottom()-5*mmToPixels,10*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Дата"); painter.drawText(mainTableRect.left(),mainTableRect.bottom()-10*mmToPixels,7*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 14)); painter.drawText(mainTableRect.left()+7*mmToPixels,mainTableRect.bottom()-10*mmToPixels,10*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 15)); painter.drawText(mainTableRect.left()+17*mmToPixels,mainTableRect.bottom()-10*mmToPixels,23*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 16)); painter.drawText(mainTableRect.left()+40*mmToPixels,mainTableRect.bottom()-10*mmToPixels,15*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 17)); painter.drawText(mainTableRect.left()+55*mmToPixels,mainTableRect.bottom()-10*mmToPixels,10*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 18)); painter.drawText(mainTableRect.left()+65*mmToPixels,mainTableRect.top(),110*mmToPixels, 15*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 2)); painter.drawText(mainTableRect.left()+65*mmToPixels, mainTableRect.bottom()+5*mmToPixels, 120*mmToPixels, 5*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 301)); painter.drawText(mainTableRect.right()-10*mmToPixels,mainTableRect.top(),10*mmToPixels, 7*mmToPixels, Qt::AlignCenter, "Лист"); painter.drawText(mainTableRect.right()-10*mmToPixels,mainTableRect.top()+7*mmToPixels,10*mmToPixels, 8*mmToPixels, Qt::AlignCenter, QString::number(currentPage)); painter.save(); // Создаем трансформацию для поворота текста на 90 градусов QTransform transform; transform.translate(lowTableRect.right(), lowTableRect.top()); transform.rotate(-90); painter.setTransform(transform); // Рисуем повернутый текст painter.drawText(0, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Инв. № подл"); painter.drawText(25*mmToPixels, 0, 35*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп. и дата"); painter.drawText(60*mmToPixels, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Взам. инв. №"); painter.drawText(85*mmToPixels, 0, 25*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Инв. № дубл"); painter.drawText(110*mmToPixels, 0, 35*mmToPixels, 5*mmToPixels, Qt::AlignCenter, "Подп. и дата"); painter.drawText(0, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 19)); painter.drawText(25*mmToPixels, 5*mmToPixels, 35*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 20)); painter.drawText(60*mmToPixels, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 21)); painter.drawText(85*mmToPixels, 5*mmToPixels, 25*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 22)); painter.drawText(110*mmToPixels, 5*mmToPixels, 35*mmToPixels, 7*mmToPixels, Qt::AlignCenter, getInscriptionValueWithProjectParams(model, projectParamModel, 23)); painter.restore(); return true; } bool PDFController::addTitleInscriptions(QPainter &painter, TitleInscriptionsModel *titleModel, const QRectF &stampRect) { if (!titleModel) { return false; } // Рисуем рамку штампа QPen stampPen(Qt::black, 0.5); painter.setPen(stampPen); painter.drawRect(stampRect); // Добавляем надписи из модели QFont stampFont("Arial", 8); painter.setFont(stampFont); QMap inscriptions = titleModel->getAllInscriptions(); int yOffset = 0; int lineHeight = 12; for (auto it = inscriptions.begin(); it != inscriptions.end(); ++it) { if (!it.value().isEmpty()) { QString text = QString("%1: %2").arg(it.key()).arg(it.value()); painter.drawText(QRectF(stampRect.x() + 5, stampRect.y() + 5 + yOffset, stampRect.width() - 10, lineHeight), text, QTextOption(Qt::AlignLeft)); yOffset += lineHeight; } } return true; } bool PDFController::addPerechenTable(QPainter &painter, PerechenTableModel *perechenModel, const QRectF &tableRect, MainController *mainController) { // Используем новый метод для отображения всех строк return addPerechenTableRange(painter, perechenModel, tableRect, 0, perechenModel->rowCount(), mainController); } bool PDFController::addPerechenTableRange(QPainter &painter, PerechenTableModel *perechenModel, const QRectF &tableRect, int startRow, int rowCount, MainController *mainController) { if (!perechenModel) { return false; } // Размеры колонок в миллиметрах (конвертируем в пиксели) // Используем правильное разрешение для PDF qreal resolution = getDeviceResolution(painter.device()); qreal mmToPixels = resolution / 25.4; // Рисуем рамку таблицы с увеличенной толщиной (0.5 мм = примерно в 5 раз толще) // Используем ту же толщину, что и для рамок ГОСТ, чтобы линии были заметными QPen tablePen(Qt::black, 0.5 * mmToPixels); tablePen.setCosmetic(false); // Важно для PDF - использовать физические единицы painter.setPen(tablePen); // Настройки шрифта для таблицы - получаем из настроек проекта int fontSize = 12; int fontStretch = 100; if (mainController && mainController->perechenTableController()) { fontSize = mainController->perechenTableController()->getFontSize(); fontStretch = mainController->perechenTableController()->getFontStretch(); } QFont tableFont = createGostFont(fontSize, false, true, fontStretch); painter.setFont(tableFont); // Заголовки колонок QStringList headers = {"Поз.\nобозначение", "Наименование", "Кол.", "Примечание"}; qreal posWidth = 20 * mmToPixels; // Поз.: 20мм qreal nameWidth = 110 * mmToPixels; // Наименование: 110мм qreal qtyWidth = 10 * mmToPixels; // Кол.: 10мм qreal noteWidth = 45 * mmToPixels; // Примечание: 45мм qreal rowHeight = 8 * mmToPixels; qreal headerHeight = 15 * mmToPixels; // Позиция начала таблицы qreal tableStartX = tableRect.x(); // Рисуем заголовки с фиксированными размерами колонок qreal currentX = tableStartX; // Колонка "Поз." (20мм) QRectF posHeaderRect(currentX, tableRect.y(), posWidth, headerHeight); painter.drawRect(posHeaderRect); painter.drawText(posHeaderRect, headers[0], QTextOption(Qt::AlignCenter)); currentX += posWidth; // Колонка "Наименование" (110мм) QRectF nameHeaderRect(currentX, tableRect.y(), nameWidth, headerHeight); painter.drawRect(nameHeaderRect); painter.drawText(nameHeaderRect, headers[1], QTextOption(Qt::AlignCenter)); currentX += nameWidth; // Колонка "Кол." (10мм) QRectF qtyHeaderRect(currentX, tableRect.y(), qtyWidth, headerHeight); painter.drawRect(qtyHeaderRect); painter.drawText(qtyHeaderRect, headers[2], QTextOption(Qt::AlignCenter)); currentX += qtyWidth; // Колонка "Примечание" (45мм) QRectF noteHeaderRect(currentX, tableRect.y(), noteWidth, headerHeight); painter.drawRect(noteHeaderRect); painter.drawText(noteHeaderRect, headers[3], QTextOption(Qt::AlignCenter)); // Рисуем данные с указанным диапазоном строк int totalRows = perechenModel->rowCount(); int endRow = qMin(startRow + rowCount, totalRows); for (int displayRow = 0; displayRow < rowCount; ++displayRow) { int row = startRow + displayRow; // Номер строки в модели currentX = tableStartX; // Колонка "Поз." (20мм) QRectF posCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, posWidth, rowHeight); painter.drawRect(posCellRect); // Если это реальная строка данных (не пустая) if (row < totalRows) { QModelIndex posIndex = perechenModel->index(row, 0); if (posIndex.isValid()) { QString cellText = perechenModel->data(posIndex, Qt::DisplayRole).toString(); // Получаем поджим для этой ячейки int cellStretch = getCellStretch(posIndex, fontStretch); QFont cellFont = createGostFont(fontSize, false, true, cellStretch); painter.setFont(cellFont); painter.drawText(posCellRect, cellText, QTextOption(Qt::AlignCenter)); // Восстанавливаем основной шрифт painter.setFont(tableFont); } } currentX += posWidth; // Колонка "Наименование" (110мм) QRectF nameCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, nameWidth, rowHeight); painter.drawRect(nameCellRect); // Если это реальная строка данных (не пустая) if (row < totalRows) { QModelIndex nameIndex = perechenModel->index(row, 1); if (nameIndex.isValid()) { QString cellText = perechenModel->data(nameIndex, Qt::DisplayRole).toString(); // Получаем поджим для этой ячейки int cellStretch = getCellStretch(nameIndex, fontStretch); QFont cellFont = createGostFont(fontSize, false, true, cellStretch); // Проверяем, является ли ячейка заголовком из PerechenCellData bool isHeader = false; bool shouldUnderline = false; QVariant cellData = perechenModel->data(nameIndex, Qt::UserRole); if (cellData.isValid() && cellData.canConvert()) { PerechenCellData cell = cellData.value(); isHeader = cell.isHeader; shouldUnderline = cell.isUnderline; } // Если это заголовок, применяем специальное форматирование if (isHeader) { // Сохраняем текущие настройки QPen originalPen = painter.pen(); QFont originalFont = painter.font(); // Устанавливаем шрифт с поджимом для заголовка painter.setFont(cellFont); // Рисуем текст по центру без переноса строк QTextOption headerTextOption(Qt::AlignCenter); headerTextOption.setWrapMode(QTextOption::NoWrap); // Явно отключаем перенос строк painter.drawText(nameCellRect, cellText.trimmed(), headerTextOption); // Проверяем, нужно ли рисовать подчеркивание if (shouldUnderline) { // Рисуем подчеркивание вручную с настраиваемым расстоянием QFontMetrics metrics(painter.font()); QRectF textRect = metrics.boundingRect(cellText.trimmed()); // Вычисляем позицию текста по центру qreal textX = nameCellRect.x() + (nameCellRect.width() - textRect.width()) / 2; qreal textY = nameCellRect.y() + (nameCellRect.height() + textRect.height()) / 2; // Настраиваемое расстояние подчеркивания от текста (в пикселях) qreal underlineOffset = 2.0; // Можно изменить это значение // Рисуем линию подчеркивания QPen underlinePen(Qt::black, 1.0); painter.setPen(underlinePen); painter.drawLine( textX, textY + underlineOffset, textX + textRect.width(), textY + underlineOffset ); } // Восстанавливаем оригинальные настройки painter.setFont(originalFont); painter.setPen(originalPen); } else { // Обычное форматирование (по левому краю) - используем drawCellWithStretch без переноса drawCellWithStretch(painter, nameIndex, nameCellRect.adjusted(2*mmToPixels,0,0,0), cellText, fontSize, fontStretch, tableFont, Qt::AlignLeft|Qt::AlignVCenter, mainController); } } } currentX += nameWidth; // Колонка "Кол." (10мм) QRectF qtyCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, qtyWidth, rowHeight); painter.drawRect(qtyCellRect); // Если это реальная строка данных (не пустая) if (row < totalRows) { QModelIndex qtyIndex = perechenModel->index(row, 2); if (qtyIndex.isValid()) { QString cellText = perechenModel->data(qtyIndex, Qt::DisplayRole).toString(); // Получаем поджим для этой ячейки int cellStretch = getCellStretch(qtyIndex, fontStretch); QFont cellFont = createGostFont(fontSize, false, true, cellStretch); painter.setFont(cellFont); painter.drawText(qtyCellRect, cellText, QTextOption(Qt::AlignCenter)); // Восстанавливаем основной шрифт painter.setFont(tableFont); } } currentX += qtyWidth; // Колонка "Примечание" (45мм) QRectF noteCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, noteWidth, rowHeight); painter.drawRect(noteCellRect); // Если это реальная строка данных (не пустая) if (row < totalRows) { QModelIndex noteIndex = perechenModel->index(row, 3); if (noteIndex.isValid()) { QString cellText = perechenModel->data(noteIndex, Qt::DisplayRole).toString(); // Получаем поджим для этой ячейки int cellStretch = getCellStretch(noteIndex, fontStretch); QFont cellFont = createGostFont(fontSize, false, true, cellStretch); painter.setFont(cellFont); painter.drawText(noteCellRect, cellText, QTextOption(Qt::AlignCenter)); // Восстанавливаем основной шрифт painter.setFont(tableFont); } } } return true; } // Утилитарные функции для работы с шрифтом ГОСТ // Вспомогательная функция для получения поджима ячейки int PDFController::getCellStretch(const QModelIndex &index, int defaultStretch) { if (!index.isValid()) { return defaultStretch; } QVariant cellData = index.model()->data(index, Qt::UserRole); if (cellData.isValid()) { // Пытаемся получить поджим из разных типов CellData if (cellData.canConvert()) { PerechenCellData cell = cellData.value(); if (cell.stretch != 100) { return cell.stretch; } } else if (cellData.canConvert()) { SpecificationPCBCellData cell = cellData.value(); if (cell.stretch != 100) { return cell.stretch; } } else if (cellData.canConvert()) { SpecificationCellData cell = cellData.value(); if (cell.stretch != 100) { return cell.stretch; } } else if (cellData.canConvert()) { VedomostCellData cell = cellData.value(); if (cell.stretch != 100) { return cell.stretch; } } } return defaultStretch; } bool PDFController::getCellUnderline(const QModelIndex &index, bool defaultUnderline) { if (!index.isValid()) { return defaultUnderline; } QVariant cellData = index.model()->data(index, Qt::UserRole); if (cellData.isValid()) { // Пытаемся получить флаг подчеркивания из разных типов CellData if (cellData.canConvert()) { SpecificationPCBCellData cell = cellData.value(); return cell.isUnderline; } else if (cellData.canConvert()) { VedomostCellData cell = cellData.value(); return cell.isUnderline; } else if (cellData.canConvert()) { SpecificationCellData cell = cellData.value(); return cell.isUnderline; } else if (cellData.canConvert()) { PerechenCellData cell = cellData.value(); return cell.isUnderline; } // Для других типов CellData пока используем значение по умолчанию // (можно добавить поддержку позже, если понадобится) } return defaultUnderline; } // Вспомогательная функция для рисования ячейки с учетом поджима // Без автоматического переноса строк - текст рисуется в одну строку // Использует масштабирование через QTransform вместо setStretch для более плавного изменения void PDFController::drawCellWithStretch(QPainter &painter, const QModelIndex &index, const QRectF &rect, const QString &text, int fontSize, int defaultStretch, const QFont &baseFont, Qt::Alignment alignment, MainController *mainController) { int cellStretch = getCellStretch(index, defaultStretch); // Создаем шрифт без поджима для измерения ширины текста QFont cellFont = createGostFont(fontSize, false, true, 100); painter.setFont(cellFont); QFontMetrics metrics(cellFont); // Вычисляем коэффициент масштабирования (stretch = 100 означает масштаб 1.0) qreal scaleX = cellStretch / 100.0; // Вычисляем ширину текста после масштабирования qreal textWidth = metrics.horizontalAdvance(text) * scaleX; // Проверяем, помещается ли текст в ячейку после масштабирования QString displayText = text; bool isOverflow = false; if (textWidth > rect.width()) { // Текст не помещается даже после масштабирования - обрезаем его с многоточием // Вычисляем максимальную ширину текста до масштабирования qreal maxTextWidth = rect.width() / scaleX; displayText = metrics.elidedText(text, Qt::ElideRight, maxTextWidth); isOverflow = true; } // Уведомляем модель о переполнении ячейки (если передан MainController и индекс валиден) if (mainController && index.isValid() && index.model()) { // Определяем тип модели и вызываем соответствующий метод // Используем dynamic_cast, так как модели наследуются от QAbstractTableModel (QObject) QAbstractItemModel *model = const_cast(index.model()); if (model) { // Пытаемся привести к конкретным типам моделей через dynamic_cast PerechenTableModel *perechenModel = dynamic_cast(model); if (perechenModel) { perechenModel->setCellOverflow(index.row(), index.column(), isOverflow); } else { SpecificationPCBTableModel *specPcbModel = dynamic_cast(model); if (specPcbModel) { specPcbModel->setCellOverflow(index.row(), index.column(), isOverflow); } else { SpecificationTableModel *specModel = dynamic_cast(model); if (specModel) { specModel->setCellOverflow(index.row(), index.column(), isOverflow); } else { VedomostTableModel *vedomostModel = dynamic_cast(model); if (vedomostModel) { vedomostModel->setCellOverflow(index.row(), index.column(), isOverflow); } } } } } } if (cellStretch == 100) { // Если поджим 100%, используем обычный шрифт без масштабирования QTextOption textOption(alignment); textOption.setWrapMode(QTextOption::NoWrap); painter.drawText(rect, displayText, textOption); } else { // Используем масштабирование через QTransform для более плавного изменения ширины // Сохраняем текущее преобразование painter.save(); // Применяем масштабирование по оси X // Масштабируем относительно левого края ячейки (для выравнивания влево) // или центра (для выравнивания по центру) qreal scaleOriginX = rect.x(); if (alignment & Qt::AlignHCenter) { scaleOriginX = rect.x() + rect.width() / 2.0; } else if (alignment & Qt::AlignRight) { scaleOriginX = rect.x() + rect.width(); } QTransform transform; transform.translate(scaleOriginX, rect.y()); transform.scale(scaleX, 1.0); transform.translate(-scaleOriginX, -rect.y()); painter.setTransform(transform, true); // Создаем расширенную область для рисования текста, чтобы он не обрезался // После применения transform с scaleX, текст будет масштабирован // Чтобы текст после масштабирования поместился в rect, нужно рисовать его // в области, которая после масштабирования будет равна rect // Формула: drawRect.width() * scaleX = rect.width() // Значит: drawRect.width() = rect.width() / scaleX QRectF drawRect = rect; drawRect.setWidth(rect.width() / scaleX); // Но также нужно учесть реальную ширину текста // Если текст уже помещается в расширенную область, используем его ширину qreal originalTextWidth = metrics.horizontalAdvance(displayText); if (originalTextWidth < drawRect.width()) { // Текст помещается, но нужно учесть выравнивание // Для выравнивания влево оставляем как есть // Для выравнивания по центру или вправо нужно сдвинуть drawRect if (alignment & Qt::AlignHCenter) { drawRect.setX(rect.x() + (rect.width() / scaleX - originalTextWidth) / 2.0); drawRect.setWidth(originalTextWidth); } else if (alignment & Qt::AlignRight) { drawRect.setX(rect.x() + rect.width() / scaleX - originalTextWidth); drawRect.setWidth(originalTextWidth); } else { // Выравнивание влево - используем полную ширину для корректного масштабирования // но текст будет рисоваться с левого края } } // Рисуем текст без переноса в расширенной области QTextOption textOption(alignment); textOption.setWrapMode(QTextOption::NoWrap); painter.drawText(drawRect, displayText, textOption); // Восстанавливаем преобразование painter.restore(); } painter.setFont(baseFont); } QFont PDFController::createGostFont(int pointSize, bool bold, bool italic, int stretch) { // Загружаем TTF шрифт из QRC ресурсов QString fontPath = ":/assets/GOST_A.TTF"; int fontId = QFontDatabase::addApplicationFont(fontPath); if (fontId == -1) { qDebug() << "PDFController::createGostFont: Не удалось загрузить шрифт из ресурсов, используем Arial"; QFont fallbackFont("Arial", pointSize); fallbackFont.setBold(bold); fallbackFont.setItalic(italic); fallbackFont.setStretch(stretch); return fallbackFont; } QStringList fontFamilies = QFontDatabase::applicationFontFamilies(fontId); if (fontFamilies.isEmpty()) { qDebug() << "PDFController::createGostFont: Не удалось получить имя семейства шрифта, используем Arial"; QFont fallbackFont("Arial", pointSize); fallbackFont.setBold(bold); fallbackFont.setItalic(italic); fallbackFont.setStretch(stretch); return fallbackFont; } QFont gostFont(fontFamilies.first(), pointSize); gostFont.setBold(bold); gostFont.setItalic(italic); gostFont.setStretch(stretch); return gostFont; } void PDFController::drawTextWithGostFont(QPainter &painter, const QRectF &rect, const QString &text, int pointSize, Qt::Alignment alignment) { QFont gostFont = createGostFont(pointSize); painter.setFont(gostFont); painter.drawText(rect, text, QTextOption(alignment)); } void PDFController::drawTextWithAutoSize(QPainter &painter, const QRectF &rect, const QString &text, int maxPointSize) { QFont testFont = createGostFont(maxPointSize); QFontMetrics metrics(testFont); // Уменьшаем размер шрифта, пока текст не поместится int pointSize = maxPointSize; while (pointSize > 6) { testFont.setPointSize(pointSize); metrics = QFontMetrics(testFont); if (metrics.horizontalAdvance(text) <= rect.width() && metrics.height() <= rect.height()) { break; } pointSize--; } painter.setFont(testFont); painter.drawText(rect, text, QTextOption(Qt::AlignCenter)); } void PDFController::drawTextMultiline(QPainter &painter, const QRectF &rect, const QString &text, const QFont &font, int maxLines) { painter.setFont(font); QFontMetrics metrics(font); // Проверяем, помещается ли текст в одну строку if (metrics.horizontalAdvance(text) <= rect.width()) { painter.drawText(rect, text, QTextOption(Qt::AlignCenter)); return; } // Разбиваем текст на слова QStringList words = text.split(' ', Qt::SkipEmptyParts); if (words.isEmpty()) { painter.drawText(rect, text, QTextOption(Qt::AlignCenter)); return; } // Пытаемся разбить на строки QStringList lines; QString currentLine = words.first(); // Проверяем, помещается ли первое слово if (metrics.horizontalAdvance(currentLine) > rect.width()) { // Если слово не помещается, обрезаем его currentLine = metrics.elidedText(currentLine, Qt::ElideRight, rect.width()); } for (int i = 1; i < words.size(); ++i) { QString testLine = currentLine + " " + words[i]; if (metrics.horizontalAdvance(testLine) <= rect.width()) { currentLine = testLine; } else { lines.append(currentLine); currentLine = words[i]; // Проверяем, помещается ли слово if (metrics.horizontalAdvance(currentLine) > rect.width()) { currentLine = metrics.elidedText(currentLine, Qt::ElideRight, rect.width()); } if (lines.size() >= maxLines - 1) { // Если достигли максимального количества строк, добавляем оставшиеся слова for (int j = i + 1; j < words.size(); ++j) { QString testCurrent = currentLine + " " + words[j]; if (metrics.horizontalAdvance(testCurrent) <= rect.width()) { currentLine = testCurrent; } else { break; } } // Обрезаем последнюю строку, если она не помещается if (metrics.horizontalAdvance(currentLine) > rect.width()) { currentLine = metrics.elidedText(currentLine, Qt::ElideRight, rect.width()); } break; } } } lines.append(currentLine); // Ограничиваем количество строк if (lines.size() > maxLines) { lines = lines.mid(0, maxLines); // Обрезаем последнюю строку, если она не помещается QString lastLine = lines.last(); if (metrics.horizontalAdvance(lastLine) > rect.width()) { lastLine = metrics.elidedText(lastLine, Qt::ElideRight, rect.width()); lines[lines.size() - 1] = lastLine; } } // Рисуем строки по центру qreal lineHeight = metrics.height(); qreal totalHeight = lines.size() * lineHeight; qreal startY = rect.top() + (rect.height() - totalHeight) / 2; for (int i = 0; i < lines.size(); ++i) { QRectF lineRect(rect.left(), startY + i * lineHeight, rect.width(), lineHeight); painter.drawText(lineRect, lines[i], QTextOption(Qt::AlignCenter)); } } QString PDFController::getInscriptionValueWithProjectParams(const TitleInscriptionsModel* titleModel, const ProjectParamTableModel* projectParamModel, int inscriptionIndex) { if (!titleModel) { return QString(); } // Получаем значение из модели надписей QString inscriptionValue = titleModel->getInscriptionValue(inscriptionIndex); // Если значение пустое, возвращаем его как есть if (inscriptionValue.isEmpty() || inscriptionValue == "-- Не выбрано --") { return ""; } // Если модель параметров проекта не передана, возвращаем значение надписи if (!projectParamModel) { return inscriptionValue; } // Получаем карту параметров проекта QMap projectParams = projectParamModel->getDataAsMap(); // Ищем параметр с таким же названием if (projectParams.contains(inscriptionValue)) { QString projectParamValue = projectParams[inscriptionValue]; // Если значение параметра проекта не пустое, возвращаем его if (!projectParamValue.isEmpty()) { return projectParamValue; } } // Если сопоставления нет или значение параметра пустое, возвращаем значение надписи return inscriptionValue; } bool PDFController::addSpecificationPcbTableRange(QPainter &painter, SpecificationPCBTableModel *specificationModel, const QRectF &tableRect, int startRow, int rowCount, MainController *mainController) { if (!specificationModel) { return false; } // Размеры колонок в миллиметрах (конвертируем в пиксели) // Используем правильное разрешение для PDF qreal resolution = getDeviceResolution(painter.device()); qreal mmToPixels = resolution / 25.4; // Рисуем рамку таблицы с увеличенной толщиной (0.5 мм = примерно в 5 раз толще) // Используем ту же толщину, что и для рамок ГОСТ, чтобы линии были заметными QPen tablePen(Qt::black, 0.5 * mmToPixels); tablePen.setCosmetic(false); // Важно для PDF - использовать физические единицы painter.setPen(tablePen); // Настройки шрифта для таблицы - получаем из настроек проекта int fontSize = 12; int fontStretch = 100; if (mainController && mainController->specificationPCBController()) { fontSize = mainController->specificationPCBController()->getFontSize(); fontStretch = mainController->specificationPCBController()->getFontStretch(); } QFont tableFont = createGostFont(fontSize, false, true, fontStretch); painter.setFont(tableFont); // Заголовки колонок для спецификации PCB QStringList headers = {"Формат", "Зона", "Поз.", "Обозначение", "Наименование", "Кол.", "Примечание"}; qreal formatWidth = 6 * mmToPixels; // Формат: 15мм qreal zoneWidth = 6 * mmToPixels; // Зона: 15мм qreal posWidth = 8 * mmToPixels; // Поз.: 15мм qreal designationWidth = 70 * mmToPixels; // Обозначение: 25мм qreal nameWidth = 63 * mmToPixels; // Наименование: 60мм qreal qtyWidth = 10 * mmToPixels; // Кол.: 10мм qreal noteWidth = 22 * mmToPixels; // Примечание: 30мм qreal headerHeight = 15*mmToPixels; qreal rowHeight = 8.035 * mmToPixels; // Позиция начала таблицы qreal tableStartX = tableRect.x(); // Рисуем заголовки с фиксированными размерами колонок qreal currentX = tableStartX; // Колонка "Формат" (15мм) QRectF formatHeaderRect(currentX, tableRect.y(), formatWidth, headerHeight); painter.drawRect(formatHeaderRect); painter.save(); QTransform transform2; transform2.translate(formatHeaderRect.left(),formatHeaderRect.bottom()); transform2.rotate(-90); painter.setTransform(transform2); painter.drawText(0,0,formatHeaderRect.height(),formatHeaderRect.width(), Qt::AlignCenter, headers[0]); painter.restore(); currentX += formatWidth; // Колонка "Зона" (15мм) QRectF zoneHeaderRect(currentX, tableRect.y(), zoneWidth, headerHeight); painter.drawRect(zoneHeaderRect); painter.save(); QTransform transform1; transform1.translate(zoneHeaderRect.left(),zoneHeaderRect.bottom()); transform1.rotate(-90); painter.setTransform(transform1); painter.drawText(0,0,zoneHeaderRect.height(),zoneHeaderRect.width(), Qt::AlignCenter, headers[1]); painter.restore(); currentX += zoneWidth; // Колонка "Поз." (15мм) QRectF posHeaderRect(currentX, tableRect.y(), posWidth, headerHeight); painter.drawRect(posHeaderRect); painter.save(); QTransform transform3; transform3.translate(posHeaderRect.left(),posHeaderRect.bottom()); transform3.rotate(-90); painter.setTransform(transform3); painter.drawRect(0,0,posHeaderRect.height(),posHeaderRect.width()); painter.drawText(0,0,posHeaderRect.height(),posHeaderRect.width(),Qt::AlignCenter ,headers[2]); painter.restore(); currentX += posWidth; // Колонка "Обозначение" (25мм) QRectF designationHeaderRect(currentX, tableRect.y(), designationWidth, headerHeight); painter.drawRect(designationHeaderRect); painter.drawText(designationHeaderRect, headers[3], QTextOption(Qt::AlignCenter)); currentX += designationWidth; // Колонка "Наименование" (60мм) QRectF nameHeaderRect(currentX, tableRect.y(), nameWidth, headerHeight); painter.drawRect(nameHeaderRect); painter.drawText(nameHeaderRect, headers[4], QTextOption(Qt::AlignCenter)); currentX += nameWidth; // Колонка "Кол." (10мм) QRectF qtyHeaderRect(currentX, tableRect.y(), qtyWidth, headerHeight); painter.drawRect(qtyHeaderRect); painter.drawText(qtyHeaderRect, headers[5], QTextOption(Qt::AlignCenter)); currentX += qtyWidth; // Колонка "Примечание" (30мм) QRectF noteHeaderRect(currentX, tableRect.y(), noteWidth, headerHeight); painter.drawRect(noteHeaderRect); painter.drawText(noteHeaderRect, headers[6], QTextOption(Qt::AlignCenter)); // Рисуем данные с указанным диапазоном строк int totalRows = specificationModel->rowCount(); int endRow = qMin(startRow + rowCount, totalRows); for (int displayRow = 0; displayRow < rowCount; ++displayRow) { int row = startRow + displayRow; // Номер строки в модели currentX = tableStartX; // Колонка "Формат" (15мм) QRectF formatCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, formatWidth, rowHeight); painter.drawRect(formatCellRect); // Если это реальная строка данных (не пустая) if (row < totalRows) { QModelIndex formatIndex = specificationModel->index(row, 0); if (formatIndex.isValid()) { QString cellText = specificationModel->data(formatIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, formatIndex, formatCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignCenter, mainController); } } currentX += formatWidth; // Колонка "Зона" (15мм) QRectF zoneCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, zoneWidth, rowHeight); painter.drawRect(zoneCellRect); if (row < totalRows) { QModelIndex zoneIndex = specificationModel->index(row, 1); if (zoneIndex.isValid()) { QString cellText = specificationModel->data(zoneIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, zoneIndex, zoneCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignCenter, mainController); } } currentX += zoneWidth; // Колонка "Поз." (15мм) QRectF posCellRect(currentX, tableRect.y() + (displayRow ) * rowHeight+headerHeight, posWidth, rowHeight); painter.drawRect(posCellRect); if (row < totalRows) { QModelIndex posIndex = specificationModel->index(row, 2); if (posIndex.isValid()) { QString cellText = specificationModel->data(posIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, posIndex, posCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignCenter, mainController); } } currentX += posWidth; // Колонка "Обозначение" (25мм) QRectF designationCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, designationWidth, rowHeight); painter.drawRect(designationCellRect); if (row < totalRows) { QModelIndex designationIndex = specificationModel->index(row, 3); if (designationIndex.isValid()) { QString cellText = " "+ specificationModel->data(designationIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, designationIndex, designationCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignLeft|Qt::AlignVCenter, mainController); } } currentX += designationWidth; // Колонка "Наименование" (60мм) QRectF nameCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, nameWidth, rowHeight); painter.drawRect(nameCellRect); if (row < totalRows) { QModelIndex nameIndex = specificationModel->index(row, 4); if (nameIndex.isValid()) { QString cellText = specificationModel->data(nameIndex, Qt::DisplayRole).toString(); // Получаем поджим для этой ячейки int cellStretch = getCellStretch(nameIndex, fontStretch); QFont cellFont = createGostFont(fontSize, false, true, cellStretch); // Проверяем, является ли ячейка заголовком из SpecificationPCBCellData bool isHeader = false; bool shouldUnderline = false; QVariant cellData = specificationModel->data(nameIndex, Qt::UserRole); if (cellData.isValid() && cellData.canConvert()) { SpecificationPCBCellData cell = cellData.value(); isHeader = cell.isHeader; shouldUnderline = cell.isUnderline; } // Если это заголовок, применяем специальное форматирование if (isHeader) { // Сохраняем текущие настройки QPen originalPen = painter.pen(); QFont originalFont = painter.font(); // Устанавливаем шрифт с поджимом painter.setFont(cellFont); // Рисуем текст по центру без переноса строк QTextOption headerTextOption(Qt::AlignCenter); headerTextOption.setWrapMode(QTextOption::NoWrap); // Явно отключаем перенос строк painter.drawText(nameCellRect, cellText.trimmed(), headerTextOption); // Проверяем, нужно ли рисовать подчеркивание (уже получено из cellData выше) if (shouldUnderline) { // Рисуем подчеркивание вручную с настраиваемым расстоянием QFontMetrics metrics(painter.font()); QRectF textRect = metrics.boundingRect(cellText.trimmed()); // Вычисляем позицию текста по центру qreal textX = nameCellRect.x() + (nameCellRect.width() - textRect.width()) / 2; qreal textY = nameCellRect.y() + (nameCellRect.height() + textRect.height()) / 2; // Настраиваемое расстояние подчеркивания от текста (в пикселях) qreal underlineOffset = 2.0; // Можно изменить это значение // Рисуем линию подчеркивания QPen underlinePen(Qt::black, 1.0); painter.setPen(underlinePen); painter.drawLine( textX, textY + underlineOffset, textX + textRect.width(), textY + underlineOffset ); } // Восстанавливаем оригинальные настройки painter.setFont(originalFont); painter.setPen(originalPen); } else { // Обычное форматирование (по левому краю) - используем drawCellWithStretch без переноса drawCellWithStretch(painter, nameIndex, nameCellRect.adjusted(2*mmToPixels,0,0,0), cellText, fontSize, fontStretch, tableFont, Qt::AlignLeft|Qt::AlignVCenter, mainController); } } } currentX += nameWidth; // Колонка "Кол." (10мм) QRectF qtyCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, qtyWidth, rowHeight); painter.drawRect(qtyCellRect); if (row < totalRows) { QModelIndex qtyIndex = specificationModel->index(row, 5); if (qtyIndex.isValid()) { QString cellText = specificationModel->data(qtyIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, qtyIndex, qtyCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignCenter, mainController); } } currentX += qtyWidth; // Колонка "Примечание" (30мм) QRectF noteCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, noteWidth, rowHeight); painter.drawRect(noteCellRect); if (row < totalRows) { QModelIndex noteIndex = specificationModel->index(row, 6); if (noteIndex.isValid()) { QString cellText = specificationModel->data(noteIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, noteIndex, noteCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignCenter, mainController); } } } return true; } bool PDFController::addSpecificationTableRange(QPainter &painter, SpecificationTableModel *specificationModel, const QRectF &tableRect, int startRow, int rowCount, MainController *mainController) { if (!specificationModel) { return false; } // Размеры колонок в миллиметрах (конвертируем в пиксели) // Используем правильное разрешение для PDF qreal resolution = getDeviceResolution(painter.device()); qreal mmToPixels = resolution / 25.4; // Рисуем рамку таблицы с увеличенной толщиной (0.5 мм = примерно в 5 раз толще) // Используем ту же толщину, что и для рамок ГОСТ, чтобы линии были заметными QPen tablePen(Qt::black, 0.5 * mmToPixels); tablePen.setCosmetic(false); // Важно для PDF - использовать физические единицы painter.setPen(tablePen); // Настройки шрифта для таблицы - получаем из настроек проекта int fontSize = 12; int fontStretch = 100; if (mainController && mainController->specificationController()) { fontSize = mainController->specificationController()->getFontSize(); fontStretch = mainController->specificationController()->getFontStretch(); } QFont tableFont = createGostFont(fontSize, false, true, fontStretch); painter.setFont(tableFont); // Заголовки колонок для спецификации материалов QStringList headers = {"Формат", "Зона", "Поз.", "Обозначение", "Наименование", "Кол.", "Примечание"}; qreal formatWidth = 6 * mmToPixels; // Формат: 15мм qreal zoneWidth = 6 * mmToPixels; // Зона: 15мм qreal posWidth = 8 * mmToPixels; // Поз.: 15мм qreal designationWidth = 70 * mmToPixels; // Обозначение: 25мм qreal nameWidth = 63 * mmToPixels; // Наименование: 60мм qreal qtyWidth = 10 * mmToPixels; // Кол.: 10мм qreal noteWidth = 22 * mmToPixels; // Примечание: 30мм qreal headerHeight = 15*mmToPixels; qreal rowHeight = 8.035 * mmToPixels; // Позиция начала таблицы qreal tableStartX = tableRect.x(); // Рисуем заголовки с фиксированными размерами колонок qreal currentX = tableStartX; // Колонка "Формат" (15мм) QRectF formatHeaderRect(currentX, tableRect.y(), formatWidth, headerHeight); painter.drawRect(formatHeaderRect); painter.save(); QTransform transform2; transform2.translate(formatHeaderRect.left(),formatHeaderRect.bottom()); transform2.rotate(-90); painter.setTransform(transform2); painter.drawText(0,0,formatHeaderRect.height(),formatHeaderRect.width(), Qt::AlignCenter, headers[0]); painter.restore(); currentX += formatWidth; // Колонка "Зона" (15мм) QRectF zoneHeaderRect(currentX, tableRect.y(), zoneWidth, headerHeight); painter.drawRect(zoneHeaderRect); painter.save(); QTransform transform1; transform1.translate(zoneHeaderRect.left(),zoneHeaderRect.bottom()); transform1.rotate(-90); painter.setTransform(transform1); painter.drawText(0,0,zoneHeaderRect.height(),zoneHeaderRect.width(), Qt::AlignCenter, headers[1]); painter.restore(); currentX += zoneWidth; // Колонка "Поз." (15мм) QRectF posHeaderRect(currentX, tableRect.y(), posWidth, headerHeight); painter.drawRect(posHeaderRect); painter.save(); QTransform transform3; transform3.translate(posHeaderRect.left(),posHeaderRect.bottom()); transform3.rotate(-90); painter.setTransform(transform3); painter.drawRect(0,0,posHeaderRect.height(),posHeaderRect.width()); painter.drawText(0,0,posHeaderRect.height(),posHeaderRect.width(),Qt::AlignCenter ,headers[2]); painter.restore(); currentX += posWidth; // Колонка "Обозначение" (25мм) QRectF designationHeaderRect(currentX, tableRect.y(), designationWidth, headerHeight); painter.drawRect(designationHeaderRect); painter.drawText(designationHeaderRect, headers[3], QTextOption(Qt::AlignCenter)); currentX += designationWidth; // Колонка "Наименование" (60мм) QRectF nameHeaderRect(currentX, tableRect.y(), nameWidth, headerHeight); painter.drawRect(nameHeaderRect); painter.drawText(nameHeaderRect, headers[4], QTextOption(Qt::AlignCenter)); currentX += nameWidth; // Колонка "Кол." (10мм) QRectF qtyHeaderRect(currentX, tableRect.y(), qtyWidth, headerHeight); painter.drawRect(qtyHeaderRect); painter.drawText(qtyHeaderRect, headers[5], QTextOption(Qt::AlignCenter)); currentX += qtyWidth; // Колонка "Примечание" (30мм) QRectF noteHeaderRect(currentX, tableRect.y(), noteWidth, headerHeight); painter.drawRect(noteHeaderRect); painter.drawText(noteHeaderRect, headers[6], QTextOption(Qt::AlignCenter)); // Рисуем данные с указанным диапазоном строк int totalRows = specificationModel->rowCount(); int endRow = qMin(startRow + rowCount, totalRows); for (int displayRow = 0; displayRow < rowCount; ++displayRow) { int row = startRow + displayRow; // Номер строки в модели currentX = tableStartX; // Колонка "Формат" (15мм) QRectF formatCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, formatWidth, rowHeight); painter.drawRect(formatCellRect); // Если это реальная строка данных (не пустая) if (row < totalRows) { QModelIndex formatIndex = specificationModel->index(row, 0); if (formatIndex.isValid()) { QString cellText = specificationModel->data(formatIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, formatIndex, formatCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignCenter, mainController); } } currentX += formatWidth; // Колонка "Зона" (15мм) QRectF zoneCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, zoneWidth, rowHeight); painter.drawRect(zoneCellRect); if (row < totalRows) { QModelIndex zoneIndex = specificationModel->index(row, 1); if (zoneIndex.isValid()) { QString cellText = specificationModel->data(zoneIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, zoneIndex, zoneCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignCenter, mainController); } } currentX += zoneWidth; // Колонка "Поз." (15мм) QRectF posCellRect(currentX, tableRect.y() + (displayRow ) * rowHeight+headerHeight, posWidth, rowHeight); painter.drawRect(posCellRect); if (row < totalRows) { QModelIndex posIndex = specificationModel->index(row, 2); if (posIndex.isValid()) { QString cellText = specificationModel->data(posIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, posIndex, posCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignCenter, mainController); } } currentX += posWidth; // Колонка "Обозначение" (25мм) QRectF designationCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, designationWidth, rowHeight); painter.drawRect(designationCellRect); if (row < totalRows) { QModelIndex designationIndex = specificationModel->index(row, 3); if (designationIndex.isValid()) { QString cellText = " " + specificationModel->data(designationIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, designationIndex, designationCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignLeft|Qt::AlignVCenter, mainController); } } currentX += designationWidth; // Колонка "Наименование" (60мм) QRectF nameCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, nameWidth, rowHeight); painter.drawRect(nameCellRect); if (row < totalRows) { QModelIndex nameIndex = specificationModel->index(row, 4); if (nameIndex.isValid()) { QString cellText = specificationModel->data(nameIndex, Qt::DisplayRole).toString(); // Получаем поджим для этой ячейки int cellStretch = getCellStretch(nameIndex, fontStretch); QFont cellFont = createGostFont(fontSize, false, true, cellStretch); // Проверяем, является ли ячейка заголовком из SpecificationCellData bool isHeader = false; bool shouldUnderline = false; QVariant cellData = specificationModel->data(nameIndex, Qt::UserRole); if (cellData.isValid() && cellData.canConvert()) { SpecificationCellData cell = cellData.value(); isHeader = cell.isHeader; shouldUnderline = cell.isUnderline; } // Если это заголовок, применяем специальное форматирование if (isHeader) { // Сохраняем текущие настройки QPen originalPen = painter.pen(); QFont originalFont = painter.font(); // Устанавливаем шрифт с поджимом painter.setFont(cellFont); // Рисуем текст по центру без переноса строк QTextOption headerTextOption(Qt::AlignCenter); headerTextOption.setWrapMode(QTextOption::NoWrap); // Явно отключаем перенос строк painter.drawText(nameCellRect, cellText.trimmed(), headerTextOption); // Проверяем, нужно ли рисовать подчеркивание (уже получено из cellData выше) if (shouldUnderline) { // Рисуем подчеркивание вручную с настраиваемым расстоянием QFontMetrics metrics(painter.font()); QRectF textRect = metrics.boundingRect(cellText.trimmed()); // Вычисляем позицию текста по центру qreal textX = nameCellRect.x() + (nameCellRect.width() - textRect.width()) / 2; qreal textY = nameCellRect.y() + (nameCellRect.height() + textRect.height()) / 2; // Настраиваемое расстояние подчеркивания от текста (в пикселях) qreal underlineOffset = 2.0; // Можно изменить это значение // Рисуем линию подчеркивания QPen underlinePen(Qt::black, 1.0); painter.setPen(underlinePen); painter.drawLine( textX, textY + underlineOffset, textX + textRect.width(), textY + underlineOffset ); } // Восстанавливаем оригинальные настройки painter.setFont(originalFont); painter.setPen(originalPen); } else { // Обычное форматирование (по левому краю) - используем drawCellWithStretch без переноса drawCellWithStretch(painter, nameIndex, nameCellRect.adjusted(2*mmToPixels,0,0,0), cellText, fontSize, fontStretch, tableFont, Qt::AlignLeft|Qt::AlignVCenter, mainController); } } } currentX += nameWidth; // Колонка "Кол." (10мм) QRectF qtyCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, qtyWidth, rowHeight); painter.drawRect(qtyCellRect); if (row < totalRows) { QModelIndex qtyIndex = specificationModel->index(row, 5); if (qtyIndex.isValid()) { QString cellText = specificationModel->data(qtyIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, qtyIndex, qtyCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignCenter, mainController); } } currentX += qtyWidth; // Колонка "Примечание" (30мм) QRectF noteCellRect(currentX, tableRect.y() + (displayRow) * rowHeight+headerHeight, noteWidth, rowHeight); painter.drawRect(noteCellRect); if (row < totalRows) { QModelIndex noteIndex = specificationModel->index(row, 6); if (noteIndex.isValid()) { QString cellText = specificationModel->data(noteIndex, Qt::DisplayRole).toString(); drawCellWithStretch(painter, noteIndex, noteCellRect, cellText, fontSize, fontStretch, tableFont, Qt::AlignLeft|Qt::AlignVCenter, mainController); } } } return true; } bool PDFController::addVedomostTableRange(QPainter &painter, VedomostTableModel *vedomostModel, const QRectF &tableRect, int startRow, int rowCount, MainController *mainController) { if (!vedomostModel) { return false; } // Размеры колонок в миллиметрах (конвертируем в пиксели) для А5 формата // Используем правильное разрешение для PDF qreal resolution = getDeviceResolution(painter.device()); qreal mmToPixels = resolution / 25.4; // Рисуем рамку таблицы с увеличенной толщиной (0.5 мм = примерно в 5 раз толще) // Используем ту же толщину, что и для рамок ГОСТ, чтобы линии были заметными QPen tablePen(Qt::black, 0.5 * mmToPixels); tablePen.setCosmetic(false); // Важно для PDF - использовать физические единицы painter.setPen(tablePen); // Настройки шрифта для таблицы - получаем из настроек проекта int fontSize = 12; int fontStretch = 100; if (mainController && mainController->vedomostController()) { fontSize = mainController->vedomostController()->getFontSize(); fontStretch = mainController->vedomostController()->getFontStretch(); } QFont tableFont = createGostFont(fontSize, false, true, fontStretch); painter.setFont(tableFont); // Заголовки колонок для ведомости покупных изделий QStringList headers = {"№ строки","Наименование", "Код продукции", "Обозначение документа на поставку", "Поставщик", "Куда входит (обозначение)", "Количество на изделие", "Количество в комплекте", "Количество на регулир", "Количество всего", "Примечание"}; qreal nnRowWidth = 7*mmToPixels; qreal nameWidth = 60 * mmToPixels; // Наименование qreal productCodeWidth = 45 * mmToPixels; // Код продукции qreal docCodeWidth = 70 * mmToPixels; // Обозначение документа на поставку qreal supplierWidth = 55 * mmToPixels; // Поставщик qreal whereUsedWidth = 70 * mmToPixels; // Куда входит (обозначение) qreal qtyPerItemWidth = 16 * mmToPixels; // Количество на изделие qreal qtyInSetWidth = 16 * mmToPixels; // Количество в комплекте qreal qtyForRegWidth = 16 * mmToPixels; // Количество на регулир qreal totalQtyWidth = 16 * mmToPixels; // Количество всего qreal noteWidth = 24 * mmToPixels; // Примечание qreal headerHeight = 27 * mmToPixels; qreal rowHeight = 8.17 * mmToPixels; // Позиция начала таблицы qreal tableStartX = tableRect.x(); // Рисуем заголовки с фиксированными размерами колонок qreal currentX = tableStartX; //qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; qreal topHeaderHeight = 9 * mmToPixels; // Высота верхней части заголовка qreal bottomHeaderHeight = 18 * mmToPixels; // Высота нижней части заголовка // Рисуем верхнюю строку заголовков (первые 6 колонок + объединенная "Количество") for (int i = 0; i < 6; ++i) { qreal colWidth = 0; switch (i) { case 0: colWidth = nnRowWidth; break; case 1: colWidth = nameWidth; break; case 2: colWidth = productCodeWidth; break; case 3: colWidth = docCodeWidth; break; case 4: colWidth = supplierWidth; break; case 5: colWidth = whereUsedWidth; break; } QRectF headerRect(currentX, tableRect.y(), colWidth, headerHeight); painter.drawRect(headerRect); // Для длинных заголовков используем поворот текста if (i ==0) { // "Обозначение документа на поставку" и "Куда входит (обозначение)" painter.save(); QTransform transform; transform.translate(headerRect.left(), headerRect.bottom()); transform.rotate(-90); painter.setTransform(transform); painter.drawText(0, 0, headerRect.height(), headerRect.width(), Qt::AlignCenter, headers[i]); painter.restore(); } else { painter.drawText(headerRect, headers[i], QTextOption(Qt::AlignCenter)); } currentX += colWidth; } // Рисуем объединенную ячейку "Количество" (4 колонки) qreal quantityTotalWidth = qtyPerItemWidth + qtyInSetWidth + qtyForRegWidth + totalQtyWidth; QRectF quantityHeaderRect(currentX, tableRect.y(), quantityTotalWidth, topHeaderHeight); painter.drawRect(quantityHeaderRect); painter.drawText(quantityHeaderRect, "Количество", QTextOption(Qt::AlignCenter)); // Рисуем нижнюю строку заголовков для колонок количества qreal bottomHeaderY = tableRect.y() + topHeaderHeight; qreal bottomCurrentX = currentX; QStringList quantityHeaders = {"на из-делии", "в ком-плекте", "на ре-гулир.", "всего"}; qreal quantityWidths[] = {qtyPerItemWidth, qtyInSetWidth, qtyForRegWidth, totalQtyWidth}; for (int i = 0; i < 4; ++i) { QRectF bottomHeaderRect(bottomCurrentX, bottomHeaderY, quantityWidths[i], bottomHeaderHeight); painter.drawRect(bottomHeaderRect); painter.drawText(bottomHeaderRect, quantityHeaders[i], QTextOption(Qt::AlignCenter)); bottomCurrentX += quantityWidths[i]; } // Рисуем последнюю колонку "Примечание" QRectF noteHeaderRect(bottomCurrentX, tableRect.y(), noteWidth, headerHeight); painter.drawRect(noteHeaderRect); painter.drawText(noteHeaderRect, headers[10], QTextOption(Qt::AlignCenter)); // Рисуем данные с указанным диапазоном строк int totalRows = vedomostModel->rowCount(); int endRow = qMin(startRow + rowCount, totalRows); for (int displayRow = 0; displayRow < rowCount; ++displayRow) { int row = startRow + displayRow; // Номер строки в модели currentX = tableStartX; // Рисуем ячейки для каждой колонки for (int col = 0; col < 11; ++col) { qreal colWidth = 0; switch (col) { case 0: colWidth = nnRowWidth; break; // № строки case 1: colWidth = nameWidth; break; // Наименование case 2: colWidth = productCodeWidth; break; // Код продукции case 3: colWidth = docCodeWidth; break; // Обозначение документа на поставку case 4: colWidth = supplierWidth; break; // Поставщик case 5: colWidth = whereUsedWidth; break; // Куда входит (обозначение) case 6: colWidth = qtyPerItemWidth; break; // Количество на изделие case 7: colWidth = qtyInSetWidth; break; // Количество в комплекте case 8: colWidth = qtyForRegWidth; break; // Количество на регулир case 9: colWidth = totalQtyWidth; break; // Количество всего case 10: colWidth = noteWidth; break; // Примечание } // Учитываем новую высоту заголовка (верхняя + нижняя части) qreal totalHeaderHeight = topHeaderHeight + bottomHeaderHeight; QRectF cellRect(currentX, tableRect.y() + (displayRow) * rowHeight + totalHeaderHeight, colWidth, rowHeight); painter.drawRect(cellRect); // Обрабатываем каждую колонку отдельно if (col == 0) { // Первая колонка - номер строки (начиная с 1) painter.drawText(cellRect, QString::number(displayRow + 1), QTextOption(Qt::AlignCenter)); } else if (row < totalRows) { // Остальные колонки - данные из модели (смещение на -1, так как первая колонка не входит в модель) QModelIndex cellIndex = vedomostModel->index(row, col - 1); if (cellIndex.isValid()) { QString cellText = " "+ vedomostModel->data(cellIndex, Qt::DisplayRole).toString(); // Проверяем, является ли ячейка заголовком (для колонки "Наименование" - col == 1) bool isHeader = false; bool shouldUnderline = false; if (col == 1) { // Колонка "Наименование" QVariant cellData = vedomostModel->data(cellIndex, Qt::UserRole); if (cellData.isValid() && cellData.canConvert()) { VedomostCellData cell = cellData.value(); isHeader = cell.isHeader; shouldUnderline = cell.isUnderline; } } if (isHeader) { // Если это заголовок, применяем специальное форматирование // Сохраняем текущие настройки QPen originalPen = painter.pen(); QFont originalFont = painter.font(); // Получаем поджим для этой ячейки int cellStretch = getCellStretch(cellIndex, fontStretch); QFont cellFont = createGostFont(fontSize, false, true, cellStretch); painter.setFont(cellFont); // Рисуем текст по центру без переноса строк QTextOption headerTextOption(Qt::AlignCenter); headerTextOption.setWrapMode(QTextOption::NoWrap); painter.drawText(cellRect, cellText.trimmed(), headerTextOption); // Проверяем, нужно ли рисовать подчеркивание if (shouldUnderline) { // Рисуем подчеркивание вручную с настраиваемым расстоянием QFontMetrics metrics(painter.font()); QRectF textRect = metrics.boundingRect(cellText.trimmed()); // Вычисляем позицию текста по центру qreal textX = cellRect.x() + (cellRect.width() - textRect.width()) / 2; qreal textY = cellRect.y() + (cellRect.height() + textRect.height()) / 2; // Настраиваемое расстояние подчеркивания от текста (в пикселях) qreal underlineOffset = 2.0; // Рисуем линию подчеркивания QPen underlinePen(Qt::black, 1.0); painter.setPen(underlinePen); painter.drawLine( textX, textY + underlineOffset, textX + textRect.width(), textY + underlineOffset ); } // Восстанавливаем оригинальные настройки painter.setFont(originalFont); painter.setPen(originalPen); } else { // Обычное форматирование Qt::Alignment alignment = (col==6||col==7||col==8||col==9) ? Qt::AlignCenter : (Qt::AlignLeft|Qt::AlignVCenter); drawCellWithStretch(painter, cellIndex, cellRect, cellText, fontSize, fontStretch, tableFont, alignment, mainController); } } } currentX += colWidth; } } return true; } // Новые методы для предварительного просмотра QList PDFController::getPerechenPagesInfo(MainController *mainController) { QList pagesInfo; if (!mainController) { qDebug() << "PDFController::getPerechenPagesInfo: MainController не передан"; return pagesInfo; } PerechenTableModel *perechenModel = mainController->perechenTableModel(); if (!perechenModel) { qDebug() << "PDFController::getPerechenPagesInfo: Модель перечня элементов недоступна"; return pagesInfo; } qDebug() << "PDFController::getPerechenPagesInfo: Количество строк в модели:" << perechenModel->rowCount(); // Константы для количества строк на страницах const int rowsOnFirstPage = 25; // На первой странице 27 строк const int rowsOnOtherPages = 32; // На последующих страницах 33 строк int totalRows = perechenModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Вычисляем общее количество страниц int totalPages = 1; int tempRow = 0; while (tempRow < totalRows) { int rowsOnThisPage = (totalPages == 1) ? rowsOnFirstPage : rowsOnOtherPages; tempRow += rowsOnThisPage; if (tempRow < totalRows) { totalPages++; } } qDebug() << "PDFController::getPerechenPagesInfo: Всего строк:" << totalRows << "всего страниц:" << totalPages; // Создаем информацию о каждой странице while (currentRow < totalRows) { PageInfo pageInfo; pageInfo.pageNumber = pageNumber; pageInfo.totalPages = totalPages; pageInfo.isFirstPage = (pageNumber == 1); pagesInfo.append(pageInfo); int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; currentRow += rowsOnThisPage; pageNumber++; qDebug() << "PDFController::getPerechenPagesInfo: Создана страница" << pageNumber - 1 << "строки" << currentRow - rowsOnThisPage << "-" << currentRow - 1; } qDebug() << "PDFController::getPerechenPagesInfo: Создано страниц:" << pagesInfo.size(); return pagesInfo; } QList PDFController::getSpecificationPcbPagesInfo(MainController *mainController) { QList pagesInfo; if (!mainController) { return pagesInfo; } SpecificationPCBTableModel *specificationModel = mainController->specificationPCBTableModel(); if (!specificationModel) { return pagesInfo; } // Константы для количества строк на страницах const int rowsOnFirstPage = 26; // На первой странице 26 строк const int rowsOnOtherPages = 32; // На последующих страницах 32 строки int totalRows = specificationModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Вычисляем общее количество страниц int totalPages = 1; int tempRow = 0; while (tempRow < totalRows) { int rowsOnThisPage = (totalPages == 1) ? rowsOnFirstPage : rowsOnOtherPages; tempRow += rowsOnThisPage; if (tempRow < totalRows) { totalPages++; } } // Создаем информацию о каждой странице while (currentRow < totalRows) { PageInfo pageInfo; pageInfo.pageNumber = pageNumber; pageInfo.totalPages = totalPages; pageInfo.isFirstPage = (pageNumber == 1); pagesInfo.append(pageInfo); int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; currentRow += rowsOnThisPage; pageNumber++; } return pagesInfo; } QList PDFController::getSpecificationPagesInfo(MainController *mainController) { QList pagesInfo; if (!mainController) { return pagesInfo; } SpecificationTableModel *specificationModel = mainController->specificationTableModel(); if (!specificationModel) { return pagesInfo; } // Константы для количества строк на страницах const int rowsOnFirstPage = 26; // На первой странице 26 строк const int rowsOnOtherPages = 32; // На последующих страницах 32 строки int totalRows = specificationModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Вычисляем общее количество страниц int totalPages = 1; int tempRow = 0; while (tempRow < totalRows) { int rowsOnThisPage = (totalPages == 1) ? rowsOnFirstPage : rowsOnOtherPages; tempRow += rowsOnThisPage; if (tempRow < totalRows) { totalPages++; } } // Создаем информацию о каждой странице while (currentRow < totalRows) { PageInfo pageInfo; pageInfo.pageNumber = pageNumber; pageInfo.totalPages = totalPages; pageInfo.isFirstPage = (pageNumber == 1); pagesInfo.append(pageInfo); int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; currentRow += rowsOnThisPage; pageNumber++; } return pagesInfo; } bool PDFController::drawPerechenPage(QPainter &painter, const PageInfo &pageInfo, MainController *mainController) { if (!mainController) { return false; } PerechenTableModel *perechenModel = mainController->perechenTableModel(); if (!perechenModel) { return false; } TitleInscriptionsModel *titleModel = mainController->titleInscriptionsModel(); if (!titleModel) { return false; } ProjectParamTableModel *projectParamModel = mainController->projectParamTableModel(); if (!projectParamModel) { return false; } // Получаем размеры страницы из painter QRectF pageRect = painter.viewport(); // Конвертируем миллиметры в пиксели qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // Константы для количества строк на страницах const int rowsOnFirstPage = 25; const int rowsOnOtherPages = 32; int totalRows = perechenModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Находим нужную страницу while (pageNumber < pageInfo.pageNumber) { int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; currentRow += rowsOnThisPage; pageNumber++; } // Определяем количество строк для текущей страницы int rowsOnThisPage = (pageInfo.isFirstPage) ? rowsOnFirstPage : rowsOnOtherPages; // Проверяем, является ли это последней страницей bool isLastPage = (currentRow + rowsOnThisPage >= totalRows); // Если это последняя страница, добавляем пустые строки до конца страницы if (isLastPage) { int remainingRows = totalRows - currentRow; int emptyRowsToAdd = rowsOnThisPage - remainingRows; rowsOnThisPage = remainingRows + emptyRowsToAdd; } // Добавляем рамку ГОСТ в зависимости от номера страницы if (pageInfo.isFirstPage) { addGostFrameA4FirstPage(painter, pageRect, titleModel, projectParamModel, pageInfo.pageNumber, pageInfo.totalPages,1); } else { addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageInfo.pageNumber, pageInfo.totalPages,1); } // Вычисляем область для таблицы QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -5*mmToPixels); // Добавляем таблицу с указанным диапазоном строк addPerechenTableRange(painter, perechenModel, tableRect, currentRow, rowsOnThisPage, mainController); return true; } bool PDFController::drawSpecificationPcbPage(QPainter &painter, const PageInfo &pageInfo, MainController *mainController) { if (!mainController) { return false; } SpecificationPCBTableModel *specificationModel = mainController->specificationPCBTableModel(); if (!specificationModel) { return false; } TitleInscriptionsModel *titleModel = mainController->titleInscriptionsModel(); if (!titleModel) { return false; } ProjectParamTableModel *projectParamModel = mainController->projectParamTableModel(); if (!projectParamModel) { return false; } // Получаем размеры страницы из painter QRectF pageRect = painter.viewport(); // Конвертируем миллиметры в пиксели qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // Константы для количества строк на страницах const int rowsOnFirstPage = 26; const int rowsOnOtherPages = 32; int totalRows = specificationModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Находим нужную страницу while (pageNumber < pageInfo.pageNumber) { int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; currentRow += rowsOnThisPage; pageNumber++; } // Определяем количество строк для текущей страницы int rowsOnThisPage = (pageInfo.isFirstPage) ? rowsOnFirstPage : rowsOnOtherPages; // Проверяем, является ли это последней страницей bool isLastPage = (currentRow + rowsOnThisPage >= totalRows); // Если это последняя страница, добавляем пустые строки до конца страницы if (isLastPage) { int remainingRows = totalRows - currentRow; int emptyRowsToAdd = rowsOnThisPage - remainingRows; rowsOnThisPage = remainingRows + emptyRowsToAdd; } // Добавляем рамку ГОСТ в зависимости от номера страницы if (pageInfo.isFirstPage) { addGostFrameA4FirstPage(painter, pageRect, titleModel, projectParamModel, pageInfo.pageNumber, pageInfo.totalPages,2); } else { addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageInfo.pageNumber, pageInfo.totalPages,2); } // Вычисляем область для таблицы QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -5*mmToPixels); // Добавляем таблицу спецификации с указанным диапазоном строк addSpecificationPcbTableRange(painter, specificationModel, tableRect, currentRow, rowsOnThisPage, mainController); return true; } bool PDFController::drawSpecificationPage(QPainter &painter, const PageInfo &pageInfo, MainController *mainController) { if (!mainController) { return false; } SpecificationTableModel *specificationModel = mainController->specificationTableModel(); if (!specificationModel) { return false; } TitleInscriptionsModel *titleModel = mainController->titleInscriptionsModel(); if (!titleModel) { return false; } ProjectParamTableModel *projectParamModel = mainController->projectParamTableModel(); if (!projectParamModel) { return false; } // Получаем размеры страницы из painter QRectF pageRect = painter.viewport(); // Конвертируем миллиметры в пиксели qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // Константы для количества строк на страницах const int rowsOnFirstPage = 26; const int rowsOnOtherPages = 32; int totalRows = specificationModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Находим нужную страницу while (pageNumber < pageInfo.pageNumber) { int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; currentRow += rowsOnThisPage; pageNumber++; } // Определяем количество строк для текущей страницы int rowsOnThisPage = (pageInfo.isFirstPage) ? rowsOnFirstPage : rowsOnOtherPages; // Проверяем, является ли это последней страницей bool isLastPage = (currentRow + rowsOnThisPage >= totalRows); // Если это последняя страница, добавляем пустые строки до конца страницы if (isLastPage) { int remainingRows = totalRows - currentRow; int emptyRowsToAdd = rowsOnThisPage - remainingRows; rowsOnThisPage = remainingRows + emptyRowsToAdd; } // Добавляем рамку ГОСТ в зависимости от номера страницы if (pageInfo.isFirstPage) { addGostFrameA4FirstPage(painter, pageRect, titleModel, projectParamModel, pageInfo.pageNumber, pageInfo.totalPages,3); } else { addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageInfo.pageNumber, pageInfo.totalPages,3); } // Вычисляем область для таблицы QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -5*mmToPixels); // Добавляем таблицу спецификации с указанным диапазоном строк addSpecificationTableRange(painter, specificationModel, tableRect, currentRow, rowsOnThisPage, mainController); return true; } QList PDFController::getVedomostPagesInfo(MainController *mainController) { QList pagesInfo; if (!mainController) { qDebug() << "PDFController::getVedomostPagesInfo: MainController не передан"; return pagesInfo; } VedomostTableModel *vedomostModel = mainController->vedomostTableModel(); if (!vedomostModel) { qDebug() << "PDFController::getVedomostPagesInfo: Модель ведомости покупных изделий недоступна"; return pagesInfo; } qDebug() << "PDFController::getVedomostPagesInfo: Количество строк в модели:" << vedomostModel->rowCount(); // Константы для количества строк на страницах (должны совпадать с экспортом) const int rowsOnFirstPage = 24; // На первой странице 24 строки (как в экспорте) const int rowsOnOtherPages = 29; // На последующих страницах 30 строк (как в экспорте) int totalRows = vedomostModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Вычисляем общее количество страниц int totalPages = 1; int tempRow = 0; while (tempRow < totalRows) { int rowsOnThisPage = (totalPages == 1) ? rowsOnFirstPage : rowsOnOtherPages; tempRow += rowsOnThisPage; if (tempRow < totalRows) { totalPages++; } } qDebug() << "PDFController::getVedomostPagesInfo: Всего строк:" << totalRows << "всего страниц:" << totalPages; // Создаем информацию о каждой странице while (currentRow < totalRows) { PageInfo pageInfo; pageInfo.pageNumber = pageNumber; pageInfo.totalPages = totalPages; pageInfo.isFirstPage = (pageNumber == 1); pagesInfo.append(pageInfo); int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; currentRow += rowsOnThisPage; pageNumber++; qDebug() << "PDFController::getVedomostPagesInfo: Создана страница" << pageNumber - 1 << "строки" << currentRow - rowsOnThisPage << "-" << currentRow - 1; } qDebug() << "PDFController::getVedomostPagesInfo: Создано страниц:" << pagesInfo.size(); return pagesInfo; } bool PDFController::drawVedomostPage(QPainter &painter, const PageInfo &pageInfo, MainController *mainController) { if (!mainController) { return false; } VedomostTableModel *vedomostModel = mainController->vedomostTableModel(); if (!vedomostModel) { return false; } TitleInscriptionsModel *titleModel = mainController->titleInscriptionsModel(); if (!titleModel) { return false; } ProjectParamTableModel *projectParamModel = mainController->projectParamTableModel(); if (!projectParamModel) { return false; } // Получаем размеры страницы из painter QRectF pageRect = painter.viewport(); // Конвертируем миллиметры в пиксели qreal mmToPixels = painter.device()->logicalDpiX() / 25.4; // Константы для количества строк на страницах (должны совпадать с экспортом) const int rowsOnFirstPage = 24; // На первой странице 24 строки (как в экспорте) const int rowsOnOtherPages = 29; // На последующих страницах 30 строк (как в экспорте) int totalRows = vedomostModel->rowCount(); int currentRow = 0; int pageNumber = 1; // Находим нужную страницу while (pageNumber < pageInfo.pageNumber) { int rowsOnThisPage = (pageNumber == 1) ? rowsOnFirstPage : rowsOnOtherPages; currentRow += rowsOnThisPage; pageNumber++; } // Определяем количество строк для текущей страницы int rowsOnThisPage = (pageInfo.isFirstPage) ? rowsOnFirstPage : rowsOnOtherPages; // Проверяем, является ли это последней страницей bool isLastPage = (currentRow + rowsOnThisPage >= totalRows); // Если это последняя страница, добавляем пустые строки до конца страницы if (isLastPage) { int remainingRows = totalRows - currentRow; int emptyRowsToAdd = rowsOnThisPage - remainingRows; rowsOnThisPage = remainingRows + emptyRowsToAdd; } // Добавляем рамку ГОСТ (используем те же методы, что и в экспорте) if (pageInfo.isFirstPage) { addGostFrameA4FirstPage(painter, pageRect, titleModel, projectParamModel, pageInfo.pageNumber, pageInfo.totalPages, 4); } else { addGostFrameA4(painter, pageRect, titleModel, projectParamModel, pageInfo.pageNumber, pageInfo.totalPages, 4); } // Вычисляем область для таблицы (используем те же отступы, что и в экспорте) QRectF tableRect = pageRect.adjusted(20*mmToPixels, 5*mmToPixels, -5*mmToPixels, -5*mmToPixels); // Добавляем таблицу ведомости с указанным диапазоном строк addVedomostTableRange(painter, vedomostModel, tableRect, currentRow, rowsOnThisPage, mainController); return true; }