src/EditRecipe.cpp

Wed, 06 Apr 2022 21:41:58 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Wed, 06 Apr 2022 21:41:58 +0200
changeset 112
9e0dfa78f349
parent 111
04f5a7c5a1dc
child 113
30a34d639e90
permissions
-rw-r--r--

Load miscs in QList.

/**
 * EditRecipe.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 "MainWindow.h"
#include "EditRecipe.h"
#include "../ui/ui_EditRecipe.h"
#include "Utils.h"



EditRecipe::EditRecipe(int id, QWidget *parent) : QDialog(parent), ui(new Ui::EditRecipe)
{
    QSqlQuery query;

    qDebug() << "EditRecipe record:" << id;
    recipe = new Recipe;
    ui->setupUi(this);
    recipe->fermentables_current = recipe->hops_current = recipe->misc_current = recipe->yeasts_current = recipe->mashs_current = -1;
    recipe->fermentables_use100 = false;
    this->recno = id;

    WindowTitle();

    ui->typeEdit->addItem(tr("Extract"));
    ui->typeEdit->addItem(tr("Partial Mash"));
    ui->typeEdit->addItem(tr("All Grain"));

    ui->color_methodEdit->addItem("Morey");
    ui->color_methodEdit->addItem("Mosher");
    ui->color_methodEdit->addItem("Daniels");
    ui->color_methodEdit->addItem("Halberstadt");
    ui->color_methodEdit->addItem("Naudts");

    ui->ibu_methodEdit->addItem("Tinseth");
    ui->ibu_methodEdit->addItem("Rager");
    ui->ibu_methodEdit->addItem("Daniels");

    ui->beerstyleEdit->addItem("");	// First add a dummy
    query.prepare("SELECT style_guide,style_letter,name FROM profile_styles ORDER BY style_guide,style_letter,name");
    query.exec();
    query.first();
    for (int i = 0; i < query.size(); i++) {
	ui->beerstyleEdit->addItem(query.value(0).toString()+" "+query.value(1).toString()+" "+query.value(2).toString());
	query.next();
    }

    if (id >= 0) {
	query.prepare("SELECT * FROM recipes WHERE record = :recno");
	query.bindValue(":recno", id);
	query.exec();
	query.next();

	recipe->record = query.value(0).toInt();
	recipe->uuid = query.value(1).toString();
	recipe->locked = query.value(2).toInt() ? true:false;
	recipe->st_name = query.value(3).toString();
	recipe->st_letter = query.value(4).toString();
	recipe->st_guide = query.value(5).toString();
	recipe->st_category = query.value(6).toString();
	recipe->st_category_number = query.value(7).toInt();
	recipe->st_type = query.value(8).toInt();
	recipe->st_og_min = query.value(9).toDouble();
	recipe->st_og_max = query.value(10).toDouble();
	recipe->st_fg_min = query.value(11).toDouble();
	recipe->st_fg_max = query.value(12).toDouble();
	recipe->st_ibu_min = query.value(13).toDouble();
	recipe->st_ibu_max = query.value(14).toDouble();
	recipe->st_color_min = query.value(15).toDouble();
	recipe->st_color_max = query.value(16).toDouble();
	recipe->st_carb_min = query.value(17).toDouble();
	recipe->st_carb_max = query.value(18).toDouble();
	recipe->st_abv_min = query.value(19).toDouble();
	recipe->st_abv_max = query.value(20).toDouble();
	recipe->name = query.value(21).toString();
	recipe->notes = query.value(22).toString();
	recipe->type = query.value(23).toInt();
	recipe->batch_size = query.value(24).toDouble();
	recipe->boil_size = query.value(25).toDouble();
	recipe->boil_time = query.value(26).toDouble();
	recipe->efficiency = query.value(27).toDouble();
	recipe->est_og = query.value(28).toDouble();
	recipe->est_fg = query.value(29).toDouble();
	recipe->est_abv = query.value(30).toDouble();
	recipe->est_color = query.value(31).toDouble();
	recipe->color_method = query.value(32).toInt();
	recipe->est_ibu = query.value(33).toDouble();
	recipe->ibu_method = query.value(34).toInt();
	recipe->est_carb = query.value(35).toDouble();

	recipe->sparge_temp = query.value(36).toDouble();
	recipe->sparge_ph = query.value(37).toDouble();
	recipe->sparge_volume = query.value(38).toDouble();
	recipe->sparge_source = query.value(39).toInt();
	recipe->sparge_acid_type = query.value(40).toInt();
	recipe->sparge_acid_perc = query.value(41).toDouble();
	recipe->sparge_acid_amount = query.value(42).toDouble();
	recipe->mash_ph = query.value(43).toDouble();
	recipe->mash_name = query.value(44).toDouble();
	recipe->calc_acid = query.value(45).toInt() ? true:false;

	recipe->w1_name = query.value(46).toString();
	recipe->w1_amount = query.value(47).toDouble();
	recipe->w1_calcium = query.value(48).toDouble();
	recipe->w1_sulfate = query.value(49).toDouble();
	recipe->w1_chloride = query.value(50).toDouble();
	recipe->w1_sodium = query.value(51).toDouble();
	recipe->w1_magnesium = query.value(52).toDouble();
	recipe->w1_total_alkalinity = query.value(53).toDouble();
	recipe->w1_ph = query.value(54).toDouble();
	recipe->w1_cost = query.value(55).toDouble();
	recipe->w2_name = query.value(56).toString();
        recipe->w2_amount = query.value(57).toDouble();
        recipe->w2_calcium = query.value(58).toDouble();
        recipe->w2_sulfate = query.value(59).toDouble();
        recipe->w2_chloride = query.value(60).toDouble();
        recipe->w2_sodium = query.value(61).toDouble();
        recipe->w2_magnesium = query.value(62).toDouble();
        recipe->w2_total_alkalinity = query.value(63).toDouble();
        recipe->w2_ph = query.value(64).toDouble();
        recipe->w2_cost = query.value(65).toDouble();
	recipe->wg_amount = query.value(66).toDouble();
        recipe->wg_calcium = query.value(67).toDouble();
        recipe->wg_sulfate = query.value(68).toDouble();
        recipe->wg_chloride = query.value(69).toDouble();
        recipe->wg_sodium = query.value(70).toDouble();
        recipe->wg_magnesium = query.value(71).toDouble();
        recipe->wg_total_alkalinity = query.value(72).toDouble();
        recipe->wg_ph = query.value(73).toDouble();
	recipe->wb_calcium = query.value(74).toDouble();
        recipe->wb_sulfate = query.value(75).toDouble();
        recipe->wb_chloride = query.value(76).toDouble();
        recipe->wb_sodium = query.value(77).toDouble();
        recipe->wb_magnesium = query.value(78).toDouble();
        recipe->wb_total_alkalinity = query.value(79).toDouble();
        recipe->wb_ph = query.value(80).toDouble();
	recipe->wa_acid_name = query.value(81).toInt();
        recipe->wa_acid_perc = query.value(82).toDouble();
        recipe->wa_base_name = query.value(83).toInt();

	QJsonParseError parseError;
        const auto& f_json = query.value(84).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) {
                qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ;
	    } else if (fermentables.isArray()) {
		for (int i = 0; i < fermentables.array().size(); i++) {
		    QJsonObject obj = fermentables.array().at(i).toObject();
		    Fermentables f;
		    f.f_name = obj["f_name"].toString();
		    f.f_origin = obj["f_origin"].toString();
		    f.f_supplier = obj["f_supplier"].toString();
		    f.f_amount = obj["f_amount"].toDouble();
		    f.f_cost = obj["f_cost"].toDouble();
		    f.f_type = obj["f_type"].toInt();
		    f.f_yield = obj["f_yield"].toDouble();
		    f.f_color = obj["f_color"].toDouble();
		    f.f_coarse_fine_diff = obj["f_coarse_fine_diff"].toDouble();
		    f.f_moisture = obj["f_moisture"].toDouble();
		    f.f_diastatic_power = obj["f_diastatic_power"].toDouble();
		    f.f_protein = obj["f_protein"].toDouble();
		    f.f_dissolved_protein = obj["f_dissolved_protein"].toDouble();
		    f.f_max_in_batch = obj["f_max_in_batch"].toDouble();
		    f.f_graintype = obj["f_graintype"].toInt();
		    f.f_added = obj["f_added"].toInt();
		    f.f_recommend_mash = obj["f_recommend_mash"].toInt() ? true:false;
		    f.f_add_after_boil = obj["f_add_after_boil"].toInt() ? true:false;
		    f.f_adjust_to_total_100 = obj["f_adjust_to_total_100"].toInt() ? true:false;
		    f.f_percentage = obj["f_percentage"].toDouble();
		    f.f_di_ph = obj["f_di_ph"].toDouble();
		    f.f_acid_to_ph_57 = obj["f_acid_to_ph_57"].toDouble();
		    if (f.f_adjust_to_total_100)
			recipe->fermentables_use100 = true;
		    recipe->fermentables.append(f);
		}
		qDebug() << "fermentables" << recipe->fermentables.size();
	    }
        } else {
	    qDebug() << "empty fermentables";
	}

	const auto& h_json = query.value(85).toString();
        if (!h_json.trimmed().isEmpty()) {
            const auto& formattedJson = QString("%1").arg(h_json);
            this->hops = QJsonDocument::fromJson(formattedJson.toUtf8(),  &parseError);
            if (parseError.error != QJsonParseError::NoError)
                qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ;
        } else {
            qDebug() << "empty hops";
        }

	const auto& m_json = query.value(86).toString();
        if (!m_json.trimmed().isEmpty()) {
            const auto& formattedJson = QString("%1").arg(m_json);
            QJsonDocument miscs = QJsonDocument::fromJson(formattedJson.toUtf8(),  &parseError);
            if (parseError.error != QJsonParseError::NoError) {
                qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset;
	    } else if (miscs.isArray()) {
		for (int i = 0; i < miscs.array().size(); i++) {
		    QJsonObject obj = miscs.array().at(i).toObject();
		    qDebug() << i << obj;
		    Miscs m;
		    m.m_name = obj["m_name"].toString();
		    m.m_amount = obj["m_amount"].toDouble();
		    m.m_type = obj["m_type"].toInt();
		    m.m_use_use = obj["m_type"].toInt();
		    m.m_time = obj["m_time"].toDouble();
		    m.m_amount_is_weight = obj["m_amount_is_weight"].toInt() ? true:false;
		    m.m_cost = obj["m_cost"].toDouble();
		    recipe->miscs.append(m);
		}
		qDebug() << "miscs" << recipe->miscs.size();
	    }
        } else {
            qDebug() << "empty miscs";
        }

	const auto& y_json = query.value(87).toString();
        if (!y_json.trimmed().isEmpty()) {
            const auto& formattedJson = QString("%1").arg(y_json);
            QJsonDocument yeasts = QJsonDocument::fromJson(formattedJson.toUtf8(),  &parseError);
            if (parseError.error != QJsonParseError::NoError) {
                qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ;
	    } else if (yeasts.isArray()) {
		for (int i = 0; i < yeasts.array().size(); i++) {
		    QJsonObject obj = yeasts.array().at(i).toObject();
		    qDebug() << i << obj;
		    Yeasts y;
		    y.y_name = obj["y_name"].toString();
		    y.y_laboratory = obj["y_laboratory"].toString();
		    y.y_product_id = obj["y_product_id"].toString();
		    y.y_amount = obj["y_amount"].toDouble();
		    y.y_type = obj["y_type"].toInt();
		    y.y_form = obj["y_form"].toInt();
		    y.y_min_temperature = obj["y_min_temperature"].toDouble();
		    y.y_max_temperature = obj["y_max_temperature"].toDouble();
		    y.y_flocculation = obj["y_flocculation"].toInt();
		    y.y_attenuation = obj["y_attenuation"].toDouble();
		    y.y_cells = obj["y_cells"].toDouble();
		    y.y_tolerance = obj["y_tolerance"].toDouble();
		    y.y_inventory = obj["y_inventory"].toDouble();
		    y.y_use = obj["y_use"].toInt();
		    y.y_sta1 = obj["y_sta1"].toInt() ? true:false;
		    y.y_bacteria = obj["y_bacteria"].toInt() ? true:false;
		    y.y_harvest_top = obj["y_harvest_top"].toInt() ? true:false;
		    y.y_harvest_time = obj["y_harvest_time"].toInt();
		    y.y_pitch_temperature = obj["y_pitch_temperature"].toDouble();
		    y.y_pofpos = obj["y_pofpos"].toInt() ? true:false;
		    y.y_zymocide = obj["y_zymocide"].toInt();
		    y.y_gr_hl_lo = obj["y_gr_hl_lo"].toInt();
		    y.y_sg_lo = obj["y_sg_lo"].toDouble();
		    y.y_gr_hl_hi = obj["y_gr_hl_hi"].toInt();
		    y.y_sg_hi = obj["y_sg_hi"].toDouble();
		    y.y_cost = obj["y_cost"].toDouble();
		    recipe->yeasts.append(y);
		}
		qDebug() << "yeasts" << recipe->yeasts.size();
	    }
        } else {
            qDebug() << "empty yeasts";
        }

	const auto& ma_json = query.value(88).toString();
        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) {
                qDebug() << "Parse error: " << parseError.errorString() << "at" << parseError.offset ;
	    } else if (mashs.isArray()) {
        	for (int i = 0; i < mashs.array().size(); i++) {
            	    QJsonObject obj = mashs.array().at(i).toObject();
//		    qDebug() << i << obj;
		    Mashs m;
		    m.step_name = obj["step_name"].toString();
		    m.step_type = obj["step_type"].toInt();
		    m.step_volume = obj["step_volume"].toDouble();
		    m.step_infuse_amount = obj["step_infuse_amount"].toDouble();
		    m.step_infuse_temp = obj["step_infuse_temp"].toDouble();
		    m.step_temp = obj["step_temp"].toDouble();
		    m.step_time = obj["step_time"].toDouble();
		    m.ramp_time = obj["ramp_time"].toDouble();
		    m.end_temp = obj["end_temp"].toDouble();
		    m.step_wg_ratio = obj["step_wg_ratio"].toDouble();
		    recipe->mashs.append(m);
		}
	    }
        } else {
            qDebug() << "empty mashs";
        }
	qDebug() << "mashs" << recipe->mashs.size();

    } else {
	/* Set some defaults */
	recipe->locked = false;
	recipe->st_name = "";
	recipe->st_letter = "";
	recipe->st_guide = "";
	recipe->st_category = "";
	recipe->st_category_number = 0;
	recipe->st_type = 0;
	recipe->st_og_min = 1.025; recipe->st_og_max = 1.100;
	recipe->st_fg_min = 1.000; recipe->st_fg_max = 1.020;
	recipe->st_ibu_min = 5; recipe->st_ibu_max = 200;
	recipe->st_color_min = 3; recipe->st_color_max = 100;
	recipe->st_carb_min = 1.0; recipe->st_carb_max = 4.5;
	recipe->st_abv_min = 1; recipe->st_abv_max = 15;
	recipe->efficiency = 75;
	recipe->batch_size = 20;
	recipe->boil_size = 24;
	recipe->boil_time = 60;
	recipe->type = 2;
	recipe->sparge_temp = 80;
        recipe->sparge_ph = 5.4;
        recipe->sparge_volume = 8;
        recipe->sparge_source = 0;
        recipe->sparge_acid_type = 0;
        recipe->sparge_acid_perc = 80;
        recipe->sparge_acid_amount = 0;
        recipe->mash_ph = 5.4;
        recipe->mash_name = "";
        recipe->calc_acid = true;
	recipe->w1_name = "";
        recipe->w1_amount = 0;
        recipe->w1_calcium = 0;
        recipe->w1_sulfate = 0;
        recipe->w1_chloride = 0;
        recipe->w1_sodium = 0;
        recipe->w1_magnesium = 0;
        recipe->w1_total_alkalinity = 0;
        recipe->w1_ph = 7;
        recipe->w1_cost = 0;
        recipe->w2_name = "";
        recipe->w2_amount = 0;
        recipe->w2_calcium = 0;
        recipe->w2_sulfate = 0;
        recipe->w2_chloride = 0;
        recipe->w2_sodium = 0;
        recipe->w2_magnesium = 0;
        recipe->w2_total_alkalinity = 0;
        recipe->w2_ph = 7;
        recipe->w2_cost = 0;
        recipe->wg_amount = 0;
        recipe->wg_calcium = 0;
        recipe->wg_sulfate = 0;
        recipe->wg_chloride = 0;
        recipe->wg_sodium = 0;
        recipe->wg_magnesium = 0;
        recipe->wg_total_alkalinity = 0;
        recipe->wg_ph = 7;
        recipe->wb_calcium = 0;
        recipe->wb_sulfate = 0;
        recipe->wb_chloride = 0;
        recipe->wb_sodium = 0;
        recipe->wb_magnesium = 0;
        recipe->wb_total_alkalinity = 0;
        recipe->wb_ph = 7;
	recipe->wa_acid_name = 0;
	recipe->wa_acid_perc = 80;
	recipe->wa_base_name = 0;

	const auto& formattedJson = QString("[]");
	this->hops = QJsonDocument::fromJson(formattedJson.toUtf8());
    }

    ui->lockedEdit->setChecked(recipe->locked);
    ui->st_nameEdit->setText(recipe->st_name);
    ui->st_groupEdit->setText(recipe->st_letter);
    ui->st_guideEdit->setText(recipe->st_guide);
    ui->st_catEdit->setText(recipe->st_category);
    ui->st_catnrEdit->setText(QString("%1").arg(recipe->st_category_number));
    ui->st_typeEdit->setText(s_types[recipe->st_type]);

    ui->nameEdit->setText(recipe->name);
    ui->notesEdit->setPlainText(recipe->notes);
    ui->typeEdit->setCurrentIndex(recipe->type);
    ui->batch_sizeEdit->setValue(recipe->batch_size);
    ui->boil_sizeEdit->setValue(recipe->boil_size);
    ui->boil_timeEdit->setValue(recipe->boil_time);
    ui->efficiencyEdit->setValue(recipe->efficiency);

    ui->est_ogEdit->setValue(recipe->est_og);
    ui->est_og2Edit->setValue(recipe->est_og);
    ui->est_og3Edit->setValue(recipe->est_og);
    ui->est_ogShow->setRange(recipe->st_og_min, recipe->st_og_max);
    ui->est_ogShow->setPrecision(3);
    ui->est_ogShow->setMarkerTextIsValue(true);
    ui->est_ogShow->setValue(recipe->est_og);

    ui->est_fgEdit->setValue(recipe->est_fg);
    ui->est_fg3Edit->setValue(recipe->est_fg);
    ui->est_fgShow->setRange(recipe->st_fg_min, recipe->st_fg_max);
    ui->est_fgShow->setPrecision(3);
    ui->est_fgShow->setMarkerTextIsValue(true);
    ui->est_fgShow->setValue(recipe->est_fg);

    ui->est_abvEdit->setValue(recipe->est_abv);
    ui->est_abv2Edit->setValue(recipe->est_abv);
    ui->est_abvShow->setRange(recipe->st_abv_min, recipe->st_abv_max);
    ui->est_abvShow->setPrecision(1);
    ui->est_abvShow->setMarkerTextIsValue(true);
    ui->est_abvShow->setValue(recipe->est_abv);

    ui->est_colorEdit->setValue(recipe->est_color);
    ui->est_colorEdit->setStyleSheet(Utils::ebc_to_style(recipe->est_color));
    ui->est_color2Edit->setValue(recipe->est_color);
    ui->est_color2Edit->setStyleSheet(Utils::ebc_to_style(recipe->est_color));
    ui->est_colorShow->setPrecision(0);
    ui->est_colorShow->setMarkerTextIsValue(true);
    ui->est_colorShow->setRange(recipe->st_color_min, recipe->st_color_max);
    ui->est_colorShow->setValue(recipe->est_color);

    ui->color_methodEdit->setCurrentIndex(recipe->color_method);

    ui->est_ibuEdit->setValue(recipe->est_ibu);
    ui->est_ibu2Edit->setValue(recipe->est_ibu);
    ui->est_ibuShow->setPrecision(0);
    ui->est_ibuShow->setMarkerTextIsValue(true);
    ui->est_ibuShow->setRange(recipe->st_ibu_min, recipe->st_ibu_max);
    ui->est_ibuShow->setValue(recipe->est_ibu);

    ui->ibu_methodEdit->setCurrentIndex(recipe->ibu_method);

    ui->est_carbEdit->setValue(recipe->est_carb);
    ui->est_carbShow->setPrecision(1);
    ui->est_carbShow->setMarkerTextIsValue(true);
    ui->est_carbShow->setRange(recipe->st_carb_min, recipe->st_carb_max);
    ui->est_carbShow->setValue(recipe->est_carb);

    // All signals from tab "Generic"
    connect(ui->lockedEdit, &QCheckBox::stateChanged, this, &EditRecipe::is_changed);
    connect(ui->nameEdit, &QLineEdit::textChanged, this, &EditRecipe::is_changed);
    connect(ui->notesEdit, SIGNAL(textChanged()), this, SLOT(is_changed()));
    connect(ui->typeEdit, &QComboBox::currentTextChanged, this, &EditRecipe::is_changed);
    connect(ui->batch_sizeEdit, &QDoubleSpinBox::textChanged, this, &EditRecipe::is_changed);
    connect(ui->boil_timeEdit, &QSpinBox::textChanged, this, &EditRecipe::is_changed);
    connect(ui->efficiencyEdit, &QDoubleSpinBox::textChanged, this, &EditRecipe::is_changed);
    connect(ui->beerstyleEdit, &QComboBox::currentTextChanged, this, &EditRecipe::style_changed);
    connect(ui->est_ogEdit, &QDoubleSpinBox::textChanged, this, &EditRecipe::is_changed);
    connect(ui->color_methodEdit, &QComboBox::currentTextChanged, this, &EditRecipe::colormethod_changed);
    connect(ui->ibu_methodEdit, &QComboBox::currentTextChanged, this, &EditRecipe::is_changed);

    // All signals from tab "Fermentables"
    ui->fermentablesTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
    connect(ui->est_og2Edit, &QDoubleSpinBox::textChanged, this, &EditRecipe::is_changed);
    connect(ui->perc_mashShow, &QProgressBar::valueChanged, this, &EditRecipe::on_perc_mash_valueChanged);
    connect(ui->perc_sugarsShow, &QProgressBar::valueChanged, this, &EditRecipe::on_perc_sugars_valueChanged);
    connect(ui->perc_caraShow, &QProgressBar::valueChanged, this, &EditRecipe::on_perc_cara_valueChanged);
    connect(ui->lintnerShow, &QProgressBar::valueChanged, this, &EditRecipe::on_lintner_valueChanged);

    // All signals from tab "Hops"
