From 3fc75009e5822e507a83f0e587cd68cf484d82ca Mon Sep 17 00:00:00 2001 From: Matt Young Date: Sun, 28 May 2023 16:50:57 +0200 Subject: [PATCH] MiscTableModel and more refactoring --- src/MainWindow.cpp | 2 +- src/measurement/UnitSystem.cpp | 20 +- src/model/Fermentable.cpp | 12 +- src/model/Fermentable.h | 7 +- src/model/Hop.cpp | 10 +- src/model/Hop.h | 5 +- src/model/Misc.cpp | 11 +- src/model/Misc.h | 7 +- src/model/NamedEntityWithInventory.cpp | 3 + src/model/NamedEntityWithInventory.h | 39 ++ src/model/Yeast.cpp | 12 +- src/model/Yeast.h | 5 +- src/tableModels/BtTableModel.h | 4 +- src/tableModels/FermentableTableModel.cpp | 206 ++-------- src/tableModels/FermentableTableModel.h | 62 +--- src/tableModels/HopTableModel.cpp | 183 +-------- src/tableModels/HopTableModel.h | 52 +-- src/tableModels/ItemDelegate.h | 30 +- src/tableModels/MiscTableModel.cpp | 433 ++-------------------- src/tableModels/MiscTableModel.h | 86 +---- src/tableModels/TableModelBase.h | 293 +++++++++++++-- src/undoRedo/SimpleUndoableUpdate.cpp | 4 +- src/utils/OptionalHelpers.cpp | 11 +- translations/bt_ca.ts | 119 ++---- translations/bt_cs.ts | 121 +----- translations/bt_de.ts | 121 +----- translations/bt_el.ts | 121 +----- translations/bt_en.ts | 147 +------- translations/bt_es.ts | 119 +----- translations/bt_et.ts | 147 +------- translations/bt_eu.ts | 147 +------- translations/bt_fr.ts | 119 ++---- translations/bt_gl.ts | 147 +------- translations/bt_hu.ts | 121 +----- translations/bt_it.ts | 119 +----- translations/bt_lv.ts | 147 +------- translations/bt_nb.ts | 121 +----- translations/bt_nl.ts | 123 +----- translations/bt_pl.ts | 121 +----- translations/bt_pt.ts | 121 +----- translations/bt_ru.ts | 121 +----- translations/bt_sr.ts | 121 +----- translations/bt_sv.ts | 123 +----- translations/bt_tr.ts | 147 +------- translations/bt_zh.ts | 121 +----- 45 files changed, 809 insertions(+), 3502 deletions(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 3d148745..aac45faa 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -658,7 +658,7 @@ void MainWindow::setupTables() miscTableModel = new MiscTableModel(miscTable); miscTableProxy = new MiscSortFilterProxyModel(miscTable,false); miscTableProxy->setSourceModel(miscTableModel); - miscTable->setItemDelegate(new MiscItemDelegate(miscTable)); + miscTable->setItemDelegate(new MiscItemDelegate(miscTable, *miscTableModel)); miscTable->setModel(miscTableProxy); connect( miscTable, &QTableView::doubleClicked, this, [&](const QModelIndex &idx) { if (idx.column() == 0) diff --git a/src/measurement/UnitSystem.cpp b/src/measurement/UnitSystem.cpp index 0df02970..86cc1a88 100644 --- a/src/measurement/UnitSystem.cpp +++ b/src/measurement/UnitSystem.cpp @@ -214,23 +214,23 @@ Measurement::Amount Measurement::UnitSystem::qstringToSI(QString qstr, Unit cons // match to a unit in another UnitSystem for the same PhysicalQuantity. If there are no matches that way, it will // return nullptr; unitToUse = Unit::getUnit(unitName, *this, true); - if (unitToUse) { - qDebug() << Q_FUNC_INFO << this->uniqueName << ":" << unitName << "interpreted as" << unitToUse->name; - } else { - qDebug() << - Q_FUNC_INFO << this->uniqueName << ":" << unitName << "not recognised for" << this->pimpl->physicalQuantity; - } +// if (unitToUse) { +// qDebug() << Q_FUNC_INFO << this->uniqueName << ":" << unitName << "interpreted as" << unitToUse->name; +// } else { +// qDebug() << +// Q_FUNC_INFO << this->uniqueName << ":" << unitName << "not recognised for" << this->pimpl->physicalQuantity; +// } } if (!unitToUse) { - qDebug() << Q_FUNC_INFO << "Defaulting to" << defUnit; +// qDebug() << Q_FUNC_INFO << "Defaulting to" << defUnit; unitToUse = &defUnit; } Measurement::Amount siAmount = unitToUse->toCanonical(amt); - qDebug() << - Q_FUNC_INFO << this->uniqueName << ": " << qstr << "is" << amt << " " << unitToUse->name << "=" << - siAmount.quantity() << "in" << siAmount.unit()->name; +// qDebug() << +// Q_FUNC_INFO << this->uniqueName << ": " << qstr << "is" << amt << " " << unitToUse->name << "=" << +// siAmount.quantity() << "in" << siAmount.unit()->name; return siAmount; } diff --git a/src/model/Fermentable.cpp b/src/model/Fermentable.cpp index dd6e92ba..2026a3ee 100644 --- a/src/model/Fermentable.cpp +++ b/src/model/Fermentable.cpp @@ -441,15 +441,6 @@ void Fermentable::setBetaGlucanWithUnits(std::optional( [this](Recipe * rec) {return rec->uses(*this);} ); } @@ -465,3 +456,6 @@ bool fermentablesLessThanByWeight(Fermentable const * const lhs, Fermentable con // Yes. I know. This seems silly, but I want the returned list in descending not ascending order. return lhs->amount() > rhs->amount(); } + +// Insert the boiler-plate stuff for inventory +INVENTORY_COMMON_CODE(Fermentable) diff --git a/src/model/Fermentable.h b/src/model/Fermentable.h index 45a4a8c9..1e109c36 100644 --- a/src/model/Fermentable.h +++ b/src/model/Fermentable.h @@ -505,8 +505,6 @@ class Fermentable : public NamedEntityWithInventory { bool isExtract () const; bool isSugar () const; - virtual double inventory() const; - //============================================ "SETTER" MEMBER FUNCTIONS ============================================ void setType (Type const val); void setAmount (double const val); @@ -557,9 +555,8 @@ class Fermentable : public NamedEntityWithInventory { void setFanWithUnits (std::optional const val); void setBetaGlucanWithUnits(std::optional const val); - virtual void setInventoryAmount(double amount); - - void save(); + // Insert boiler-plate declarations for inventory + INVENTORY_COMMON_HEADER_DEFNS virtual Recipe * getOwningRecipe(); diff --git a/src/model/Hop.cpp b/src/model/Hop.cpp index 2e8d3e9c..3cc1d3fc 100644 --- a/src/model/Hop.cpp +++ b/src/model/Hop.cpp @@ -294,10 +294,6 @@ std::optional Hop::pinene_pct() const { return this->m_ std::optional Hop::polyphenols_pct() const { return this->m_polyphenols_pct; } std::optional Hop::xanthohumol_pct() const { return this->m_xanthohumol_pct; } -double Hop::inventory() const { - return InventoryUtils::getAmount(*this); -} - //============================================= "SETTER" MEMBER FUNCTIONS ============================================== void Hop::setAlpha_pct (double const val) { this->setAndNotify(PropertyNames::Hop::alpha_pct, this->m_alpha_pct, this->enforceMinAndMax(val, "alpha", 0.0, 100.0)); } void Hop::setAmount_kg (double const val) { this->setAndNotify(PropertyNames::Hop::amount_kg, this->m_amount_kg, this->enforceMin (val, "amount") ); } @@ -329,9 +325,6 @@ void Hop::setPinene_pct (std::optional const val) { th void Hop::setPolyphenols_pct (std::optional const val) { this->setAndNotify(PropertyNames::Hop::polyphenols_pct, this->m_polyphenols_pct, this->enforceMinAndMax(val, "polyphenols_pct", 0.0, 100.0)); } void Hop::setXanthohumol_pct (std::optional const val) { this->setAndNotify(PropertyNames::Hop::xanthohumol_pct, this->m_xanthohumol_pct, this->enforceMinAndMax(val, "xanthohumol_pct", 0.0, 100.0)); } -void Hop::setInventoryAmount(double num) { InventoryUtils::setAmount(*this, num); } - - Recipe * Hop::getOwningRecipe() { return ObjectStoreWrapper::findFirstMatching( [this](Recipe * rec) {return rec->uses(*this);} ); } @@ -345,3 +338,6 @@ bool hopLessThanByTime(Hop const * const lhs, Hop const * const rhs) { } return lhs->use() < rhs->use(); } + +// Insert the boiler-plate stuff for inventory +INVENTORY_COMMON_CODE_MO(Hop) diff --git a/src/model/Hop.h b/src/model/Hop.h index 624a426e..97c5a9a4 100644 --- a/src/model/Hop.h +++ b/src/model/Hop.h @@ -260,8 +260,6 @@ class Hop : public NamedEntityWithInventory { std::optional polyphenols_pct () const; std::optional xanthohumol_pct () const; - virtual double inventory() const; - //============================================ "SETTER" MEMBER FUNCTIONS ============================================ void setAlpha_pct (double const val); void setAmount_kg (double const val); @@ -293,7 +291,8 @@ class Hop : public NamedEntityWithInventory { void setPolyphenols_pct (std::optional const val); void setXanthohumol_pct (std::optional const val); - virtual void setInventoryAmount(double const val); + // Insert boiler-plate declarations for inventory + INVENTORY_COMMON_HEADER_DEFNS virtual Recipe * getOwningRecipe(); diff --git a/src/model/Misc.cpp b/src/model/Misc.cpp index 13a9c9b4..e21a07ff 100644 --- a/src/model/Misc.cpp +++ b/src/model/Misc.cpp @@ -189,15 +189,10 @@ void Misc::setAmountWithUnits(MassOrVolumeAmt const val) { } //========================OTHER METHODS========================================= -double Misc::inventory() const { - return InventoryUtils::getAmount(*this); -} - -void Misc::setInventoryAmount(double var) { - InventoryUtils::setAmount(*this, var); - return; -} Recipe * Misc::getOwningRecipe() { return ObjectStoreWrapper::findFirstMatching( [this](Recipe * rec) {return rec->uses(*this);} ); } + +// Insert the boiler-plate stuff for inventory +INVENTORY_COMMON_CODE(Misc) diff --git a/src/model/Misc.h b/src/model/Misc.h index 89112d1a..0431de30 100644 --- a/src/model/Misc.h +++ b/src/model/Misc.h @@ -161,8 +161,6 @@ class Misc : public NamedEntityWithInventory { QString producer () const; QString productId () const; - virtual double inventory() const; - //============================================ "SETTER" MEMBER FUNCTIONS ============================================ void setType (Type const val); void setUse (std::optional const val); @@ -177,9 +175,8 @@ class Misc : public NamedEntityWithInventory { void setProducer (QString const & val); void setProductId (QString const & val); - //! \brief The amount in inventory in either kg or L, depending on \c amountIsWeight(). - virtual void setInventoryAmount( double var ); - + // Insert boiler-plate declarations for inventory + INVENTORY_COMMON_HEADER_DEFNS virtual Recipe * getOwningRecipe(); diff --git a/src/model/NamedEntityWithInventory.cpp b/src/model/NamedEntityWithInventory.cpp index e90af9cc..5930d021 100644 --- a/src/model/NamedEntityWithInventory.cpp +++ b/src/model/NamedEntityWithInventory.cpp @@ -26,6 +26,9 @@ TypeLookup const NamedEntityWithInventory::typeLookup { { // PROPERTY_TYPE_LOOKUP_ENTRY(PropertyNames::NamedEntityWithInventory::inventory, NamedEntityWithInventory::m_inventory , Measurement::PqEitherMassOrVolume ), PROPERTY_TYPE_LOOKUP_ENTRY(PropertyNames::NamedEntityWithInventory::inventoryId, NamedEntityWithInventory::m_inventory_id), + + PROPERTY_TYPE_LOOKUP_ENTRY_NO_MV(PropertyNames::NamedEntityWithInventory::inventoryWithUnits, NamedEntityWithInventory, inventoryWithUnits, Measurement::PqEitherMassOrVolume ), + }, // Parent class lookup &NamedEntity::typeLookup diff --git a/src/model/NamedEntityWithInventory.h b/src/model/NamedEntityWithInventory.h index 73989b99..2c78fe5f 100644 --- a/src/model/NamedEntityWithInventory.h +++ b/src/model/NamedEntityWithInventory.h @@ -25,6 +25,7 @@ #define AddPropertyName(property) namespace PropertyNames::NamedEntityWithInventory { BtStringConst const property{#property}; } AddPropertyName(inventory ) AddPropertyName(inventoryId) +AddPropertyName(inventoryWithUnits) #undef AddPropertyName //=========================================== End of property name constants =========================================== //====================================================================================================================== @@ -55,6 +56,14 @@ class NamedEntityWithInventory : public NamedEntity { //! \brief The inventory table id, needed for signals Q_PROPERTY(int inventoryId READ inventoryId WRITE setInventoryId ) + /** + * \brief Amounts of \c Fermentable and \c Misc can be measured by mass or by volume (depending usually on what it + * is). + * + * NOTE: This property \b cannot be used to change between mass and volume. + */ + Q_PROPERTY(MassOrVolumeAmt inventoryWithUnits READ inventoryWithUnits WRITE setInventoryWithUnits) + /** * \brief Override \c NamedEntity::makeChild() as we have additional work to do for objects with inventory. * Specifically, a child object needs to have the same inventory as its parent. @@ -66,12 +75,42 @@ class NamedEntityWithInventory : public NamedEntity { virtual double inventory() const = 0; int inventoryId() const; + virtual MassOrVolumeAmt inventoryWithUnits() const = 0; virtual void setInventoryAmount(double amount) = 0; void setInventoryId(int key); + virtual void setInventoryWithUnits(MassOrVolumeAmt const val) = 0; protected: int m_inventory_id; }; +/** + * \brief Derived classes should include this in their header file + */ +#define INVENTORY_COMMON_HEADER_DEFNS \ + virtual double inventory() const; \ + virtual MassOrVolumeAmt inventoryWithUnits() const; \ + virtual void setInventoryAmount(double amount); \ + virtual void setInventoryWithUnits(MassOrVolumeAmt const val); + +/** + * \brief Derived classes should include this in their implementation file if they support measuring by volume and by + * mass + */ +#define INVENTORY_COMMON_CODE(NeName) \ +double NeName::inventory() const { return InventoryUtils::getAmount(*this); } \ +MassOrVolumeAmt NeName::inventoryWithUnits() const { return MassOrVolumeAmt{InventoryUtils::getAmount(*this), this->amountIsWeight() ? Measurement::Units::kilograms : Measurement::Units::liters}; } \ +void NeName::setInventoryAmount(double num) { InventoryUtils::setAmount(*this, num); return; } \ +void NeName::setInventoryWithUnits(MassOrVolumeAmt const val) { this->setInventoryAmount(val.quantity()); return; } + +/** + * \brief Derived classes should include this in their implementation file if they support measuring by mass only + */ +#define INVENTORY_COMMON_CODE_MO(NeName) \ +double NeName::inventory() const { return InventoryUtils::getAmount(*this); } \ +MassOrVolumeAmt NeName::inventoryWithUnits() const { return MassOrVolumeAmt{InventoryUtils::getAmount(*this), Measurement::Units::kilograms}; } \ +void NeName::setInventoryAmount(double num) { InventoryUtils::setAmount(*this, num); return; } \ +void NeName::setInventoryWithUnits(MassOrVolumeAmt const val) { this->setInventoryAmount(val.quantity()); return; } + #endif diff --git a/src/model/Yeast.cpp b/src/model/Yeast.cpp index 2f7e2939..7d4f8046 100644 --- a/src/model/Yeast.cpp +++ b/src/model/Yeast.cpp @@ -179,10 +179,6 @@ double Yeast::maxTemperature_c() const { return m_maxTemperature_c; } double Yeast::attenuation_pct() const { return m_attenuation_pct; } -double Yeast::inventory() const { - return InventoryUtils::getAmount(*this); -} - int Yeast::timesCultured() const { return m_timesCultured; } int Yeast::maxReuse() const { return m_maxReuse; } @@ -234,11 +230,6 @@ void Yeast::setAmount(double var) { this->enforceMin(var, "amount", 0.0)); } -void Yeast::setInventoryAmount(double var) { - InventoryUtils::setAmount(*this, var); - return; -} - // .:TBD:. I'm not wild about using "quanta" here (presumably to mean number of packets or number of cultures) // Storing an int in a double is safe, so, for now, just leave this in place but as a wrapper around the more // generic setInventoryAmount(). @@ -312,3 +303,6 @@ void Yeast::setAddToSecondary( bool var ) { Recipe * Yeast::getOwningRecipe() { return ObjectStoreWrapper::findFirstMatching( [this](Recipe * rec) {return rec->uses(*this);} ); } + +// Insert the boiler-plate stuff for inventory +INVENTORY_COMMON_CODE(Yeast) diff --git a/src/model/Yeast.h b/src/model/Yeast.h index bc76afd4..c821e63f 100644 --- a/src/model/Yeast.h +++ b/src/model/Yeast.h @@ -140,7 +140,6 @@ class Yeast : public NamedEntityWithInventory { void setType( Type t); void setForm( Form f); void setAmount( double var); - virtual void setInventoryAmount(double var); void setInventoryQuanta(int var); void setAmountIsWeight( bool var); void setLaboratory( const QString& var); @@ -163,7 +162,6 @@ class Yeast : public NamedEntityWithInventory { const QString formString() const; const QString formStringTr() const; double amount() const; - virtual double inventory() const; bool amountIsWeight() const; QString laboratory() const; QString productID() const; @@ -179,6 +177,9 @@ class Yeast : public NamedEntityWithInventory { int maxReuse() const; bool addToSecondary() const; + // Insert boiler-plate declarations for inventory + INVENTORY_COMMON_HEADER_DEFNS + virtual Recipe * getOwningRecipe(); signals: diff --git a/src/tableModels/BtTableModel.h b/src/tableModels/BtTableModel.h index 91873c85..e62d4eda 100644 --- a/src/tableModels/BtTableModel.h +++ b/src/tableModels/BtTableModel.h @@ -339,8 +339,8 @@ class BtTableModelRecipeObserver : public BtTableModel { std::initializer_list columnInfos); ~BtTableModelRecipeObserver(); -protected: - Recipe* recObs; + // Normally this would be protected, but it needs to be public for TableModelBase to access + Recipe * recObs; }; /** diff --git a/src/tableModels/FermentableTableModel.cpp b/src/tableModels/FermentableTableModel.cpp index d2f57103..49366b2b 100644 --- a/src/tableModels/FermentableTableModel.cpp +++ b/src/tableModels/FermentableTableModel.cpp @@ -39,14 +39,10 @@ #include "measurement/Unit.h" #include "model/Inventory.h" #include "model/Recipe.h" -///#include "PersistentSettings.h" #include "tableModels/ItemDelegate.h" #include "utils/BtStringConst.h" #include "widgets/BtComboBox.h" -// .:TODO:. We need to unify some of the logic from Misc into common code with Fermentable so we can write the handling -// for weight/volume once. What's here for the moment is showing weight/volume but not allowing it to be edited. - //=====================CLASS FermentableTableModel============================== FermentableTableModel::FermentableTableModel(QTableView* parent, bool editable) : BtTableModelInventory{ @@ -54,16 +50,16 @@ FermentableTableModel::FermentableTableModel(QTableView* parent, bool editable) editable, { // NOTE: Need PropertyNames::Fermentable::amountWithUnits not PropertyNames::Fermentable::amount below so we - // can handle mass-or-volume generically in TableModelBase. - SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Name , tr("Name" ), Fermentable, PropertyNames::NamedEntity::name ), - SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Type , tr("Type" ), Fermentable, PropertyNames::Fermentable::type , EnumInfo{Fermentable::typeStringMapping, Fermentable::typeDisplayNames}), - SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Amount , tr("Amount" ), Fermentable, PropertyNames::Fermentable::amountWithUnits), - SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Inventory, tr("Inventory" ), Fermentable, PropertyNames::Fermentable::amount ), // No inventory property name TODO Fix this! - SMART_COLUMN_HEADER_DEFN(FermentableTableModel, IsWeight , tr("Amount Type"), Fermentable, PropertyNames::Fermentable::amountIsWeight, BoolInfo{tr("Volume" ), tr("Weight")}), - SMART_COLUMN_HEADER_DEFN(FermentableTableModel, IsMashed , tr("Method" ), Fermentable, PropertyNames::Fermentable::isMashed , BoolInfo{tr("Not mashed"), tr("Mashed")}), - SMART_COLUMN_HEADER_DEFN(FermentableTableModel, AfterBoil, tr("Addition" ), Fermentable, PropertyNames::Fermentable::addAfterBoil , BoolInfo{tr("Normal" ), tr("Late" )}), - SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Yield , tr("Yield %" ), Fermentable, PropertyNames::Fermentable::yield_pct , PrecisionInfo{1}), - SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Color , tr("Color" ), Fermentable, PropertyNames::Fermentable::color_srm , PrecisionInfo{1}), + // can handle mass-or-volume generically in TableModelBase. Same for inventoryWithUnits. + SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Name , tr("Name" ), Fermentable, PropertyNames::NamedEntity::name ), + SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Type , tr("Type" ), Fermentable, PropertyNames::Fermentable::type , EnumInfo{Fermentable::typeStringMapping, Fermentable::typeDisplayNames}), + SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Amount , tr("Amount" ), Fermentable, PropertyNames::Fermentable::amountWithUnits ), + SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Inventory, tr("Inventory" ), Fermentable, PropertyNames::NamedEntityWithInventory::inventoryWithUnits), + SMART_COLUMN_HEADER_DEFN(FermentableTableModel, IsWeight , tr("Amount Type"), Fermentable, PropertyNames::Fermentable::amountIsWeight , BoolInfo{tr("Volume" ), tr("Weight")}), + SMART_COLUMN_HEADER_DEFN(FermentableTableModel, IsMashed , tr("Method" ), Fermentable, PropertyNames::Fermentable::isMashed , BoolInfo{tr("Not mashed"), tr("Mashed")}), + SMART_COLUMN_HEADER_DEFN(FermentableTableModel, AfterBoil, tr("Addition" ), Fermentable, PropertyNames::Fermentable::addAfterBoil , BoolInfo{tr("Normal" ), tr("Late" )}), + SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Yield , tr("Yield %" ), Fermentable, PropertyNames::Fermentable::yield_pct , PrecisionInfo{1}), + SMART_COLUMN_HEADER_DEFN(FermentableTableModel, Color , tr("Color" ), Fermentable, PropertyNames::Fermentable::color_srm , PrecisionInfo{1}), } }, TableModelBase{}, @@ -84,106 +80,16 @@ FermentableTableModel::~FermentableTableModel() = default; // .:TODO:.:JSON:. Now that fermentables can also be measured by volume, we might need to rethink this void FermentableTableModel::added (std::shared_ptr item) { if (item->amountIsWeight()) { this->totalFermMass_kg += item->amount(); } return; } void FermentableTableModel::removed(std::shared_ptr item) { if (item->amountIsWeight()) { this->totalFermMass_kg -= item->amount(); } return; } -void FermentableTableModel::removedAll() { this->totalFermMass_kg = 0; return; }; - -void FermentableTableModel::observeRecipe(Recipe* rec) { - if (this->recObs) { - qDebug() << Q_FUNC_INFO << "Unobserve Recipe #" << this->recObs->key() << "(" << this->recObs->name() << ")"; - disconnect(this->recObs, nullptr, this, nullptr); - this->removeAll(); - } - - this->recObs = rec; - if (this->recObs) { - qDebug() << Q_FUNC_INFO << "Observe Recipe #" << this->recObs->key() << "(" << this->recObs->name() << ")"; - - connect(this->recObs, &NamedEntity::changed, this, &FermentableTableModel::changed); - this->addFermentables(this->recObs->getAll()); - } - return; -} - -void FermentableTableModel::observeDatabase(bool val) { - if ( val ) { - // Observing a database and a recipe are mutually exclusive. - this->observeRecipe(nullptr); - - this->removeAll(); - connect(&ObjectStoreTyped::getInstance(), &ObjectStoreTyped::signalObjectInserted, this, &FermentableTableModel::addFermentable); - connect(&ObjectStoreTyped::getInstance(), &ObjectStoreTyped::signalObjectDeleted, this, &FermentableTableModel::removeFermentable); - this->addFermentables(ObjectStoreWrapper::getAll()); - } else { - disconnect(&ObjectStoreTyped::getInstance(), nullptr, this, nullptr); - this->removeAll(); - } - return; -} - -void FermentableTableModel::addFermentable(int fermId) { - auto ferm = ObjectStoreWrapper::getById(fermId); - qDebug() << Q_FUNC_INFO << ferm->name(); - - // Check to see if it's already in the list - if (this->rows.contains(ferm)) { - return; - } - - // If we are observing the database, ensure that the ferm is undeleted and fit to display. - if (this->recObs == nullptr && (ferm->deleted() || !ferm->display())) { - return; - } - - // If we are watching a Recipe and the new Fermentable does not belong to it then there is nothing for us to do - if (this->recObs) { - Recipe * recipeOfNewFermentable = ferm->getOwningRecipe(); - if (recipeOfNewFermentable && this->recObs->key() != recipeOfNewFermentable->key()) { - qDebug() << - Q_FUNC_INFO << "Ignoring signal about new Ferementable #" << ferm->key() << "as it belongs to Recipe #" << - recipeOfNewFermentable->key() << "and we are watching Recipe #" << this->recObs->key(); - return; - } - } - - this->add(ferm); - return; -} - -void FermentableTableModel::addFermentables(QList > ferms) { - qDebug() << Q_FUNC_INFO << "Add up to " << ferms.size() << " fermentables to existing list of " << this->rows.size(); - - auto tmp = this->removeDuplicates(ferms, this->recObs); - - qDebug() << Q_FUNC_INFO << QString("After de-duping, adding %1 fermentables").arg(tmp.size()); - - int size = this->rows.size(); - if (size+tmp.size()) { - beginInsertRows( QModelIndex(), size, size+tmp.size()-1 ); - this->rows.append(tmp); - - for (auto ferm : tmp) { - connect(ferm.get(), &NamedEntity::changed, this, &FermentableTableModel::changed); - if (ferm->amountIsWeight()) { - totalFermMass_kg += ferm->amount(); - } - } - - endInsertRows(); - } -} - -void FermentableTableModel::removeFermentable([[maybe_unused]] int fermId, - std::shared_ptr object) { - this->remove(std::static_pointer_cast(object)); - return; -} - -void FermentableTableModel::updateTotalGrains() { +void FermentableTableModel::updateTotals() { this->totalFermMass_kg = 0; for (auto const & ferm : this->rows) { if (ferm->amountIsWeight()) { totalFermMass_kg += ferm->amount(); } } + if (this->displayPercentages && this->rowCount() > 0) { + emit headerDataChanged(Qt::Vertical, 0, this->rowCount() - 1); + } return; } @@ -205,40 +111,6 @@ void FermentableTableModel::changedInventory(int invKey, BtStringConst const & p return; } -void FermentableTableModel::changed(QMetaProperty prop, [[maybe_unused]] QVariant val) { -// qDebug() << Q_FUNC_INFO << prop.name(); - - // Is sender one of our fermentables? - Fermentable* fermSender = qobject_cast(sender()); - if (fermSender) { - int ii = this->findIndexOf(fermSender); - if (ii < 0) { - return; - } - - this->updateTotalGrains(); - emit dataChanged(QAbstractItemModel::createIndex(ii, 0), - QAbstractItemModel::createIndex(ii, this->columnCount() - 1)); - if (displayPercentages && rowCount() > 0) { - emit headerDataChanged(Qt::Vertical, 0, rowCount() - 1); - } - return; - } - - // See if our recipe gained or lost fermentables. - Recipe* recSender = qobject_cast(sender()); - if (recSender && recSender == recObs && prop.name() == PropertyNames::Recipe::fermentableIds) { - this->removeAll(); - this->addFermentables(this->recObs->getAll()); - } - - return; -} - -int FermentableTableModel::rowCount(QModelIndex const & /*parent*/) const { - return this->rows.size(); -} - QVariant FermentableTableModel::data(QModelIndex const & index, int role) const { if (!this->isIndexOk(index)) { return QVariant(); @@ -255,22 +127,9 @@ QVariant FermentableTableModel::data(QModelIndex const & index, int role) const case FermentableTableModel::ColumnIndex::Yield: case FermentableTableModel::ColumnIndex::Color: case FermentableTableModel::ColumnIndex::Amount: + case FermentableTableModel::ColumnIndex::Inventory: return this->readDataFromModel(index, role); - case FermentableTableModel::ColumnIndex::Inventory: - if (role == Qt::DisplayRole) { - return QVariant( - Measurement::displayAmount(Measurement::Amount{ - row->inventory(), - row->amountIsWeight() ? Measurement::Units::kilograms : - Measurement::Units::liters - }, - 3, - this->get_ColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - std::nullopt) - ); - } - break; // No default case as we want the compiler to warn us if we missed one } return QVariant(); @@ -333,8 +192,8 @@ bool FermentableTableModel::setData(QModelIndex const & index, } bool retVal = false; - auto row = this->rows[index.row()]; + auto row = this->rows[index.row()]; Measurement::PhysicalQuantity physicalQuantity = row->amountIsWeight() ? Measurement::PhysicalQuantity::Mass: Measurement::PhysicalQuantity::Volume; @@ -350,36 +209,13 @@ bool FermentableTableModel::setData(QModelIndex const & index, return this->writeDataToModel(index, value, role); case FermentableTableModel::ColumnIndex::Inventory: - retVal = value.canConvert(QVariant::String); - if (retVal) { - MainWindow::instance().doOrRedoUpdate( - *row, - TYPE_INFO(Fermentable, NamedEntityWithInventory, inventory), - Measurement::qStringToSI(value.toString(), - physicalQuantity, - this->get_ColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - this->get_ColumnInfo(columnIndex).getForcedRelativeScale()).quantity(), - tr("Change Fermentable Inventory Amount") - ); - } - break; + return this->writeDataToModel(index, value, role, physicalQuantity); case FermentableTableModel::ColumnIndex::Amount: - retVal = value.canConvert(QVariant::String); + retVal = this->writeDataToModel(index, value, role, physicalQuantity); if (retVal) { - // This is where the amount of a fermentable in a recipe gets updated - // We need to refer back to the MainWindow to make this an undoable operation - MainWindow::instance().doOrRedoUpdate( - *row, - TYPE_INFO(Fermentable, amount), - Measurement::qStringToSI(value.toString(), - physicalQuantity, - this->get_ColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - this->get_ColumnInfo(columnIndex).getForcedRelativeScale()).quantity(), - tr("Change Fermentable Amount") - ); - if (rowCount() > 0) { - headerDataChanged( Qt::Vertical, 0, rowCount()-1 ); // Need to re-show header (grain percent). + if (this->rowCount() > 0) { + headerDataChanged(Qt::Vertical, 0, this->rowCount() - 1); // Need to re-show header (grain percent). } } break; @@ -389,6 +225,8 @@ bool FermentableTableModel::setData(QModelIndex const & index, return retVal; } +// Insert the boiler-plate stuff that we cannot do in TableModelBase +TABLE_MODEL_COMMON_CODE(Fermentable, fermentable) //=========================================== CLASS FermentableItemDelegate ============================================ // Insert the boiler-plate stuff that we cannot do in ItemDelegate diff --git a/src/tableModels/FermentableTableModel.h b/src/tableModels/FermentableTableModel.h index 0469cdba..559d98c6 100644 --- a/src/tableModels/FermentableTableModel.h +++ b/src/tableModels/FermentableTableModel.h @@ -42,10 +42,8 @@ class BtStringConst; class Fermentable; class Recipe; -// // You have to get the order of everything right with traits classes, but the end result is that we can refer to // FermentableTableModel::ColumnIndex::Color etc. -// class FermentableTableModel; template <> struct TableModelTraits { enum class ColumnIndex { @@ -69,54 +67,11 @@ template <> struct TableModelTraits { class FermentableTableModel : public BtTableModelInventory, public TableModelBase { Q_OBJECT -public: - FermentableTableModel(QTableView* parent=nullptr, bool editable=true); - virtual ~FermentableTableModel(); - - // - // This block of functions is called from the TableModelBase class - // - void added (std::shared_ptr item); - void removed(std::shared_ptr item); - void removedAll(); + TABLE_MODEL_COMMON_DECL(Fermentable) - //! \brief Observe a recipe's list of fermentables. - void observeRecipe(Recipe* rec); - //! \brief If true, we model the database's list of fermentables. - void observeDatabase(bool val); -private: - //! \brief Watch all the \b ferms for changes. - void addFermentables(QList > ferms); public: //! \brief True if you want to display percent of each grain in the row header. - void setDisplayPercentages( bool var ); - - //! \brief Reimplemented from QAbstractTableModel. - virtual int rowCount(QModelIndex const & parent = QModelIndex()) const; - //! \brief Reimplemented from QAbstractTableModel. - virtual QVariant data(QModelIndex const & index, int role = Qt::DisplayRole) const; - //! \brief Reimplemented from QAbstractTableModel - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - //! \brief Reimplemented from QAbstractTableModel. - virtual Qt::ItemFlags flags(const QModelIndex& index) const; - //! \brief Reimplemented from QAbstractTableModel. - virtual bool setData(QModelIndex const & index, QVariant const & value, int role = Qt::EditRole); - -public slots: - //! \brief Watch \b ferm for changes. - void addFermentable(int fermId); - - void removeFermentable(int fermId, std::shared_ptr object); - - /** - * \brief Catch changes to Recipe, Database, and Fermentable. - * NB: Needs to be public, not private, as accessed from \c TableModelBase - */ - void changed(QMetaProperty, QVariant); - -private slots: - //! \brief Catches changes to inventory - void changedInventory(int invKey, BtStringConst const & propertyName); + void setDisplayPercentages(bool var); private: //! \brief Recalculate the total amount of grains in the model. @@ -139,18 +94,7 @@ class FermentableItemDelegate : public QItemDelegate, public ItemDelegate { Q_OBJECT -public: - FermentableItemDelegate(QTableView * parent, FermentableTableModel & tableModel); - virtual ~FermentableItemDelegate(); - - //! \brief Reimplemented from QItemDelegate. - virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; - //! \brief Reimplemented from QItemDelegate. - virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; - //! \brief Reimplemented from QItemDelegate. - virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; - //! \brief Reimplemented from QItemDelegate. - virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; + ITEM_DELEGATE_COMMON_DECL(Fermentable) }; #endif diff --git a/src/tableModels/HopTableModel.cpp b/src/tableModels/HopTableModel.cpp index d6046921..67bb6d5c 100644 --- a/src/tableModels/HopTableModel.cpp +++ b/src/tableModels/HopTableModel.cpp @@ -52,10 +52,12 @@ HopTableModel::HopTableModel(QTableView * parent, bool editable) : parent, editable, { + // Note that we have to use PropertyNames::NamedEntityWithInventory::inventoryWithUnits because + // PropertyNames::NamedEntityWithInventory::inventory is not implemented SMART_COLUMN_HEADER_DEFN(HopTableModel, Name , tr("Name" ), Hop, PropertyNames::NamedEntity::name), SMART_COLUMN_HEADER_DEFN(HopTableModel, Alpha , tr("Alpha %" ), Hop, PropertyNames::Hop::alpha_pct , PrecisionInfo{1}), SMART_COLUMN_HEADER_DEFN(HopTableModel, Amount , tr("Amount" ), Hop, PropertyNames::Hop::amount_kg ), - SMART_COLUMN_HEADER_DEFN(HopTableModel, Inventory, tr("Inventory"), Hop, PropertyNames::Hop::amount_kg ), // No inventory property name + SMART_COLUMN_HEADER_DEFN(HopTableModel, Inventory, tr("Inventory"), Hop, PropertyNames::NamedEntityWithInventory::inventoryWithUnits ), SMART_COLUMN_HEADER_DEFN(HopTableModel, Form , tr("Form" ), Hop, PropertyNames::Hop::form , EnumInfo{Hop::formStringMapping, Hop::formDisplayNames}), SMART_COLUMN_HEADER_DEFN(HopTableModel, Use , tr("Use" ), Hop, PropertyNames::Hop::use , EnumInfo{Hop::useStringMapping, Hop::useDisplayNames }), SMART_COLUMN_HEADER_DEFN(HopTableModel, Time , tr("Time" ), Hop, PropertyNames::Hop::time_min ), @@ -77,109 +79,7 @@ HopTableModel::~HopTableModel() = default; void HopTableModel::added ([[maybe_unused]] std::shared_ptr item) { return; } void HopTableModel::removed([[maybe_unused]] std::shared_ptr item) { return; } -void HopTableModel::removedAll() { return; } - -void HopTableModel::observeRecipe(Recipe * rec) { - if (this->recObs) { - disconnect(this->recObs, nullptr, this, nullptr); - this->removeAll(); - } - - this->recObs = rec; - if (this->recObs) { - connect(this->recObs, &NamedEntity::changed, this, &HopTableModel::changed); - this->addHops(this->recObs->getAll()); - } - return; -} - -void HopTableModel::observeDatabase(bool val) { - if (val) { - observeRecipe(nullptr); - removeAll(); - connect(&ObjectStoreTyped::getInstance(), &ObjectStoreTyped::signalObjectInserted, this, - &HopTableModel::addHop); - connect(&ObjectStoreTyped::getInstance(), - &ObjectStoreTyped::signalObjectDeleted, - this, - &HopTableModel::removeHop); - this->addHops(ObjectStoreWrapper::getAll()); - } else { - removeAll(); - disconnect(&ObjectStoreTyped::getInstance(), nullptr, this, nullptr); - } - return; -} - -void HopTableModel::addHop(int hopId) { - auto hopAdded = ObjectStoreTyped::getInstance().getById(hopId); - if (!hopAdded) { - // Not sure this should ever happen in practice, but, if there ever is no hop with the specified ID, there's not - // a lot we can do. - qWarning() << Q_FUNC_INFO << "Received signal that Hop ID" << hopId << "added, but unable to retrieve the Hop"; - return; - } - - if (this->rows.contains(hopAdded)) { - return; - } - - // If we are observing the database, ensure that the item is undeleted and - // fit to display. - if (this->recObs == nullptr && (hopAdded->deleted() || !hopAdded->display())) { - return; - } - - // If we are watching a Recipe and the new Hop does not belong to it then there is nothing for us to do - if (this->recObs) { - Recipe * recipeOfNewHop = hopAdded->getOwningRecipe(); - if (recipeOfNewHop && this->recObs->key() != recipeOfNewHop->key()) { - qDebug() << - Q_FUNC_INFO << "Ignoring signal about new Hop #" << hopAdded->key() << "as it belongs to Recipe #" << - recipeOfNewHop->key() << "and we are watching Recipe #" << this->recObs->key(); - return; - } - } - - int size = this->rows.size(); - beginInsertRows(QModelIndex(), size, size); - this->rows.append(hopAdded); - connect(hopAdded.get(), &NamedEntity::changed, this, &HopTableModel::changed); - endInsertRows(); - return; -} - -void HopTableModel::addHops(QList< std::shared_ptr > hops) { - decltype(hops) tmp; - - for (auto hop : hops) { - if (recObs == nullptr && (hop->deleted() || !hop->display())) { - continue; - } - if (!this->rows.contains(hop)) { - tmp.append(hop); - } - } - - int size = this->rows.size(); - if (size + tmp.size()) { - beginInsertRows(QModelIndex(), size, size + tmp.size() - 1); - this->rows.append(tmp); - - for (auto hop : tmp) { - connect(hop.get(), &NamedEntity::changed, this, &HopTableModel::changed); - } - - endInsertRows(); - } - return; -} - -void HopTableModel::removeHop([[maybe_unused]] int hopId, - std::shared_ptr object) { - this->remove(std::static_pointer_cast(object)); - return; -} +void HopTableModel::updateTotals() { return; } void HopTableModel::setShowIBUs(bool var) { showIBUs = var; @@ -197,40 +97,6 @@ void HopTableModel::changedInventory(int invKey, BtStringConst const & propertyN return; } -void HopTableModel::changed(QMetaProperty prop, [[maybe_unused]] QVariant val) { - - // Find the notifier in the list - Hop * hopSender = qobject_cast(sender()); - if (hopSender) { - int ii = this->findIndexOf(hopSender); - if (ii < 0) { - return; - } - - emit dataChanged(QAbstractItemModel::createIndex(ii, 0), - QAbstractItemModel::createIndex(ii, this->columnCount() - 1)); - emit headerDataChanged(Qt::Vertical, ii, ii); - return; - } - - // See if sender is our recipe. - Recipe * recSender = qobject_cast(sender()); - if (recSender && recSender == recObs) { - if (QString(prop.name()) == PropertyNames::Recipe::hopIds) { - removeAll(); - this->addHops(recObs->getAll()); - } - if (rowCount() > 0) { - emit headerDataChanged(Qt::Vertical, 0, rowCount() - 1); - } - return; - } -} - -int HopTableModel::rowCount(const QModelIndex & /*parent*/) const { - return this->rows.size(); -} - QVariant HopTableModel::data(const QModelIndex & index, int role) const { if (!this->isIndexOk(index)) { return QVariant(); @@ -245,16 +111,9 @@ QVariant HopTableModel::data(const QModelIndex & index, int role) const { case HopTableModel::ColumnIndex::Time: case HopTableModel::ColumnIndex::Form: case HopTableModel::ColumnIndex::Amount: + case HopTableModel::ColumnIndex::Inventory: return this->readDataFromModel(index, role); - case HopTableModel::ColumnIndex::Inventory: - if (role == Qt::DisplayRole) { - return QVariant(Measurement::displayAmount(Measurement::Amount{row->inventory(), Measurement::Units::kilograms}, - 3, - this->get_ColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - this->get_ColumnInfo(columnIndex).getForcedRelativeScale())); - } - break; // No default case as we want the compiler to warn us if we missed one } return QVariant(); @@ -302,37 +161,11 @@ bool HopTableModel::setData(const QModelIndex & index, const QVariant & value, i case HopTableModel::ColumnIndex::Use: case HopTableModel::ColumnIndex::Form: case HopTableModel::ColumnIndex::Time: + case HopTableModel::ColumnIndex::Amount: return this->writeDataToModel(index, value, role); case HopTableModel::ColumnIndex::Inventory: - retVal = value.canConvert(QVariant::String); - if (retVal) { - MainWindow::instance().doOrRedoUpdate( - *row, - TYPE_INFO(Hop, NamedEntityWithInventory, inventory), - Measurement::qStringToSI(value.toString(), - Measurement::PhysicalQuantity::Mass, - this->get_ColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - this->get_ColumnInfo(columnIndex).getForcedRelativeScale()).quantity(), - tr("Change Hop Inventory Amount") - ); - } - break; - - case HopTableModel::ColumnIndex::Amount: - retVal = value.canConvert(QVariant::String); - if (retVal) { - MainWindow::instance().doOrRedoUpdate( - *row, - TYPE_INFO(Hop, amount_kg), - Measurement::qStringToSI(value.toString(), - Measurement::PhysicalQuantity::Mass, - this->get_ColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - this->get_ColumnInfo(columnIndex).getForcedRelativeScale()).quantity(), - tr("Change Hop Amount") - ); - } - break; + return this->writeDataToModel(index, value, role, Measurement::PhysicalQuantity::Mass); // No default case as we want the compiler to warn us if we missed one } @@ -344,6 +177,8 @@ bool HopTableModel::setData(const QModelIndex & index, const QVariant & value, i return retVal; } +// Insert the boiler-plate stuff that we cannot do in TableModelBase +TABLE_MODEL_COMMON_CODE(Hop, hop) //=============================================== CLASS HopItemDelegate ================================================ // Insert the boiler-plate stuff that we cannot do in ItemDelegate diff --git a/src/tableModels/HopTableModel.h b/src/tableModels/HopTableModel.h index 5f1c4665..bb07a9e8 100644 --- a/src/tableModels/HopTableModel.h +++ b/src/tableModels/HopTableModel.h @@ -59,46 +59,11 @@ template <> struct TableModelTraits { class HopTableModel : public BtTableModelInventory, public TableModelBase { Q_OBJECT -public: - - HopTableModel(QTableView* parent=nullptr, bool editable=true); - virtual ~HopTableModel(); - - // - // This block of functions is called from the TableModelBase class - // - void added (std::shared_ptr item); - void removed(std::shared_ptr item); - void removedAll(); + TABLE_MODEL_COMMON_DECL(Hop) - //! \brief Observe a recipe's list of hops. - void observeRecipe(Recipe* rec); - //! \brief If true, we model the database's list of hops. - void observeDatabase(bool val); +public: //! \brief Show ibus in the vertical header. void setShowIBUs( bool var ); -private: - //! \brief Watch all the \c hops for changes. - void addHops(QList< std::shared_ptr > hops); - -public: - //! \brief Reimplemented from QAbstractTableModel. - virtual int rowCount(QModelIndex const & parent = QModelIndex()) const; - //! \brief Reimplemented from QAbstractTableModel. - virtual QVariant data(QModelIndex const & index, int role = Qt::DisplayRole) const; - //! \brief Reimplemented from QAbstractTableModel - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - //! \brief Reimplemented from QAbstractTableModel. - virtual Qt::ItemFlags flags(const QModelIndex& index) const; - //! \brief Reimplemented from QAbstractTableModel. - virtual bool setData(QModelIndex const & index, QVariant const & value, int role = Qt::EditRole); - -public slots: - void changed(QMetaProperty, QVariant); - void changedInventory(int invKey, BtStringConst const & propertyName); - //! \brief Add a hop to the model. - void addHop(int hopId); - void removeHop(int hopId, std::shared_ptr object); private: bool showIBUs; // True if you want to show the IBU contributions in the table rows. @@ -116,18 +81,7 @@ class HopItemDelegate : public QItemDelegate, public ItemDelegate { Q_OBJECT -public: - HopItemDelegate(QTableView * parent, HopTableModel & tableModel); - virtual ~HopItemDelegate(); - - //! \brief Reimplemented from QItemDelegate. - virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; - //! \brief Reimplemented from QItemDelegate. - virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; - //! \brief Reimplemented from QItemDelegate. - virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; - //! \brief Reimplemented from QItemDelegate. - virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; + ITEM_DELEGATE_COMMON_DECL(Hop) }; #endif diff --git a/src/tableModels/ItemDelegate.h b/src/tableModels/ItemDelegate.h index 33330169..c235926e 100644 --- a/src/tableModels/ItemDelegate.h +++ b/src/tableModels/ItemDelegate.h @@ -191,14 +191,6 @@ class ItemDelegate { // FermentableTableModel::data, etc) will have done all the work for us (including handling optional and forced // units etc) and provided a suitable QString in the QVariant. QLineEdit * line = qobject_cast(editor); -/// if (typeInfo.isOptional()) { -/// bool hasValue = false; -/// Optional::removeOptionalWrapper(modelData, typeInfo, &hasValue); -/// if (!hasValue) { -/// line->setText(""); -/// return; -/// } -/// } line->setText(modelData.toString()); return; @@ -283,6 +275,28 @@ class ItemDelegate { NO_COPY_DECLARATIONS(ItemDelegate) }; +/** + * \brief Derived classes should include this in their header file, right after Q_OBJECT + * + * Note: + * - As elsewhere, we have to be careful about comment formats in macro definitions + * - We cannot put the whole class declaration in the macro as (I think) it confuses the Qt MOC + */ +#define ITEM_DELEGATE_COMMON_DECL(NeName) \ + public: \ + NeName##ItemDelegate(QTableView * parent, NeName##TableModel & tableModel); \ + virtual ~NeName##ItemDelegate(); \ + \ + /** \brief Reimplemented from QItemDelegate. */ \ + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; \ + /** \brief Reimplemented from QItemDelegate. */ \ + virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; \ + /** \brief Reimplemented from QItemDelegate. */ \ + virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; \ + /** \brief Reimplemented from QItemDelegate. */ \ + virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; \ + + /** * \brief Derived classes should include this in their implementation file */ diff --git a/src/tableModels/MiscTableModel.cpp b/src/tableModels/MiscTableModel.cpp index d62cf3da..22cfda5e 100644 --- a/src/tableModels/MiscTableModel.cpp +++ b/src/tableModels/MiscTableModel.cpp @@ -42,16 +42,18 @@ MiscTableModel::MiscTableModel(QTableView* parent, bool editable) : parent, editable, { - SMART_COLUMN_HEADER_DEFN(MiscTableModel, Name , tr("Name" ), Misc, PropertyNames::NamedEntity::name ), - SMART_COLUMN_HEADER_DEFN(MiscTableModel, Type , tr("Type" ), Misc, PropertyNames::Misc::type ), - SMART_COLUMN_HEADER_DEFN(MiscTableModel, Use , tr("Use" ), Misc, PropertyNames::Misc::use ), - SMART_COLUMN_HEADER_DEFN(MiscTableModel, Time , tr("Time" ), Misc, PropertyNames::Misc::time_min ), - SMART_COLUMN_HEADER_DEFN(MiscTableModel, Amount , tr("Amount" ), Misc, PropertyNames::Misc::amount ), - SMART_COLUMN_HEADER_DEFN(MiscTableModel, Inventory, tr("Inventory" ), Misc, PropertyNames::Misc::amount ), // No inventory property name - SMART_COLUMN_HEADER_DEFN(MiscTableModel, IsWeight , tr("Amount Type"), Misc, PropertyNames::Misc::amountIsWeight), + // NOTE: Need PropertyNames::Fermentable::amountWithUnits not PropertyNames::Fermentable::amount below so we + // can handle mass-or-volume generically in TableModelBase. Same for inventoryWithUnits. + SMART_COLUMN_HEADER_DEFN(MiscTableModel, Name , tr("Name" ), Misc, PropertyNames::NamedEntity::name ), + SMART_COLUMN_HEADER_DEFN(MiscTableModel, Type , tr("Type" ), Misc, PropertyNames::Misc::type , EnumInfo{Misc::typeStringMapping, Misc::typeDisplayNames}), + SMART_COLUMN_HEADER_DEFN(MiscTableModel, Use , tr("Use" ), Misc, PropertyNames::Misc::use , EnumInfo{Misc:: useStringMapping, Misc:: useDisplayNames}), + SMART_COLUMN_HEADER_DEFN(MiscTableModel, Time , tr("Time" ), Misc, PropertyNames::Misc::time_min ), + SMART_COLUMN_HEADER_DEFN(MiscTableModel, Amount , tr("Amount" ), Misc, PropertyNames::Misc::amountWithUnits ), + SMART_COLUMN_HEADER_DEFN(MiscTableModel, Inventory, tr("Inventory" ), Misc, PropertyNames::NamedEntityWithInventory::inventoryWithUnits), + SMART_COLUMN_HEADER_DEFN(MiscTableModel, IsWeight , tr("Amount Type"), Misc, PropertyNames::Misc::amountIsWeight , BoolInfo{tr("Volume" ), tr("Weight")}), } }, - BtTableModelData{} { + TableModelBase{} { this->rows.clear(); setObjectName("miscTableModel"); @@ -66,132 +68,12 @@ MiscTableModel::MiscTableModel(QTableView* parent, bool editable) : MiscTableModel::~MiscTableModel() = default; -BtTableModel::ColumnInfo const & MiscTableModel::getColumnInfo(MiscTableModel::ColumnIndex const columnIndex) const { - return this->BtTableModel::getColumnInfo(static_cast(columnIndex)); -} - -void MiscTableModel::observeRecipe(Recipe* rec) { - if (this->recObs) { - qDebug() << Q_FUNC_INFO << "Unwatching Recipe" << this->recObs; - disconnect(this->recObs, nullptr, this, nullptr); - removeAll(); - } - - this->recObs = rec; - if (this->recObs) { - qDebug() << Q_FUNC_INFO << "Watching Recipe" << this->recObs; - connect(this->recObs, &NamedEntity::changed, this, &MiscTableModel::changed); - this->addMiscs(this->recObs->getAll()); - } -} - -void MiscTableModel::observeDatabase(bool val) { - if (val) { - observeRecipe(nullptr); - removeAll(); - connect(&ObjectStoreTyped::getInstance(), &ObjectStoreTyped::signalObjectInserted, this, &MiscTableModel::addMisc); - connect(&ObjectStoreTyped::getInstance(), &ObjectStoreTyped::signalObjectDeleted, this, &MiscTableModel::removeMisc); - this->addMiscs(ObjectStoreWrapper::getAll()); - } else { - removeAll(); - disconnect(&ObjectStoreTyped::getInstance(), nullptr, this, nullptr ); - } - return; -} - -void MiscTableModel::addMisc(int miscId) { - auto misc = ObjectStoreWrapper::getById(miscId); - - if (this->rows.contains(misc) ) { - return; - } - - // If we are observing the database, ensure that the item is undeleted and - // fit to display. - if (recObs == nullptr && (misc->deleted() || !misc->display())) { - return; - } - - // If we are watching a Recipe and the new Misc does not belong to it then there is nothing for us to do - if (this->recObs) { - auto recipeOfNewMisc = misc->getOwningRecipe(); - if (recipeOfNewMisc && this->recObs->key() != recipeOfNewMisc->key()) { - qDebug() << - Q_FUNC_INFO << "Ignoring signal about new Misc #" << misc->key() << "as it belongs to Recipe #" << - recipeOfNewMisc->key() << "and we are watching Recipe #" << this->recObs->key(); - return; - } - } - - int size = this->rows.size(); - beginInsertRows( QModelIndex(), size, size ); - this->rows.append(misc); - connect(misc.get(), &NamedEntity::changed, this, &MiscTableModel::changed ); - //reset(); // Tell everybody that the table has changed. - endInsertRows(); - return; -} - -void MiscTableModel::addMiscs(QList > miscs) { - auto tmp = this->removeDuplicates(miscs, this->recObs); - - int size = this->rows.size(); - if (size+tmp.size()) { - beginInsertRows( QModelIndex(), size, size+tmp.size()-1 ); - this->rows.append(tmp); - - for (auto ii : tmp) { - connect(ii.get(), &NamedEntity::changed, this, &MiscTableModel::changed); - } - - endInsertRows(); - } -} - -// Returns true when misc is successfully found and removed. -void MiscTableModel::removeMisc([[maybe_unused]] int miscId, - std::shared_ptr object) { - this->remove(std::static_pointer_cast(object)); - return; -} - -bool MiscTableModel::remove(std::shared_ptr misc) { - int i = this->rows.indexOf(misc); - if (i >= 0 ) { - beginRemoveRows( QModelIndex(), i, i ); - disconnect(misc.get(), nullptr, this, nullptr); - this->rows.removeAt(i); - //reset(); // Tell everybody the table has changed. - endRemoveRows(); - - return true; - } - - return false; -} - -void MiscTableModel::removeAll() -{ - if (this->rows.size()) - { - beginRemoveRows( QModelIndex(), 0, this->rows.size()-1 ); - while( !this->rows.isEmpty() ) - { - disconnect( this->rows.takeLast().get(), nullptr, this, nullptr ); - } - endRemoveRows(); - } -} - -int MiscTableModel::rowCount(const QModelIndex& /*parent*/) const { - return this->rows.size(); -} +void MiscTableModel::added ([[maybe_unused]] std::shared_ptr item) { return; } +void MiscTableModel::removed([[maybe_unused]] std::shared_ptr item) { return; } +void MiscTableModel::updateTotals() { return; } QVariant MiscTableModel::data(QModelIndex const & index, int role) const { - - // Ensure the row is ok. - if (index.row() >= static_cast(this->rows.size())) { - qWarning() << Q_FUNC_INFO << "Bad model index. row = " << index.row(); + if (!this->isIndexOk(index)) { return QVariant(); } @@ -201,73 +83,15 @@ QVariant MiscTableModel::data(QModelIndex const & index, int role) const { auto const columnIndex = static_cast(index.column()); switch (columnIndex) { case MiscTableModel::ColumnIndex::Name: - if (role == Qt::DisplayRole) { - return QVariant(row->name()); - } - break; case MiscTableModel::ColumnIndex::Type: - if (role == Qt::DisplayRole) { - return QVariant(Misc::typeDisplayNames[row->type()]); - } - if (role == Qt::UserRole) { - return QVariant(static_cast(row->type())); - } - break; case MiscTableModel::ColumnIndex::Use: - if (role == Qt::DisplayRole) { - return QVariant(Misc::useDisplayNames[row->use()]); - } - if (role == Qt::UserRole) { - return QVariant::fromValue(Optional::toOptInt(row->use())); - } - return QVariant(); case MiscTableModel::ColumnIndex::Time: - if (role == Qt::DisplayRole) { - return QVariant(Measurement::displayAmount(Measurement::Amount{row->time_min(), Measurement::Units::minutes}, - 3, - std::nullopt, - this->getColumnInfo(columnIndex).getForcedRelativeScale())); - } - break; - case MiscTableModel::ColumnIndex::Inventory: - if (role == Qt::DisplayRole) { - return QVariant( - Measurement::displayAmount(Measurement::Amount{ - row->inventory(), - row->amountIsWeight() ? Measurement::Units::kilograms : - Measurement::Units::liters - }, - 3, - this->getColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - std::nullopt) - ); - } - break; - case MiscTableModel::ColumnIndex::Amount: - if (role == Qt::DisplayRole) { - return QVariant( - Measurement::displayAmount(Measurement::Amount{ - row->amount(), - row->amountIsWeight() ? Measurement::Units::kilograms : - Measurement::Units::liters - }, - 3, - this->getColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - std::nullopt) - ); - } - break; case MiscTableModel::ColumnIndex::IsWeight: - if (role == Qt::DisplayRole) { - return QVariant(Measurement::descAmountIsWeight[static_cast(row->amountIsWeight())]); - } - if (role == Qt::UserRole) { - return QVariant(row->amountIsWeight()); - } - break; - default: - qWarning() << Q_FUNC_INFO << "Bad model index. column = " << index.column(); - break; + case MiscTableModel::ColumnIndex::Amount: + case MiscTableModel::ColumnIndex::Inventory: + return this->readDataFromModel(index, role); + + // No default case as we want the compiler to warn us if we missed one } return QVariant(); } @@ -294,8 +118,7 @@ Qt::ItemFlags MiscTableModel::flags(QModelIndex const & index) const { bool MiscTableModel::setData(QModelIndex const & index, QVariant const & value, [[maybe_unused]] int role) { - - if (index.row() >= static_cast(this->rows.size())) { + if (!this->isIndexOk(index)) { return false; } @@ -307,90 +130,17 @@ bool MiscTableModel::setData(QModelIndex const & index, auto const columnIndex = static_cast(index.column()); switch (columnIndex) { case MiscTableModel::ColumnIndex::Name: - if (value.canConvert(QVariant::String)) { - MainWindow::instance().doOrRedoUpdate(*row, - TYPE_INFO(Misc, NamedEntity, name), - value.toString(), - tr("Change Misc Name")); - } else { - return false; - } - break; case MiscTableModel::ColumnIndex::Type: - if (!value.canConvert(QVariant::Int)) { - return false; - } - MainWindow::instance().doOrRedoUpdate( - new SimpleUndoableUpdate(*row, - TYPE_INFO(Misc, type), - value.toInt(), - tr("Change Misc Type")) - ); - break; case MiscTableModel::ColumnIndex::Use: - if (!value.canConvert>()) { - return false; - } - MainWindow::instance().doOrRedoUpdate( - new SimpleUndoableUpdate(*row, - TYPE_INFO(Misc, use), - value, - tr("Change Misc Use")) - ); - break; case MiscTableModel::ColumnIndex::Time: - if (!value.canConvert(QVariant::String)) { - return false; - } - MainWindow::instance().doOrRedoUpdate( - *row, - TYPE_INFO(Misc, time_min), - Measurement::qStringToSI(value.toString(), - Measurement::PhysicalQuantity::Time, - this->getColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - this->getColumnInfo(columnIndex).getForcedRelativeScale()).quantity(), - tr("Change Misc Time") - ); - break; - case MiscTableModel::ColumnIndex::Inventory: - if (!value.canConvert(QVariant::String)) { - return false; - } - MainWindow::instance().doOrRedoUpdate( - *row, - TYPE_INFO(Misc, NamedEntityWithInventory, inventory), - Measurement::qStringToSI(value.toString(), - physicalQuantity, - this->getColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - this->getColumnInfo(columnIndex).getForcedRelativeScale()).quantity(), - tr("Change Misc Inventory Amount") - ); - break; - case MiscTableModel::ColumnIndex::Amount: - if (!value.canConvert(QVariant::String)) { - return false; - } - MainWindow::instance().doOrRedoUpdate( - *row, - TYPE_INFO(Misc, amount), - Measurement::qStringToSI(value.toString(), - physicalQuantity, - this->getColumnInfo(columnIndex).getForcedSystemOfMeasurement(), - this->getColumnInfo(columnIndex).getForcedRelativeScale()).quantity(), - tr("Change Misc Amount") - ); - break; case MiscTableModel::ColumnIndex::IsWeight: - if (!value.canConvert(QVariant::Bool)) { - return false; - } - MainWindow::instance().doOrRedoUpdate(*row, - TYPE_INFO(Misc, amountIsWeight), - value.toBool(), - tr("Change Misc Amount Type")); - break; - default: - return false; + return this->writeDataToModel(index, value, role); + + case MiscTableModel::ColumnIndex::Amount: + case MiscTableModel::ColumnIndex::Inventory: + return this->writeDataToModel(index, value, role, physicalQuantity); + + // No default case as we want the compiler to warn us if we missed one } emit dataChanged(index, index); @@ -409,128 +159,9 @@ void MiscTableModel::changedInventory(int invKey, BtStringConst const & property return; } -void MiscTableModel::changed(QMetaProperty prop, [[maybe_unused]] QVariant val) { - Misc * miscSender = qobject_cast(sender()); - if (miscSender) { - int ii = this->findIndexOf(miscSender); - if (ii >= 0) { - emit dataChanged(QAbstractItemModel::createIndex(ii, 0), - QAbstractItemModel::createIndex(ii, this->columnCount() - 1) ); - } - return; - } - - // See if sender is our recipe. - Recipe* recSender = qobject_cast(sender()); - if (recSender && recSender == this->recObs) { - if (QString(prop.name()) == PropertyNames::Recipe::miscIds) { - this->removeAll(); - this->addMiscs(this->recObs->getAll()); - } - if (rowCount() > 0) { - emit headerDataChanged( Qt::Vertical, 0, rowCount()-1 ); - } - return; - } - - return; -} - -//======================CLASS MiscItemDelegate=========================== +// Insert the boiler-plate stuff that we cannot do in TableModelBase +TABLE_MODEL_COMMON_CODE(Misc, misc) +//=============================================== CLASS MiscItemDelegate =============================================== -MiscItemDelegate::MiscItemDelegate(QObject* parent) : QItemDelegate(parent) { - return; -} - -QWidget* MiscItemDelegate::createEditor(QWidget *parent, - QStyleOptionViewItem const & /*option*/, - QModelIndex const & index) const { - auto const columnIndex = static_cast(index.column()); - if (columnIndex == MiscTableModel::ColumnIndex::Type) { - BtComboBox * typeBox = new BtComboBox(parent); - BT_COMBO_BOX_INIT_NOMV(MiscItemDelegate::createEditor, typeBox, Misc, type); - typeBox->setMinimumWidth(typeBox->minimumSizeHint().width()); - typeBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); - return typeBox; - } - - if (columnIndex == MiscTableModel::ColumnIndex::Use) { - BtComboBox * useBox = new BtComboBox(parent); - BT_COMBO_BOX_INIT_NOMV(MiscItemDelegate::createEditor, useBox, Misc, use); - useBox->setMinimumWidth(useBox->minimumSizeHint().width()); - useBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); - return useBox; - } - - if (columnIndex == MiscTableModel::ColumnIndex::IsWeight) { - QComboBox *box = new QComboBox(parent); - - box->addItem(tr("Weight")); - box->addItem(tr("Volume")); - box->setMinimumWidth(box->minimumSizeHint().width()); - box->setSizeAdjustPolicy(QComboBox::AdjustToContents); - return box; - } - - return new QLineEdit(parent); -} - -void MiscItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { - auto const columnIndex = static_cast(index.column()); - - if (columnIndex == MiscTableModel::ColumnIndex::Type || - columnIndex == MiscTableModel::ColumnIndex::Use) { - BtComboBox * box = qobject_cast(editor); - if (!box) { - return; - } - if (columnIndex == MiscTableModel::ColumnIndex::Type) { - box->setValue(static_cast(index.model()->data(index, Qt::UserRole).toInt())); - } else { - box->setValue(Optional::fromOptInt(index.model()->data(index, Qt::UserRole).value >())); - } - } else if (columnIndex == MiscTableModel::ColumnIndex::IsWeight) { - QComboBox* box = qobject_cast(editor); - if (!box) { - return; - } - box->setCurrentIndex(index.model()->data(index, Qt::UserRole).toInt()); - } else { - QLineEdit* line = static_cast(editor); - - line->setText(index.model()->data(index, Qt::DisplayRole).toString()); - } - - return; -} - -void MiscItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { - auto const columnIndex = static_cast(index.column()); -/// ××× AND OBVIOUSLY THIS IS WRONG TOO! - if (columnIndex == MiscTableModel::ColumnIndex::Type || - columnIndex == MiscTableModel::ColumnIndex::Use || - columnIndex == MiscTableModel::ColumnIndex::IsWeight) { - QComboBox* box = static_cast(editor); - int ndx = box->currentIndex(); - int curr = model->data(index, Qt::UserRole).toInt(); - - if (curr != ndx) { - model->setData(index, ndx, Qt::EditRole); - } - } else { - QLineEdit* line = static_cast(editor); - - if (line->isModified()) { - model->setData(index, line->text(), Qt::EditRole); - } - } - - return; -} - -void MiscItemDelegate::updateEditorGeometry(QWidget * editor, - QStyleOptionViewItem const & option, - [[maybe_unused]] QModelIndex const & index) const { - editor->setGeometry(option.rect); - return; -} +// Insert the boiler-plate stuff that we cannot do in ItemDelegate +ITEM_DELEGATE_COMMON_CODE(Misc) diff --git a/src/tableModels/MiscTableModel.h b/src/tableModels/MiscTableModel.h index 5f3f868b..e1c4bc5d 100644 --- a/src/tableModels/MiscTableModel.h +++ b/src/tableModels/MiscTableModel.h @@ -21,37 +21,24 @@ #define TABLEMODELS_MISCTABLEMODEL_H #pragma once -#include - -#include #include -#include #include #include -#include #include #include -#include "measurement/Unit.h" -#include "model/Misc.h" #include "tableModels/BtTableModelInventory.h" +#include "tableModels/ItemDelegate.h" +#include "tableModels/TableModelBase.h" -// Forward declarations. class BtStringConst; -class MiscItemDelegate; class Misc; -class MiscTableWidget; class Recipe; -/*! - * \class MiscTableModel - * - * \brief Table model for a list of miscs. - */ -class MiscTableModel : public BtTableModelInventory, public BtTableModelData { - Q_OBJECT - -public: +// You have to get the order of everything right with traits classes, but the end result is that we can refer to +// MiscTableModel::ColumnIndex::Type etc. +class MiscTableModel; +template <> struct TableModelTraits { enum class ColumnIndex { Name , Type , @@ -61,66 +48,31 @@ class MiscTableModel : public BtTableModelInventory, public BtTableModelData > miscs); - //! \brief Clear the model. - void removeAll(); - - //! \brief Reimplemented from QAbstractTableModel - virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; - //! \brief Reimplemented from QAbstractTableModel - virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; - //! \brief Reimplemented from QAbstractTableModel - virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - //! \brief Reimplemented from QAbstractTableModel - virtual Qt::ItemFlags flags(const QModelIndex& index ) const; - //! \brief Reimplemented from QAbstractTableModel - virtual bool setData( const QModelIndex& index, const QVariant& value, int role = Qt::EditRole ); - bool remove(std::shared_ptr misc); - -public slots: - //! \brief Add a misc to the model. - void addMisc(int miscId); - //! \brief Remove a misc from the model. - void removeMisc(int miscId, std::shared_ptr object); +/*! + * \class MiscTableModel + * + * \brief Table model for a list of miscs. + */ +class MiscTableModel : public BtTableModelInventory, public TableModelBase { + Q_OBJECT -private slots: - //! \brief Catch changes to Recipe, Database, and Misc. - void changed(QMetaProperty, QVariant); - void changedInventory(int invKey, BtStringConst const & propertyName); + TABLE_MODEL_COMMON_DECL(Misc) }; - +//=============================================== CLASS MiscItemDelegate =============================================== /*! * \class MiscItemDelegate * * \brief Item delegate for misc tables. * \sa MiscTableModel */ -class MiscItemDelegate : public QItemDelegate { +class MiscItemDelegate : public QItemDelegate, + public ItemDelegate { Q_OBJECT -public: - MiscItemDelegate(QObject* parent = nullptr); - - // Inherited functions. - virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; - virtual void setEditorData(QWidget *editor, const QModelIndex &index) const; - virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; - virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; - -private: + ITEM_DELEGATE_COMMON_DECL(Misc) }; #endif diff --git a/src/tableModels/TableModelBase.h b/src/tableModels/TableModelBase.h index 8bf4f80c..06eba864 100644 --- a/src/tableModels/TableModelBase.h +++ b/src/tableModels/TableModelBase.h @@ -20,6 +20,8 @@ #include #include +#include "database/ObjectStoreTyped.h" +#include "database/ObjectStoreWrapper.h" #include "MainWindow.h" #include "measurement/Measurement.h" #include "tableModels/BtTableModel.h" @@ -40,16 +42,16 @@ struct TableModelTraits; /** * \brief See comment in tableModels/BtTableModel.h for more info on inheritance structure * - * Classes inheriting from this one need to declare the following functions which are then implemented by - * including the TABLE_MODEL_COMMON_CODE in the .cpp file: - * ColumnInfo const & getColumnInfo(ColumnIndex const columnIndex) const; + * Classes inheriting from this one need to include the TABLE_MODEL_COMMON_DECL macro in their header file and + * the TABLE_MODEL_COMMON_CODE macro in their .cpp file: * * Subclasses also need to declare and implement the following functions (with the obvious substitutions for NS): * void added (std::shared_ptr item); // Updates any global info as a result of item being added * void removed(std::shared_ptr item); // Updates any global info as a result of item being removed - * void removedAll(); // Updates any global info as a result of all items being removed - * // (Better than repeated calls to removed() because avoids - * // rounding errors on running totals.) + * void updateTotals(); // Updates any global info, eg as a result of an item changed or + * // all items being removed. (Better in latter case than repeated + * // calls to removed() because avoids rounding errors on running + * // totals.) */ template class TableModelBase { @@ -80,6 +82,49 @@ class TableModelBase { return m_derived->BtTableModel::getColumnInfo(static_cast(columnIndex)); } + /** + * \brief Observe a recipe's list of NE (hops, fermentables. etc_ + */ + void observeRecipe(Recipe * rec) { + if (m_derived->recObs) { + qDebug() << + Q_FUNC_INFO << "Unobserve Recipe #" << m_derived->recObs->key() << "(" << m_derived->recObs->name() << ")"; + m_derived->disconnect(m_derived->recObs, nullptr, m_derived, nullptr); + this->removeAll(); + } + + m_derived->recObs = rec; + if (m_derived->recObs) { + qDebug() << + Q_FUNC_INFO << "Observe Recipe #" << m_derived->recObs->key() << "(" << m_derived->recObs->name() << ")"; + m_derived->connect(m_derived->recObs, &NamedEntity::changed, m_derived, &Derived::changed); + + // TBD: Commented out version doesn't compile on GCC + // this->addItems(m_derived->recObs->getAll()); + this->addItems(rec->getAll()); + } + return; + } + + /** + * \brief If true, we model the database's list of NE (hops, fermentables. etc_. + */ + void observeDatabase(bool val) { + if (val) { + // Observing a database and a recipe are mutually exclusive. + this->observeRecipe(nullptr); + this->removeAll(); + m_derived->connect(&ObjectStoreTyped::getInstance(), &ObjectStoreTyped::signalObjectInserted, m_derived, &Derived::addItem); + m_derived->connect(&ObjectStoreTyped::getInstance(), &ObjectStoreTyped::signalObjectDeleted , m_derived, &Derived::removeItem); + this->addItems(ObjectStoreWrapper::getAll()); + } else { + m_derived->disconnect(&ObjectStoreTyped::getInstance(), nullptr, m_derived, nullptr); + this->removeAll(); + } + return; + + } + /** * \brief Return the \c i-th row in the model. * Returns \c nullptr on failure. @@ -105,7 +150,7 @@ class TableModelBase { for (auto ii : items) { if (!recipe && (ii->deleted() || !ii->display())) { - continue; + continue; } if (!this->rows.contains(ii) ) { tmp.append(ii); @@ -159,6 +204,30 @@ class TableModelBase { } void add(std::shared_ptr item) { + qDebug() << Q_FUNC_INFO << item->name(); + + // Check to see if it's already in the list + if (this->rows.contains(item)) { + return; + } + + // If we are observing the database, ensure that the item is undeleted and fit to display. + if (m_derived->recObs == nullptr && (item->deleted() || !item->display())) { + return; + } + + // If we are watching a Recipe and the new item does not belong to it then there is nothing for us to do + if (m_derived->recObs) { + Recipe * recipeOfNewItem = item->getOwningRecipe(); + if (recipeOfNewItem && m_derived->recObs->key() != recipeOfNewItem->key()) { + qDebug() << + Q_FUNC_INFO << "Ignoring signal about new" << NE::staticMetaObject.className() << "#" << item->key() << + "as it belongs to Recipe #" << recipeOfNewItem->key() << "and we are watching Recipe #" << + m_derived->recObs->key(); + return; + } + } + int size = this->rows.size(); m_derived->beginInsertRows(QModelIndex(), size, size); this->rows.append(item); @@ -190,6 +259,33 @@ class TableModelBase { protected: + /** + * \brief Watch all the \c NE for changes. + */ + void addItems(QList< std::shared_ptr > items) { + qDebug() << + Q_FUNC_INFO << "Add up to " << items.size() << "of" << NE::staticMetaObject.className() << + "to existing list of" << this->rows.size(); + + auto tmp = this->removeDuplicates(items, m_derived->recObs); + + qDebug() << Q_FUNC_INFO << "After de-duping, adding " << tmp.size() << "of" << NE::staticMetaObject.className(); + + int size = this->rows.size(); + if (size + tmp.size()) { + m_derived->beginInsertRows(QModelIndex(), size, size + tmp.size() - 1); + this->rows.append(tmp); + + for (auto item : tmp) { + m_derived->connect(item.get(), &NamedEntity::changed, m_derived, &Derived::changed); + m_derived->added(item); + } + + m_derived->endInsertRows(); + } + return; + } + /** * \brief Clear the model. */ @@ -200,10 +296,10 @@ class TableModelBase { while (!this->rows.empty()) { auto item = this->rows.takeLast(); m_derived->disconnect(item.get(), nullptr, m_derived, nullptr); - //m_derived->removed(item); // Shouldn't be necessary as we call removedAll() below + //m_derived->removed(item); // Shouldn't be necessary as we call updateTotals() below } m_derived->endRemoveRows(); - m_derived->removedAll(); + m_derived->updateTotals(); } return; } @@ -280,20 +376,34 @@ class TableModelBase { TypeInfo const & typeInfo = columnInfo.typeInfo; /// qDebug() << Q_FUNC_INFO << columnInfo.columnFqName << "TypeInfo is" << typeInfo; + // First handle the cases where ItemDelegate::readDataFromModel wants "raw" data + if (std::holds_alternative(*typeInfo.fieldType)) { + auto const nonPhysicalQuantity = std::get(*typeInfo.fieldType); + if (nonPhysicalQuantity == NonPhysicalQuantity::Enum || + nonPhysicalQuantity == NonPhysicalQuantity::Bool) { + if (role != Qt::DisplayRole) { + return modelData; + } + } + } + + // Next handle unset optional values bool hasValue = false; if (typeInfo.isOptional()) { + // This does the right thing even for enums - see comment in utils/OptionalHelpers.cpp Optional::removeOptionalWrapper(modelData, typeInfo, &hasValue); if (!hasValue) { return QString{""}; } } + // Now we know: + // - the value is either not optional or is optional and set + // - we need to return a string if (std::holds_alternative(*typeInfo.fieldType)) { auto const nonPhysicalQuantity = std::get(*typeInfo.fieldType); if (nonPhysicalQuantity == NonPhysicalQuantity::Enum) { - if (role != Qt::DisplayRole) { - return modelData; - } + Q_ASSERT(role == Qt::DisplayRole); Q_ASSERT(columnInfo.extras); Q_ASSERT(std::holds_alternative(*columnInfo.extras)); @@ -306,9 +416,7 @@ class TableModelBase { } if (nonPhysicalQuantity == NonPhysicalQuantity::Bool) { - if (role != Qt::DisplayRole) { - return modelData; - } + Q_ASSERT(role == Qt::DisplayRole); Q_ASSERT(columnInfo.extras); Q_ASSERT(std::holds_alternative(*columnInfo.extras)); @@ -396,10 +504,19 @@ class TableModelBase { * \brief Child classes should call this from their \c setData() member function (overriding * \c QAbstractTableModel::setData()) to write data for any column that does not require special handling * + * \param physicalQuantity Needs to be supplied if and only if the column type is + * \c Measurement::Mixed2PhysicalQuantities + * * \return \c true if successful, \c false otherwise */ - bool writeDataToModel(QModelIndex const & index, QVariant const & value, int const role) const { -// qDebug().noquote() << Q_FUNC_INFO << "role = " << role << Logging::getStackTrace(); + bool writeDataToModel(QModelIndex const & index, + QVariant const & value, + int const role, + std::optional physicalQuantity = std::nullopt) const { + if (role != Qt::EditRole) { +// qCritical().noquote() << Q_FUNC_INFO << "Unexpected role: " << role << Logging::getStackTrace(); + return false; + } auto row = this->rows[index.row()]; auto const columnIndex = static_cast(index.column()); auto const & columnInfo = this->get_ColumnInfo(columnIndex); @@ -419,23 +536,42 @@ class TableModelBase { Q_ASSERT(value.canConvert(QVariant::String)); if (std::holds_alternative(*typeInfo.fieldType)) { - Measurement::Amount amount = - Measurement::qStringToSI(value.toString(), - std::get(*typeInfo.fieldType), - columnInfo.getForcedSystemOfMeasurement(), - columnInfo.getForcedRelativeScale()); - if (typeInfo.typeIndex == typeid(double)) { - processedValue = QVariant::fromValue(amount.quantity()); - } else { - processedValue = QVariant::fromValue(amount); - } + // It's a coding error if physicalQuantity was supplied - because it's known in advance from the field type + Q_ASSERT(!physicalQuantity); + // Might seem a bit odd to overwrite the parameter here, but it allows us to share most of the code for + // PhysicalQuantity and Mixed2PhysicalQuantities + physicalQuantity = std::get(*typeInfo.fieldType); + } else { + // This should be the only possibility left + Q_ASSERT(std::holds_alternative(*typeInfo.fieldType)); + // It's a coding error if physicalQuantity was not supplied + Q_ASSERT(physicalQuantity); + } + Measurement::Amount amount = + Measurement::qStringToSI(value.toString(), + *physicalQuantity, + columnInfo.getForcedSystemOfMeasurement(), + columnInfo.getForcedRelativeScale()); + if (typeInfo.typeIndex == typeid(double)) { + processedValue = QVariant::fromValue(amount.quantity()); } else { - // We need Derived to have handled the case where its a Mixed2PhysicalQuantities such as MassOrVolumeAmt, - // so it's a coding error if we get here. - qCritical().noquote() << - Q_FUNC_INFO << "Unexpected type" << typeInfo << ". Call stack:" << Logging::getStackTrace(); - Q_ASSERT(false); + // Comments above in readDataFromModel apply equally here. You can cast between MassOrVolumeAmt and + // Measurement::Amount, but not between QVariant and QVariant, so + // we have to do the casting before we wrap. + if ( typeInfo.typeIndex == typeid(MassOrVolumeAmt )) { + processedValue = QVariant::fromValue(static_cast(amount)); + } else if (typeInfo.typeIndex == typeid(MassOrVolumeConcentrationAmt)) { + processedValue = QVariant::fromValue(static_cast(amount)); + } else if (typeInfo.typeIndex == typeid(Measurement::Amount )) { + processedValue = QVariant::fromValue( amount ); + } else { + // It's a coding error if we get here + qCritical() << + Q_FUNC_INFO << columnInfo.columnFqName << "Don't know how to parse" << columnInfo.propertyName << + "TypeInfo:" << typeInfo << ", value:" << value << ", amount:" << amount; + Q_ASSERT(false); + } } } @@ -458,4 +594,97 @@ class TableModelBase { QList< std::shared_ptr > rows; }; +/** + * \brief Derived classes should include this in their header file, right after Q_OBJECT + * + * Note we have to be careful about comment formats in macro definitions + */ +#define TABLE_MODEL_COMMON_DECL(NeName) \ + public: \ + NeName##TableModel(QTableView * parent = nullptr, bool editable = true); \ + virtual ~NeName##TableModel(); \ + \ + /* This block of functions is called from the TableModelBase class */ \ + void added (std::shared_ptr item); \ + void removed(std::shared_ptr item); \ + void updateTotals(); \ + \ + /** \brief Reimplemented from QAbstractTableModel. */ \ + virtual int rowCount(QModelIndex const & parent = QModelIndex()) const; \ + /** \brief Reimplemented from QAbstractTableModel. */ \ + virtual QVariant data(QModelIndex const & index, int role = Qt::DisplayRole) const; \ + /** \brief Reimplemented from QAbstractTableModel. */ \ + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; \ + /** \brief Reimplemented from QAbstractTableModel. */ \ + virtual Qt::ItemFlags flags(const QModelIndex& index) const; \ + /** \brief Reimplemented from QAbstractTableModel. */ \ + virtual bool setData(QModelIndex const & index, QVariant const & value, int role = Qt::EditRole); \ + \ + public slots: \ + /** \brief Watch \b NeName for changes. */ \ + void addItem(int itemId); \ + \ + void removeItem(int itemId, std::shared_ptr object); \ + \ + /** \brief Catch changes to Recipe, Database, and NeName. NB: Needs to be public, not private, as accessed from \c TableModelBase */ \ + void changed(QMetaProperty, QVariant); \ + \ + /** \brief Catches changes to inventory. NOTE This is not implemented where not relevant (eg \c MashStepTableModel). */ \ + void changedInventory(int invKey, BtStringConst const & propertyName); \ + +/** + * \brief Derived classes should include this in their .cpp file + * + * Note we have to be careful about comment formats in macro definitions + */ +#define TABLE_MODEL_COMMON_CODE(NeName, LcNeName) \ + int NeName##TableModel::rowCount([[maybe_unused]] QModelIndex const & parent) const { \ + return this->rows.size(); \ + } \ + void NeName##TableModel::addItem(int itemId) { \ + auto itemToAdd = ObjectStoreWrapper::getById(itemId); \ + if (!itemToAdd) { \ + /* Not sure this should ever happen in practice, but, if there ever is no item with the */ \ + /* specified ID, there's not a lot we can do. */ \ + qWarning() << \ + Q_FUNC_INFO << "Received signal that" << NeName::staticMetaObject.className() << "ID" << \ + itemId << "added, but unable to retrieve the" << NeName::staticMetaObject.className(); \ + return; \ + } \ + this->add(itemToAdd); \ + return; \ + } \ + void NeName##TableModel::removeItem([[maybe_unused]] int itemId, std::shared_ptr object) { \ + this->remove(std::static_pointer_cast(object)); \ + return; \ + } \ + void NeName##TableModel::changed(QMetaProperty prop, [[maybe_unused]] QVariant val) { \ + /* Is sender one of our items? */ \ + NeName* itemSender = qobject_cast(sender()); \ + if (itemSender) { \ + int ii = this->findIndexOf(itemSender); \ + if (ii < 0) { \ + return; \ + } \ + \ + this->updateTotals(); \ + emit dataChanged(QAbstractItemModel::createIndex(ii, 0), \ + QAbstractItemModel::createIndex(ii, this->columnCount() - 1)); \ + emit headerDataChanged(Qt::Vertical, ii, ii); \ + return; \ + } \ + \ + /* See if our recipe gained or lost items. */ \ + Recipe* recSender = qobject_cast(sender()); \ + if (recSender && recSender == recObs && prop.name() == PropertyNames::Recipe::LcNeName##Ids) { \ + this->removeAll(); \ + this->addItems(this->recObs->getAll()); \ + if (rowCount() > 0) { \ + emit headerDataChanged(Qt::Vertical, 0, rowCount() - 1); \ + } \ + } \ + \ + return; \ + } \ + #endif diff --git a/src/undoRedo/SimpleUndoableUpdate.cpp b/src/undoRedo/SimpleUndoableUpdate.cpp index 3df707f4..bd3a682f 100644 --- a/src/undoRedo/SimpleUndoableUpdate.cpp +++ b/src/undoRedo/SimpleUndoableUpdate.cpp @@ -62,11 +62,11 @@ bool SimpleUndoableUpdate::undoOrRedo(bool const isUndo) { bool success = this->updatee.setProperty(*this->typeInfo.propertyName, isUndo ? this->oldValue : this->newValue); // It's a coding error if we tried to update a non-existent property - Q_ASSERT(success && "Trying to update non-existent property"); if (!success) { qCritical() << - Q_FUNC_INFO << "Could not" << (isUndo ? "undo" : "redo") << " update of " << + Q_FUNC_INFO << "Could not" << (isUndo ? "undo" : "(re)do") << " update of " << this->updatee.metaObject()->className() << "property" << this->typeInfo.propertyName; } + Q_ASSERT(success && "Trying to update non-existent property"); return success; } diff --git a/src/utils/OptionalHelpers.cpp b/src/utils/OptionalHelpers.cpp index ae3933b5..5f30a74c 100644 --- a/src/utils/OptionalHelpers.cpp +++ b/src/utils/OptionalHelpers.cpp @@ -22,6 +22,8 @@ #include "utils/TypeLookup.h" void Optional::removeOptionalWrapper(QVariant & propertyValue, TypeInfo const & typeInfo, bool * hasValue) { + // It's a coding error to call this for a non-optional type + Q_ASSERT(typeInfo.isOptional()); // Most common field type is double, so check it first // QString is also pretty common, but it's never optional because an empty string suffices for "no data" @@ -30,9 +32,16 @@ void Optional::removeOptionalWrapper(QVariant & propertyValue, TypeInfo const & if (typeInfo.typeIndex == typeid(unsigned int)) { removeOptionalWrapper(propertyValue, hasValue); return; } if (typeInfo.typeIndex == typeid(bool )) { removeOptionalWrapper(propertyValue, hasValue); return; } + // If the native type is an enum, then the QVariant should actually contain an int + if (typeInfo.isEnum() && propertyValue.canConvert>()) { + removeOptionalWrapper(propertyValue, hasValue); + return; + } + // It's a coding error if we reached here qCritical().noquote() << - Q_FUNC_INFO << "Unexpected type" << typeInfo << ". Call stack:" << Logging::getStackTrace(); + Q_FUNC_INFO << "Unexpected type" << typeInfo << ", propertyValue" << propertyValue << ". Call stack:" << + Logging::getStackTrace(); Q_ASSERT(false); return; diff --git a/translations/bt_ca.ts b/translations/bt_ca.ts index 04312164..50b22073 100644 --- a/translations/bt_ca.ts +++ b/translations/bt_ca.ts @@ -1386,46 +1386,10 @@ Log file may contain more details. Addition Addició - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Tipus de quantitat - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Volum @@ -1679,35 +1643,35 @@ Log file may contain more details. HopItemDelegate Boil - Bullit + Bullit Dry Hop - «Dry Hop» + «Dry Hop» Mash - Maceració + Maceració First Wort - Primer most + Primer most Aroma - Aroma + Aroma Leaf - Flor + Flor Pellet - Pèl·let + Pèl·let Plug - «Plug» + «Plug» @@ -1740,34 +1704,6 @@ Log file may contain more details. Inventory Existències - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2499,11 +2435,11 @@ Log file may contain more details. Weight - Massa + Massa Volume - Volum + Volum @@ -2537,31 +2473,18 @@ Log file may contain more details. Existències - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Volum - Change Misc Amount - + Weight + Massa + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3558,15 +3481,15 @@ Log file may contain more details. Late - Més tard + Més tard Not mashed - No macerat + No macerat Mashed - Macerat + Macerat Weight diff --git a/translations/bt_cs.ts b/translations/bt_cs.ts index b197e110..52ba7d45 100644 --- a/translations/bt_cs.ts +++ b/translations/bt_cs.ts @@ -1315,46 +1315,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Druh množství - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Objem @@ -1604,35 +1568,35 @@ Log file may contain more details. HopItemDelegate Boil - Chmelovar + Chmelovar Dry Hop - Dry hop + Dry hop Mash - Do vystírky (mash hop) + Do vystírky (mash hop) First Wort - Při vyslazování (first wort) + Při vyslazování (first wort) Aroma - Aromatický + Aromatický Leaf - Hlávkový + Hlávkový Pellet - Granulovaný + Granulovaný Plug - Lisovaný + Lisovaný @@ -1665,34 +1629,6 @@ Log file may contain more details. Inventory Sklad - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2424,11 +2360,11 @@ Log file may contain more details. Weight - Hmotnost + Hmotnost Volume - Objem + Objem @@ -2462,31 +2398,18 @@ Log file may contain more details. Sklad - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Objem - Change Misc Amount - + Weight + Hmotnost + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3483,15 +3406,11 @@ Log file may contain more details. Late - Pozdní - - - Not mashed - + Pozdní Mashed - Šrotovaný + Šrotovaný Weight diff --git a/translations/bt_de.ts b/translations/bt_de.ts index 5194825f..35e5d471 100644 --- a/translations/bt_de.ts +++ b/translations/bt_de.ts @@ -1354,46 +1354,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Mengenangabe - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Volumen @@ -1647,35 +1611,35 @@ Log file may contain more details. HopItemDelegate Boil - Kochen + Kochen Dry Hop - Stopfhopfen + Stopfhopfen Mash - Maische + Maische First Wort - Vorderwürze + Vorderwürze Aroma - Aroma + Aroma Leaf - Blatt + Blatt Pellet - Pellet + Pellet Plug - Presshopfen + Presshopfen @@ -1708,34 +1672,6 @@ Log file may contain more details. Inventory Lagerbestand - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2467,11 +2403,11 @@ Log file may contain more details. Weight - Gewicht + Gewicht Volume - Volumen + Volumen @@ -2505,31 +2441,18 @@ Log file may contain more details. Lagerbestand - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Volumen - Change Misc Amount - + Weight + Gewicht + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3526,15 +3449,11 @@ Log file may contain more details. Late - Spät - - - Not mashed - + Spät Mashed - Gemaischt + Gemaischt Weight diff --git a/translations/bt_el.ts b/translations/bt_el.ts index 86a28149..fad65860 100644 --- a/translations/bt_el.ts +++ b/translations/bt_el.ts @@ -1315,46 +1315,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Μονάδα μέτρησης - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Όγκος @@ -1608,35 +1572,35 @@ Log file may contain more details. HopItemDelegate Boil - Στο Βράσιμο + Στο Βράσιμο Dry Hop - στον κάδο ζύμωσης + στον κάδο ζύμωσης Mash - Στο σκεύος σακχ/σης + Στο σκεύος σακχ/σης First Wort - Πρίν το βράσιμο + Πρίν το βράσιμο Aroma - Άρωμα + Άρωμα Leaf - σε φύλλα + σε φύλλα Pellet - Σφαιρίδια + Σφαιρίδια Plug - Ανθός + Ανθός @@ -1669,34 +1633,6 @@ Log file may contain more details. Inventory Ευρετήριο ειδών - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2428,11 +2364,11 @@ Log file may contain more details. Weight - Βάρος + Βάρος Volume - Όγκος + Όγκος @@ -2466,31 +2402,18 @@ Log file may contain more details. Ευρετήριο ειδών - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Όγκος - Change Misc Amount - + Weight + Βάρος + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3487,15 +3410,11 @@ Log file may contain more details. Late - Στο τέλος - - - Not mashed - + Στο τέλος Mashed - στο σκεύος σακχαροποίησης + στο σκεύος σακχαροποίησης Weight diff --git a/translations/bt_en.ts b/translations/bt_en.ts index 19e48053..2b3e04e8 100644 --- a/translations/bt_en.ts +++ b/translations/bt_en.ts @@ -857,46 +857,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume @@ -1056,41 +1020,6 @@ Log file may contain more details. - - HopItemDelegate - - Boil - - - - Dry Hop - - - - Mash - - - - First Wort - - - - Aroma - - - - Leaf - - - - Pellet - - - - Plug - - - HopTableModel @@ -1121,34 +1050,6 @@ Log file may contain more details. Inventory - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -1715,17 +1616,6 @@ Log file may contain more details. - - MiscItemDelegate - - Weight - - - - Volume - - - MiscTableModel @@ -1757,31 +1647,18 @@ Log file may contain more details. - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount + Volume - Change Misc Amount + Weight + + + NE - Change Misc Amount Type + Change %1 %2 @@ -2652,18 +2529,6 @@ Log file may contain more details. Carbonation Mass Per Volume - - Late - - - - Not mashed - - - - Mashed - - Weight diff --git a/translations/bt_es.ts b/translations/bt_es.ts index 1c629d3b..4effdadb 100644 --- a/translations/bt_es.ts +++ b/translations/bt_es.ts @@ -1378,46 +1378,10 @@ Log file may contain more details. Addition Adición - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Tipo de Cantidad - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume @@ -1667,35 +1631,35 @@ Log file may contain more details. HopItemDelegate Boil - Hervir + Hervir Dry Hop - Dry Hop + Dry Hop Mash - Maceración + Maceración First Wort - Mosto Inicial + Mosto Inicial Aroma - Aroma + Aroma Leaf - Flor + Flor Pellet - Pellet + Pellet Plug - Tableta + Tableta @@ -1728,34 +1692,6 @@ Log file may contain more details. Inventory Inventario - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2487,11 +2423,11 @@ Log file may contain more details. Weight - Peso + Peso Volume - Volumen + Volumen @@ -2525,31 +2461,18 @@ Log file may contain more details. Inventario - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount + Volume - Change Misc Amount + Weight + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3544,17 +3467,9 @@ Log file may contain more details. Carbonation Mass Per Volume - - Late - - - - Not mashed - - Mashed - Macerado + Macerado Weight diff --git a/translations/bt_et.ts b/translations/bt_et.ts index eb8f0a77..cdb724aa 100644 --- a/translations/bt_et.ts +++ b/translations/bt_et.ts @@ -908,46 +908,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume @@ -1107,41 +1071,6 @@ Log file may contain more details. - - HopItemDelegate - - Boil - - - - Dry Hop - - - - Mash - - - - First Wort - - - - Aroma - - - - Leaf - - - - Pellet - - - - Plug - - - HopTableModel @@ -1172,34 +1101,6 @@ Log file may contain more details. Inventory - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -1766,17 +1667,6 @@ Log file may contain more details. - - MiscItemDelegate - - Weight - - - - Volume - - - MiscTableModel @@ -1808,31 +1698,18 @@ Log file may contain more details. - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount + Volume - Change Misc Amount + Weight + + + NE - Change Misc Amount Type + Change %1 %2 @@ -2703,18 +2580,6 @@ Log file may contain more details. Carbonation Mass Per Volume - - Late - - - - Not mashed - - - - Mashed - - Weight diff --git a/translations/bt_eu.ts b/translations/bt_eu.ts index 5264f1cb..268f7686 100644 --- a/translations/bt_eu.ts +++ b/translations/bt_eu.ts @@ -916,46 +916,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume @@ -1115,41 +1079,6 @@ Log file may contain more details. - - HopItemDelegate - - Boil - - - - Dry Hop - - - - Mash - - - - First Wort - - - - Aroma - - - - Leaf - - - - Pellet - - - - Plug - - - HopTableModel @@ -1180,34 +1109,6 @@ Log file may contain more details. Inventory - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -1774,17 +1675,6 @@ Log file may contain more details. - - MiscItemDelegate - - Weight - - - - Volume - - - MiscTableModel @@ -1816,31 +1706,18 @@ Log file may contain more details. - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount + Volume - Change Misc Amount + Weight + + + NE - Change Misc Amount Type + Change %1 %2 @@ -2711,18 +2588,6 @@ Log file may contain more details. Carbonation Mass Per Volume - - Late - - - - Not mashed - - - - Mashed - - Weight diff --git a/translations/bt_fr.ts b/translations/bt_fr.ts index 4e1752bf..a115ad15 100644 --- a/translations/bt_fr.ts +++ b/translations/bt_fr.ts @@ -1386,46 +1386,10 @@ Log file may contain more details. Addition Ajout - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Type de quantité - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Volume @@ -1683,35 +1647,35 @@ Log file may contain more details. HopItemDelegate Boil - Ébullition + Ébullition Dry Hop - Houblonnage à cru + Houblonnage à cru Mash - Empâtage + Empâtage First Wort - Pré-ébullition + Pré-ébullition Aroma - Arômatique + Arômatique Leaf - Cône + Cône Pellet - Pellet + Pellet Plug - Plug + Plug @@ -1744,34 +1708,6 @@ Log file may contain more details. Inventory Inventaire - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2503,11 +2439,11 @@ Log file may contain more details. Weight - Poids + Poids Volume - Volume + Volume @@ -2541,31 +2477,18 @@ Log file may contain more details. Inventaire - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Volume - Change Misc Amount - + Weight + Poids + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3562,15 +3485,15 @@ Log file may contain more details. Late - Tardif + Tardif Not mashed - Non empâté + Non empâté Mashed - Empâté + Empâté Weight diff --git a/translations/bt_gl.ts b/translations/bt_gl.ts index f5d76801..d095d152 100644 --- a/translations/bt_gl.ts +++ b/translations/bt_gl.ts @@ -1053,46 +1053,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume @@ -1259,41 +1223,6 @@ Log file may contain more details. Novo - - HopItemDelegate - - Boil - - - - Dry Hop - - - - Mash - - - - First Wort - - - - Aroma - - - - Leaf - - - - Pellet - - - - Plug - - - HopTableModel @@ -1324,34 +1253,6 @@ Log file may contain more details. Inventory - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -1925,17 +1826,6 @@ Log file may contain more details. Novo - - MiscItemDelegate - - Weight - - - - Volume - - - MiscTableModel @@ -1967,31 +1857,18 @@ Log file may contain more details. - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount + Volume - Change Misc Amount + Weight + + + NE - Change Misc Amount Type + Change %1 %2 @@ -2862,18 +2739,6 @@ Log file may contain more details. Carbonation Mass Per Volume - - Late - - - - Not mashed - - - - Mashed - - Weight diff --git a/translations/bt_hu.ts b/translations/bt_hu.ts index 2ed82e0a..1d5ad8d4 100644 --- a/translations/bt_hu.ts +++ b/translations/bt_hu.ts @@ -1358,46 +1358,10 @@ Log file may contain more details. Addition Hozzáadás - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Mennyiségi egység - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Mennyiség @@ -1655,35 +1619,35 @@ Log file may contain more details. HopItemDelegate Boil - Forralás + Forralás Dry Hop - Hidegkomló + Hidegkomló Mash - Cefre + Cefre First Wort - Színlé + Színlé Aroma - Aroma + Aroma Leaf - leveles + leveles Pellet - Pellet + Pellet Plug - Nagy pellet (komlódugó) + Nagy pellet (komlódugó) @@ -1716,34 +1680,6 @@ Log file may contain more details. Inventory Készlet - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2471,11 +2407,11 @@ Log file may contain more details. Weight - Súly + Súly Volume - Mennyiség + Mennyiség @@ -2509,31 +2445,18 @@ Log file may contain more details. Készlet - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Mennyiség - Change Misc Amount - + Weight + Súly + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3526,15 +3449,11 @@ Log file may contain more details. Late - Később hozzáadott - - - Not mashed - + Később hozzáadott Mashed - Cefrézve + Cefrézve Weight diff --git a/translations/bt_it.ts b/translations/bt_it.ts index 75552890..cd4aceb7 100644 --- a/translations/bt_it.ts +++ b/translations/bt_it.ts @@ -1398,46 +1398,10 @@ Log file may contain more details. Addition Aggiungi - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Tipo di Quantità - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Volume @@ -1683,35 +1647,35 @@ Log file may contain more details. HopItemDelegate Boil - Bollire + Bollire Dry Hop - Dry Hop + Dry Hop Mash - Ammostamento + Ammostamento First Wort - Primo mosto + Primo mosto Aroma - Aroma + Aroma Leaf - foglia + foglia Pellet - Pellet + Pellet Plug - Plug + Plug @@ -1744,34 +1708,6 @@ Log file may contain more details. Inventory Magazzino - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2503,11 +2439,11 @@ Log file may contain more details. Weight - Peso + Peso Volume - Volume + Volume @@ -2541,31 +2477,18 @@ Log file may contain more details. Magazzino - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Volume - Change Misc Amount + Weight + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3562,15 +3485,11 @@ Log file may contain more details. Late - Tardivo + Tardivo Not mashed - Non usato in Mash - - - Mashed - + Non usato in Mash Weight diff --git a/translations/bt_lv.ts b/translations/bt_lv.ts index 55c43ffd..7dfbf582 100644 --- a/translations/bt_lv.ts +++ b/translations/bt_lv.ts @@ -978,46 +978,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume @@ -1184,41 +1148,6 @@ Log file may contain more details. Jauns - - HopItemDelegate - - Boil - - - - Dry Hop - - - - Mash - - - - First Wort - - - - Aroma - - - - Leaf - - - - Pellet - - - - Plug - - - HopTableModel @@ -1249,34 +1178,6 @@ Log file may contain more details. Inventory - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -1850,17 +1751,6 @@ Log file may contain more details. Jauns - - MiscItemDelegate - - Weight - - - - Volume - - - MiscTableModel @@ -1892,31 +1782,18 @@ Log file may contain more details. - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount + Volume - Change Misc Amount + Weight + + + NE - Change Misc Amount Type + Change %1 %2 @@ -2787,18 +2664,6 @@ Log file may contain more details. Carbonation Mass Per Volume - - Late - - - - Not mashed - - - - Mashed - - Weight diff --git a/translations/bt_nb.ts b/translations/bt_nb.ts index e913fb27..f643ba8f 100644 --- a/translations/bt_nb.ts +++ b/translations/bt_nb.ts @@ -1315,46 +1315,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Enhetstype - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Volum @@ -1604,35 +1568,35 @@ Log file may contain more details. HopItemDelegate Boil - Kok + Kok Dry Hop - Tørrhumle + Tørrhumle Mash - Mesk + Mesk First Wort - Skylling + Skylling Aroma - Aroma + Aroma Leaf - Blomst + Blomst Pellet - Pellet + Pellet Plug - Plugg + Plugg @@ -1665,34 +1629,6 @@ Log file may contain more details. Inventory Lagerbeholdning - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2424,11 +2360,11 @@ Log file may contain more details. Weight - Vekt + Vekt Volume - Volum + Volum @@ -2462,31 +2398,18 @@ Log file may contain more details. Lagerbeholdning - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Volum - Change Misc Amount - + Weight + Vekt + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3483,15 +3406,11 @@ Log file may contain more details. Late - Sen - - - Not mashed - + Sen Mashed - Mesket + Mesket Weight diff --git a/translations/bt_nl.ts b/translations/bt_nl.ts index 087090b3..6d55a41f 100644 --- a/translations/bt_nl.ts +++ b/translations/bt_nl.ts @@ -1370,46 +1370,10 @@ Log file may contain more details. Addition Toevoeging - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Hoeveelheid Type - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Volume @@ -1671,35 +1635,35 @@ Log file may contain more details. HopItemDelegate Boil - Koken + Koken Dry Hop - Dry Hop + Dry Hop Mash - Maisch + Maisch First Wort - Eerste Wort + Eerste Wort Aroma - Aroma + Aroma Leaf - Blad + Blad Pellet - Pellet + Pellet Plug - Geperste hop + Geperste hop @@ -1732,34 +1696,6 @@ Log file may contain more details. Inventory Inventaris - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2499,11 +2435,11 @@ Log file may contain more details. Weight - Gewicht + Gewicht Volume - Volume + Volume @@ -2537,31 +2473,18 @@ Log file may contain more details. Inventaris - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Volume - Change Misc Amount - + Weight + Gewicht + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3542,17 +3465,9 @@ Log file may contain more details. Carbonation Mass Per Volume - - Late - - Not mashed - Niet gemaischt - - - Mashed - + Niet gemaischt Weight diff --git a/translations/bt_pl.ts b/translations/bt_pl.ts index e592a7d7..994054c0 100644 --- a/translations/bt_pl.ts +++ b/translations/bt_pl.ts @@ -1303,46 +1303,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Rodzaj kwoty - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Objętość @@ -1580,35 +1544,35 @@ Log file may contain more details. HopItemDelegate Boil - Goryczka + Goryczka Dry Hop - Chmielenie na zimno + Chmielenie na zimno Mash - Do zacierania + Do zacierania First Wort - Chmielenie przedniej brzeczki + Chmielenie przedniej brzeczki Aroma - Aromat + Aromat Leaf - Szyszka + Szyszka Pellet - Granulat + Granulat Plug - Tabletka + Tabletka @@ -1641,34 +1605,6 @@ Log file may contain more details. Inventory Magazyn - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2388,11 +2324,11 @@ Log file may contain more details. Weight - Waga + Waga Volume - Objętość + Objętość @@ -2426,31 +2362,18 @@ Log file may contain more details. Magazyn - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Objętość - Change Misc Amount - + Weight + Waga + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3447,15 +3370,11 @@ Log file may contain more details. Late - Dodawany późno - - - Not mashed - + Dodawany późno Mashed - Zacierany + Zacierany Weight diff --git a/translations/bt_pt.ts b/translations/bt_pt.ts index b4cfdacc..335a0678 100644 --- a/translations/bt_pt.ts +++ b/translations/bt_pt.ts @@ -1354,46 +1354,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Tipo Quantidade - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Volume @@ -1631,35 +1595,35 @@ Log file may contain more details. HopItemDelegate Boil - Fervura + Fervura Dry Hop - Lúpulo Seco + Lúpulo Seco Mash - Mosto + Mosto First Wort - Primeiro mosto + Primeiro mosto Aroma - Aroma + Aroma Leaf - Folha + Folha Pellet - Pastilha + Pastilha Plug - Plugue + Plugue @@ -1692,34 +1656,6 @@ Log file may contain more details. Inventory Inventário - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2451,11 +2387,11 @@ Log file may contain more details. Weight - Peso + Peso Volume - Volume + Volume @@ -2489,31 +2425,18 @@ Log file may contain more details. Inventário - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Volume - Change Misc Amount - + Weight + Peso + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3510,15 +3433,11 @@ Log file may contain more details. Late - Tarde - - - Not mashed - + Tarde Mashed - Mosturação + Mosturação Weight diff --git a/translations/bt_ru.ts b/translations/bt_ru.ts index 32a99af6..e5ad1fef 100644 --- a/translations/bt_ru.ts +++ b/translations/bt_ru.ts @@ -1362,46 +1362,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Объём @@ -1651,35 +1615,35 @@ Log file may contain more details. HopItemDelegate Boil - Кипячение + Кипячение Dry Hop - Сухое охмеление + Сухое охмеление Mash - Затор + Затор First Wort - Первое сусло + Первое сусло Aroma - Аромат + Аромат Leaf - Листовой + Листовой Pellet - Гранулы + Гранулы Plug - Пробка + Пробка @@ -1712,34 +1676,6 @@ Log file may contain more details. Inventory Инвентарь - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2475,11 +2411,11 @@ Log file may contain more details. Weight - Вес + Вес Volume - Объём + Объём @@ -2513,31 +2449,18 @@ Log file may contain more details. Инвентарь - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Объём - Change Misc Amount - + Weight + Вес + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3542,15 +3465,11 @@ Log file may contain more details. Late - Поздно - - - Not mashed - + Поздно Mashed - Затёрто + Затёрто Weight diff --git a/translations/bt_sr.ts b/translations/bt_sr.ts index 919c8554..9f50a305 100644 --- a/translations/bt_sr.ts +++ b/translations/bt_sr.ts @@ -1175,46 +1175,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Тип количине - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Запремина @@ -1452,35 +1416,35 @@ Log file may contain more details. HopItemDelegate Boil - Кључање + Кључање Dry Hop - Суво хмељње + Суво хмељње Mash - Укомљавање + Укомљавање First Wort - Прва сладовина + Прва сладовина Aroma - Арома + Арома Leaf - Лист + Лист Pellet - Грануле + Грануле Plug - Чеп + Чеп @@ -1513,34 +1477,6 @@ Log file may contain more details. Inventory Инвентар - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2248,11 +2184,11 @@ Log file may contain more details. Weight - Тежина + Тежина Volume - Запремина + Запремина @@ -2286,31 +2222,18 @@ Log file may contain more details. Инвентар - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Запремина - Change Misc Amount - + Weight + Тежина + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3287,15 +3210,11 @@ Log file may contain more details. Late - Касно - - - Not mashed - + Касно Mashed - За комљење + За комљење Weight diff --git a/translations/bt_sv.ts b/translations/bt_sv.ts index 21cd7bab..7e963626 100644 --- a/translations/bt_sv.ts +++ b/translations/bt_sv.ts @@ -1370,46 +1370,10 @@ Log file may contain more details. Addition Tillägg - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type Mängdbeteckning - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume Volym @@ -1667,35 +1631,35 @@ Log file may contain more details. HopItemDelegate Boil - Kokning + Kokning Dry Hop - Torrhumling + Torrhumling Mash - Mäsk + Mäsk First Wort - Första Vörten + Första Vörten Aroma - Arom + Arom Leaf - Löv + Löv Pellet - Pellets + Pellets Plug - Puck + Puck @@ -1728,34 +1692,6 @@ Log file may contain more details. Inventory Lager - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2491,11 +2427,11 @@ Log file may contain more details. Weight - Vikt + Vikt Volume - Volym + Volym @@ -2529,31 +2465,18 @@ Log file may contain more details. Lager - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount - + Volume + Volym - Change Misc Amount - + Weight + Vikt + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3528,17 +3451,9 @@ Log file may contain more details. Carbonation Mass Per Volume - - Late - - Not mashed - Mäskas ej - - - Mashed - + Mäskas ej Weight diff --git a/translations/bt_tr.ts b/translations/bt_tr.ts index 2e27df4c..5a99b6c9 100644 --- a/translations/bt_tr.ts +++ b/translations/bt_tr.ts @@ -912,46 +912,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume @@ -1111,41 +1075,6 @@ Log file may contain more details. - - HopItemDelegate - - Boil - - - - Dry Hop - - - - Mash - - - - First Wort - - - - Aroma - - - - Leaf - - - - Pellet - - - - Plug - - - HopTableModel @@ -1176,34 +1105,6 @@ Log file may contain more details. Inventory - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -1770,17 +1671,6 @@ Log file may contain more details. - - MiscItemDelegate - - Weight - - - - Volume - - - MiscTableModel @@ -1812,31 +1702,18 @@ Log file may contain more details. - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount + Volume - Change Misc Amount + Weight + + + NE - Change Misc Amount Type + Change %1 %2 @@ -2707,18 +2584,6 @@ Log file may contain more details. Carbonation Mass Per Volume - - Late - - - - Not mashed - - - - Mashed - - Weight diff --git a/translations/bt_zh.ts b/translations/bt_zh.ts index 420af4c1..3e591ce8 100644 --- a/translations/bt_zh.ts +++ b/translations/bt_zh.ts @@ -1311,46 +1311,10 @@ Log file may contain more details. Addition - - Change Fermentable Name - - - - Change Fermentable Type - - - - Change Fermentable Amount - - - - Change Yield - - - - Change Color - - - - Change Add After Boil - - Amount Type 金额类型MiscTableModel | - - Change Fermentable Inventory Amount - - - - Change Fermentable Amount Type - - - - Change Fermentable Is Mashed - - Volume @@ -1576,35 +1540,35 @@ Log file may contain more details. HopItemDelegate Boil - 熬Boil + 熬Boil Dry Hop - 干Dry Hop + 干Dry Hop Mash - 糖化Mash + 糖化Mash First Wort - 第一次麦芽汁First Wort + 第一次麦芽汁First Wort Aroma - 香气Aroma + 香气Aroma Leaf - 叶Leaf + 叶Leaf Pellet - 丸Pellet + 丸Pellet Plug - 插头Plug + 插头Plug @@ -1637,34 +1601,6 @@ Log file may contain more details. Inventory - - Change Hop Name - - - - Change Hop Alpha % - - - - Change Hop Inventory Amount - - - - Change Hop Amount - - - - Change Hop Use - - - - Change Hop Form - - - - Change Hop Time - - HydrometerTool @@ -2388,11 +2324,7 @@ Log file may contain more details. Weight - 重量 - - - Volume - + 重量 @@ -2426,31 +2358,18 @@ Log file may contain more details. - Change Misc Name - - - - Change Misc Type - - - - Change Misc Use - - - - Change Misc Time - - - - Change Misc Inventory Amount + Volume - Change Misc Amount - + Weight + 重量 + + + NE - Change Misc Amount Type + Change %1 %2 @@ -3447,15 +3366,11 @@ Log file may contain more details. Late - 晚Late - - - Not mashed - + 晚Late Mashed - 捣碎Mashed + 捣碎Mashed Weight