#include "printer.h" #include "templatelayout.h" #include "statistics.h" #include "helpers.h" #include #include #include #include #include Printer::Printer(QPaintDevice *paintDevice, print_options *printOptions, template_options *templateOptions, PrintMode printMode) { this->paintDevice = paintDevice; this->printOptions = printOptions; this->templateOptions = templateOptions; this->printMode = printMode; dpi = 0; done = 0; webView = new QWebView(); } Printer::~Printer() { delete webView; } void Printer::putProfileImage(QRect profilePlaceholder, QRect viewPort, QPainter *painter, struct dive *dive, QPointer profile) { int x = profilePlaceholder.x() - viewPort.x(); int y = profilePlaceholder.y() - viewPort.y(); // use the placeHolder and the viewPort position to calculate the relative position of the dive profile. QRect pos(x, y, profilePlaceholder.width(), profilePlaceholder.height()); profile->plotDive(dive, true); if (!printOptions->color_selected) { QImage image(pos.width(), pos.height(), QImage::Format_ARGB32); QPainter imgPainter(&image); imgPainter.setRenderHint(QPainter::Antialiasing); imgPainter.setRenderHint(QPainter::SmoothPixmapTransform); profile->render(&imgPainter, QRect(0, 0, pos.width(), pos.height())); imgPainter.end(); // convert QImage to grayscale before rendering for (int i = 0; i < image.height(); i++) { QRgb *pixel = reinterpret_cast(image.scanLine(i)); QRgb *end = pixel + image.width(); for (; pixel != end; pixel++) { int gray_val = qGray(*pixel); *pixel = QColor(gray_val, gray_val, gray_val).rgb(); } } painter->drawImage(pos, image); } else { profile->render(painter, pos); } } void Printer::flowRender() { // add extra padding at the bottom to pages with height not divisible by view port int paddingBottom = pageSize.height() - (webView->page()->mainFrame()->contentsSize().height() % pageSize.height()); QString styleString = QString::fromUtf8("padding-bottom: ") + QString::number(paddingBottom) + "px;"; webView->page()->mainFrame()->findFirstElement("body").setAttribute("style", styleString); // render the Qwebview QPainter painter; QRect viewPort(0, 0, 0, 0); painter.begin(paintDevice); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); // get all references to dontbreak divs int start = 0, end = 0; int fullPageResolution = webView->page()->mainFrame()->contentsSize().height(); QWebElementCollection dontbreak = webView->page()->mainFrame()->findAllElements(".dontbreak"); foreach (QWebElement dontbreakElement, dontbreak) { if ((dontbreakElement.geometry().y() + dontbreakElement.geometry().height()) - start < pageSize.height()) { // One more element can be placed end = dontbreakElement.geometry().y() + dontbreakElement.geometry().height(); } else { // fill the page with background color QRect fullPage(0, 0, pageSize.width(), pageSize.height()); QBrush fillBrush(templateOptions->color_palette.color1); painter.fillRect(fullPage, fillBrush); QRegion reigon(0, 0, pageSize.width(), end - start); viewPort.setRect(0, start, pageSize.width(), end - start); // render the base Html template webView->page()->mainFrame()->render(&painter, QWebFrame::ContentsLayer, reigon); // scroll the webview to the next page webView->page()->mainFrame()->scroll(0, dontbreakElement.geometry().y() - start); // rendering progress is 4/5 of total work emit(progessUpdated((end * 80.0 / fullPageResolution) + done)); // add new pages only in print mode, while previewing we don't add new pages if (printMode == Printer::PRINT) static_cast(paintDevice)->newPage(); else { painter.end(); return; } start = dontbreakElement.geometry().y(); } } // render the remianing page QRect fullPage(0, 0, pageSize.width(), pageSize.height()); QBrush fillBrush(templateOptions->color_palette.color1); painter.fillRect(fullPage, fillBrush); QRegion reigon(0, 0, pageSize.width(), end - start); webView->page()->mainFrame()->render(&painter, QWebFrame::ContentsLayer, reigon); painter.end(); } void Printer::render(int Pages = 0) { // keep original preferences QPointer profile = MainWindow::instance()->graphics(); int profileFrameStyle = profile->frameStyle(); int animationOriginal = prefs.animation_speed; double fontScale = profile->getFontPrintScale(); double printFontScale = 1.0; // apply printing settings to profile profile->setFrameStyle(QFrame::NoFrame); profile->setPrintMode(true, !printOptions->color_selected); profile->setToolTipVisibile(false); prefs.animation_speed = 0; // render the Qwebview QPainter painter; QRect viewPort(0, 0, pageSize.width(), pageSize.height()); painter.begin(paintDevice); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); // get all refereces to diveprofile class in the Html template QWebElementCollection collection = webView->page()->mainFrame()->findAllElements(".diveprofile"); QSize originalSize = profile->size(); if (collection.count() > 0) { printFontScale = (double)collection.at(0).geometry().size().height() / (double)profile->size().height(); profile->resize(collection.at(0).geometry().size()); } profile->setFontPrintScale(printFontScale); int elemNo = 0; for (int i = 0; i < Pages; i++) { // render the base Html template webView->page()->mainFrame()->render(&painter, QWebFrame::ContentsLayer); // render all the dive profiles in the current page while (elemNo < collection.count() && collection.at(elemNo).geometry().y() < viewPort.y() + viewPort.height()) { // dive id field should be dive_{{dive_no}} se we remove the first 5 characters QString diveIdString = collection.at(elemNo).attribute("id"); int diveId = diveIdString.remove(0, 5).toInt(0, 10); putProfileImage(collection.at(elemNo).geometry(), viewPort, &painter, get_dive_by_uniq_id(diveId), profile); elemNo++; } // scroll the webview to the next page webView->page()->mainFrame()->scroll(0, pageSize.height()); viewPort.adjust(0, pageSize.height(), 0, pageSize.height()); // rendering progress is 4/5 of total work emit(progessUpdated((i * 80.0 / Pages) + done)); if (i < Pages - 1 && printMode == Printer::PRINT) static_cast(paintDevice)->newPage(); } painter.end(); // return profle settings profile->setFrameStyle(profileFrameStyle); profile->setPrintMode(false); profile->setFontPrintScale(fontScale); profile->setToolTipVisibile(true); profile->resize(originalSize); prefs.animation_speed = animationOriginal; //replot the dive after returning the settings profile->plotDive(0, true); } //value: ranges from 0 : 100 and shows the progress of the templating engine void Printer::templateProgessUpdated(int value) { done = value / 5; //template progess if 1/5 of total work emit progessUpdated(done); } void Printer::print() { // we can only print if "PRINT" mode is selected if (printMode != Printer::PRINT) { return; } QPrinter *printerPtr; printerPtr = static_cast(paintDevice); TemplateLayout t(printOptions, templateOptions); connect(&t, SIGNAL(progressUpdated(int)), this, SLOT(templateProgessUpdated(int))); dpi = printerPtr->resolution(); //rendering resolution = selected paper size in inchs * printer dpi pageSize.setHeight(std::ceil(printerPtr->pageRect(QPrinter::Inch).height() * dpi)); pageSize.setWidth(std::ceil(printerPtr->pageRect(QPrinter::Inch).width() * dpi)); webView->page()->setViewportSize(pageSize); webView->page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); // export border width with at least 1 pixel templateOptions->border_width = std::max(1, pageSize.width() / 1000); webView->setHtml(t.generate()); if (printOptions->color_selected && printerPtr->colorMode()) { printerPtr->setColorMode(QPrinter::Color); } else { printerPtr->setColorMode(QPrinter::GrayScale); } // apply user settings int divesPerPage; // get number of dives per page from data-numberofdives attribute in the body of the selected template bool ok; divesPerPage = webView->page()->mainFrame()->findFirstElement("body").attribute("data-numberofdives").toInt(&ok); if (!ok) { divesPerPage = 1; // print each dive in a single page if the attribute is missing or malformed //TODO: show warning } int Pages; if (divesPerPage == 0) { flowRender(); } else { Pages = ceil(getTotalWork(printOptions) / (float)divesPerPage); render(Pages); } } void Printer::print_statistics() { QPrinter *printerPtr; printerPtr = static_cast(paintDevice); stats_t total_stats; total_stats.selection_size = 0; total_stats.total_time.seconds = 0; QString html; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; int i = 0; while (stats_yearly != NULL && stats_yearly[i].period) { html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; total_stats.selection_size += stats_yearly[i].selection_size; total_stats.total_time.seconds += stats_yearly[i].total_time.seconds; i++; } html += "
YearDivesTotal TimeAvg TimeShortest TimeLongest TimeAvg DepthMin DepthMax DepthAvg SACMin SACMax SACMin TempMax Temp
" + QString::number(stats_yearly[i].period) + "" + QString::number(stats_yearly[i].selection_size) + "" + QString::fromUtf8(get_time_string(stats_yearly[i].total_time.seconds, 0)) + "" + QString::fromUtf8(get_minutes(stats_yearly[i].total_time.seconds / stats_yearly[i].selection_size)) + "" + QString::fromUtf8(get_minutes(stats_yearly[i].shortest_time.seconds)) + "" + QString::fromUtf8(get_minutes(stats_yearly[i].longest_time.seconds)) + "" + get_depth_string(stats_yearly[i].avg_depth) + "" + get_depth_string(stats_yearly[i].min_depth) + "" + get_depth_string(stats_yearly[i].max_depth) + "" + get_volume_string(stats_yearly[i].avg_sac) + "" + get_volume_string(stats_yearly[i].min_sac) + "" + get_volume_string(stats_yearly[i].max_sac) + "" + QString::number(stats_yearly[i].min_temp == 0 ? 0 : get_temp_units(stats_yearly[i].min_temp, NULL)) + "" + QString::number(stats_yearly[i].max_temp == 0 ? 0 : get_temp_units(stats_yearly[i].max_temp, NULL)) + "
"; webView->setHtml(html); webView->print(printerPtr); } void Printer::previewOnePage() { if (printMode == PREVIEW) { TemplateLayout t(printOptions, templateOptions); pageSize.setHeight(paintDevice->height()); pageSize.setWidth(paintDevice->width()); webView->page()->setViewportSize(pageSize); // initialize the border settings templateOptions->border_width = std::max(1, pageSize.width() / 1000); webView->setHtml(t.generate()); bool ok; int divesPerPage = webView->page()->mainFrame()->findFirstElement("body").attribute("data-numberofdives").toInt(&ok); if (!ok) { divesPerPage = 1; // print each dive in a single page if the attribute is missing or malformed //TODO: show warning } if (divesPerPage == 0) { flowRender(); } else { render(1); } } }