//    connect(ui->hopsTable, SIGNAL(cellChanged(int, int)), this, SLOT(cell_Changed(int, int)));

    // All signals from tab "Miscs"
//    connect(ui->hopsTable, SIGNAL(cellChanged(int, int)), this, SLOT(cell_Changed(int, int)));

    // All signals from tab "Yeasts"
//    connect(ui->hopsTable, SIGNAL(cellChanged(int, int)), this, SLOT(cell_Changed(int, int)));

    // All signals from tab "Mash"
//    connect(ui->hopsTable, SIGNAL(cellChanged(int, int)), this, SLOT(cell_Changed(int, int)));

    // All signals from tab "Water"

    ui->saveButton->setEnabled(false);
    ui->deleteButton->setEnabled((id >= 0) ? true:false);

    emit refreshAll();
}


EditRecipe::~EditRecipe()
{
    qDebug() << "EditRecipe done start";
    delete ui;
    emit entry_changed();
    qDebug() << "EditRecipe done final";
}


bool EditRecipe::ferment_sort_test(const Fermentables &D1, const Fermentables &D2)
{
    return (D1.f_added <= D2.f_added) && (D1.f_amount >= D2.f_amount) && (D1.f_color < D2.f_color);
}


void EditRecipe::refreshFermentables()
{
    QString w;
    QWidget* pWidget;
    QHBoxLayout* pLayout;
    QTableWidgetItem *item;
    QLabel *label;

    qDebug() << "refreshFermentables" << recipe->fermentables.size();
    std::sort(recipe->fermentables.begin(), recipe->fermentables.end(), ferment_sort_test);

    /*
     * During filling the table turn off the cellChanged signal because every cell that is filled
     * triggers the cellChanged signal. The QTableWidget has no better signal to use.
     */
    this->ignoreChanges = true;

    const QStringList labels({tr("Supplier"), tr("Fermentable"), tr("EBC"), tr("Type"), tr("Graintype"), tr("When"), tr("Yield"),
		    	      tr("Amount"), tr("Procent"), tr("100%"), tr("Delete"), tr("Edit") });
    ui->fermentablesTable->setColumnCount(12);
    ui->fermentablesTable->setColumnWidth(0, 150);     /* Supplier	*/
    ui->fermentablesTable->setColumnWidth(1, 225);     /* Fermentable	*/
    ui->fermentablesTable->setColumnWidth(2,  50);     /* Color		*/
    ui->fermentablesTable->setColumnWidth(3,  75);     /* Type		*/
    ui->fermentablesTable->setColumnWidth(4,  75);     /* Graintype	*/
    ui->fermentablesTable->setColumnWidth(5,  75);     /* Added		*/
    ui->fermentablesTable->setColumnWidth(6,  60);     /* Yield		*/
    ui->fermentablesTable->setColumnWidth(7,  90);     /* Amount	*/
    ui->fermentablesTable->setColumnWidth(8,  60);     /* Procent	*/
    ui->fermentablesTable->setColumnWidth(9,  50);     /* 100%		*/
    ui->fermentablesTable->setColumnWidth(10, 80);     /* Delete	*/
    ui->fermentablesTable->setColumnWidth(11, 80);     /* Edit		*/
    ui->fermentablesTable->setHorizontalHeaderLabels(labels);
    ui->fermentablesTable->verticalHeader()->hide();
    ui->fermentablesTable->setRowCount(recipe->fermentables.size());

    for (int i = 0; i < recipe->fermentables.size(); i++) {

	ui->fermentablesTable->setItem(i, 0, new QTableWidgetItem(recipe->fermentables.at(i).f_supplier));
	ui->fermentablesTable->setItem(i, 1, new QTableWidgetItem(recipe->fermentables.at(i).f_name));

        w = QString("%1").arg(recipe->fermentables.at(i).f_color, 1, 'f', 0, '0');
        item = new QTableWidgetItem(w);
        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->fermentablesTable->setItem(i, 2, item);

	item = new QTableWidgetItem(f_types[recipe->fermentables.at(i).f_type]);
	item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
	ui->fermentablesTable->setItem(i, 3, item);

        item = new QTableWidgetItem(f_graintypes[recipe->fermentables.at(i).f_graintype]);
        item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
        ui->fermentablesTable->setItem(i, 4, item);

        item = new QTableWidgetItem(f_added[recipe->fermentables.at(i).f_added]);
        item->setTextAlignment(Qt::AlignCenter|Qt::AlignVCenter);
        ui->fermentablesTable->setItem(i, 5, item);

        item = new QTableWidgetItem(QString("%1%").arg(recipe->fermentables.at(i).f_yield, 2, 'f', 1, '0'));
        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->fermentablesTable->setItem(i, 6, item);

        item = new QTableWidgetItem(QString("%1 Kg").arg(recipe->fermentables.at(i).f_amount, 4, 'f', 3, '0'));
        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->fermentablesTable->setItem(i, 7, item);

        item = new QTableWidgetItem(QString("%1%").arg(recipe->fermentables.at(i).f_percentage, 2, 'f', 1, '0'));
        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->fermentablesTable->setItem(i, 8, item);

	if (recipe->fermentables.at(i).f_adjust_to_total_100) {
		pWidget = new QWidget();
            	label = new QLabel;
            	label->setPixmap(QPixmap(":icons/silk/tick.png"));
            	pLayout = new QHBoxLayout(pWidget);
            	pLayout->addWidget(label);
            	pLayout->setAlignment(Qt::AlignCenter);
            	pLayout->setContentsMargins(0, 0, 0, 0);
            	pWidget->setLayout(pLayout);
            	ui->fermentablesTable->setCellWidget(i, 9, pWidget);
	} else {
		ui->fermentablesTable->removeCellWidget(i, 9);
	}

	/* Add the Delete row button */
        pWidget = new QWidget();
        QPushButton* btn_dele = new QPushButton();
        btn_dele->setObjectName(QString("%1").arg(i));  /* Send row with the button */
        btn_dele->setText(tr("Delete"));
        connect(btn_dele, SIGNAL(clicked()), this, SLOT(on_deleteFermentRow_clicked()));
        pLayout = new QHBoxLayout(pWidget);
        pLayout->addWidget(btn_dele);
        pLayout->setContentsMargins(5, 0, 5, 0);
        pWidget->setLayout(pLayout);
        ui->fermentablesTable->setCellWidget(i, 10, pWidget);

	pWidget = new QWidget();
	QPushButton* btn_edit = new QPushButton();
	btn_edit->setObjectName(QString("%1").arg(i));  /* Send row with the button */
	btn_edit->setText(tr("Edit"));
	connect(btn_edit, SIGNAL(clicked()), this, SLOT(on_editFermentRow_clicked()));
	pLayout = new QHBoxLayout(pWidget);
        pLayout->addWidget(btn_edit);
	pLayout->setContentsMargins(5, 0, 5, 0);
        pWidget->setLayout(pLayout);
        ui->fermentablesTable->setCellWidget(i, 11, pWidget);
    }
    this->ignoreChanges = false;
}


