src/PrinterDialog.cpp

Thu, 22 Sep 2022 11:33:45 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Thu, 22 Sep 2022 11:33:45 +0200
changeset 405
2c828cc3d943
parent 386
2e30c9c20d22
child 411
c78f8cf11849
permissions
-rw-r--r--

Fix checklist mash steps overflow.

/**
 * Printer.cpp is part of bmsapp.
 *
 * bmsapp is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * bmsapp is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "PrinterDialog.h"
#include "Utils.h"
#include "EditRecipe.h"
#include "EditProduct.h"
#include "config.h"
#include "global.h"

#include <QPrintPreviewDialog>
#include <QDebug>
#include <QtSql>


PrinterDialog::PrinterDialog(int job, int rec, QWidget* parent) : QDialog(parent)
{
    qDebug() << "PrinterDialog start job" << job << "rec" << rec;

    p_job = job;
    p_rec = rec;

    QPrinter printer(QPrinter::ScreenResolution);
    QPrintPreviewDialog preview(&printer, this);
    connect(&preview, &QPrintPreviewDialog::paintRequested, this, &PrinterDialog::printDocument);
    preview.exec();
}


PrinterDialog::~PrinterDialog() {}


void PrinterDialog::printDocument(QPrinter *printer)
{
    qDebug() << "PrinterDialog printDocument()";

    QRect rectangle;
    QRect boundingRect;
    QPainter painter;
    QString w;
    QSqlQuery query;

    const QColor c_header(255, 150, 100, 255);
    const QColor c_line1( 210, 245, 255, 255);
    const QColor c_line2( 255, 255, 210, 255);
    const QColor f_line(  250, 195,  65, 255);
    const QColor h_line(  100, 250,  65, 255);
    const QColor y_line(  175, 175, 255, 255);
    const QColor mw_line( 240, 140, 130, 255);
    const QColor mf_line(  95, 180,  25, 255);
    const QColor ms_line( 240, 250,  65, 255);
    const QColor mo_line( 210, 245, 255, 255);
    const QColor line(  175, 175, 255, 255); // also y_line
    const QColor w_line(  120, 255, 250, 255);

    const QStringList y_unit({tr("pkg"), tr("gr"), tr("ml"), tr("ml"), tr("ml"), tr("ml"), tr("gr")});
    const QStringList color_method({ "Morey", "Mosher", "Daniels", "Halberstadt", "Naudts" });

    painter.begin(printer);
    qreal y = 0;

    if (p_job == PR_SUPPLIES) {
	qInfo() << "Print supplies";

	/*
	 * Print supplies in stock
	 */
	double	tot_fermentables = 0, tot_hops = 0, tot_yeasts = 0, tot_miscs = 0;

	printHeader(&painter);
	y = 120;
	/* Fermentables supplies header */
	painter.setFont(QFont("Helvetica", 9, QFont::Bold));
	painter.setPen(Qt::black);
	painter.fillRect( 20, y,   715, 20, c_header);
	painter.drawText( 20, y+4,  80, 20, Qt::AlignLeft, tr("Type"));
	painter.drawText(100, y+4, 100, 20, Qt::AlignLeft, tr("Supplier"));
	painter.drawText(200, y+4, 260, 20, Qt::AlignLeft, tr("Fermentable"));
	painter.drawText(460, y+4, 115, 20, Qt::AlignRight, tr("Stock"));
	painter.drawText(575, y+4,  80, 20, Qt::AlignRight, tr("Price/Kg"));
	painter.drawText(655, y+4,  80, 20, Qt::AlignRight, tr("Value"));
	y += 20;
	painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	query.exec("SELECT type,name,supplier,inventory,cost FROM inventory_fermentables WHERE inventory > 0 ORDER BY type,supplier,name");
	query.first();
	for (int i = 0 ; i < query.size() ; i++ ) {
	    if ((y + 20) > painter.device()->height()) {
                printer->newPage();
		printHeader(&painter);
                y = 120;
            }
	    painter.fillRect( 20, y,   715, 20, (i % 2) ? c_line1:c_line2);
	    painter.drawText( 20, y+4,  80, 20, Qt::AlignLeft, QCoreApplication::translate("FermentableType", g_fermentable_types[query.value(0).toInt()]));
	    painter.drawText(100, y+4, 100, 20, Qt::AlignLeft, query.value(2).toString());
	    painter.drawText(200, y+4, 260, 20, Qt::AlignLeft, query.value(1).toString());
	    w = QString("%1 kg").arg(query.value(3).toDouble(), 10, 'f', 3);
	    painter.drawText(460, y+4, 115, 20, Qt::AlignRight, w);
	    w = QString("%1 €").arg(query.value(4).toDouble(), 8, 'f', 2);
	    painter.drawText(575, y+4,  80, 20, Qt::AlignRight, w);
	    w = QString("%1 €").arg(query.value(3).toDouble() * query.value(4).toDouble(), 8, 'f', 2);
	    tot_fermentables += (query.value(3).toDouble() * query.value(4).toDouble());
	    painter.drawText(655, y+4,  80, 20, Qt::AlignRight, w);
	    query.next();
	    y += 20;
	}
	painter.fillRect( 20, y,   715, 20, c_header);
	painter.drawText( 20, y+4, 100, 20, Qt::AlignLeft, tr("Total"));
	w = QString("%1 €").arg(tot_fermentables, 8, 'f', 2);
	painter.drawText(655, y+4,  80, 20, Qt::AlignRight, w);
	y += 20;

	/* Hops supplies */
	query.exec("SELECT name,form,origin,inventory,cost FROM inventory_hops WHERE inventory > 0 ORDER BY origin,name");
        query.first();
	if ((y + 80 + (query.size() * 20)) > painter.device()->height()) {	/* Rows + header + footer + blank */
	    printer->newPage();
	    printHeader(&painter);
	    y = 120;
	} else {
	    y += 40;
	}
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.setPen(Qt::black);
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Country"));
	painter.drawText(140, y+4, 240, 20, Qt::AlignLeft, tr("Hop name"));
	painter.drawText(380, y+4,  80, 20, Qt::AlignLeft, tr("Form"));
	painter.drawText(460, y+4, 115, 20, Qt::AlignRight, tr("Stock"));
        painter.drawText(575, y+4,  80, 20, Qt::AlignRight, tr("Price/Kg"));
        painter.drawText(655, y+4,  80, 20, Qt::AlignRight, tr("Value"));
	y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	for (int i = 0; i < query.size(); i++) {
	    if ((y + 20) > painter.device()->height()) {
		printer->newPage();
		printHeader(&painter);
		y = 120;
	    }
	    painter.fillRect( 20, y,   715, 20, (i % 2) ? c_line1:c_line2);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, query.value(2).toString());
	    painter.drawText(140, y+4, 240, 20, Qt::AlignLeft, query.value(0).toString());
	    painter.drawText(380, y+4,  80, 20, Qt::AlignLeft, QCoreApplication::translate("HopForm", g_hop_forms[query.value(1).toInt()]));
	    if (query.value(3).toDouble() < 0.6)
		w = QString("%1 gr").arg(query.value(3).toDouble() * 1000.0, 10, 'f', 1);
	    else
	        w = QString("%1 kg").arg(query.value(3).toDouble(), 10, 'f', 3);
            painter.drawText(460, y+4, 115, 20, Qt::AlignRight, w);
            w = QString("%1 €").arg(query.value(4).toDouble(), 8, 'f', 2);
            painter.drawText(575, y+4,  80, 20, Qt::AlignRight, w);
            w = QString("%1 €").arg(query.value(3).toDouble() * query.value(4).toDouble(), 8, 'f', 2);
            tot_hops += (query.value(3).toDouble() * query.value(4).toDouble());
            painter.drawText(655, y+4,  80, 20, Qt::AlignRight, w);
            query.next();
            y += 20;
	}
	painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 100, 20, Qt::AlignLeft, tr("Total"));
        w = QString("%1 €").arg(tot_hops, 8, 'f', 2);
        painter.drawText(655, y+4,  80, 20, Qt::AlignRight, w);
	y += 20;

	/* Yeasts supplies */
	query.exec("SELECT name,laboratory,product_id,form,inventory,cost FROM inventory_yeasts WHERE inventory > 0 ORDER BY laboratory,product_id");
        query.first();
	if ((y + 80 + (query.size() * 20)) > painter.device()->height()) {      /* Rows + header + footer + blank */
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 40;
        }
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.setPen(Qt::black);
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Laboratory"));
        painter.drawText(140, y+4, 120, 20, Qt::AlignLeft, tr("Product"));
        painter.drawText(260, y+4, 235, 20, Qt::AlignLeft, tr("Yeast"));
        painter.drawText(495, y+4,  80, 20, Qt::AlignRight, tr("Stock"));
        painter.drawText(575, y+4,  80, 20, Qt::AlignRight, tr("Price/Kg"));
        painter.drawText(655, y+4,  80, 20, Qt::AlignRight, tr("Value"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	for (int i = 0; i < query.size(); i++) {
	    if ((y + 20) > painter.device()->height()) {
                printer->newPage();
		printHeader(&painter);
                y = 120;
            }
            painter.fillRect( 20, y,   715, 20, (i % 2) ? c_line1:c_line2);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, query.value(1).toString());
	    painter.drawText(140, y+4, 120, 20, Qt::AlignLeft, query.value(2).toString());
	    painter.drawText(260, y+4, 235, 20, Qt::AlignLeft, query.value(0).toString());
	    if (query.value(3).toInt() == 0)
		w = QString("%1 %2").arg(query.value(4).toDouble(), 10, 'f', 1).arg(y_unit[query.value(3).toInt()]);
	    else
		w = QString("%1 %2").arg(query.value(4).toDouble() * 1000.0, 10, 'f', 1).arg(y_unit[query.value(3).toInt()]);
            painter.drawText(495, y+4,  80, 20, Qt::AlignRight, w);
            w = QString("%1 €").arg(query.value(5).toDouble(), 8, 'f', 2);
            painter.drawText(575, y+4,  80, 20, Qt::AlignRight, w);
            w = QString("%1 €").arg(query.value(4).toDouble() * query.value(5).toDouble(), 8, 'f', 2);
            tot_yeasts += (query.value(4).toDouble() * query.value(5).toDouble());
            painter.drawText(655, y+4,  80, 20, Qt::AlignRight, w);
            query.next();
            y += 20;
	}
	painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 100, 20, Qt::AlignLeft, tr("Total"));
        w = QString("%1 €").arg(tot_yeasts, 8, 'f', 2);
        painter.drawText(655, y+4,  80, 20, Qt::AlignRight, w);
        y += 20;

	/* Miscs supplies */
	query.exec("SELECT name,type,amount_is_weight,inventory,cost FROM inventory_miscs WHERE inventory > 0 ORDER BY type,name");
        query.first();
	if ((y + 80 + (query.size() * 20)) > painter.device()->height()) {      /* Rows + header + footer + blank */
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 40;
        }
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.setPen(Qt::black);
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Type"));
        painter.drawText(140, y+4, 320, 20, Qt::AlignLeft, tr("Ingredient"));
        painter.drawText(460, y+4, 115, 20, Qt::AlignRight, tr("Stock"));
        painter.drawText(575, y+4,  80, 20, Qt::AlignRight, tr("Price/Kg"));
        painter.drawText(655, y+4,  80, 20, Qt::AlignRight, tr("Value"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	for (int i = 0; i < query.size(); i++) {
            if ((y + 20) > painter.device()->height()) {
                printer->newPage();
                printHeader(&painter);
                y = 120;
            }
            painter.fillRect( 20, y,   715, 20, (i % 2) ? c_line1:c_line2);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, QCoreApplication::translate("MiscType", g_misc_types[query.value(1).toInt()]));
            painter.drawText(140, y+4, 320, 20, Qt::AlignLeft, query.value(0).toString());
            if (query.value(2).toInt())
                w = QString("%1 gr").arg(query.value(3).toDouble() * 1000.0, 10, 'f', 1);
            else
                w = QString("%1 ml").arg(query.value(3).toDouble() * 1000.0, 10, 'f', 1);
            painter.drawText(460, y+4, 115, 20, Qt::AlignRight, w);
            w = QString("%1 €").arg(query.value(4).toDouble(), 8, 'f', 2);
            painter.drawText(575, y+4,  80, 20, Qt::AlignRight, w);
            w = QString("%1 €").arg(query.value(3).toDouble() * query.value(4).toDouble(), 8, 'f', 2);
            tot_miscs += (query.value(3).toDouble() * query.value(4).toDouble());
            painter.drawText(655, y+4,  80, 20, Qt::AlignRight, w);
            query.next();
            y += 20;
        }
	painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 100, 20, Qt::AlignLeft, tr("Total"));
        w = QString("%1 €").arg(tot_miscs, 8, 'f', 2);
        painter.drawText(655, y+4,  80, 20, Qt::AlignRight, w);
        y += 20;

    } else if (p_job == PR_YEASTBANK) {
	qInfo() << "Print yeastbank";

	/*
	 * Print yeast in the private yeast bank.
	 */
	printHeader(&painter);
        y = 120;

	painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.setPen(Qt::black);
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 180, 20, Qt::AlignLeft, tr("Yeast"));
        painter.drawText(200, y+4, 230, 20, Qt::AlignLeft, tr("Description"));
	painter.drawText(430, y+4,  80, 20, Qt::AlignCenter, tr("Type"));
	painter.drawText(510, y+4,  80, 20, Qt::AlignCenter, tr("Form"));
        painter.drawText(590, y+4,  70, 20, Qt::AlignRight, tr("Stock"));
        painter.drawText(665, y+4,  70, 20, Qt::AlignLeft, tr("Date"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	query.prepare("SELECT name,type,form,inventory,production_date,short_desc "
		       "FROM inventory_yeasts WHERE inventory > 0 AND laboratory = :my_lab ORDER BY product_id");
	query.bindValue(":my_lab", my_yeastlab);
	query.exec();
        query.first();
	for (int i = 0; i < query.size(); i++) {
	    painter.fillRect( 20, y,   715, 20, (i % 2) ? c_line1:c_line2);
            painter.drawText( 20, y+4, 180, 20, Qt::AlignLeft, query.value(0).toString());
	    painter.drawText(200, y+4, 230, 20, Qt::AlignLeft, query.value(5).toString());
	    painter.drawText(430, y+4,  80, 20, Qt::AlignCenter, QCoreApplication::translate("YeastType", g_yeast_types[query.value(1).toInt()]));
	    painter.drawText(510, y+4,  80, 20, Qt::AlignCenter, QCoreApplication::translate("YeastForm", g_yeast_forms[query.value(2).toInt()]));

	    if (query.value(2).toInt() == 0)
                w = QString("%1 %2").arg(query.value(3).toDouble(), 10, 'f', 1).arg(y_unit[query.value(2).toInt()]);
            else
                w = QString("%1 %2").arg(query.value(3).toDouble() * 1000.0, 10, 'f', 1).arg(y_unit[query.value(2).toInt()]);
	    painter.drawText(590, y+4,  70, 20, Qt::AlignRight, w);
	    painter.drawText(665, y+4,  70, 20, Qt::AlignLeft, query.value(4).toString());
	    query.next();
	    y += 20;
	}
    } else if (p_job == PR_RECIPE) {

	qInfo() << "Print recipe" << recipe->record;

	printHeader(&painter);
        y = 120;
	/* Generic header */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.setPen(Qt::black);
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 715, 20, Qt::AlignCenter, tr("Recipe overview"));
	y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	painter.fillRect( 20, y,   330, 20, c_line1);
	painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Brew type"));
	painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QCoreApplication::translate("Recipe_type", g_recipe_types[recipe->type]));
	painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Efficiency"));
        painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 %").arg(recipe->efficiency, 1, 'f', 1));
	y += 20;
	painter.fillRect( 20, y,   330, 20, c_line1);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Boil time"));
        painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1 minutes.").arg(recipe->boil_time, 1, 'f', 0));
	painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Batch size"));
        painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 L.").arg(recipe->batch_size, 1, 'f', 1));
	y += 20;
	painter.fillRect( 20, y,   330, 20, c_line1);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Start SG"));
        painter.drawText(170, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(recipe->est_og, 1, 'f', 3));
	painter.drawText(260, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(recipe->st_og_min, 1, 'f', 3).arg(recipe->st_og_max, 1, 'f', 3));
        painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("End SG"));
        painter.drawText(555, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(recipe->est_fg, 1, 'f', 3));
	painter.drawText(645, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(recipe->st_fg_min, 1, 'f', 3).arg(recipe->st_fg_max, 1, 'f', 3));
	y += 20;
	painter.fillRect( 20, y,   330, 20, c_line1);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Estimated Alcohol"));
        painter.drawText(170, y+4,  90, 20, Qt::AlignLeft, QString("%1%").arg(recipe->est_abv, 1, 'f', 1));
	painter.drawText(260, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(recipe->st_abv_min, 1, 'f', 1).arg(recipe->st_abv_max, 1, 'f', 1));
        painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Estimated CO2 vol"));
        painter.drawText(555, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(recipe->est_carb, 1, 'f', 1));
	painter.drawText(645, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(recipe->st_carb_min, 1, 'f', 1).arg(recipe->st_carb_max, 1, 'f', 1));
	y += 20;
	painter.fillRect( 20, y,   150, 20, c_line1);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Color (") + color_method[recipe->color_method] + ")");
	painter.fillRect(170, y,   180, 20, Utils::ebc_to_color(recipe->est_color));
	if (recipe->est_color > 30)
	    painter.setPen(Qt::white);
        painter.drawText(170, y+4,  90, 20, Qt::AlignLeft, QString("%1 EBC").arg(recipe->est_color, 1, 'f', 0));
	painter.drawText(260, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(recipe->st_color_min, 1, 'f', 0).arg(recipe->st_color_max, 1, 'f', 0));
	painter.setPen(Qt::black);
        painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("IBU (") + g_ibu_method[recipe->ibu_method] + ")");
        painter.drawText(555, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(recipe->est_ibu, 1, 'f', 1));
	painter.drawText(645, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(recipe->st_ibu_min, 1, 'f', 0).arg(recipe->st_ibu_max, 1, 'f', 0));
	y += 40;

	/* Fermentables */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.setPen(Qt::black);
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft, tr("Fermentable"));
        painter.drawText(285, y+4,  70, 20, Qt::AlignRight, tr("Percent"));
        painter.drawText(360, y+4,  70, 20, Qt::AlignRight, tr("Yield"));
        painter.drawText(435, y+4,  80, 20, Qt::AlignLeft, tr("Type"));
        painter.drawText(520, y+4,  80, 20, Qt::AlignLeft, tr("Use at"));
        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
	painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
        y += 20;
	painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	double cost_fermentables = 0;
	QString soort, amount, use;
	for (int i = 0; i < recipe->fermentables.size(); i++) {
	    double cost = recipe->fermentables.at(i).amount * recipe->fermentables.at(i).cost;
	    cost_fermentables += cost;

	    if (recipe->fermentables.at(i).type == 0)
		soort = QCoreApplication::translate("FermentableGraintype", g_fermentable_graintypes[recipe->fermentables.at(i).graintype]);
	    else
		soort = QCoreApplication::translate("FermentableType", g_fermentable_types[recipe->fermentables.at(i).type]);

	    if (recipe->fermentables.at(i).amount > 100)
		amount = QString("%1 kg").arg(recipe->fermentables.at(i).amount, 1, 'f', 1);
	    else if (recipe->fermentables.at(i).amount > 10)
		amount = QString("%1 kg").arg(recipe->fermentables.at(i).amount, 1, 'f', 2);
	    else
		amount = QString("%1 gr").arg(recipe->fermentables.at(i).amount * 1000, 1, 'f', 0);

	    painter.fillRect( 20, y,   715, 20, f_line);

	    painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft,	recipe->fermentables.at(i).name +
			    					QString(", %1 EBC (").arg(recipe->fermentables.at(i).color, 1, 'f', 0) +
								recipe->fermentables.at(i).supplier + ")");
	    painter.drawText(285, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(recipe->fermentables.at(i).percentage, 1, 'f', 1));
	    painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(recipe->fermentables.at(i).yield, 1, 'f', 1));
	    painter.drawText(435, y+4,  80, 20, Qt::AlignLeft,  soort);
	    painter.drawText(520, y+4,  80, 20, Qt::AlignLeft,  QCoreApplication::translate("FermentableAdded", g_fermentable_added[recipe->fermentables.at(i).added]));
	    painter.drawText(605, y+4,  60, 20, Qt::AlignRight, amount);
	    painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
	    y += 20;
	}
	painter.fillRect(670, y,    60, 20, c_line1);
	painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_fermentables, 1, 'f', 3));
	y += 40;

	/* Hops */
	painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft, tr("Hop"));
        painter.drawText(285, y+4,  70, 20, Qt::AlignRight, tr("Alpha"));
        painter.drawText(360, y+4,  70, 20, Qt::AlignRight, tr("IBU"));
        painter.drawText(435, y+4,  80, 20, Qt::AlignLeft, tr("Type"));
        painter.drawText(520, y+4,  80, 20, Qt::AlignLeft, tr("Use at"));
        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
        y += 20;
	painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	double cost_hops = 0;
	for (int i = 0; i < recipe->hops.size(); i++) {

	    double cost = recipe->hops.at(i).amount * recipe->hops.at(i).cost;
	    cost_hops += cost;
	    double ibu = Utils::toIBU(recipe->hops.at(i).useat, recipe->hops.at(i).form, recipe->preboil_sg, recipe->est_og, recipe->batch_size,
			    	      recipe->hops.at(i).amount, recipe->hops.at(i).time, recipe->hops.at(i).alpha,
				      recipe->ibu_method, 0, recipe->hops.at(i).time, 0, recipe->boil_time, 0, 0, 0,
				      recipe->hops.at(i).utilisation, recipe->hops.at(i).bu_factor);

	    if (recipe->hops.at(i).useat == 2 || recipe->hops.at(i).useat == 4)	// Boil or Whirlpool
		use = QCoreApplication::translate("HopUse", g_hop_useat[recipe->hops.at(i).useat]) + QString(" %1 min").arg(recipe->hops.at(i).time);
	    else if (recipe->hops.at(i).useat == 5)					// Dryhop
		use = QCoreApplication::translate("HopUse", g_hop_useat[recipe->hops.at(i).useat]) + QString(" %1 days").arg(recipe->hops.at(i).time / 1440);
	    else
		use = QCoreApplication::translate("HopUse", g_hop_useat[recipe->hops.at(i).useat]);

	    if (recipe->hops.at(i).amount > 1)
		amount = QString("%1 kg").arg(recipe->hops.at(i).amount, 1, 'f', 3);
	    else
		amount = QString("%1 gr").arg(recipe->hops.at(i).amount * 1000, 1, 'f', 1);

	    painter.fillRect( 20, y,   715, 20, h_line);
	    painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft,  recipe->hops.at(i).name + " (" + recipe->hops.at(i).origin + ")");
	    painter.drawText(285, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(recipe->hops.at(i).alpha, 1, 'f', 1));
	    painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(ibu, 1, 'f', 1));
	    painter.drawText(435, y+4,  80, 20, Qt::AlignLeft,  QCoreApplication::translate("HopForm", g_hop_forms[recipe->hops.at(i).form]));
	    painter.drawText(520, y+4,  80, 20, Qt::AlignLeft,	use);
	    painter.drawText(605, y+4,  60, 20, Qt::AlignRight, amount);
            painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
	    y += 20;
	}
	painter.fillRect(670, y,    60, 20, c_line1);
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_hops, 1, 'f', 3));
        y += 40;

	/* Yeasts */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 335, 20, Qt::AlignLeft, tr("Yeast"));
        painter.drawText(360, y+4,  70, 20, Qt::AlignRight, tr("Attn"));
        painter.drawText(435, y+4,  80, 20, Qt::AlignLeft, tr("Type"));
        painter.drawText(520, y+4,  80, 20, Qt::AlignLeft, tr("Use at"));
        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
        double cost_yeasts = 0;
	for (int i = 0; i < recipe->yeasts.size(); i++) {
	    double cost = recipe->yeasts.at(i).amount * recipe->yeasts.at(i).cost;
	    cost_yeasts += cost;

	    if (recipe->yeasts.at(i).form == 0)
		amount = QString("%1 pack").arg(recipe->yeasts.at(i).amount, 1, 'f', 0);
	    else if (recipe->yeasts.at(i).form == 1 || recipe->yeasts.at(i).form == 6)
		amount = QString("%1 gr").arg(recipe->yeasts.at(i).amount * 1000.0, 1, 'f', 1);
	    else
		amount = QString("%1 ml").arg(recipe->yeasts.at(i).amount * 1000.0, 1, 'f', 1);

	    painter.fillRect( 20, y,   715, 20, y_line);
            painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft,  recipe->yeasts.at(i).laboratory + " " +
			    					recipe->yeasts.at(i).product_id + " (" +
								recipe->yeasts.at(i).name + ")");
	    painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(recipe->yeasts.at(i).attenuation, 1, 'f', 1));
	    painter.drawText(435, y+4,  80, 20, Qt::AlignLeft,	QCoreApplication::translate("YeastForm", g_yeast_forms[recipe->yeasts.at(i).form]));
	    painter.drawText(520, y+4,  80, 20, Qt::AlignLeft,	QCoreApplication::translate("YeastUse", g_yeast_use[recipe->yeasts.at(i).use]));
	    painter.drawText(605, y+4,  60, 20, Qt::AlignRight,	amount);
	    painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
	    y += 20;
	}
	painter.fillRect(670, y,    60, 20, c_line1);
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_yeasts, 1, 'f', 3));

	if ((y + 80 + (recipe->miscs.size() * 20)) > painter.device()->height()) {      /* Rows + header + footer + blank */
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 40;
        }

	/* Miscs */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 410, 20, Qt::AlignLeft, tr("Misc ingredient"));
        painter.drawText(435, y+4,  80, 20, Qt::AlignLeft, tr("Type"));
        painter.drawText(520, y+4,  80, 20, Qt::AlignLeft, tr("Use at"));
        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
        double cost_miscs = 0;
	for (int i = 0; i < recipe->miscs.size(); i++) {
	    double cost = recipe->miscs.at(i).amount * recipe->miscs.at(i).cost;
	    cost_miscs += cost;

	    if (recipe->miscs.at(i).use_use == 2)
		use = QCoreApplication::translate("MiscUse", g_misc_uses[recipe->miscs.at(i).use_use]) + QString(" %1 min").arg(recipe->miscs.at(i).time);
	    else
		use = QCoreApplication::translate("MiscUse", g_misc_uses[recipe->miscs.at(i).use_use]);

	    if (recipe->miscs.at(i).type == 4)					// Water agent
		painter.fillRect( 20, y,   715, 20, mw_line);
	    else if (recipe->miscs.at(i).type == 3)					// Fining
		painter.fillRect( 20, y,   715, 20, mf_line);
	    else if (recipe->miscs.at(i).type < 3 || recipe->miscs.at(i).type == 5)	// Spice, Herb, Flavour, Yeast nutrient
		painter.fillRect( 20, y,   715, 20, ms_line);
	    else
	    	painter.fillRect( 20, y,   715, 20, mo_line);
            painter.drawText( 20, y+4, 410, 20, Qt::AlignLeft,  recipe->miscs.at(i).name);
	    painter.drawText(435, y+4,  80, 20, Qt::AlignLeft,	QCoreApplication::translate("MiscType", g_misc_types[recipe->miscs.at(i).type]));
	    painter.drawText(520, y+4,  80, 20, Qt::AlignLeft,	use);
	    painter.drawText(605, y+4,  60, 20, Qt::AlignRight,
			    QString("%1 %2").arg(recipe->miscs.at(i).amount * 1000.0, 1, 'f', 2).arg(recipe->miscs.at(i).amount_is_weight ? "gr":"ml"));
	    painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
	    y += 20;
	}
	painter.fillRect(670, y,    60, 20, c_line1);
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_miscs, 1, 'f', 3));

	if ((y + 60 + (recipe->mashs.size() * 20)) > painter.device()->height()) {      /* Rows + header + blank */
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 40;
        }

	/* Mash */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 160, 20, Qt::AlignLeft, tr("Mash step"));
	painter.drawText(180, y+4,  80, 20, Qt::AlignLeft, tr("Step type"));
        painter.drawText(260, y+4,  60, 20, Qt::AlignRight, tr("Start °C"));
	painter.drawText(325, y+4,  60, 20, Qt::AlignRight, tr("End °C"));
	painter.drawText(390, y+4,  60, 20, Qt::AlignRight, tr("Time"));
        painter.drawText(455, y+4,  60, 20, Qt::AlignRight, tr("Ramp"));
	painter.drawText(520, y+4,  60, 20, Qt::AlignRight, tr("L/kg"));
        painter.drawText(585, y+4,  70, 20, Qt::AlignRight, tr("Inf/dec L."));
        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, tr("Inf/dec °C"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	for (int i = 0; i < recipe->mashs.size(); i++) {
	    painter.fillRect( 20, y,   715, 20, line);
	    painter.drawText( 20, y+4, 160, 20, Qt::AlignLeft,	recipe->mashs.at(i).step_name);
	    painter.drawText(180, y+4,  80, 20, Qt::AlignLeft,	QCoreApplication::translate("StepType", g_step_types[recipe->mashs.at(i).step_type]));
	    painter.drawText(260, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(recipe->mashs.at(i).step_temp, 1, 'f', 1));
	    painter.drawText(325, y+4,  60, 20, Qt::AlignRight,	QString("%1").arg(recipe->mashs.at(i).end_temp, 1, 'f', 1));
	    painter.drawText(390, y+4,  60, 20, Qt::AlignRight,	QString("%1").arg(recipe->mashs.at(i).step_time, 1, 'f', 0));
	    painter.drawText(455, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(recipe->mashs.at(i).ramp_time, 1, 'f', 0));
	    painter.drawText(520, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(recipe->mashs.at(i).step_wg_ratio, 1, 'f', 2));
	    if (recipe->mashs.at(i).step_type != 1) {
		painter.drawText(585, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->mashs.at(i).step_infuse_amount, 1, 'f', 1));
		painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->mashs.at(i).step_infuse_temp, 1, 'f', 1));
	    }
	    y += 20;
	}

	if ((y + 100 + ((recipe->w2_amount > 0) ? 40:0)) > painter.device()->height()) {      /* waters + header + blank */
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 40;
        }

	/* Water */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  tr("Water source"));
        painter.drawText(170, y+4,  70, 20, Qt::AlignRight, tr("Volume"));
        painter.drawText(240, y+4,  70, 20, Qt::AlignRight, tr("Ca"));
        painter.drawText(310, y+4,  70, 20, Qt::AlignRight, tr("Mg"));
        painter.drawText(380, y+4,  70, 20, Qt::AlignRight, tr("CaCO3"));
        painter.drawText(450, y+4,  70, 20, Qt::AlignRight, tr("Na"));
        painter.drawText(520, y+4,  70, 20, Qt::AlignRight, tr("Cl"));
        painter.drawText(590, y+4,  70, 20, Qt::AlignRight, tr("SO4"));
        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, tr("pH"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	painter.fillRect( 20, y,   715, 20, w_line);
	painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  recipe->w1_name);
	painter.drawText(170, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(recipe->w1_amount, 1, 'f', 1));
	painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w1_calcium, 1, 'f', 1));
	painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w1_magnesium, 1, 'f', 1));
	painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w1_total_alkalinity, 1, 'f', 1));
	painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w1_sodium, 1, 'f', 1));
	painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w1_chloride, 1, 'f', 1));
	painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w1_sulfate, 1, 'f', 1));
	painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w1_ph, 1, 'f', 2));
	y += 20;
	if (recipe->w2_amount > 0) {
	    /*
	     * If there is dillution water, show it and the mixed result too.
	     */
            painter.fillRect( 20, y,   715, 20, w_line);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  recipe->w2_name);
            painter.drawText(170, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(recipe->w2_amount, 1, 'f', 1));
            painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w2_calcium, 1, 'f', 1));
            painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w2_magnesium, 1, 'f', 1));
            painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w2_total_alkalinity, 1, 'f', 1));
            painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w2_sodium, 1, 'f', 1));
            painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w2_chloride, 1, 'f', 1));
            painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w2_sulfate, 1, 'f', 1));
            painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->w2_ph, 1, 'f', 2));
            y += 20;
            painter.fillRect( 20, y,   715, 20, w_line);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  tr("Mixed water"));
            painter.drawText(170, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(recipe->wg_amount, 1, 'f', 1));
            painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wg_calcium, 1, 'f', 1));
            painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wg_magnesium, 1, 'f', 1));
            painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wg_total_alkalinity, 1, 'f', 1));
            painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wg_sodium, 1, 'f', 1));
            painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wg_chloride, 1, 'f', 1));
            painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wg_sulfate, 1, 'f', 1));
            painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wg_ph, 1, 'f', 2));
            y += 20;
	}
	painter.fillRect( 20, y,   715, 20, w_line);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  tr("Treated mash water"));
        painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wb_calcium, 1, 'f', 1));
        painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wb_magnesium, 1, 'f', 1));
        painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wb_total_alkalinity, 1, 'f', 1));
        painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wb_sodium, 1, 'f', 1));
        painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wb_chloride, 1, 'f', 1));
        painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wb_sulfate, 1, 'f', 1));
        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->wb_ph, 1, 'f', 2));
	y += 20;
	painter.fillRect( 20, y,   715, 20, w_line);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  tr("Treated sparge water"));
        painter.drawText(170, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(recipe->sparge_volume, 1, 'f', 1));
        painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->ws_calcium, 1, 'f', 1));
        painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->ws_magnesium, 1, 'f', 1));
        painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->ws_total_alkalinity, 1, 'f', 1));
        painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->ws_sodium, 1, 'f', 1));
        painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->ws_chloride, 1, 'f', 1));
        painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->ws_sulfate, 1, 'f', 1));
        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(recipe->sparge_ph, 1, 'f', 2));
        y += 20;

    	/*
    	 * Print recipe notes if present.
    	 */
    	if (recipe->notes.length()) {
    	    QStringList lines = recipe->notes.split("\n");

    	    if (lines.size() && recipe->notes != "") {
            	if ((y + 80 + (lines.size() * 20)) > painter.device()->height()) {
            	    printer->newPage();
            	    printHeader(&painter);
            	    y = 120;
            	} else {
            	    y += 40;
            	}

	    	/* Notes header */
            	painter.setFont(QFont("Helvetica", 9, QFont::Bold));
            	painter.setPen(Qt::black);
            	painter.fillRect( 20, y,   715, 20, c_header);
            	painter.drawText( 20, y+4, 715, 20, Qt::AlignCenter, tr("Recipe notes"));
            	y += 20;
            	painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	    	for (int i = 0; i < lines.size(); i++) {
            	    painter.fillRect( 20, y,   715, 20, c_line1);
	    	    painter.drawText( 20, y+4, 715, 20, Qt::AlignLeft, lines[i]);
	     	    y += 20;
	    	}
	    }
	}

    } else if (p_job == PR_PRODUCT) {

	qInfo() << "print product" << product->record;
	printHeader(&painter);
        y = 120;
        /* Generic header */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.setPen(Qt::black);
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 715, 20, Qt::AlignCenter, tr("Product overview"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
        painter.fillRect( 20, y,   330, 20, c_line1);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Brew type"));
        painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QCoreApplication::translate("RecipeType", g_recipe_types[product->type]));
        painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Efficiency"));
        painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 %").arg(product->efficiency, 1, 'f', 1));
        y += 20;
        painter.fillRect( 20, y,   330, 20, c_line1);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Boil time"));
        painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1 minutes.").arg(product->boil_time, 1, 'f', 0));
        painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Batch size"));
	if (product->divide_type) {
	    painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 L. of %2 L.").arg(product->batch_size, 1, 'f', 1)
			    .arg(product->batch_size / product->divide_factor, 1, 'f', 1));
	} else {
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 L.").arg(product->batch_size, 1, 'f', 1));
	}
        y += 20;
        painter.fillRect( 20, y,   330, 20, c_line1);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Start SG"));
        painter.drawText(170, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(product->est_og, 1, 'f', 3));
        painter.drawText(260, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_og_min, 1, 'f', 3).arg(product->st_og_max, 1, 'f', 3));
        painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("End SG"));
        painter.drawText(555, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(product->est_fg, 1, 'f', 3));
        painter.drawText(645, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_fg_min, 1, 'f', 3).arg(product->st_fg_max, 1, 'f', 3));
        y += 20;
        painter.fillRect( 20, y,   330, 20, c_line1);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Estimated Alcohol"));
        painter.drawText(170, y+4,  90, 20, Qt::AlignLeft, QString("%1%").arg(product->est_abv, 1, 'f', 1));
        painter.drawText(260, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_abv_min, 1, 'f', 1).arg(product->st_abv_max, 1, 'f', 1));
        painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Estimated CO2 vol"));
        painter.drawText(555, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(product->est_carb, 1, 'f', 1));
        painter.drawText(645, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_carb_min, 1, 'f', 1).arg(product->st_carb_max, 1, 'f', 1));
        y += 20;
        painter.fillRect( 20, y,   150, 20, c_line1);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Color (") + color_method[product->color_method] + ")");
        painter.fillRect(170, y,   180, 20, Utils::ebc_to_color(product->est_color));
        if (product->est_color > 30)
            painter.setPen(Qt::white);
        painter.drawText(170, y+4,  90, 20, Qt::AlignLeft, QString("%1 EBC").arg(product->est_color, 1, 'f', 0));
        painter.drawText(260, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_color_min, 1, 'f', 0).arg(product->st_color_max, 1, 'f', 0));
	painter.setPen(Qt::black);
        painter.fillRect(405, y,   330, 20, c_line1);
        painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("IBU (") + g_ibu_method[product->ibu_method] + ")");
        painter.drawText(555, y+4,  90, 20, Qt::AlignLeft, QString("%1").arg(product->est_ibu, 1, 'f', 1));
        painter.drawText(645, y+4,  90, 20, Qt::AlignLeft, QString("(%1 - %2)").arg(product->st_ibu_min, 1, 'f', 0).arg(product->st_ibu_max, 1, 'f', 0));
	y += 20;
	painter.fillRect( 20, y,   330, 20, c_line1);
	painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Beer style"));
	painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, product->st_name);
	painter.fillRect(405, y,   330, 20, c_line1);
	painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Stage"));
	painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QCoreApplication::translate("ProdStages", g_prod_stages[product->stage]));
	if (product->divide_parts) {
	    y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Split batch"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QCoreApplication::translate("Splitter", g_prod_split[product->divide_type]));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Batch number"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 of %2").arg(product->divide_part + 1).arg(product->divide_parts + 1));
	}
        y += 40;

	/* Fermentables */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.setPen(Qt::black);
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft, tr("Fermentable"));
        painter.drawText(285, y+4,  70, 20, Qt::AlignRight, tr("Percent"));
        painter.drawText(360, y+4,  70, 20, Qt::AlignRight, tr("Yield"));
        painter.drawText(435, y+4,  80, 20, Qt::AlignLeft, tr("Type"));
        painter.drawText(520, y+4,  80, 20, Qt::AlignLeft, tr("Use at"));
        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
        double cost_fermentables = 0;
        QString soort, amount, use;
        for (int i = 0; i < product->fermentables.size(); i++) {
            double cost = product->fermentables.at(i).amount * product->fermentables.at(i).cost;
            cost_fermentables += cost;

            if (product->fermentables.at(i).type == 0)
                soort = QCoreApplication::translate("FermentableGraintype", g_fermentable_graintypes[product->fermentables.at(i).graintype]);
            else
                soort = QCoreApplication::translate("FermentableType", g_fermentable_types[product->fermentables.at(i).type]);

            if (product->fermentables.at(i).amount > 100)
                amount = QString("%1 kg").arg(product->fermentables.at(i).amount, 1, 'f', 1);
            else if (product->fermentables.at(i).amount > 10)
                amount = QString("%1 kg").arg(product->fermentables.at(i).amount, 1, 'f', 2);
            else
                amount = QString("%1 gr").arg(product->fermentables.at(i).amount * 1000, 1, 'f', 0);

            painter.fillRect( 20, y,   715, 20, f_line);

            painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft,  product->fermentables.at(i).name +
                                                                QString(", %1 EBC (").arg(product->fermentables.at(i).color, 1, 'f', 0) +
                                                                product->fermentables.at(i).supplier + ")");
	    if (product->fermentables.at(i).added < FERMENTABLE_ADDED_BOTTLE)
            	painter.drawText(285, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(product->fermentables.at(i).percentage, 1, 'f', 1));
	    else
		painter.drawText(285, y+4,  70, 20, Qt::AlignRight, "");
            painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(product->fermentables.at(i).yield, 1, 'f', 1));
            painter.drawText(435, y+4,  80, 20, Qt::AlignLeft,  soort);
            painter.drawText(520, y+4,  80, 20, Qt::AlignLeft,  QCoreApplication::translate("FermentableAdded", g_fermentable_added[product->fermentables.at(i).added]));
            painter.drawText(605, y+4,  60, 20, Qt::AlignRight, amount);
            painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
            y += 20;
        }
        painter.fillRect(670, y,    60, 20, c_line1);
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_fermentables, 1, 'f', 3));
        y += 40;

	/* Hops */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft, tr("Hop"));
        painter.drawText(285, y+4,  70, 20, Qt::AlignRight, tr("Alpha"));
        painter.drawText(360, y+4,  70, 20, Qt::AlignRight, tr("IBU"));
        painter.drawText(435, y+4,  80, 20, Qt::AlignLeft, tr("Type"));
        painter.drawText(520, y+4,  80, 20, Qt::AlignLeft, tr("Use at"));
        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
        double cost_hops = 0;
        for (int i = 0; i < product->hops.size(); i++) {

            double cost = product->hops.at(i).amount * product->hops.at(i).cost;
            cost_hops += cost;
            double ibu = Utils::toIBU(product->hops.at(i).useat, product->hops.at(i).form, product->preboil_sg, product->est_og3, product->batch_size,
                                      product->hops.at(i).amount, product->hops.at(i).time, product->hops.at(i).alpha,
                                      product->ibu_method, product->brew_whirlpool9, product->brew_whirlpool7, product->brew_whirlpool6,
				      product->boil_time, product->brew_cooling_method, 0, 0, product->hops.at(i).utilisation, product->hops.at(i).bu_factor);

            if (product->hops.at(i).useat == 2 || product->hops.at(i).useat == 4)     // Boil or Whirlpool
                use = QCoreApplication::translate("HopUse", g_hop_useat[product->hops.at(i).useat]) + QString(" %1 min").arg(product->hops.at(i).time);
            else if (product->hops.at(i).useat == 5)                                   // Dryhop
                use = QCoreApplication::translate("HopUse", g_hop_useat[product->hops.at(i).useat]) + QString(" %1 days").arg(product->hops.at(i).time / 1440);
            else
                use = QCoreApplication::translate("HopUse", g_hop_useat[product->hops.at(i).useat]);

            if (product->hops.at(i).amount > 1)
                amount = QString("%1 kg").arg(product->hops.at(i).amount, 1, 'f', 3);
            else
                amount = QString("%1 gr").arg(product->hops.at(i).amount * 1000, 1, 'f', 1);

            painter.fillRect( 20, y,   715, 20, h_line);
            painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft,  product->hops.at(i).name + " (" + product->hops.at(i).origin + ")");
            painter.drawText(285, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(product->hops.at(i).alpha, 1, 'f', 1));
            painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(ibu, 1, 'f', 1));
            painter.drawText(435, y+4,  80, 20, Qt::AlignLeft,  QCoreApplication::translate("HopForm", g_hop_forms[product->hops.at(i).form]));
            painter.drawText(520, y+4,  80, 20, Qt::AlignLeft,  use);
            painter.drawText(605, y+4,  60, 20, Qt::AlignRight, amount);
            painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
            y += 20;
        }
        painter.fillRect(670, y,    60, 20, c_line1);
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_hops, 1, 'f', 3));
        y += 40;

	/* Yeasts */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 335, 20, Qt::AlignLeft, tr("Yeast"));
        painter.drawText(360, y+4,  70, 20, Qt::AlignRight, tr("Attn"));
        painter.drawText(435, y+4,  80, 20, Qt::AlignLeft, tr("Type"));
        painter.drawText(520, y+4,  80, 20, Qt::AlignLeft, tr("Use at"));
        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
        double cost_yeasts = 0;
        for (int i = 0; i < product->yeasts.size(); i++) {
            double cost = product->yeasts.at(i).amount * product->yeasts.at(i).cost;
            cost_yeasts += cost;

            if (product->yeasts.at(i).form == 0)
                amount = QString("%1 pack").arg(product->yeasts.at(i).amount, 1, 'f', 0);
            else if (product->yeasts.at(i).form == 1 || product->yeasts.at(i).form == 6)
                amount = QString("%1 gr").arg(product->yeasts.at(i).amount * 1000.0, 1, 'f', 1);
            else
                amount = QString("%1 ml").arg(product->yeasts.at(i).amount * 1000.0, 1, 'f', 1);

            painter.fillRect( 20, y,   715, 20, y_line);
            painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft,  product->yeasts.at(i).laboratory + " " +
                                                                product->yeasts.at(i).product_id + " (" +
                                                                product->yeasts.at(i).name + ")");
            painter.drawText(360, y+4,  70, 20, Qt::AlignRight, QString("%1%").arg(product->yeasts.at(i).attenuation, 1, 'f', 1));
            painter.drawText(435, y+4,  80, 20, Qt::AlignLeft,  QCoreApplication::translate("YeastForm", g_yeast_forms[product->yeasts.at(i).form]));
            painter.drawText(520, y+4,  80, 20, Qt::AlignLeft,  QCoreApplication::translate("YeastUse", g_yeast_use[product->yeasts.at(i).use]));
            painter.drawText(605, y+4,  60, 20, Qt::AlignRight, amount);
            painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
            y += 20;
        }
	if (product->starter_enable && product->prop_volume[0]) {
	    int st = 0;
	    double sv = 0;
	    for (int i = 0; i < 4; i++) {
		if (product->prop_volume[i] > 0.0) {
		    st++;
		    if (product->prop_volume[i] > sv)
			sv = product->prop_volume[i];
		}
	    }
	    painter.fillRect( 20, y,   715, 20, y_line);
            painter.drawText( 20, y+4, 260, 20, Qt::AlignLeft,  QString(tr("%1 step yeaststarter")).arg(st));
	    painter.drawText(520, y+4,  80, 20, Qt::AlignLeft,  QString(tr("Before")));
	    painter.drawText(605, y+4,  60, 20, Qt::AlignRight, QString("%1 L").arg(sv, 1, 'f', 3));
	    y += 20;
	}
        painter.fillRect(670, y,    60, 20, c_line1);
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_yeasts, 1, 'f', 3));

        if ((y + 80 + (product->miscs.size() * 20)) > painter.device()->height()) {      /* Rows + header + footer + blank */
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 40;
        }

	/* Miscs */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 410, 20, Qt::AlignLeft, tr("Misc ingredient"));
        painter.drawText(435, y+4,  80, 20, Qt::AlignLeft, tr("Type"));
        painter.drawText(520, y+4,  80, 20, Qt::AlignLeft, tr("Use at"));
        painter.drawText(605, y+4,  60, 20, Qt::AlignRight, tr("Amount"));
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, tr("Cost"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
        double cost_miscs = 0;
        for (int i = 0; i < product->miscs.size(); i++) {
            double cost = product->miscs.at(i).amount * product->miscs.at(i).cost;
            cost_miscs += cost;

            if (product->miscs.at(i).use_use == 2)
                use = QCoreApplication::translate("MiscUse", g_misc_uses[product->miscs.at(i).use_use]) + QString(" %1 min").arg(product->miscs.at(i).time);
            else
                use = QCoreApplication::translate("MiscUse", g_misc_uses[product->miscs.at(i).use_use]);

            if (product->miscs.at(i).type == 4)                                        // Water agent
                painter.fillRect( 20, y,   715, 20, mw_line);
            else if (product->miscs.at(i).type == 3)                                   // Fining
                painter.fillRect( 20, y,   715, 20, mf_line);
            else if (product->miscs.at(i).type < 3 || product->miscs.at(i).type == 5) // Spice, Herb, Flavour, Yeast nutrient
                painter.fillRect( 20, y,   715, 20, ms_line);
            else
                painter.fillRect( 20, y,   715, 20, mo_line);
            painter.drawText( 20, y+4, 410, 20, Qt::AlignLeft,  product->miscs.at(i).name);
            painter.drawText(435, y+4,  80, 20, Qt::AlignLeft,  QCoreApplication::translate("MiscType", g_misc_types[product->miscs.at(i).type]));
            painter.drawText(520, y+4,  80, 20, Qt::AlignLeft,  use);
            painter.drawText(605, y+4,  60, 20, Qt::AlignRight,
                            QString("%1 %2").arg(product->miscs.at(i).amount * 1000.0, 1, 'f', 2).arg(product->miscs.at(i).amount_is_weight ? "gr":"ml"));
            painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost, 1, 'f', 3));
            y += 20;
        }
        painter.fillRect(670, y,    60, 20, c_line1);
        painter.drawText(670, y+4,  60, 20, Qt::AlignRight, QString("%1 €").arg(cost_miscs, 1, 'f', 3));

        if ((y + 60 + (product->mashs.size() * 20)) > painter.device()->height()) {      /* Rows + header + blank */
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 40;
        }

	/* Mash */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 160, 20, Qt::AlignLeft, tr("Mash step"));
        painter.drawText(180, y+4,  80, 20, Qt::AlignLeft, tr("Step type"));
        painter.drawText(260, y+4,  60, 20, Qt::AlignRight, tr("Start °C"));
        painter.drawText(325, y+4,  60, 20, Qt::AlignRight, tr("End °C"));
        painter.drawText(390, y+4,  60, 20, Qt::AlignRight, tr("Time"));
        painter.drawText(455, y+4,  60, 20, Qt::AlignRight, tr("Ramp"));
        painter.drawText(520, y+4,  60, 20, Qt::AlignRight, tr("L/kg"));
        painter.drawText(585, y+4,  70, 20, Qt::AlignRight, tr("Inf/dec L."));
        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, tr("Inf/dec °C"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
        for (int i = 0; i < product->mashs.size(); i++) {
            painter.fillRect( 20, y,   715, 20, line);
            painter.drawText( 20, y+4, 160, 20, Qt::AlignLeft,  product->mashs.at(i).step_name);
            painter.drawText(180, y+4,  80, 20, Qt::AlignLeft,  QCoreApplication::translate("StepType", g_step_types[product->mashs.at(i).step_type]));
            painter.drawText(260, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_temp, 1, 'f', 1));
            painter.drawText(325, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).end_temp, 1, 'f', 1));
            painter.drawText(390, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_time, 1, 'f', 0));
            painter.drawText(455, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).ramp_time, 1, 'f', 0));
            painter.drawText(520, y+4,  60, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_wg_ratio, 1, 'f', 2));
            if (product->mashs.at(i).step_type != 1) {
                painter.drawText(585, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_infuse_amount, 1, 'f', 1));
                painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->mashs.at(i).step_infuse_temp, 1, 'f', 1));
            }
            y += 20;
        }

        if ((y + 100 + ((product->w2_amount > 0) ? 40:0)) > painter.device()->height()) {      /* waters + header + blank */
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 40;
        }

	/* Water */
        painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.fillRect( 20, y,   715, 20, c_header);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  tr("Water source"));
        painter.drawText(170, y+4,  70, 20, Qt::AlignRight, tr("Volume"));
        painter.drawText(240, y+4,  70, 20, Qt::AlignRight, tr("Ca"));
        painter.drawText(310, y+4,  70, 20, Qt::AlignRight, tr("Mg"));
        painter.drawText(380, y+4,  70, 20, Qt::AlignRight, tr("CaCO3"));
        painter.drawText(450, y+4,  70, 20, Qt::AlignRight, tr("Na"));
        painter.drawText(520, y+4,  70, 20, Qt::AlignRight, tr("Cl"));
        painter.drawText(590, y+4,  70, 20, Qt::AlignRight, tr("SO4"));
        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, tr("pH"));
        y += 20;
        painter.setFont(QFont("Helvetica", 9, QFont::Normal));
        painter.fillRect( 20, y,   715, 20, w_line);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  product->w1_name);
        painter.drawText(170, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(product->w1_amount, 1, 'f', 1));
        painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_calcium, 1, 'f', 1));
        painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_magnesium, 1, 'f', 1));
        painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_total_alkalinity, 1, 'f', 1));
        painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_sodium, 1, 'f', 1));
        painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_chloride, 1, 'f', 1));
        painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_sulfate, 1, 'f', 1));
        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w1_ph, 1, 'f', 2));
        y += 20;
	if (product->w2_amount > 0) {
            /*
             * If there is dillution water, show it and the mixed result too.
             */
            painter.fillRect( 20, y,   715, 20, w_line);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  product->w2_name);
            painter.drawText(170, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(product->w2_amount, 1, 'f', 1));
            painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_calcium, 1, 'f', 1));
            painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_magnesium, 1, 'f', 1));
            painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_total_alkalinity, 1, 'f', 1));
            painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_sodium, 1, 'f', 1));
            painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_chloride, 1, 'f', 1));
            painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_sulfate, 1, 'f', 1));
            painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->w2_ph, 1, 'f', 2));
            y += 20;
            painter.fillRect( 20, y,   715, 20, w_line);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  tr("Mixed water"));
            painter.drawText(170, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(product->wg_amount, 1, 'f', 1));
            painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_calcium, 1, 'f', 1));
            painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_magnesium, 1, 'f', 1));
            painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_total_alkalinity, 1, 'f', 1));
            painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_sodium, 1, 'f', 1));
            painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_chloride, 1, 'f', 1));
            painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_sulfate, 1, 'f', 1));
            painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wg_ph, 1, 'f', 2));
            y += 20;
        }
        painter.fillRect( 20, y,   715, 20, w_line);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  tr("Treated mash water"));
        painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_calcium, 1, 'f', 1));
        painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_magnesium, 1, 'f', 1));
        painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_total_alkalinity, 1, 'f', 1));
        painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_sodium, 1, 'f', 1));
        painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_chloride, 1, 'f', 1));
        painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_sulfate, 1, 'f', 1));
        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->wb_ph, 1, 'f', 2));
        y += 20;
	painter.fillRect( 20, y,   715, 20, w_line);
        painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft,  tr("Treated sparge water"));
	painter.drawText(170, y+4,  70, 20, Qt::AlignRight, QString("%1 L").arg(product->sparge_volume, 1, 'f', 1));
        painter.drawText(240, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->ws_calcium, 1, 'f', 1));
        painter.drawText(310, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->ws_magnesium, 1, 'f', 1));
        painter.drawText(380, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->ws_total_alkalinity, 1, 'f', 1));
        painter.drawText(450, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->ws_sodium, 1, 'f', 1));
        painter.drawText(520, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->ws_chloride, 1, 'f', 1));
        painter.drawText(590, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->ws_sulfate, 1, 'f', 1));
        painter.drawText(660, y+4,  70, 20, Qt::AlignRight, QString("%1").arg(product->sparge_ph, 1, 'f', 2));
        y += 20;

	/*
         * Print product notes if present.
         */
        if (product->notes.length()) {
            QStringList lines = product->notes.split("\n");

            if (lines.size() && product->notes != "") {
                if ((y + 80 + (lines.size() * 20)) > painter.device()->height()) {
                    printer->newPage();
                    printHeader(&painter);
                    y = 120;
                } else {
                    y += 40;
                }

                /* Notes header */
                painter.setFont(QFont("Helvetica", 9, QFont::Bold));
                painter.setPen(Qt::black);
                painter.fillRect( 20, y,   715, 20, c_header);
                painter.drawText( 20, y+4, 715, 20, Qt::AlignCenter, tr("Recipe notes"));
                y += 20;
                painter.setFont(QFont("Helvetica", 9, QFont::Normal));
                for (int i = 0; i < lines.size(); i++) {
                    painter.fillRect( 20, y,   715, 20, c_line1);
                    painter.drawText( 20, y+4, 715, 20, Qt::AlignLeft, lines[i]);
                    y += 20;
                }
            }
        }

	if (product->stage > PROD_STAGE_BREW) {
	    if ((y + 100) > painter.device()->height()) {
		printer->newPage();
		printHeader(&painter);
		y = 120;
            } else {
            	y += 40;
            }
	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
            painter.setPen(Qt::black);
            painter.fillRect( 20, y,   715, 20, c_header);
            painter.drawText( 20, y+2, 715, 20, Qt::AlignCenter, tr("Product brewday"));
            y += 20;
	    painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	    painter.fillRect( 20, y,   300, 20, c_line1);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Brewday start"));
            painter.drawText(140, y+4, 180, 20, Qt::AlignLeft, product->brew_date_start.toString("dd MMM yyyy  hh:mm"));
            painter.fillRect(435, y,   300, 20, c_line1);
            painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Brewday end"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, product->brew_date_end.toString("dd MMM yyyy  hh:mm"));

	    /* Mash history */
	    if ((y + 60 + (product->mashs.size() * 20)) > painter.device()->height()) {
                printer->newPage();
                printHeader(&painter);
                y = 120;
            } else {
                y += 40;
            }
	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
	    painter.fillRect( 20, y,   715, 20, line);
	    painter.drawText( 40, y+4, 250, 20, Qt::AlignLeft, tr("Mash step"));
	    painter.drawText(290, y+4, 120, 20, Qt::AlignLeft, tr("Step type"));
	    painter.drawText(400, y+4, 110, 20, Qt::AlignLeft, tr("Temperature"));
	    painter.drawText(510, y+4,  75, 20, Qt::AlignLeft, tr("Minutes"));
	    painter.drawText(585, y+4,  75, 20, Qt::AlignLeft, tr("SG"));
	    painter.drawText(660, y+4,  75, 20, Qt::AlignLeft, tr("pH"));
	    painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	    y += 20;
	    for (int i = 0; i < product->mashs.size(); i++) {
		painter.fillRect( 20, y,   715, 20, c_line1);
		painter.drawText( 20, y+4,  20, 20, Qt::AlignCenter, QString("%1").arg(i + 1));
		painter.drawText( 40, y+4, 250, 20, Qt::AlignLeft, product->mashs.at(i).step_name);
		painter.drawText(290, y+4, 120, 20, Qt::AlignLeft, QCoreApplication::translate("StepType", g_step_types[product->mashs.at(i).step_type]));
		painter.drawText(400, y+4, 110, 20, Qt::AlignLeft, QString("%1 - %2°C").
				arg(product->mashs.at(i).step_temp, 1, 'f', 1).arg(product->mashs.at(i).end_temp, 1, 'f', 1));
		painter.drawText(510, y+4,  75, 20, Qt::AlignLeft, QString("%1").arg(product->mashs.at(i).step_time, 1, 'f', 0));
		painter.drawText(585, y+4,  75, 20, Qt::AlignLeft, QString("%1").arg(product->mashs.at(i).step_sg, 1, 'f', 3));
		painter.drawText(660, y+4,  75, 20, Qt::AlignLeft, QString("%1").arg(product->mashs.at(i).step_ph, 1, 'f', 1));
		y += 20;
	    }

	    /* Brew history */
	    if ((y + 470) > painter.device()->height()) {
                printer->newPage();
                printHeader(&painter);
                y = 120;
            } else {
                y += 20;
            }
	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
            painter.fillRect( 20, y,   715, 20, line);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Brew item"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, tr("Expected"));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, tr("Reached"));
	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, tr("Difference"));
	    painter.setFont(QFont("Helvetica", 9, QFont::Normal));
            y += 20;
	    painter.fillRect( 20, y,   715, 20, c_line1);
	    painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Mash pH"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->mash_ph, 1, 'f', 2));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_mash_ph, 1, 'f', 2));
	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->mash_ph, product->brew_mash_ph, 2, " pH"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Mash density"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, strDensity(product->est_mash_sg));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, strDensity(product->brew_mash_sg));
	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_mash_sg, product->brew_mash_sg, 3, " SG"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Mash efficiency"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, "100%");
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->brew_mash_efficiency, 1, 'f', 1));
	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(100.0, product->brew_mash_efficiency, 1, "%"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Sparge pH"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->sparge_ph, 1, 'f', 2));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_sparge_ph, 1, 'f', 2));
	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->sparge_ph, product->brew_sparge_ph, 2, " pH"));
	    y += 25;

            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Pre boil pH"));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_preboil_ph, 1, 'f', 2));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Pre boil density"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, strDensity(product->preboil_sg));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, strDensity(product->brew_preboil_sg));
	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->preboil_sg, product->brew_preboil_sg, 3, " SG"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Pre boil volume"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->boil_size * 1.04, 1, 'f', 1));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_preboil_volume, 1, 'f', 1));
	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->boil_size * 1.04, product->brew_preboil_volume, 1, " L"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Pre boil efficiency"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->efficiency, 1, 'f', 1));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->brew_preboil_efficiency, 1, 'f', 1));
	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->efficiency, product->brew_preboil_efficiency, 1, "%"));
	    y += 25;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("After boil pH"));
	    //painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_preboil_ph, 1, 'f', 2));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 pH").arg(product->brew_aboil_ph, 1, 'f', 2));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("After boil density"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, strDensity(product->est_og));
            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, strDensity(product->brew_aboil_sg));
            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_og, product->brew_aboil_sg, 3, " SG"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("After boil volume"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->batch_size * 1.04, 1, 'f', 1));
            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_aboil_volume, 1, 'f', 1));
            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->batch_size * 1.04, product->brew_aboil_volume, 1, " L"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("After boil efficiency"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->efficiency, 1, 'f', 1));
            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1%").arg(product->brew_aboil_efficiency, 1, 'f', 1));
            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->efficiency, product->brew_aboil_efficiency, 1, "%"));
	    y += 25;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Chiller and trub loss"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->eq_trub_chiller_loss, 1, 'f', 1));
            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_fermenter_tcloss, 1, 'f', 1));
            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->eq_trub_chiller_loss, product->brew_fermenter_tcloss, 1, " L"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Top up water"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->eq_top_up_water, 1, 'f', 1));
            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_fermenter_extrawater, 1, 'f', 1));
            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->eq_top_up_water, product->brew_fermenter_extrawater, 1, " L"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Fermenter volume"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->batch_size - product->eq_trub_chiller_loss, 1, 'f', 1));
            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 L").arg(product->brew_fermenter_volume, 1, 'f', 1));
            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->batch_size - product->eq_trub_chiller_loss, product->brew_fermenter_volume, 1, " L"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Fermenter density"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, strDensity(product->est_og));
            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, strDensity(product->brew_fermenter_sg));
            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_og, product->brew_fermenter_sg, 3, " SG"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Fermenter color"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 EBC").arg(product->est_color, 1, 'f', 0));
	    painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 EBC").arg(product->brew_fermenter_color, 1, 'f', 0));
	    painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_color, product->brew_fermenter_color, 0, " EBC"));
	    y += 20;
            painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Fermenter IBU"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 IBU").arg(product->est_ibu, 1, 'f', 0));
            painter.drawText(450, y+4, 200, 20, Qt::AlignLeft, QString("%1 IBU").arg(product->brew_fermenter_ibu, 1, 'f', 0));
            painter.drawText(650, y+4,  85, 20, Qt::AlignLeft, strDiff(product->est_ibu, product->brew_fermenter_ibu, 0, " IBU"));
	    y += 25;
            painter.fillRect( 20, y,   430, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Cooling method"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QCoreApplication::translate("ChillerType", g_chiller_types[product->brew_cooling_method]));
	    y += 20;
            painter.fillRect( 20, y,   430, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Cooling temperature"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1°C").arg(product->brew_cooling_to, 1, 'f', 1));
	    y += 20;
            painter.fillRect( 20, y,   430, 20, c_line1);
            painter.drawText( 20, y+4, 230, 20, Qt::AlignLeft, tr("Cooling time"));
	    painter.drawText(250, y+4, 200, 20, Qt::AlignLeft, QString("%1 min").arg(product->brew_cooling_time, 1, 'f', 0));
	}

	if (product->stage > PROD_STAGE_TERTIARY) {
	    if ((y + 200) > painter.device()->height()) {
                printer->newPage();
                printHeader(&painter);
                y = 120;
            } else {
                y += 40;
            }
	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
            painter.setPen(Qt::black);
            painter.fillRect( 20, y,   715, 20, c_header);
            painter.drawText( 20, y+2, 715, 20, Qt::AlignCenter, tr("Product fermentation"));
            y += 20;
            painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Primary start temp"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->primary_start_temp, 1, 'f', 1));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Primary peak temp"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->primary_max_temp, 1, 'f', 1));
	    y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Primary end temp"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->primary_end_temp, 1, 'f', 1));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Primary density"));
	    painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 SG").arg(product->primary_end_sg, 1, 'f', 3));
	    y += 20;
            painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Primary end date"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, product->primary_end_date.toString("dd MMM yyyy"));
	    y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Secondary end temp"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->secondary_temp, 1, 'f', 1));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Secondary density"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 SG").arg(product->secondary_end_sg, 1, 'f', 3));
	    y += 20;
            painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Secondary end date"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, product->secondary_end_date.toString("dd MMM yyyy"));
	    y += 20;
            painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Tertiary temperature"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->tertiary_temp, 1, 'f', 1));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Final density"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 SG").arg(product->fg, 1, 'f', 3));
	    y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Tertiary end date"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, product->package_date.toString("dd MMM yyyy"));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Apperant attenuation"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1%").arg(Utils::calc_svg(product->brew_fermenter_sg, product->fg), 1, 'f', 1));
	}

	if (product->stage > PROD_STAGE_PACKAGE) {
	    if ((y + ((product->package_infuse_amount > 0) ? 305:265)) > painter.device()->height()) {
                printer->newPage();
                printHeader(&painter);
                y = 120;
            } else {
                y += 40;
            }
            painter.setFont(QFont("Helvetica", 9, QFont::Bold));
            painter.setPen(Qt::black);
            painter.fillRect( 20, y,   715, 20, c_header);
            painter.drawText( 20, y+2, 715, 20, Qt::AlignCenter, tr("Package product"));
            y += 20;
            painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Package date"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, product->package_date.toString("dd MMM yyyy"));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Package volume"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 L").arg(product->package_volume, 1, 'f', 1));
            y += 20;
	    painter.setFont(QFont("Helvetica", 9, QFont::Normal));
            painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Alcohol volume"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1%").arg(product->package_abv, 1, 'f', 2));
	    y += 20;
	    if (product->package_infuse_amount > 0) {
		painter.fillRect( 20, y,   330, 20, c_line1);
            	painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Infuse volume"));
            	painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1 L").arg(product->package_infuse_amount, 1, 'f', 3));
            	painter.fillRect(405, y,   330, 20, c_line1);
            	painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Infuse alcohol"));
            	painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1%").arg(product->package_infuse_abv, 1, 'f', 2));
            	y += 20;
		painter.fillRect( 20, y,   715, 20, c_line1);
		painter.drawText( 20, y+4, 715, 20, Qt::AlignLeft, product->package_infuse_notes);
		y += 20;
	    }
	    y += 5;
	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
	    painter.fillRect( 20, y,   330, 20, line);
	    painter.drawText( 20, y+2, 330, 20, Qt::AlignCenter, tr("Bottles"));
	    painter.fillRect(405, y,   330, 20, line);
	    painter.drawText(405, y+2, 330, 20, Qt::AlignCenter, tr("Kegs"));
	    y += 20;
	    painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Bottles volume"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1 L").arg(product->bottle_amount, 1, 'f', 1));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Kegs volume"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 L").arg(product->keg_amount, 1, 'f', 1));
            y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Bottles CO2 volumes"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1 L").arg(product->bottle_carbonation, 1, 'f', 1));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Kegs CO2 volumes"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 L").arg(product->keg_carbonation, 1, 'f', 1));
	    y += 20;
	    QString bsugar = "", ksugar = "";
	    double bamount = 0, kamount = 0;
	    for (int i = 0; i < product->fermentables.size(); i++) {
		if (product->fermentables.at(i).added == FERMENTABLE_ADDED_BOTTLE) {
		    bsugar = product->fermentables.at(i).name;
		    bamount = product->fermentables.at(i).amount;
		}
		if (product->fermentables.at(i).added == FERMENTABLE_ADDED_KEGS) {
		    ksugar = product->fermentables.at(i).name;
                    kamount = product->fermentables.at(i).amount;
		}
	    }
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Sugar"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, bsugar);
            painter.fillRect(405, y,   330, 20, c_line1);
	    if (product->keg_forced_carb) {
                painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Forced carbonation"));
                painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, tr("Yes"));
            } else {
            	painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Sugar"));
            	painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, ksugar);
	    }
            y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Sugar amount"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1 Kg").arg(bamount, 1, 'f', 3));
	    if (! product->keg_forced_carb) {
		painter.fillRect(405, y,   330, 20, c_line1);
            	painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Sugar amount"));
            	painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 Kg").arg(kamount, 1, 'f', 3));
	    }
            y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Water amount"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1 L").arg(product->bottle_priming_water, 1, 'f', 3));
	    if (! product->keg_forced_carb) {
            	painter.fillRect(405, y,   330, 20, c_line1);
            	painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Water amount"));
            	painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 L").arg(product->keg_priming_water, 1, 'f', 3));
	    }
            y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Alcohol volume"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1%").arg(product->bottle_abv, 1, 'f', 2));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Alcohol volume"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1%").arg(product->keg_abv, 1, 'f', 2));
            y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Pressure"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1 bar").arg(product->bottle_bar, 1, 'f', 2));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Pressure"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1 bar").arg(product->keg_bar, 1, 'f', 2));
	    y += 20;
	    painter.fillRect( 20, y,   330, 20, c_line1);
            painter.drawText( 20, y+4, 150, 20, Qt::AlignLeft, tr("Carbonation temp"));
            painter.drawText(170, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->bottle_carbonation_temp, 1, 'f', 1));
            painter.fillRect(405, y,   330, 20, c_line1);
            painter.drawText(405, y+4, 150, 20, Qt::AlignLeft, tr("Carbonation temp"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1°C").arg(product->keg_carbonation_temp, 1, 'f', 1));
	}

	if (product->stage > PROD_STAGE_TASTE) {
	    QStringList lines = product->taste_notes.split("\n");

            if (lines.size() && (product->taste_notes != "")) {
                if ((y + 220 + (lines.size() * 20)) > painter.device()->height()) {
                    printer->newPage();
                    printHeader(&painter);
                    y = 120;
                } else {
                    y += 40;
                }
	    } else {
		if ((y + 220) > painter.device()->height()) {
		    printer->newPage();
                    printHeader(&painter);
                    y = 120;
                } else {
                    y += 40;
                }
	    }
	    painter.setFont(QFont("Helvetica", 9, QFont::Bold));
            painter.setPen(Qt::black);
            painter.fillRect( 20, y,   715, 20, c_header);
            painter.drawText( 20, y+2, 715, 20, Qt::AlignCenter, tr("Tasting notes"));
            y += 20;
            painter.setFont(QFont("Helvetica", 9, QFont::Normal));
            painter.fillRect( 20, y,   300, 20, c_line1);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Tasting date"));
            painter.drawText(120, y+4, 180, 20, Qt::AlignLeft, product->taste_date.toString("dd MMM yyyy"));
            painter.fillRect(435, y,   300, 20, c_line1);
            painter.drawText(435, y+4, 120, 20, Qt::AlignLeft, tr("Taste score"));
            painter.drawText(555, y+4, 180, 20, Qt::AlignLeft, QString("%1").arg(product->taste_rate, 1, 'f', 1));
            y += 20;
	    painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Color"));
            painter.drawText(120, y+4, 595, 20, Qt::AlignLeft, product->taste_color);
	    y += 20;
	    painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Transparency"));
            painter.drawText(120, y+4, 595, 20, Qt::AlignLeft, product->taste_transparency);
            y += 20;
	    painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Head"));
            painter.drawText(120, y+4, 595, 20, Qt::AlignLeft, product->taste_head);
            y += 20;
	    painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Aroma"));
            painter.drawText(120, y+4, 595, 20, Qt::AlignLeft, product->taste_aroma);
            y += 20;
	    painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Taste"));
            painter.drawText(120, y+4, 595, 20, Qt::AlignLeft, product->taste_taste);
            y += 20;
	    painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Mouthfeel"));
            painter.drawText(120, y+4, 595, 20, Qt::AlignLeft, product->taste_mouthfeel);
            y += 20;
	    painter.fillRect( 20, y,   715, 20, c_line1);
            painter.drawText( 20, y+4, 120, 20, Qt::AlignLeft, tr("Aftertaste"));
            painter.drawText(120, y+4, 595, 20, Qt::AlignLeft, product->taste_aftertaste);
            y += 25;
	    for (int i = 0; i < lines.size(); i++) {
		painter.fillRect( 20, y,   715, 20, c_line1);
                painter.drawText( 20, y+4, 715, 20, Qt::AlignLeft, lines[i]);
                y += 20;
            }
	}

    } else if (p_job == PR_CHECKLIST) {

	double	factor = 1.0 / product->divide_factor;
	double	mashwater = 0;
	int	numsalts = 0;

	qInfo() << "Print checklist" << product->record << "factor" << factor << product->divide_factor;
        printHeader(&painter);
        y = 120;

	/* First item, a yeast starter if needed, days before brewday. */
	if (product->starter_enable && product->prop_volume[0]) {
	    checkHeader(&painter, &y, tr("Make a yeast starter"));
	    int	days = 0;
	    int	last = 0;
	    QString s = "";
	    for (int i = 0; i < 4; i++) {
		if (product->prop_volume[i]) {
		    last = i;
		    if (product->prop_type[i] == STARTERS_STIRRED)
			days += 2;
		    else if (product->prop_type[i] == STARTERS_SHAKEN)
			days += 4;
		    else
			days += 6;	// Simple starter
		}
	    }
	    checkLine(&painter, &y, QString(tr("Start about %1 days before brewday with the starter.")).arg(days));
	    for (int i = 0; i < 4; i++) {
		if (product->prop_volume[i]) {
		    checkLine(&painter, &y, QString(tr("Starter step %1 of %2 liter with SG %3")).arg(i+1).arg(product->prop_volume[i], 1, 'f', 3).
				arg(product->starter_sg, 1, 'f', 3));
		    QString w = tr(" until there is enough yeast");
		    if (product->prop_type[i] == STARTERS_STIRRED)
		    	checkLine(&painter, &y, QString(tr("about 24 hours on a stirplate"))+w);
		    else if (product->prop_type[i] == STARTERS_SHAKEN)
		    	checkLine(&painter, &y, QString(tr("shake often for a few days"))+w);
		    else
		    	checkLine(&painter, &y, QString(tr("let it rest for almost a week"))+w);
		    if (i < last) {
		    	checkLine(&painter, &y, QString(tr("place starter in the fridge for 24 hours")));
		    	checkLine(&painter, &y, QString(tr("remove starter from the fridge and decant")));
		    } else {
		    	checkLine(&painter, &y, QString(tr("place starter in the fridge until brewday")));
		    	checkLine(&painter, &y, QString(tr("remove starter from the fridge and decant")));
		    }
		}
	    }
	    y += 20;
	}

	checkHeader(&painter, &y, tr("Mash water and treatment"));
	checkLine(&painter, &y, QString("%1 liter water `%2`").arg(product->w1_amount * factor, 1, 'f', 1).arg(product->w1_name));
	mashwater += product->w1_amount * factor;
	if (product->w2_name != "" && product->w2_amount > 0) {
	    checkLine(&painter, &y, QString("%1 liter water `%2`").arg(product->w2_amount * factor, 1, 'f', 1).arg(product->w2_name));
	    mashwater += product->w2_amount * factor;
	}
	for (int i = 0; i < product->miscs.size(); i++) {
	    if (product->miscs.at(i).type == MISC_TYPES_WATER_AGENT && product->miscs.at(i).use_use == MISC_USES_MASH) {
		QString unit = (product->miscs.at(i).amount_is_weight) ? "gr":"ml";
		checkLine(&painter, &y, QString("%1 %2 %3").arg(product->miscs.at(i).amount * 1000 * factor, 1, 'f', 2).arg(unit).arg(product->miscs.at(i).name));
		numsalts++;
	    }
	}
	y += 20;

	checkHeader(&painter, &y, tr("Sparge water and treatment"));
	QString sw = "";
	if (product->sparge_source == 0) {
	    checkLine(&painter, &y, QString("%1 liter water `%2`").arg(product->sparge_volume * factor, 1, 'f', 1).arg(product->w1_name));
	} else if (product->sparge_source == 1) {
	    checkLine(&painter, &y, QString("%1 liter water `%2`").arg(product->sparge_volume * factor, 1, 'f', 1).arg(product->w2_name));
	} else if (product->sparge_source == 2) {
	    checkLine(&painter, &y, QString("%1 liter water `%2`")
			    .arg(product->sparge_volume * (product->w1_amount / (product->w1_amount+product->w2_amount)) * factor, 1, 'f', 1)
			    .arg(product->w1_name));
	    checkLine(&painter, &y, QString("%1 liter water `%2`")
			    .arg(product->sparge_volume * (product->w2_amount / (product->w1_amount+product->w2_amount)) * factor, 1, 'f', 1)
			    .arg(product->w2_name));
	}
	for (int i = 0; i < product->miscs.size(); i++) {
            if (product->miscs.at(i).type == MISC_TYPES_WATER_AGENT && product->miscs.at(i).use_use == MISC_USES_SPARGE) {
                QString unit = (product->miscs.at(i).amount_is_weight) ? "gr":"ml";
                checkLine(&painter, &y, QString("%1 %2 %3").arg(product->miscs.at(i).amount * 1000 * factor, 1, 'f', 2).arg(unit).arg(product->miscs.at(i).name));
                numsalts++;
            }
        }
	y += 20;

	checkHeader(&painter, &y, tr("Weight and mill the malts"));
	for (int i = 0; i < product->fermentables.size(); i++) {
	    if (product->fermentables.at(i).added == FERMENTABLE_ADDED_MASH) {
		checkLine(&painter, &y, QString("%1 kg `%2` (%3)").arg(product->fermentables.at(i).amount * factor, 1, 'f', 3).
				arg(product->fermentables.at(i).name).arg(product->fermentables.at(i).supplier));
	    }
	}
	checkLine(&painter, &y, QString(tr("Mill the malts")));

	int lines = 0;
	int loop = 0;
	for (int i = 0; i < product->mashs.size(); i++) {
	    if (loop == 0) {
		lines += 3;
		if (numsalts > 0)
		    lines++;
		for (int j = 0; j < product->hops.size(); j++) {
		    if (product->hops.at(j).useat == HOP_USEAT_MASH) {
			lines++;
		    }
		}
		for (int j = 0; j < product->miscs.size(); j++) {
		    if ((product->miscs.at(j).use_use == MISC_USES_MASH) && (product->miscs.at(j).type != MISC_TYPES_WATER_AGENT)) {
			lines++;
		    }
		}
	    } else {
		lines++;
	    }
	    lines++;
	    loop++;
	}
	lines++;
	qDebug() << "check" << lines << y + (lines * 20) << painter.device()->height();
        if ((y + (lines * 20)) > painter.device()->height()) {
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 20;
        }

	checkHeader(&painter, &y, tr("Mash"));
	loop = 0;
	double l, mvol = 0, msugars = 0;
	for (int i = 0; i < product->mashs.size(); i++) {
	    if (product->mashs.at(i).step_type == 0)
		mvol += product->mashs.at(i).step_infuse_amount * factor;	// We need this later
	    if (loop == 0) {
		if (product->mashs.at(i).step_type == 0)
		    l = product->mashs.at(i).step_infuse_amount * factor;
		else
		    l = mashwater;
		checkLine(&painter, &y, QString(tr("Heat %1 liter water to %2°C (%3 cm below kettle top)"))
			.arg(mashwater, 1, 'f', 1).arg(product->mashs.at(i).step_infuse_temp, 1, 'f', 1)
			.arg(Utils::kettle_cm(l, product->eq_tun_volume, product->eq_tun_height), 1, 'f', 1));
		if (numsalts > 0)
		    checkLine(&painter, &y, QString(tr("Add brouwzouten")));
		checkLine(&painter, &y, QString(tr("Add malts and dough-in")));
		for (int j = 0; j < product->hops.size(); j++) {
		    if (product->hops.at(j).useat == HOP_USEAT_MASH) {
			checkLine(&painter, &y, QString(tr("Add %1 gram `%2` hop")).arg(product->hops.at(j).amount * 1000 * factor, 1, 'f', 1)
			       .arg(product->hops.at(j).name));
		    }
		}
		for (int j = 0; j < product->miscs.size(); j++) {
		    if ((product->miscs.at(j).use_use == MISC_USES_MASH) && (product->miscs.at(j).type != MISC_TYPES_WATER_AGENT)) {
			QString unit = (product->miscs.at(j).amount_is_weight) ? "gr":"ml";
			checkLine(&painter, &y, QString(tr("Add %1 %2 `%3`")).arg(product->miscs.at(j).amount * 1000 * factor, 1, 'f', 2)
				.arg(unit).arg(product->miscs.at(j).name));
		    }
		}
	    } else {	// loop > 0
		if (product->mashs.at(i).step_type == 0) {	// Infusion
		    checkLine(&painter, &y, QString(tr("Add %1 liter water of %2°C")).arg(product->mashs.at(i).step_infuse_amount * factor, 1, 'f', 1)
				.arg(product->mashs.at(i).step_infuse_temp, 1, 'f', 1));
		} else if (product->mashs.at(i).step_type == 1) {	// Direct heat
		    checkLine(&painter, &y, QString(tr("Heat upto %1°C")).arg(product->mashs.at(i).step_temp, 1, 'f', 1));
		} else {	// Decoction
		    checkLine(&painter, &y, QString(tr("Take, heat, boil and return %1 part of the mash"))
				.arg(product->mashs.at(i).step_infuse_amount * factor, 1, 'f', 1));
		}
	    }
	    if (product->mashs.at(i).step_temp != product->mashs.at(i).end_temp) {
                checkInput(&painter, &y, QString(tr("%1 minutes from %2°C to %3°C")).arg(product->mashs.at(i).step_time)
                                .arg(product->mashs.at(i).step_temp, 1, 'f', 1).arg(product->mashs.at(i).end_temp, 1, 'f', 1), QString(tr("Brix")));
            } else {
                checkInput(&painter, &y, QString(tr("%1 minutes at %2°C")).arg(product->mashs.at(i).step_time)
                                .arg(product->mashs.at(i).step_temp, 1, 'f', 1), QString(tr("Brix")));
            }
	    if (loop == 0)
		checkInput(&painter, &y, QString(tr("Measure and adjust pH (target %1 pH)")).arg(product->mash_ph, 1, 'f', 2), QString(tr("pH")));
	    loop++;
	}
	double est_masg_sg = 0, sugardensity = 1.611, grainabsorbtion = 0;
	for (int i = 0; i < product->fermentables.size(); i++) {
	    if (product->fermentables.at(i).added == FERMENTABLE_ADDED_MASH) {
		double d = product->fermentables.at(i).amount * factor * (product->fermentables.at(i).yield / 100) *
			   (1 - product->fermentables.at(i).moisture / 100);
		mvol += product->fermentables.at(i).amount * factor * (product->fermentables.at(i).moisture / 100);
		grainabsorbtion += my_grain_absorbtion * product->fermentables.at(i).amount * factor;
		msugars += d;
	    }
	}
	double v = msugars / sugardensity + mvol;
	double plato = 1000.0 * msugars / (v * 10.0);	// deg. Plato
	double mash_sg = Utils::plato_to_sg(plato);
	checkInput(&painter, &y, QString(tr("Target SG end mash: ")) + strDensity(mash_sg), QString(tr("SG")));
	if ((y + 140) > painter.device()->height()) {
            printer->newPage();
            printHeader(&painter);
            y = 120;
	} else {
            y += 20;
	}

	checkHeader(&painter, &y, tr("Lauter and Sparge"));
	checkLine(&painter, &y, QString(tr("Heat sparge water to %1°C")).arg(product->sparge_temp, 1, 'f', 1));
	checkInput(&painter, &y, QString(tr("Bring water to %1 pH with %2 ml. `%3`")).arg(product->sparge_ph, 1, 'f', 2)
			.arg(product->sparge_acid_amount * 1000 * factor, 1, 'f', 2).arg(my_acids.at(product->sparge_acid_type).name_en), QString(tr("pH")));
	checkLine(&painter, &y, QString(tr("Sparge with close to %1 liter water"))
			.arg(((product->boil_size * factor) - mashwater + grainabsorbtion + product->eq_lauter_deadspace) * 1.03, 1, 'f', 1));
	checkInput(&painter, &y, QString(tr("Target volume in boil kettle: %1 liter (%2 cm below kettle top)"))
			.arg(product->boil_size * factor * 1.04, 1, 'f', 1)
			.arg(Utils::kettle_cm(product->boil_size * factor * 1.04, product->eq_kettle_volume, product->eq_kettle_height), 1, 'f', 1),
			QString(tr("cm")));
	checkInput(&painter, &y, QString(tr("Target SG in boil kettle: ")) + strDensity(product->preboil_sg), QString(tr("SG")));
	checkInput(&painter, &y, "", QString(tr("pH")));
	for (int i = 0; i < product->hops.size(); i++) {
	    if (product->hops.at(i).useat == HOP_USEAT_FWH) {
		checkLine(&painter, &y, QString(tr("Add %1 gr `%2` hop after sparge")).arg(product->hops.at(i).amount * 1000 * factor, 1, 'f', 1)
			.arg(product->hops.at(i).name));
	    }
	}

	if (checkSplit(&painter, &y, 1))
	    factor = 1;
	/* Boil, how much space do we need */
	lines = 0;
	if (product->boil_time == 0) {
	   lines = 3;
	} else {
	   lines = 5;
	   if (product->brew_cooling_method == CHILLER_TYPE_EMERSION)
		lines++;
	   for (int i = 0; i < product->fermentables.size(); i++) {
		if (product->fermentables.at(i).added == FERMENTABLE_ADDED_BOIL)
		    lines++;
	   }
	   for (int i = 0; i < product->hops.size(); i++) {
		if (product->hops.at(i).useat == HOP_USEAT_BOIL || product->hops.at(i).useat == HOP_USEAT_AROMA)
		    lines++;
	   }
	   for (int i = 0; i < product->miscs.size(); i++) {
		if (product->miscs.at(i).use_use == MISC_USES_BOIL)
		    lines++;
	   }
	}
	qDebug() << "check" << lines << y + (lines * 20) << painter.device()->height();
	if ((y + (lines * 20)) > painter.device()->height()) {
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 20;
        }
	checkHeader(&painter, &y, tr("Boil"));
	if (product->boil_time > 0) {
	    checkLine(&painter, &y, QString(tr("Total boiltime: %1 minutes")).arg(product->boil_time, 1, 'f', 0));
	    for (int i = product->boil_time; i >= 0; i--) {
		if (i == 10) {
		    for (int j = 0; j < product->fermentables.size(); j++) {
			if (product->fermentables.at(j).added == FERMENTABLE_ADDED_BOIL)
			    checkLine(&painter, &y, QString(tr("%1 kg `%2` at 10 minutes before end of boil"))
				.arg(product->fermentables.at(j).amount * factor, 1, 'f', 3)
				.arg(product->fermentables.at(j).name));
		    }
		    if (product->brew_cooling_method == CHILLER_TYPE_EMERSION)
			checkLine(&painter, &y, QString(tr("Place emersion chiller at 10 minutes before end of boil")));
		}
		for (int j = 0; j < product->hops.size(); j++) {
		    if ((product->hops.at(j).useat == HOP_USEAT_BOIL || product->hops.at(j).useat == HOP_USEAT_AROMA) && product->hops.at(j).time == i) {
			if (i == 0)
			    checkLine(&painter, &y, QString(tr("%1 gr `%2` at flameout")).arg(product->hops.at(j).amount * 1000 * factor, 1, 'f', 2)
				.arg(product->hops.at(j).name));
			else
			    checkLine(&painter, &y, QString(tr("%1 gr `%2` at %3 minutes before end of boil"))
				.arg(product->hops.at(j).amount * 1000 * factor, 1, 'f', 2).arg(product->hops.at(j).name).arg(i));
		    }
		}
		for (int j = 0; j < product->miscs.size(); j++) {
		    if (product->miscs.at(j).use_use == MISC_USES_BOIL && product->miscs.at(j).time == i) {
			QString unit = (product->miscs.at(j).amount_is_weight) ? "gr":"ml";
			if (i == 0)
			    checkLine(&painter, &y, QString(tr("%1 %2 `%3` at flameout"))
				.arg(product->miscs.at(j).amount * 1000 * factor, 1, 'f', 2).arg(unit).arg(product->miscs.at(j).name));
			else
			    checkLine(&painter, &y, QString(tr("%1 %2 `%3` at %4 minutes before end of boil"))
				.arg(product->miscs.at(j).amount * 1000 * factor, 1, 'f', 2).arg(unit).arg(product->miscs.at(j).name).arg(i));
		    }
		}
	    }
	    checkInput(&painter, &y, QString(tr("Target volume at end of boil: %1 liter (%2 cm below kettle top)"))
			.arg(product->batch_size * 1.04 * factor, 1, 'f', 1)
			.arg(Utils::kettle_cm(product->batch_size * 1.04 * factor, product->eq_kettle_volume, product->eq_kettle_height)),
			QString(tr("cm")));
	    checkInput(&painter, &y, QString(tr("Target SG at end of boil: ")) + strDensity(product->est_og3), QString(tr("SG")));
	    checkInput(&painter, &y, "", QString(tr("pH")));
	    if (checkSplit(&painter, &y, 2))
            	factor = 1;
	} else {
	    checkLine(&painter, &y, QString(tr("This is a `no-boil` recipe")));
	}

	/* Whirlpools and chilling */
	lines = 5;
	if (product->brew_whirlpool9)
	    lines++;
	if (product->brew_whirlpool7)
            lines++;
	if (product->brew_whirlpool6)
            lines++;
	if (product->brew_whirlpool2)
            lines++;
	for (int i = 0; i < product->hops.size(); i++) {
	    if (product->hops.at(i).useat == HOP_USEAT_WHIRLPOOL)
		lines++;
	}
	if ((y + (lines * 20)) > painter.device()->height()) {
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 20;
        }
	if ((product->brew_whirlpool9 + product->brew_whirlpool7 + product->brew_whirlpool6 + product->brew_whirlpool2) > 0) {
	    checkHeader(&painter, &y, tr("Whirlpool(s) and cooling"));
	    if (product->brew_whirlpool9 > 0)
		checkLine(&painter, &y, QString(tr("Wirlpool for %1 minutes. Keep temp above 85°C")).arg(product->brew_whirlpool9, 1, 'f', 0));
	    if (product->brew_whirlpool7 > 0)
                checkLine(&painter, &y, QString(tr("Wirlpool for %1 minutes. Keep temp between 72 and 79°C")).arg(product->brew_whirlpool7, 1, 'f', 0));
	    if (product->brew_whirlpool6 > 0)
                checkLine(&painter, &y, QString(tr("Wirlpool for %1 minutes. Keep temp between 60 and 66°C")).arg(product->brew_whirlpool6, 1, 'f', 0));
	    for (int i = 0; i < product->hops.size(); i++) {
            	if (product->hops.at(i).useat == HOP_USEAT_WHIRLPOOL)
		    checkLine(&painter, &y, QString(tr("%1 gr `%2` for %3 minutes in the whirlpool"))
			.arg(product->hops.at(i).amount * 1000 * factor, 1, 'f', 1).arg(product->hops.at(i).name)
			.arg(product->hops.at(i).time));
	    }
	    checkLine(&painter, &y, QString(tr("Cool to %1°C")).arg(product->brew_cooling_to, 1, 'f', 1));
	    if (product->brew_whirlpool2 > 0)
                checkLine(&painter, &y, QString(tr("Wirlpool for %1 minutes.")).arg(product->brew_whirlpool2, 1, 'f', 0));
	} else {
	    checkHeader(&painter, &y, tr("Cooling"));
	    checkLine(&painter, &y, QString(tr("Cool to %1°C")).arg(product->brew_cooling_to, 1, 'f', 1));
	}
	checkLine(&painter, &y, QString(tr("Desinfect fermenter and pump and hoses if needed")));
	checkInput(&painter, &y, QString(tr("Transfer wort to fermenter")), QString(tr("Liter")));
	if (checkSplit(&painter, &y, 3))
            factor = 1;

	double climate = product->brew_cooling_to;
    	lines = 3;
    	for (int i = 0; i < product->yeasts.size(); i++) {
	    if (product->yeasts.at(i).use == YEAST_USE_PRIMARY) {
	    	lines++;
	    	if (product->yeasts.at(i).type == YEAST_TYPES_KVEIK && (product->yeasts.at(i).pitch_temperature > 0))
		    lines++;
	    }
    	}
    	if (product->brew_aeration_type > 0)
	    lines++;
	if (product->brew_fermenter_extrawater > 0)
	    lines++;
    	if ((y + (lines * 20)) > painter.device()->height()) {
            printer->newPage();
            printHeader(&painter);
            y = 120;
        } else {
            y += 20;
        }
	double dry = 0;
	checkHeader(&painter, &y, tr("Yeast pitching and fermentation"));
	for (int i = 0; i < product->yeasts.size(); i++) {
            if (product->yeasts.at(i).use == YEAST_USE_PRIMARY) {
		switch (product->yeasts.at(i).form) {
		    case YEAST_FORMS_LIQUID:	checkLine(&painter, &y, QString(tr("%1 pack %2, `%3` yeast")).arg(product->yeasts.at(i).amount)
							.arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
			    			break;
		    case YEAST_FORMS_DRY:	dry += product->yeasts.at(i).amount * 1000 * factor;
		    case YEAST_FORMS_DRIED:	checkLine(&painter, &y, QString(tr("%1 gram %2, `%3` yeast"))
							.arg(product->yeasts.at(i).amount * 1000 * factor, 1, 'f', 1)
							.arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
						break;
		    default:			checkLine(&painter, &y, QString(tr("%1 ml %2, `%3` yeast"))
							.arg(product->yeasts.at(i).amount * 1000 * factor, 1, 'f', 0)
							.arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
						break;
		}
		if (product->yeasts.at(i).type == YEAST_TYPES_KVEIK && (product->yeasts.at(i).pitch_temperature > 0)) {
		    checkLine(&painter, &y, QString(tr("Pitch yeast at %1°C")).arg(product->yeasts.at(i).pitch_temperature, 1, 'f', 1));
		    climate = product->yeasts.at(i).pitch_temperature;
		}
	    }
	}
	if (dry > 0) {
	    checkLine(&painter, &y, QString(tr("Pitch yeast dry into the wort")));
	} else {
	    if (product->starter_enable && product->prop_volume[0])
		checkLine(&painter, &y, QString(tr("Add decanted yeast starter")));
	    else
		checkLine(&painter, &y, QString(tr("Add the yeast")));
	}
	if (product->brew_fermenter_extrawater)
	    checkLine(&painter, &y, QString(tr("Add %1 liter water in the fermenter")).arg(product->brew_fermenter_extrawater * factor, 1, 'f', 1));
	if (product->brew_aeration_type > 0)
	    checkLine(&painter, &y, QString(tr("Aerate %1 minutes with %2")).arg(product->brew_aeration_time)
		.arg((product->brew_aeration_type == 1) ? "air":"oxygen"));
	checkLine(&painter, &y, QString(tr("Set fermentation start temperature to %1°C")).arg(climate, 1, 'f', 1));
	checkLine(&painter, &y, QString(tr("Start fermentation")));

	/* During primary fermentation */
	lines = 0;
	for (int i = 0; i < product->fermentables.size(); i++)
	    if (product->fermentables.at(i).added == FERMENTABLE_ADDED_FERMENTATION)
		lines++;
	for (int i = 0; i < product->miscs.size(); i++)
	    if (product->miscs.at(i).use_use == MISC_USES_PRIMARY)
		lines++;
	if (lines) {
	    if ((y + 20 + (lines * 20)) > painter.device()->height()) {
            	printer->newPage();
            	printHeader(&painter);
            	y = 120;
            } else {
            	y += 20;
            }
	    checkHeader(&painter, &y, tr("Primary fermentation"));
	    for (int i = 0; i < product->fermentables.size(); i++) {
		if (product->fermentables.at(i).added == FERMENTABLE_ADDED_FERMENTATION)
		    checkLine(&painter, &y, QString(tr("Add %1 kg `%2` on day 3 or 4")).arg(product->fermentables.at(i).amount * factor, 1, 'f', 3)
			.arg(product->fermentables.at(i).name));
	    }
	    for (int i = 0; i < product->miscs.size(); i++) {
		if (product->miscs.at(i).use_use == MISC_USES_PRIMARY) {
		    QString unit = (product->miscs.at(i).amount_is_weight) ? "gr":"ml";
		    checkLine(&painter, &y, QString(tr("Add %1 %2 `%3` on day 3 or 4")).arg(product->miscs.at(i).amount * 1000 * factor, 1, 'f', 3)
			.arg(unit).arg(product->miscs.at(i).name));
		}
	    }
	}
	if (checkSplit(&painter, &y, 4))
            factor = 1;

	/* During secondary fermentation, yeast */
	lines = 0;
	for (int i = 0; i < product->yeasts.size(); i++) {
	    if (product->yeasts.at(i).use == YEAST_USE_SECONDARY)
		lines++;
	    if (product->yeasts.at(i).harvest_time > 0)
		lines++;
	}
	if (lines) {
	    if ((y + 20 + (lines * 20)) > painter.device()->height()) {
                printer->newPage();
                printHeader(&painter);
                y = 120;
            } else {
                y += 20;
            }
            checkHeader(&painter, &y, tr("Secondary fermentation"));
	    for (int i = 0; i < product->yeasts.size(); i++) {
		if (product->yeasts.at(i).use == YEAST_USE_SECONDARY) {
		    if (product->yeasts.at(i).form == YEAST_FORMS_LIQUID) {
			checkLine(&painter, &y, QString(tr("Add %1 pack %2, `%3` yeast (with starter if needed)"))
			    .arg(product->yeasts.at(i).amount).arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
		    } else if (product->yeasts.at(i).form == YEAST_FORMS_DRY) {
			checkLine(&painter, &y, QString(tr("Add %1 gram %2, `%3`")).arg(product->yeasts.at(i).amount * 1000 * factor, 1, 'f', 1)
			    .arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
		    } else {
			checkLine(&painter, &y, QString(tr("Add %1 gram %2, `%3` yeast (with starter if needed)"))
			    .arg(product->yeasts.at(i).amount * 1000 * factor, 1, 'f', 1)
			    .arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
		    }
		}
		if (product->yeasts.at(i).harvest_time > 0) {
		    checkLine(&painter, &y, QString(tr("After %1 hours harvest yeast from the %2")).arg(product->yeasts.at(i).harvest_time)
			    .arg((product->yeasts.at(i).harvest_top > 0) ? "top":"bottom"));
		}
	    }
	}
	if (checkSplit(&painter, &y, 5))
            factor = 1;

	/* During tertiary fermentation */
        lines = 0;
	for (int i = 0; i < product->fermentables.size(); i++)
            if (product->fermentables.at(i).added == FERMENTABLE_ADDED_LAGERING)
                lines++;
	for (int i = 0; i < product->hops.size(); i++)
	    if (product->hops.at(i).useat == HOP_USEAT_DRY_HOP)
		lines++;
        for (int i = 0; i < product->miscs.size(); i++)
            if (product->miscs.at(i).use_use == MISC_USES_SECONDARY)
                lines++;
        for (int i = 0; i < product->yeasts.size(); i++) {
            if (product->yeasts.at(i).use == YEAST_USE_TERTIARY)
                lines++;
        }
        if (lines) {
            if ((y + 20 + (lines * 20)) > painter.device()->height()) {
                printer->newPage();
                printHeader(&painter);
                y = 120;
            } else {
                y += 20;
            }
            checkHeader(&painter, &y, tr("Tertiary fermentation"));
	    for (int i = 0; i < product->fermentables.size(); i++) {
                if (product->fermentables.at(i).added == FERMENTABLE_ADDED_LAGERING)
                    checkLine(&painter, &y, QString(tr("Add %1 kg `%2`")).arg(product->fermentables.at(i).amount * factor, 1, 'f', 3)
                        .arg(product->fermentables.at(i).name));
            }
	    for (int i = 0; i < product->hops.size(); i++) {
		if (product->hops.at(i).useat == HOP_USEAT_DRY_HOP) {
		    checkLine(&painter, &y, QString(tr("Add %1 gram `%2` for %3 days")).arg(product->hops.at(i).amount * 1000 * factor, 1, 'f', 1)
			.arg(product->hops.at(i).name).arg(product->hops.at(i).time / 1440));
		}
	    }
	    for (int i = 0; i < product->yeasts.size(); i++) {
	    	if (product->yeasts.at(i).use == YEAST_USE_TERTIARY) {
                    if (product->yeasts.at(i).form == YEAST_FORMS_LIQUID) {
                        checkLine(&painter, &y, QString(tr("Add %1 pack %2, `%3` yeast (with starter if needed)"))
                            .arg(product->yeasts.at(i).amount).arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
                    } else if (product->yeasts.at(i).form == YEAST_FORMS_DRY) {
                        checkLine(&painter, &y, QString(tr("Add %1 gram %2, `%3`")).arg(product->yeasts.at(i).amount * 1000 * factor, 1, 'f', 1)
                            .arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
                    } else {
                        checkLine(&painter, &y, QString(tr("Add %1 ml %2, `%3` yeast (with starter if needed)"))
                            .arg(product->yeasts.at(i).amount * 1000 * factor, 1, 'f', 1)
                            .arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
                    }
                }
	    }
            for (int i = 0; i < product->miscs.size(); i++) {
                if (product->miscs.at(i).use_use == MISC_USES_SECONDARY) {
                    QString unit = (product->miscs.at(i).amount_is_weight) ? "gr":"ml";
                    checkLine(&painter, &y, QString(tr("Add %1 %2 `%3` for %4 days")).arg(product->miscs.at(i).amount * 1000.0 * factor, 1, 'f', 2)
                        .arg(unit).arg(product->miscs.at(i).name).arg(product->miscs.at(i).time / 1440));
                }
            }
	}
	if (checkSplit(&painter, &y, 6))
            factor = 1;

	/* During packaging */
	lines = 0;
	for (int i = 0; i < product->fermentables.size(); i++)
            if (product->fermentables.at(i).added >= FERMENTABLE_ADDED_BOTTLE)
                lines++;
	for (int i = 0; i < product->hops.size(); i++)
	    if (product->hops.at(i).useat == HOP_USEAT_BOTTLING)
		lines++;
        for (int i = 0; i < product->miscs.size(); i++)
            if (product->miscs.at(i).use_use == MISC_USES_BOTTLING)
                lines++;
        for (int i = 0; i < product->yeasts.size(); i++)
            if (product->yeasts.at(i).use == YEAST_USE_BOTTLE)
                lines++;
	if (lines) {
            if ((y + 20 + (lines * 20)) > painter.device()->height()) {
                printer->newPage();
                printHeader(&painter);
                y = 120;
            } else {
                y += 20;
            }
            checkHeader(&painter, &y, tr("Packaging"));
            for (int i = 0; i < product->fermentables.size(); i++) {
                if (product->fermentables.at(i).added == FERMENTABLE_ADDED_BOTTLE)
                    checkLine(&painter, &y, QString(tr("Bottling add %1 kg `%2` with %3 liter water"))
			.arg(product->fermentables.at(i).amount * factor, 1, 'f', 3)
                        .arg(product->fermentables.at(i).name).arg(product->bottle_priming_water * factor, 1, 'f', 3));
		if (product->fermentables.at(i).added == FERMENTABLE_ADDED_KEGS)
                    checkLine(&painter, &y, QString(tr("Kegging add %1 kg `%2` with %3 liter water"))
			.arg(product->fermentables.at(i).amount * factor, 1, 'f', 3)
                        .arg(product->fermentables.at(i).name).arg(product->keg_priming_water * factor, 1, 'f', 3));
            }
	    for (int i = 0; i < product->yeasts.size(); i++) {
            	if (product->yeasts.at(i).use == YEAST_USE_BOTTLE) {
		    if (product->yeasts.at(i).form == YEAST_FORMS_LIQUID) {
                        checkLine(&painter, &y, QString(tr("Add %1, `%2` as bottle yeast"))
                            .arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
                    } else if (product->yeasts.at(i).form == YEAST_FORMS_DRY) {
                        checkLine(&painter, &y, QString(tr("Add %1 gram %2, `%3` as bottle yeast"))
			    .arg(product->yeasts.at(i).amount * 1000 * factor, 1, 'f', 1)
                            .arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
                    } else {
                        checkLine(&painter, &y, QString(tr("Add %1 ml %2, `%3` as bottle yeast"))
                            .arg(product->yeasts.at(i).amount * 1000 * factor, 1, 'f', 1)
                            .arg(product->yeasts.at(i).product_id).arg(product->yeasts.at(i).name));
                    }
		}
	    }
	    for (int i = 0; i < product->miscs.size(); i++) {
                if (product->miscs.at(i).use_use == MISC_USES_BOTTLING) {
                    QString unit = (product->miscs.at(i).amount_is_weight) ? "gr":"ml";
                    checkLine(&painter, &y, QString(tr("Add %1 %2 `%3` during bottling")).arg(product->miscs.at(i).amount * 1000 * factor, 1, 'f', 2)
                        .arg(unit).arg(product->miscs.at(i).name));
                }
            }
	    for (int i = 0; i < product->hops.size(); i++) {
		if (product->hops.at(i).useat == HOP_USEAT_BOTTLING) {
		    checkLine(&painter, &y, QString(tr("Add %1 gr `%2`")).arg(product->hops.at(i).amount * 1000 * factor, 1, 'f', 2)
				    .arg(product->hops.at(i).name));
		}
	    }
	}
    } else if (p_job == PR_REP_TOTAL) {

	qInfo() << "Print total production";
	printHeader(&painter);
        y = 120;

	/* Report header */
	painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        painter.setPen(Qt::black);
        painter.fillRect( 20, y,   540, 20, c_header);
	painter.drawText( 20, y+4,  80, 20, Qt::AlignHCenter, tr("Number"));
	painter.drawText(100, y+4,  80, 20, Qt::AlignHCenter, tr("Year"));
	painter.drawText(180, y+4, 120, 20, Qt::AlignRight, tr("Brew sessions"));
	painter.drawText(300, y+4, 120, 20, Qt::AlignRight, tr("Brew volume"));
	painter.drawText(420, y+4, 120, 20, Qt::AlignRight, tr("Average volume"));
	y += 20;
	painter.setFont(QFont("Helvetica", 9, QFont::Normal));
	query.exec("SELECT DISTINCT YEAR(package_date) FROM products WHERE package_date ORDER BY package_date");
	query.first();
	int regel = 0, brews = 0, total = 0;
	double packaged = 0, tvolume = 0, average;
	QString year = "";
	for (int i = 0 ; i < query.size() ; i++ ) {
	    if ((y + 20) > painter.device()->height()) {
                printer->newPage();
                printHeader(&painter);
                y = 120;
            }

	    brews = 0;
	    packaged = 0;
	    regel++;
	    year = query.value(0).toString();
	    QSqlQuery query2;
	    query2.exec("SELECT package_volume FROM products WHERE package_date AND YEAR(package_date) = '" + year + "'");
	    while (query2.next()) {
		brews++;
		total++;
		packaged += query2.value(0).toDouble();
		tvolume += query2.value(0).toDouble();
	    }
	    average = packaged / brews;
	    painter.fillRect( 20, y,   540, 20, (i % 2) ? c_line1:c_line2);
	    painter.drawText( 20, y+4,  80, 20, Qt::AlignCenter, QString("%1").arg(regel));
            painter.drawText(100, y+4, 100, 20, Qt::AlignCenter, year);
	    painter.drawText(180, y+4, 120, 20, Qt::AlignRight, QString("%1").arg(brews));
	    painter.drawText(300, y+4, 120, 20, Qt::AlignRight, QString("%1 L").arg(packaged, 2, 'f', 1, '0'));
	    painter.drawText(420, y+4, 120, 20, Qt::AlignRight, QString("%1 L").arg(average, 2, 'f', 1, '0'));
	    query.next();
            y += 20;
	}
	average = tvolume / total;
	painter.fillRect(180, y,   360, 20, w_line);
	painter.drawText(180, y+4, 120, 20, Qt::AlignRight, QString("%1").arg(total));
	painter.drawText(300, y+4, 120, 20, Qt::AlignRight, QString("%1 L").arg(tvolume, 2, 'f', 1, '0'));
	painter.drawText(420, y+4, 120, 20, Qt::AlignRight, QString("%1 L").arg(average, 2, 'f', 1, '0'));
	y += 20;

    } else if (p_job == PR_REP_EFF) {

	qInfo() << "Print efficiency";
        y = painter.device()->height() + 100;

	query.exec("SELECT * FROM products WHERE package_date AND type='2' ORDER BY code");
	query.first();
	for (int i = 0 ; i < query.size() ; i++ ) {
            if ((y + 20) > painter.device()->height()) {
		if (i > 0)
                    printer->newPage();
                printHeader(&painter);
                y = 120;

		/* Report header */
        	painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        	painter.setPen(Qt::black);
        	painter.fillRect( 20, y,   715, 20, c_header);
        	painter.drawText( 25, y+4,  65, 20, Qt::AlignLeft, tr("Code"));
        	painter.drawText( 90, y+4, 200, 20, Qt::AlignLeft, tr("Name"));
        	painter.drawText(290, y+4, 120, 20, Qt::AlignLeft, tr("Beer style"));
        	painter.drawText(410, y+4,  80, 20, Qt::AlignRight, tr("Max extract"));
        	painter.drawText(490, y+4,  80, 20, Qt::AlignRight, tr("Mash eff."));
        	painter.drawText(570, y+4,  80, 20, Qt::AlignRight, tr("Sparge eff"));
        	painter.drawText(650, y+4,  80, 20, Qt::AlignRight, tr("Boil eff"));
        	y += 20;
        	painter.setFont(QFont("Helvetica", 9, QFont::Normal));
            }

	    /*
	     * Data is not always available, calculate the missing pieces.
	     */
	    double mvol = 0, msugars = 0, ssugars = 0;
	    QJsonParseError parseError;

	    const auto& ma_json = query.value("json_mashs").toString().trimmed();
	    if (!ma_json.trimmed().isEmpty()) {
		const auto& formattedJson = QString("%1").arg(ma_json);
		QJsonDocument mashs = QJsonDocument::fromJson(formattedJson.toUtf8(),  &parseError);
		if (parseError.error != QJsonParseError::NoError) {
		    qWarning() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ;
		} else if (mashs.isArray()) {
		    for (int j = 0; j < mashs.array().size(); j++) {
			QJsonObject obj = mashs.array().at(j).toObject();
			if (obj["step_type"].toInt() == 0)
			    mvol += obj["step_infuse_amount"].toDouble();
		    }
		}
	    }

	    const auto& f_json = query.value("json_fermentables").toString();
	    if (!f_json.trimmed().isEmpty()) {
		const auto& formattedJson = QString("%1").arg(f_json);
		QJsonDocument fermentables = QJsonDocument::fromJson(formattedJson.toUtf8(),  &parseError);
		if (parseError.error != QJsonParseError::NoError) {
		    qWarning() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ;
		} else if (fermentables.isArray()) {
		    for (int j = 0; j < fermentables.array().size(); j++) {
			QJsonObject obj = fermentables.array().at(j).toObject();
			if (obj["f_added"].toInt() == 0) {
			    double d = obj["f_amount"].toDouble() * (obj["f_yield"].toDouble() / 100) * (1 - obj["f_moisture"].toDouble() / 100);
			    ssugars += obj["f_amount"].toDouble();
			    mvol += obj["f_amount"].toDouble() * obj["f_moisture"].toDouble() / 100;
			    msugars += d;
			}
		    }
		}
	    }

	    double sugardensity = 1.611;
	    double v = msugars / sugardensity + mvol;
	    double plato = 1000 * msugars / (v * 10);	// deg. Plato
	    double mash_efficiency = query.value("brew_mash_efficiency").toDouble();
	    double mash_sg = query.value("brew_mash_sg").toDouble();
	    if ((mash_efficiency == 0) && (mash_sg > 1)) {
		mash_efficiency = 100 * Utils::sg_to_plato(mash_sg) / plato;
	    }
	    double mash_extract = 100 * msugars / ssugars;
	    double preboil_sg = query.value("brew_preboil_sg").toDouble();
	    double preboil_volume = query.value("brew_preboil_volume").toDouble();
	    double est_preboil_plato = Utils::sg_to_plato(preboil_sg) * (preboil_volume / 1.04) * preboil_sg * 10 / 1000;
	    double preboil_efficiency = query.value("brew_preboil_efficiency").toDouble();
	    if ((msugars > 0) && (preboil_efficiency == 0))
		preboil_efficiency = est_preboil_plato / msugars * 100;
	    if (preboil_efficiency < 0)
		preboil_efficiency = 0;
	    double aboil_efficiency = query.value("brew_aboil_efficiency").toDouble();

	    painter.fillRect( 20, y,   715, 20, (i % 2) ? c_line1:c_line2);
	    painter.drawText( 25, y+4,  65, 20, Qt::AlignLeft, query.value("code").toString());
	    painter.drawText( 90, y+4, 200, 20, Qt::AlignLeft, query.value("name").toString());
	    painter.drawText(290, y+4, 120, 20, Qt::AlignLeft, query.value("st_name").toString());
	    painter.drawText(410, y+4,  80, 20, Qt::AlignRight, QString("%1%").arg(mash_extract, 2, 'f', 1, '0'));
	    painter.drawText(490, y+4,  80, 20, Qt::AlignRight, QString("%1%").arg(mash_efficiency, 2, 'f', 1, '0'));
	    painter.drawText(570, y+4,  80, 20, Qt::AlignRight, QString("%1%").arg(preboil_efficiency, 2, 'f', 1, '0'));
	    painter.drawText(650, y+4,  80, 20, Qt::AlignRight, QString("%1%").arg(aboil_efficiency, 2, 'f', 1, '0'));
	    query.next();
	    y += 20;
	}

    } else if (p_job == PR_REP_SVG) {

	qInfo() << "Print fermentations";
	y = painter.device()->height() + 100;
	QString y_name, y_lab, y_product;

	/*
	 * Works from MariaDB 10.6.x and later, MySQL 8.x and later.
	 * Pick the first yeast record, that should be the one used for primary.
	 */
	query.exec("SELECT code,name,brew_date_end,primary_end_temp,primary_end_date,secondary_temp,secondary_end_date,tertiary_temp,"
			"package_date,brew_fermenter_sg,fg,json_yeasts,"
		      	"JSON_EXTRACT(json_yeasts, '$[0].y_laboratory') AS yeastLab,JSON_EXTRACT(json_yeasts, '$[0].y_product_id') AS yeastID "	
			"FROM products WHERE package_date AND type='2' ORDER BY yeastID");
	query.first();

	for (int i = 0 ; i < query.size() ; i++ ) {
            if ((y + 20) > painter.device()->height()) {
		if (i > 0)
                    printer->newPage();
                printHeader(&painter);
                y = 120;

		/* Report header */
        	painter.setFont(QFont("Helvetica", 9, QFont::Bold));
        	painter.setPen(Qt::black);
        	painter.fillRect( 20, y,   715, 20, c_header);
        	painter.drawText( 25, y+4,  65, 20, Qt::AlignLeft, tr("Code"));
        	painter.drawText( 90, y+4, 180, 20, Qt::AlignLeft, tr("Name"));
        	painter.drawText(270, y+4, 110, 20, Qt::AlignLeft, tr("Yeast"));
        	painter.drawText(380, y+4,  60, 20, Qt::AlignHCenter, tr("Primary"));
        	painter.drawText(440, y+4,  60, 20, Qt::AlignHCenter, tr("Secondary"));
        	painter.drawText(500, y+4,  60, 20, Qt::AlignHCenter, tr("Tertiary"));
		painter.drawText(560, y+4,  40, 20, Qt::AlignRight, tr("Days"));
		painter.drawText(600, y+4,  40, 20, Qt::AlignRight, tr("OG"));
		painter.drawText(640, y+4,  40, 20, Qt::AlignRight, tr("FG"));
        	painter.drawText(680, y+4,  50, 20, Qt::AlignRight, tr("AA"));
        	y += 20;
        	painter.setFont(QFont("Helvetica", 9, QFont::Normal));
            }

	    int primary = query.value("brew_date_end").toDate().daysTo(query.value("primary_end_date").toDate());
	    int secondary = query.value("primary_end_date").toDate().daysTo(query.value("secondary_end_date").toDate());
	    int tertiary = query.value("secondary_end_date").toDate().daysTo(query.value("package_date").toDate());
	    int total = query.value("brew_date_end").toDate().daysTo(query.value("package_date").toDate());
	    double og = query.value("brew_fermenter_sg").toDouble();
	    double fg = query.value("fg").toDouble();
	    double aa = Utils::calc_svg(og, fg);

	    painter.fillRect( 20, y,   715, 20, (i % 2) ? c_line1:c_line2);
	    painter.drawText( 25, y+4,  65, 20, Qt::AlignLeft, query.value("code").toString());
            painter.drawText( 90, y+4, 180, 20, Qt::AlignLeft, query.value("name").toString());
	    painter.drawText(270, y+4, 110, 20, Qt::AlignLeft, query.value("yeastID").toString() + " " + query.value("yeastLab").toString());
	    painter.drawText(380, y+4,  40, 20, Qt::AlignRight, QString("%1°").arg(query.value("primary_end_temp").toDouble(), 2, 'f', 1));
            painter.drawText(420, y+4,  20, 20, Qt::AlignRight, QString("%1").arg(primary));
	    painter.drawText(440, y+4,  40, 20, Qt::AlignRight, QString("%1°").arg(query.value("secondary_temp").toDouble(), 2, 'f', 1));
            painter.drawText(480, y+4,  20, 20, Qt::AlignRight, QString("%1").arg(secondary));
	    painter.drawText(500, y+4,  40, 20, Qt::AlignRight, QString("%1°").arg(query.value("tertiary_temp").toDouble(), 2, 'f', 1));
	    painter.drawText(540, y+4,  20, 20, Qt::AlignRight, QString("%1").arg(tertiary));
	    painter.drawText(560, y+4,  40, 20, Qt::AlignRight, QString("%1").arg(total));
	    painter.drawText(600, y+4,  40, 20, Qt::AlignRight, QString("%1").arg(og, 4, 'f', 3, '0'));
	    painter.drawText(640, y+4,  40, 20, Qt::AlignRight, QString("%1").arg(fg, 4, 'f', 3, '0'));
	    painter.drawText(680, y+4,  50, 20, Qt::AlignRight, QString("%1%").arg(aa, 2, 'f', 1, '0'));

	    query.next();
            y += 20;
	}
    }

    painter.end();
}


void PrinterDialog::checkHeader(QPainter *painter, qreal *y, QString text)
{
    painter->setFont(QFont("Arial", 10, QFont::Bold));
    painter->setPen(Qt::black);
    painter->drawText(50, *y, 700, 20, Qt::AlignLeft, text);
    painter->setFont(QFont("Arial", 10, QFont::Normal));
    *y += 20;
}


/*
 * Draw a checkbox and text.
 */
void PrinterDialog::checkLine(QPainter *painter, qreal *y, QString text)
{
    painter->drawRect(24, *y, 16, 16);
    painter->drawText(50, *y,630, 20, Qt::AlignLeft, text);
    *y += 20;
}


void PrinterDialog::checkInput(QPainter *painter, qreal *y, QString text, QString prompt)
{
    if (text != "") {
    	painter->drawRect(24, *y, 16, 16);
    	painter->drawText(50, *y,480, 20, Qt::AlignLeft, text);
    }
    painter->drawText(515, *y, 150, 20, Qt::AlignRight, QString(tr("Measured:")) + QString(" _________"));
    painter->drawText(675, *y,  60, 20, Qt::AlignLeft, prompt);
    *y += 20;
}


bool PrinterDialog::checkSplit(QPainter *painter, qreal *y, int moment)
{
    if (product->divide_type && product->divide_type == moment) {
	*y += 20;
	painter->setFont(QFont("Helvetica", 14, QFont::Bold));
	painter->drawText(20, *y, 715, 20, Qt::AlignCenter,
			QString(tr("%1 split the batch here!")).arg(QCoreApplication::translate("Splitter", g_prod_split[product->divide_type])));
    	painter->setFont(QFont("Arial", 10, QFont::Normal));
	*y += 26;
	return true;
    }
    return false;
}


QString PrinterDialog::strDiff(double v1, double v2, int decimals, QString suffix)
{
    return QString("%1%2%3").arg((v2 > v1) ? "+":"").arg(v2 - v1, 1, 'f', decimals).arg(suffix);
}


QString PrinterDialog::strDensity(double density)
{
    return QString("%1 SG %2°Brix %3°P").arg(density, 1, 'f', 3).arg(Utils::sg_to_brix(density), 1, 'f', 1).arg(Utils::sg_to_plato(density), 1, 'f', 1);
}


void PrinterDialog::printHeader(QPainter *painter)
{
    QPixmap outPixmap = QPixmap();
    outPixmap.loadFromData(my_logoByteArray);
    int w = outPixmap.width();
    int h = outPixmap.height();
    /* Make sure to keep the logo aspect ratio */
    if (w == h) {
	painter->drawPixmap(20, 0, 100, 100, outPixmap);
    } else if (w > h) {
	painter->drawPixmap(20, 0, 100, (h * 100) / w, outPixmap);
    } else {
	painter->drawPixmap(20, 0, (w * 100) / h, 100, outPixmap);
    }

    /* The fat header line */
    painter->setFont(QFont("Helvetica",18, QFont::Bold));
    if (p_job == PR_SUPPLIES) {
	painter->drawText(140, 0,  500, 40, Qt::AlignLeft, tr("Inventory") + " " + my_brewery_name);
    } else if (p_job == PR_YEASTBANK) {
	painter->drawText(140, 0,  500, 40, Qt::AlignLeft, tr("Yeastbank") + " " + my_brewery_name);
    } else if (p_job == PR_RECIPE) {
	painter->drawText(140, 0,  500, 40, Qt::AlignLeft, recipe->name);
    } else if (p_job == PR_PRODUCT || p_job == PR_CHECKLIST) {
        painter->drawText(140, 0,  500, 40, Qt::AlignLeft, product->code + "  " + product->name);
    } else if (p_job == PR_REP_TOTAL) {
	painter->drawText(140, 0,  500, 40, Qt::AlignLeft, tr("Year production") + " " + my_brewery_name);
    } else if (p_job == PR_REP_EFF) {
	painter->drawText(140, 0,  500, 40, Qt::AlignLeft, tr("Brew efficiency") + " " + my_brewery_name);
    } else if (p_job == PR_REP_SVG) {
	painter->drawText(140, 0,  500, 40, Qt::AlignLeft, tr("Fermentations") + " " + my_brewery_name);
    } else {
        painter->drawText(140, 0,  500, 40, Qt::AlignLeft, "?? " + my_brewery_name);
    }
    /* The first normal header line */
    painter->setFont(QFont("Helvetica",10, QFont::Normal));
    painter->drawText(140,35,  80, 20, Qt::AlignLeft, tr("Date and time"));
    painter->drawText(220,35, 400, 20, Qt::AlignLeft, ": " + QDateTime::currentDateTime().toString("dd-MMM-yyyy hh:mm"));
    if (p_job == PR_RECIPE) {
	painter->drawText(140,55,  80, 20, Qt::AlignLeft, tr("Beer style"));
    	painter->drawText(220,55, 400, 20, Qt::AlignLeft, ": " + recipe->st_name);
    }
    if (p_job == PR_PRODUCT || p_job == PR_CHECKLIST) {
        painter->drawText(140,55,  80, 20, Qt::AlignLeft, tr("Beer style"));
        painter->drawText(220,55, 400, 20, Qt::AlignLeft, ": " + product->st_name);
    }
    /* The report itself may print more lines from y = 55. */
}

mercurial