void EditRecipe::refreshHops()
{
}


void EditRecipe::refreshMiscs()
{
}


void EditRecipe::refreshYeasts()
{
}


void EditRecipe::refreshMashs()
{
}


void EditRecipe::refreshAll()
{
    refreshFermentables();

    calcFermentables();
}


void EditRecipe::calcFermentables()
{
    int		i;
    double	psugar = 0, pcara = 0, d, s = 0, x, color;
    double	vol = 0;		// Volume sugars after boil
    double	addedS = 0;		// Added sugars after boil
    double	addedmass = 0;		// Added mass after boil
    double	mvol = 0;		// Mash volume
    double	lintner = 0;		// Total recipe lintner
    double	mashkg = 0;
    double	sugarsf = 0;		// fermentable sugars mash + boil
    double	sugarsm = 0;		// fermentable sugars in mash
    double	sugardensity = 1.611;	// kg/l in solution
    double	mashtime = 0;		// Total mash time
    double	mashtemp = 0;		// Average mash temperature
    double	mashinfuse = 0;		// Mash infuse amount
    double	colort = 0;		// Colors srm * vol totals
    double	colorh = 0;		// Colors ebc * vol * kt
    double	colorn = 0;		// Colors ebc * pt * pct

    qDebug() << "calcFermentables()";

    /*
     * Get average mashtemp and mashtime from the Mash schedule.
     * It is possible that the schedule is not (yet) present.
     */
    if (recipe->mashs.size() > 0) {
	for (i = 0; i < recipe->mashs.size(); i++) {
	    if (recipe->mashs.at(i).step_type == 0)		// Infusion
		mashinfuse += recipe->mashs.at(i).step_infuse_amount;
	    if (recipe->mashs.at(i).step_temp < 75) {		// Ignore mashout
		mashtime += recipe->mashs.at(i).step_time;
		mashtemp += recipe->mashs.at(i).step_time * recipe->mashs.at(i).step_temp;
	    }
	}
	mashtemp = mashtemp / mashtime;
	mvol = mashinfuse;
	qDebug() << "  mash time" << mashtime << "temp" << mashtemp << "infuse" << mashinfuse;
    } else {
	qDebug() << "  no mash schedule";
    }

    if (recipe->fermentables.size() < 1) {
	qDebug() << "  no fermentables, return.";
	return;
    }
    qDebug() << "  adjust to 100" << recipe->fermentables_use100;

    for (i = 0; i < recipe->fermentables.size(); i++) {
	if (recipe->fermentables.at(i).f_type == 1 && recipe->fermentables.at(i).f_added < 4)		// Sugars
	    psugar += recipe->fermentables.at(i).f_percentage;
	if (recipe->fermentables.at(i).f_graintype == 2 && recipe->fermentables.at(i).f_added < 4)	// Crystal/Cara
	    pcara += recipe->fermentables.at(i).f_percentage;
	d = recipe->fermentables.at(i).f_amount * (recipe->fermentables.at(i).f_yield / 100) * (1 - recipe->fermentables.at(i).f_moisture / 100);
	if (recipe->fermentables.at(i).f_added == 0) {					// Mash
	    if (mvol > 0) {							// If mash volume is known
		mvol += recipe->fermentables.at(i).f_amount * recipe->fermentables.at(i).f_moisture / 100;
		s += d;
	    }
	    d = ui->efficiencyEdit->value() / 100 * d;
	    sugarsm += d;
	    mashkg += recipe->fermentables.at(i).f_amount;
	}
	if (recipe->fermentables.at(i).f_added == 0 || recipe->fermentables.at(i).f_added == 1)		// Mash or boil
	    sugarsf += d;
	if (recipe->fermentables.at(i).f_added == 2 || recipe->fermentables.at(i).f_added == 3) {		// Fermentation or lagering
	    x = (recipe->fermentables.at(i).f_yield / 100) * (1 - recipe->fermentables.at(i).f_moisture / 100);
	    addedS += recipe->fermentables.at(i).f_amount * x;
	    addedmass += recipe->fermentables.at(i).f_amount;
	    vol += (x * sugardensity + (1 - x) * 1) * recipe->fermentables.at(i).f_amount;
	}
	if (recipe->fermentables.at(i).f_added == 0 && (recipe->fermentables.at(i).f_type == 0 || recipe->fermentables.at(i).f_type == 4) && recipe->fermentables.at(i).f_color < 50) {
	    lintner += recipe->fermentables.at(i).f_diastatic_power * recipe->fermentables.at(i).f_amount;
	}
	if (recipe->fermentables.at(i).f_added < 4) {
	    colort += recipe->fermentables.at(i).f_amount * Utils::ebc_to_srm(recipe->fermentables.at(i).f_color);
	    colorh += recipe->fermentables.at(i).f_amount * recipe->fermentables.at(i).f_color * Utils::get_kt(recipe->fermentables.at(i).f_color);
	    colorn += (recipe->fermentables.at(i).f_percentage / 100) * recipe->fermentables.at(i).f_color;	// For 8.6 Pt wort.
	}
    }
    qDebug() << "  colort" << colort << "colorh" << colorh << "colorn" << colorn;
    qDebug() << "  psugar" << psugar << "pcara" << pcara << "mvol" << mvol;
    qDebug() << "  sugarsf" << sugarsf << "sugarsm" << sugarsm;

    double og = Utils::estimate_sg(sugarsf + addedS, ui->batch_sizeEdit->value());
    qDebug() << "  OG" << ui->est_ogEdit->value() << og;
    ui->est_ogEdit->setValue(og);
    ui->est_og2Edit->setValue(og);
    ui->est_og3Edit->setValue(og);
    ui->est_ogShow->setValue(og);

    double preboil_sg = Utils::estimate_sg(sugarsm, ui->boil_sizeEdit->value());
    qDebug() << "  preboil SG" << preboil_sg;

    /*
     * Color of the wort
     */
    if (ui->color_methodEdit->currentIndex() == 4) {		// Naudts
	color = round(((Utils::sg_to_plato(og) / 8.6) * colorn) + (ui->boil_timeEdit->value() / 60));
    } else if (ui->color_methodEdit->currentIndex() == 3) {	// Hans Halberstadt
	double bv = 0.925;					// Beer loss efficiency
	double sr = 0.95;					// Mash and sparge efficiency
	color = round((4.46 * bv * sr) / ui->batch_sizeEdit->value() * colorh);
    } else {
	double cw = colort / ui->batch_sizeEdit->value() * 8.34436;
	color = Utils::kw_to_ebc(ui->color_methodEdit->currentIndex(), cw);
    }
    qDebug() << "  color" << ui->est_colorEdit->value() << color;
    ui->est_colorEdit->setValue(color);
    ui->est_colorEdit->setStyleSheet(Utils::ebc_to_style(color));
    ui->est_color2Edit->setValue(color);
    ui->est_color2Edit->setStyleSheet(Utils::ebc_to_style(color));
    ui->est_colorShow->setValue(color);

    /*
     * We don't have a equipment profile in recipes,
     * so we assume a certain guessed mashtun size.
     */
    ui->perc_mashShow->setValue(round(mashkg / (ui->boil_sizeEdit->value() / 3) * 100));
    ui->perc_sugarsShow->setValue(round(psugar));
    ui->perc_caraShow->setValue(round(pcara));
    qDebug() << "  lintner" << lintner << "  mashkg" << mashkg << "final" << round(lintner / mashkg);
    ui->lintnerShow->setValue(round(lintner / mashkg));

    /*
     * Calculate the apparant attenuation.
     */
    double svg = 0;
    if (recipe->yeasts.size() > 0) {
        for (i = 0; i < recipe->yeasts.size(); i++) {
	    if (recipe->yeasts.at(i).y_use == 0) {		// Used in primary
		if (recipe->yeasts.at(i).y_attenuation > svg)
		    svg = recipe->yeasts.at(i).y_attenuation;	// Take the highest if multiple yeasts.
	    }
	    // TODO: brett or others in secondary.
	}
	qDebug() << "  SVG" << svg;
    }
    if (svg == 0)
	svg = 77.0;

    double fg;
    if (mashkg > 0 && mashinfuse > 0 && mashtime > 0 && mashtemp > 0)
	fg = Utils::estimate_fg(psugar, pcara, mashinfuse / mashkg, mashtime, mashtemp, svg, og);
    else
	fg = Utils::estimate_fg(psugar, pcara, 0, 0, 0, svg, og);
    qDebug() << "  FG" << ui->est_fgEdit->value() << fg;
    ui->est_fgEdit->setValue(fg);
    ui->est_fg3Edit->setValue(fg);
    ui->est_fgShow->setValue(fg);

    double abv = Utils::abvol(og, fg);
    qDebug() << "  ABV" << ui->est_abvEdit->value() << abv;
    ui->est_abvEdit->setValue(abv);
    ui->est_abv2Edit->setValue(abv);
    ui->est_abvShow->setValue(abv);

    /*
     * Calculate kilocalories/liter. Formula from brouwhulp.
     * Take the alcohol and sugar parts and then combine.
     */
    double alc = 1881.22 * fg * (og - fg) / (1.775 - og);
    double sug = 3550 * fg * (0.1808 * og + 0.8192 * fg - 1.0004);
    ui->calEdit->setValue(round((alc + sug) / (12 * 0.0295735296)));
}


void EditRecipe::on_perc_mash_valueChanged(int value)
{
    if (value < 90)
	ui->perc_mashShow->setStyleSheet(bar_green);
    else if (value < 100)
	ui->perc_mashShow->setStyleSheet(bar_orange);
    else
	ui->perc_mashShow->setStyleSheet(bar_red);
}


void EditRecipe::on_perc_sugars_valueChanged(int value)
{
    if (value < 20)
	ui->perc_sugarsShow->setStyleSheet(bar_green);
    else
	ui->perc_sugarsShow->setStyleSheet(bar_red);
}


void EditRecipe::on_perc_cara_valueChanged(int value)
{
    if (value < 25)
	ui->perc_caraShow->setStyleSheet(bar_green);
    else
	ui->perc_caraShow->setStyleSheet(bar_red);
}


void EditRecipe::on_lintner_valueChanged(int value)
{
    if (value < 30)
	ui->lintnerShow->setStyleSheet(bar_red);
    else if (value < 40)
	ui->lintnerShow->setStyleSheet(bar_orange);
    else
	ui->lintnerShow->setStyleSheet(bar_green);
}


/*
 * Window header, mark any change with '**'
 */
void EditRecipe::WindowTitle()
{
    QString txt;

    if (this->recno < 0) {
	txt = QString(tr("BMSapp - Add new recipe"));
    } else {
	txt = QString(tr("BMSapp - Edit recipe %1").arg(this->recno));
    }

    if (this->textIsChanged) {
	txt.append((QString(" **")));
    }
    setWindowTitle(txt);
}


void EditRecipe::on_saveButton_clicked()
{
    QSqlQuery query;

    /* If there are errors in the form, show a message and do "return;" */
    if (ui->nameEdit->text().length() < 2) {
	QMessageBox::warning(this, tr("Edit Recipe"), tr("Name empty or too short."));
	return;
    }

    if (this->textIsChanged) {
    	if (this->recno == -1) {
    	    query.prepare("INSERT INTO recipes SET locked=:locked, st_name=:st_name, st_letter=:st_letter, "
		"st_guide=:st_guide, st_category=:st_category, st_category_number=:st_catnr, st_type=:st_type, "
		"st_og_min=:st_og_min, st_og_max=:st_og_max, st_fg_min=:st_fg_min, st_fg_max=:st_fg_max, "
		"st_ibu_min=:st_ibu_min, st_ibu_max=:st_ibu_max, st_color_min=:st_color_min, st_color_max=:st_color_max, "
		"st_carb_min=:st_carb_min, st_carb_max=:st_carb_max, st_abv_min=:st_abv_min, st_abv_max=:st_abv_max, "
		"name=:name, notes:=notes, type=:type, batch_size=:batch_size, boil_size=:boil_size, "
		"boil_time=:boil_time, efficiency=:efficiency, "
		"uuid = :uuid");
    	} else {
	    query.prepare("UPDATE recipes SET locked=:locked, st_name=:st_name, st_letter=:st_letter, "
		"st_guide=:st_guide, st_category=:st_category, st_category_number=:st_catnr, st_type=:st_type, "
                "st_og_min=:st_og_min, st_og_max=:st_og_max, st_fg_min=:st_fg_min, st_fg_max=:st_fg_max, "
                "st_ibu_min=:st_ibu_min, st_ibu_max=:st_ibu_max, st_color_min=:st_color_min, st_color_max=:st_color_max, "
                "st_carb_min=:st_carb_min, st_carb_max=:st_carb_max, st_abv_min=:st_abv_min, st_abv_max=:st_abv_max, "
                "name=:name, notes:=notes, type=:type, batch_size=:batch_size, boil_size=:boil_size, "
		"boil_time=:boil_time, efficiency=:efficiency "
                " WHERE record = :recno");
    	}
	query.bindValue(":locked", ui->lockedEdit->isChecked() ? 1:0);
	query.bindValue(":st_name", ui->st_nameEdit->text());
	query.bindValue(":st_letter", ui->st_groupEdit->text());
	query.bindValue(":st_guide", ui->st_guideEdit->text());
	query.bindValue(":st_category", ui->st_catEdit->text());
	query.bindValue(":st_catnr", recipe->st_type);
	query.bindValue(":st_og_min", QString("%1").arg(ui->est_ogShow->minval(), 4, 'f', 3, '0'));
	query.bindValue(":st_og_max", QString("%1").arg(ui->est_ogShow->maxval(), 4, 'f', 3, '0'));
	query.bindValue(":st_fg_min", QString("%1").arg(ui->est_fgShow->minval(), 4, 'f', 3, '0'));
        query.bindValue(":st_fg_max", QString("%1").arg(ui->est_fgShow->maxval(), 4, 'f', 3, '0'));
	query.bindValue(":st_ibu_min", QString("%1").arg(ui->est_ibuShow->minval(), 4, 'f', 3, '0'));
        query.bindValue(":st_ibu_max", QString("%1").arg(ui->est_ibuShow->maxval(), 4, 'f', 3, '0'));
	query.bindValue(":st_color_min", QString("%1").arg(ui->est_colorShow->minval(), 4, 'f', 3, '0'));
        query.bindValue(":st_color_max", QString("%1").arg(ui->est_colorShow->maxval(), 4, 'f', 3, '0'));
	query.bindValue(":st_carb_min", QString("%1").arg(ui->est_carbShow->minval(), 4, 'f', 3, '0'));
        query.bindValue(":st_carb_max", QString("%1").arg(ui->est_carbShow->maxval(), 4, 'f', 3, '0'));
	query.bindValue(":st_abv_min", QString("%1").arg(ui->est_abvShow->minval(), 4, 'f', 3, '0'));
        query.bindValue(":st_abv_max", QString("%1").arg(ui->est_abvShow->maxval(), 4, 'f', 3, '0'));
	query.bindValue(":name", ui->nameEdit->text());
	query.bindValue(":notes", ui->notesEdit->toPlainText());
	query.bindValue(":type", ui->typeEdit->currentIndex());
	query.bindValue(":batch_size", QString("%1").arg(ui->batch_sizeEdit->value(), 2, 'f', 1, '0'));
	query.bindValue(":boil_size", QString("%1").arg(ui->boil_sizeEdit->value(), 2, 'f', 1, '0'));
	query.bindValue(":boil_time", QString("%1").arg(ui->boil_timeEdit->value(), 2, 'f', 1, '0'));
	query.bindValue(":efficiency", QString("%1").arg(ui->efficiencyEdit->value(), 2, 'f', 1, '0'));
	query.bindValue(":est_og", QString("%1").arg(ui->est_ogEdit->value(), 4, 'f', 3, '0'));
	query.bindValue(":est_fg", QString("%1").arg(ui->est_fgEdit->value(), 4, 'f', 3, '0'));
	query.bindValue(":est_abv", QString("%1").arg(ui->est_abvEdit->value(), 2, 'f', 1, '0'));
	query.bindValue(":est_color", QString("%1").arg(ui->est_colorEdit->value(), 1, 'f', 0, '0'));
	query.bindValue(":color_method", ui->color_methodEdit->currentIndex());
	query.bindValue(":est_ibu", QString("%1").arg(ui->est_ibuEdit->value(), 1, 'f', 0, '0'));
	query.bindValue(":ibu_method", ui->ibu_methodEdit->currentIndex());
	query.bindValue(":est_carb", QString("%1").arg(ui->est_carbEdit->value(), 2, 'f', 1, '0'));

	if (this->recno == -1) {
	    query.bindValue(":uuid", QUuid::createUuid().toString().mid(1, 36));
	} else {
	    query.bindValue(":recno", this->recno);
	}
	qDebug() << query.lastQuery();
//	query.exec();
	if (query.lastError().isValid()) {
	    qDebug() << "EditRecipe" << query.lastError();
	    QMessageBox::warning(this, tr("Database error"),
                        tr("MySQL error: %1\n%2\n%3")
                        .arg(query.lastError().nativeErrorCode())
                        .arg(query.lastError().driverText())
                        .arg(query.lastError().databaseText()));
	} else {
	    qDebug() << "EditRecipe Saved";
	}
    }

    ui->saveButton->setEnabled(false);
    this->textIsChanged = false;
    WindowTitle();
}


void EditRecipe::on_deleteButton_clicked()
{
    QSqlQuery query;

    query.prepare("DELETE FROM recipes WHERE record = :recno");
    query.bindValue(":recno", this->recno);
    query.exec();
    if (query.lastError().isValid()) {
	qDebug() << "EditRecipe" << query.lastError();
	QMessageBox::warning(this, tr("Database error"),
                        tr("MySQL error: %1\n%2\n%3")
                        .arg(query.lastError().nativeErrorCode())
                        .arg(query.lastError().driverText())
                        .arg(query.lastError().databaseText()));
    } else {
	qDebug() << "EditRecipe Deleted" << this->recno;
    }

    this->close();
    this->setResult(1);
}


void EditRecipe::is_changed()
{
    ui->saveButton->setEnabled(true);
    ui->deleteButton->setEnabled((this->recno >= 0) ? true:false);
    this->textIsChanged = true;
    WindowTitle();
}


/*
 * New beerstyle is selected.
 */
void EditRecipe::style_changed()
{
    QSqlQuery query;

    if (ui->beerstyleEdit->currentIndex() < 1)
	return;

    query.prepare("SELECT * FROM profile_styles ORDER BY style_guide,style_letter,name");
    query.exec();
    query.first();
    // Skip to the record index.
    for (int i = 0; i < (ui->beerstyleEdit->currentIndex() - 1); i++) {
        query.next();
    }
    // Set relevant fields and update ranges.
    recipe->st_name = query.value(1).toString();
    recipe->st_category = query.value(2).toString();
    recipe->st_category_number = query.value(3).toInt();
    recipe->st_letter = query.value(4).toString();
    recipe->st_guide = query.value(5).toString();
    recipe->st_type = query.value(6).toInt();
    recipe->st_og_min = query.value(7).toDouble();
    recipe->st_og_max = query.value(8).toDouble();
    recipe->st_fg_min = query.value(9).toDouble();
    recipe->st_fg_max = query.value(10).toDouble();
    recipe->st_ibu_min = query.value(11).toDouble();
    recipe->st_ibu_max = query.value(12).toDouble();
    recipe->st_color_min = query.value(13).toDouble();
    recipe->st_color_max = query.value(14).toDouble();
    recipe->st_carb_min = query.value(15).toDouble();
    recipe->st_carb_max = query.value(16).toDouble();
    recipe->st_abv_min = query.value(17).toDouble();
    recipe->st_abv_max = query.value(18).toDouble();

    ui->st_nameEdit->setText(recipe->st_name);
    ui->st_groupEdit->setText(recipe->st_letter);
    ui->st_guideEdit->setText(recipe->st_guide);
    ui->st_catEdit->setText(recipe->st_category);
    ui->st_catnrEdit->setText(QString("%1").arg(recipe->st_category_number));
    ui->st_typeEdit->setText(s_types[recipe->st_type]);

    ui->est_ogShow->setRange(query.value(7).toDouble(), query.value(8).toDouble());
    ui->est_fgShow->setRange(query.value(9).toDouble(), query.value(10).toDouble());
    ui->est_ibuShow->setRange(query.value(11).toDouble(), query.value(12).toDouble());
    ui->est_colorShow->setRange(query.value(13).toDouble(), query.value(14).toDouble());
    ui->est_carbShow->setRange(query.value(15).toDouble(), query.value(16).toDouble());
    ui->est_abvShow->setRange(query.value(17).toDouble(), query.value(18).toDouble());

    is_changed();
}


void EditRecipe::colormethod_changed()
{
    calcFermentables();
    is_changed();
}


/* TODO: move this code to MySQL save */
void EditRecipe::fermentable_Json()
{
    QTableWidgetItem *item;
    QJsonArray array;

    qDebug() << "fermentable_Json()";

    for (int i = 0; i < recipe->fermentables.size(); i++) {

        QJsonObject obj;
	obj.insert("f_acid_to_ph_57", recipe->fermentables.at(i).f_acid_to_ph_57);
        obj.insert("f_add_after_boil", recipe->fermentables.at(i).f_add_after_boil);
        obj.insert("f_added", recipe->fermentables.at(i).f_added);
        obj.insert("f_adjust_to_total_100", recipe->fermentables.at(i).f_adjust_to_total_100);
        obj.insert("f_amount", recipe->fermentables.at(i).f_added);
        obj.insert("f_coarse_fine_diff", recipe->fermentables.at(i).f_coarse_fine_diff);
        obj.insert("f_color", recipe->fermentables.at(i).f_color);
        obj.insert("f_cost", recipe->fermentables.at(i).f_cost);
        obj.insert("f_di_ph", recipe->fermentables.at(i).f_di_ph);
        obj.insert("f_diastatic_power", recipe->fermentables.at(i).f_diastatic_power);
        obj.insert("f_dissolved_protein", recipe->fermentables.at(i).f_dissolved_protein);
        obj.insert("f_graintype", recipe->fermentables.at(i).f_graintype);
        obj.insert("f_max_in_batch", recipe->fermentables.at(i).f_max_in_batch);
        obj.insert("f_moisture", recipe->fermentables.at(i).f_moisture);
        obj.insert("f_name", recipe->fermentables.at(i).f_name);
        obj.insert("f_origin", recipe->fermentables.at(i).f_origin);
        obj.insert("f_percentage", recipe->fermentables.at(i).f_percentage);
        obj.insert("f_protein", recipe->fermentables.at(i).f_protein);
        obj.insert("f_recommend_mash", recipe->fermentables.at(i).f_recommend_mash);
        obj.insert("f_supplier", recipe->fermentables.at(i).f_supplier);
        obj.insert("f_type", recipe->fermentables.at(i).f_type);
        obj.insert("f_yield", recipe->fermentables.at(i).f_yield);
	qDebug() << "fermentable_Json" << i << obj;
	array.append(obj);      /* Append this object */
    }

    qDebug() << array;
    /* Copy to the global array and refresh */
//    this->fermentables.setArray(array);
}


void EditRecipe::on_deleteFermentRow_clicked()
{
    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
    int row = pb->objectName().toInt();
    qDebug() << "Delete fermentable row" << row;

    int rc = QMessageBox::warning(this, tr("Delete fermentable"), tr("Delete %1").arg(recipe->fermentables.at(row).f_name),
		    QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
    if (rc == QMessageBox::No)
	return;

    ui->fermentablesTable->removeRow(row);
//    recalculate percentages
//    fermentable_Json();
}


void EditRecipe::ferment_amount_changed(double val)
{
    QTableWidgetItem *item;
    double	total = 0, perc;

    if (recipe->fermentables_use100)
	return;

    qDebug() << "ferment_amount_changed()" << editrow << val;
    this->ignoreChanges = true;

    recipe->fermentables[editrow].f_amount = val;
    item = new QTableWidgetItem(QString("%1 Kg").arg(val, 4, 'f', 3, '0'));
    item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
    ui->fermentablesTable->setItem(editrow, 7, item);

    for (int i = 0; i < recipe->fermentables.size(); i++)
	total += recipe->fermentables.at(i).f_amount;

    /*
     * Recalculate the percentages
     */
    for (int i = 0; i < recipe->fermentables.size(); i++) {
	perc = recipe->fermentables.at(i).f_amount / total * 100;
	recipe->fermentables[i].f_percentage = perc;
	item = new QTableWidgetItem(QString("%1%").arg(perc, 2, 'f', 1, '0'));
        item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
        ui->fermentablesTable->setItem(i, 8, item);
	if (i == editrow)
	    this->pctEdit->setValue(perc);
    }
    this->ignoreChanges = false;
}

void EditRecipe::ferment_pct_changed(double val)
{
    if (! recipe->fermentables_use100)
        return;

    qDebug() << "ferment_pct_changed()" << val;
}


void EditRecipe::on_editFermentRow_clicked()
{
    QPushButton *pb = qobject_cast<QPushButton *>(QObject::sender());
    editrow = pb->objectName().toInt();
    qDebug() << "Edit fermentable row" << editrow;
    Fermentables backup = recipe->fermentables.at(editrow);

    QDialog* dialog = new QDialog(this);
    dialog->resize(738, 287);
    QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
    buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
    buttonBox->setGeometry(QRect(30, 240, 671, 32));
    buttonBox->setLayoutDirection(Qt::LeftToRight);
    buttonBox->setOrientation(Qt::Horizontal);
    buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
    buttonBox->setCenterButtons(true);
    QLabel *nameLabel = new QLabel(dialog);
    nameLabel->setObjectName(QString::fromUtf8("nameLabel"));
    nameLabel->setText(tr("Current ingredient:"));
    nameLabel->setGeometry(QRect(10, 10, 141, 20));
    nameLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *supplierLabel = new QLabel(dialog);
    supplierLabel->setObjectName(QString::fromUtf8("supplierLabel"));
    supplierLabel->setText(tr("Supplier:"));
    supplierLabel->setGeometry(QRect(10, 40, 141, 20));
    supplierLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *amountLabel = new QLabel(dialog);
    amountLabel->setObjectName(QString::fromUtf8("amountLabel"));
    amountLabel->setText(tr("Amount in kg:"));
    amountLabel->setGeometry(QRect(10, 100, 141, 20));
    amountLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *pctLabel = new QLabel(dialog);
    pctLabel->setObjectName(QString::fromUtf8("pctLabel"));
    pctLabel->setText(tr("Percentage in batch:"));
    pctLabel->setGeometry(QRect(10, 130, 141, 20));
    pctLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *to100Label = new QLabel(dialog);
    to100Label->setObjectName(QString::fromUtf8("to100Label"));
    to100Label->setText(tr("Auto fill to 100%:"));
    to100Label->setGeometry(QRect(10, 160, 141, 20));
    to100Label->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *addedLabel = new QLabel(dialog);
    addedLabel->setObjectName(QString::fromUtf8("addedLabel"));
    addedLabel->setText(tr("Use at:"));
    addedLabel->setGeometry(QRect(10, 190, 141, 20));
    addedLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *selectLabel = new QLabel(dialog);
    selectLabel->setObjectName(QString::fromUtf8("selectLabel"));
    selectLabel->setText(tr("Select ingredient:"));
    selectLabel->setGeometry(QRect(10, 70, 141, 20));
    selectLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *instockLabel = new QLabel(dialog);
    instockLabel->setObjectName(QString::fromUtf8("instockLabel"));
    instockLabel->setText(tr("In stock:"));
    instockLabel->setGeometry(QRect(420, 70, 121, 20));
    instockLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    QLabel *maxLabel = new QLabel(dialog);
    maxLabel->setObjectName(QString::fromUtf8("maxLabel"));
    maxLabel->setText(tr("Max in batch:"));
    maxLabel->setGeometry(QRect(420, 130, 121, 20));
    maxLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);

    selectEdit = new QComboBox(dialog);
    selectEdit->setObjectName(QString::fromUtf8("selectEdit"));
    selectEdit->setGeometry(QRect(160, 70, 251, 23));
    nameEdit = new QLineEdit(dialog);
    nameEdit->setObjectName(QString::fromUtf8("nameEdit"));
    nameEdit->setText(recipe->fermentables.at(editrow).f_name);
    nameEdit->setGeometry(QRect(160, 10, 511, 23));
    nameEdit->setReadOnly(true);
    supplierEdit = new QLineEdit(dialog);
    supplierEdit->setObjectName(QString::fromUtf8("supplierEdit"));
    supplierEdit->setText(recipe->fermentables.at(editrow).f_supplier);
    supplierEdit->setGeometry(QRect(160, 40, 511, 23));
    supplierEdit->setReadOnly(true);
    amountEdit = new QDoubleSpinBox(dialog);
    amountEdit->setObjectName(QString::fromUtf8("amountEdit"));
    amountEdit->setGeometry(QRect(160, 100, 121, 24));
    amountEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    amountEdit->setAccelerated(true);
    amountEdit->setDecimals(3);
    amountEdit->setReadOnly(recipe->fermentables_use100);
    amountEdit->setMaximum(100000.0);
    amountEdit->setSingleStep(0.0010);
    amountEdit->setValue(recipe->fermentables.at(editrow).f_amount);
    connect(amountEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::ferment_amount_changed);

    pctEdit = new QDoubleSpinBox(dialog);
    pctEdit->setObjectName(QString::fromUtf8("pctEdit"));
    pctEdit->setGeometry(QRect(160, 130, 121, 24));
    pctEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    pctEdit->setAccelerated(true);
    pctEdit->setDecimals(1);
    if (recipe->fermentables_use100) {
    	if (recipe->fermentables.at(editrow).f_adjust_to_total_100)
	    pctEdit->setReadOnly(true);
    	else
    	    pctEdit->setReadOnly(false);
    } else {
	pctEdit->setReadOnly(true);
    }
    pctEdit->setMaximum(100.0);
    pctEdit->setSingleStep(0.1);
    pctEdit->setValue(recipe->fermentables.at(editrow).f_percentage);
    connect(pctEdit, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &EditRecipe::ferment_pct_changed);

    addedEdit = new QComboBox(dialog);
    addedEdit->setObjectName(QString::fromUtf8("addedEdit"));
    addedEdit->setGeometry(QRect(160, 190, 161, 23));
    addedEdit->addItem(tr("Mash"));
    addedEdit->addItem(tr("Boil"));
    addedEdit->addItem(tr("Fermentation"));
    addedEdit->addItem(tr("Lagering"));
    addedEdit->addItem(tr("Bottle"));
    addedEdit->addItem(tr("Kegs"));
    addedEdit->setCurrentIndex(recipe->fermentables.at(editrow).f_added);

    to100Edit = new QCheckBox(dialog);
    to100Edit->setObjectName(QString::fromUtf8("to100Edit"));
    to100Edit->setGeometry(QRect(160, 160, 85, 21));
    to100Edit->setChecked(recipe->fermentables.at(editrow).f_adjust_to_total_100);

    instockEdit = new QCheckBox(dialog);
    instockEdit->setObjectName(QString::fromUtf8("instockEdit"));
    instockEdit->setGeometry(QRect(550, 70, 85, 21));

    maxEdit = new QDoubleSpinBox(dialog);
    maxEdit->setObjectName(QString::fromUtf8("maxEdit"));
    maxEdit->setGeometry(QRect(550, 130, 121, 24));
    maxEdit->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
    maxEdit->setReadOnly(true);
    maxEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
    maxEdit->setDecimals(1);
    maxEdit->setValue(recipe->fermentables.at(editrow).f_max_in_batch);

    connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
    connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
    dialog->exec();
    if (dialog->result() == QDialog::Rejected) {
	qDebug() << "rejected";
	// restore fermentbackup
	// recalculate percentages
    } else {
	qDebug() << "accepted";
	// fermentrow to final

	//fermentable_Json(); segfault !
    }

    // disconnect
    // return
    emit refreshAll();
}


void EditRecipe::on_quitButton_clicked()
{
    if (this->textIsChanged) {
	int rc = QMessageBox::warning(this, tr("Recipe changed"), tr("The recipe has been modified. Save changes?"),
                                QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Save);
        switch (rc) {
            case QMessageBox::Save:
                        on_saveButton_clicked();
                        break;  /* Saved and then Quit */
            case QMessageBox::Discard:
                        break;  /* Quit without Save */
            case QMessageBox::Cancel:
                        return; /* Return to the editor page */
        }
    }

    this->close();
    this->setResult(1);
}

mercurial