parent
349fec17ac
commit
3fd7bdb842
14 changed files with 896 additions and 17 deletions
@ -0,0 +1,121 @@ |
|||||||
|
CREATE TABLE keylookup ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
word TEXT, |
||||||
|
item TEXT, |
||||||
|
ingkey TEXT, |
||||||
|
count INTEGER, |
||||||
|
PRIMARY KEY (id) |
||||||
|
); |
||||||
|
CREATE TABLE info ( |
||||||
|
version_super INTEGER, |
||||||
|
version_major INTEGER, |
||||||
|
version_minor INTEGER, |
||||||
|
last_access INTEGER, |
||||||
|
rowid INTEGER NOT NULL, |
||||||
|
PRIMARY KEY (rowid) |
||||||
|
); |
||||||
|
CREATE TABLE recipe ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
title TEXT, |
||||||
|
instructions TEXT, |
||||||
|
modifications TEXT, |
||||||
|
cuisine TEXT, |
||||||
|
rating INTEGER, |
||||||
|
description TEXT, |
||||||
|
source TEXT, |
||||||
|
preptime INTEGER, |
||||||
|
cooktime INTEGER, |
||||||
|
servings FLOAT, |
||||||
|
yields FLOAT, |
||||||
|
yield_unit VARCHAR(32), |
||||||
|
image BLOB, |
||||||
|
thumb BLOB, |
||||||
|
deleted BOOLEAN, |
||||||
|
recipe_hash VARCHAR(32), |
||||||
|
ingredient_hash VARCHAR(32), |
||||||
|
link TEXT, |
||||||
|
last_modified INTEGER, |
||||||
|
PRIMARY KEY (id), |
||||||
|
CHECK (deleted IN (0, 1)) |
||||||
|
); |
||||||
|
CREATE TABLE plugin_info ( |
||||||
|
plugin TEXT, |
||||||
|
id INTEGER NOT NULL, |
||||||
|
version_super INTEGER, |
||||||
|
version_major INTEGER, |
||||||
|
version_minor INTEGER, |
||||||
|
plugin_version VARCHAR(32), |
||||||
|
PRIMARY KEY (id) |
||||||
|
); |
||||||
|
CREATE TABLE categories ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
recipe_id INTEGER, |
||||||
|
category TEXT, |
||||||
|
PRIMARY KEY (id), |
||||||
|
FOREIGN KEY(recipe_id) REFERENCES recipe (id) |
||||||
|
); |
||||||
|
CREATE TABLE ingredients ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
recipe_id INTEGER, |
||||||
|
refid INTEGER, |
||||||
|
unit TEXT, |
||||||
|
amount FLOAT, |
||||||
|
rangeamount FLOAT, |
||||||
|
item TEXT, |
||||||
|
ingkey TEXT, |
||||||
|
optional BOOLEAN, |
||||||
|
shopoptional INTEGER, |
||||||
|
inggroup TEXT, |
||||||
|
position INTEGER, |
||||||
|
deleted BOOLEAN, |
||||||
|
PRIMARY KEY (id), |
||||||
|
CHECK (deleted IN (0, 1)), |
||||||
|
FOREIGN KEY(recipe_id) REFERENCES recipe (id), |
||||||
|
FOREIGN KEY(refid) REFERENCES recipe (id), |
||||||
|
CHECK (optional IN (0, 1)) |
||||||
|
); |
||||||
|
CREATE TABLE IF NOT EXISTS "pantry" ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
ingkey TEXT(32), |
||||||
|
pantry BOOLEAN, |
||||||
|
PRIMARY KEY (id), |
||||||
|
CHECK (pantry IN (0, 1)) |
||||||
|
); |
||||||
|
CREATE TABLE unitdict ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
ukey VARCHAR(150), |
||||||
|
value VARCHAR(150), |
||||||
|
PRIMARY KEY (id) |
||||||
|
); |
||||||
|
CREATE TABLE crossunitdict ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
cukey VARCHAR(150), |
||||||
|
value VARCHAR(150), |
||||||
|
PRIMARY KEY (id) |
||||||
|
); |
||||||
|
CREATE TABLE density ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
dkey VARCHAR(150), |
||||||
|
value VARCHAR(150), |
||||||
|
PRIMARY KEY (id) |
||||||
|
); |
||||||
|
CREATE TABLE shopcatsorder ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
shopcategory TEXT(32), |
||||||
|
position INTEGER, |
||||||
|
PRIMARY KEY (id) |
||||||
|
); |
||||||
|
CREATE TABLE convtable ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
ckey VARCHAR(150), |
||||||
|
value VARCHAR(150), |
||||||
|
PRIMARY KEY (id) |
||||||
|
); |
||||||
|
CREATE TABLE IF NOT EXISTS "shopcats" ( |
||||||
|
id INTEGER NOT NULL, |
||||||
|
ingkey TEXT(32), |
||||||
|
shopcategory TEXT, |
||||||
|
position INTEGER, |
||||||
|
PRIMARY KEY (id) |
||||||
|
); |
||||||
|
CREATE TABLE IF NOT EXISTS "recipe_ingredients" ("Recipe_id" integer not null, "ingredientHash_id" integer not null, unique ("ingredientHash_id")); |
@ -0,0 +1,161 @@ |
|||||||
|
package com.mousetech.gourmetj; |
||||||
|
|
||||||
|
import com.mousetech.gourmetj.utils.IngredientDigester; |
||||||
|
import com.mousetech.gourmetj.utils.IngredientDigester.IngredientAmountFormat; |
||||||
|
|
||||||
|
public class ShopIngredient implements Comparable<Object> { |
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param shopCat |
||||||
|
* @param ingkey |
||||||
|
*/ |
||||||
|
public ShopIngredient( String shopCat, String item, |
||||||
|
String ingkey) { |
||||||
|
this.shopCat = shopCat; |
||||||
|
this.ingkey = ingkey; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructor. |
||||||
|
* |
||||||
|
* @param amount |
||||||
|
* @param unit |
||||||
|
* @param item |
||||||
|
* @param ingkey |
||||||
|
* @param shopCat |
||||||
|
*/ |
||||||
|
public ShopIngredient( double amount, String unit, |
||||||
|
String item, String ingkey, |
||||||
|
String shopCat) { |
||||||
|
this.amount = amount; |
||||||
|
this.unit = unit; |
||||||
|
this.item = item; |
||||||
|
this.ingkey = ingkey; |
||||||
|
this.shopCat = shopCat; |
||||||
|
} |
||||||
|
|
||||||
|
private String shopCat; |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the shopCat |
||||||
|
*/ |
||||||
|
public String getShopCat() { |
||||||
|
return shopCat; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param shopCat the shopCat to set |
||||||
|
*/ |
||||||
|
public void setShopCat(String shopCat) { |
||||||
|
this.shopCat = shopCat; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the ingkey |
||||||
|
*/ |
||||||
|
public String getIngkey() { |
||||||
|
return ingkey; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param ingkey the ingkey to set |
||||||
|
*/ |
||||||
|
public void setIngkey(String ingkey) { |
||||||
|
this.ingkey = ingkey; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the amount |
||||||
|
*/ |
||||||
|
public double getAmount() { |
||||||
|
return amount; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param amount the amount to set |
||||||
|
*/ |
||||||
|
public void setAmount(double amount) { |
||||||
|
this.amount = amount; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the displayAmount |
||||||
|
*/ |
||||||
|
public String getDisplayAmount() { |
||||||
|
return IngredientDigester.displayAmount( |
||||||
|
IngredientAmountFormat.IA_TEXT, this.getAmount(), |
||||||
|
null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the unit |
||||||
|
*/ |
||||||
|
public String getUnit() { |
||||||
|
return unit; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param unit the unit to set |
||||||
|
*/ |
||||||
|
public void setUnit(String unit) { |
||||||
|
this.unit = unit; |
||||||
|
} |
||||||
|
|
||||||
|
private String item; |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the item |
||||||
|
*/ |
||||||
|
public String getItem() { |
||||||
|
return item; |
||||||
|
} |
||||||
|
|
||||||
|
private String ingkey; |
||||||
|
private double amount; |
||||||
|
private String displayAmount; |
||||||
|
private String unit; |
||||||
|
|
||||||
|
@Override |
||||||
|
public int compareTo(Object o) { |
||||||
|
if ((o == null) || !(o instanceof ShopIngredient)) { |
||||||
|
throw new RuntimeException( |
||||||
|
"Invalid shipIngredient comparison"); |
||||||
|
} |
||||||
|
ShopIngredient o1 = (ShopIngredient) o; |
||||||
|
int i = relate(this.getItem(), o1.getItem()); |
||||||
|
if (i != 0) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
i = relate(this.getShopCat(), o1.getShopCat()); |
||||||
|
if (i != 0) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
// TODO: normalize case, singular/plural/abbreviations
|
||||||
|
i = relate(this.getUnit(), o1.getUnit()); |
||||||
|
if (i != 0) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
return i; // ZERO
|
||||||
|
} |
||||||
|
|
||||||
|
private int relate(String item2, String item3) { |
||||||
|
if ((item2 == null) && (item3 == null)) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
if (item2 == null) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
if (item3 == null) { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
return item2.compareTo(item3); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return this.getAmount() + " " + this.getUnit() + " " |
||||||
|
+ this.getItem() + " " + this.getIngkey() + " " |
||||||
|
+ this.getShopCat(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,213 @@ |
|||||||
|
package com.mousetech.gourmetj; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Comparator; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import javax.annotation.PostConstruct; |
||||||
|
import javax.faces.event.AjaxBehaviorEvent; |
||||||
|
import javax.faces.view.ViewScoped; |
||||||
|
import javax.inject.Inject; |
||||||
|
import javax.inject.Named; |
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils; |
||||||
|
import org.primefaces.event.ReorderEvent; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import com.mousetech.gourmetj.persistence.dao.ShopcatRepository; |
||||||
|
import com.mousetech.gourmetj.persistence.model.Ingredient; |
||||||
|
import com.mousetech.gourmetj.persistence.model.Recipe; |
||||||
|
import com.mousetech.gourmetj.persistence.model.Shopcat; |
||||||
|
|
||||||
|
@Named |
||||||
|
@ViewScoped |
||||||
|
public class ShoppingListBean implements Serializable { |
||||||
|
|
||||||
|
/** |
||||||
|
* Serial version for session save/restore |
||||||
|
*/ |
||||||
|
private static final long serialVersionUID = |
||||||
|
7449440266704831598L; |
||||||
|
|
||||||
|
/* Logger */ |
||||||
|
|
||||||
|
@SuppressWarnings("unused") |
||||||
|
private static final Logger log = |
||||||
|
LoggerFactory.getLogger(ShoppingListBean.class); |
||||||
|
|
||||||
|
@Inject |
||||||
|
private UserSession userSession; |
||||||
|
|
||||||
|
private List<ShopIngredient> siList; |
||||||
|
|
||||||
|
// private List<ShopIngredient> ingredientList;
|
||||||
|
|
||||||
|
@PostConstruct |
||||||
|
public void init() { |
||||||
|
// Load up details on recipes
|
||||||
|
this.siList = new ArrayList<ShopIngredient>(30); |
||||||
|
buildMaps(); |
||||||
|
} |
||||||
|
|
||||||
|
public List<Recipe> getRecipeList() { |
||||||
|
return this.userSession.getShoppingList(); |
||||||
|
} |
||||||
|
|
||||||
|
public List<ShopIngredient> getIngredientList() { |
||||||
|
return this.siList; |
||||||
|
} |
||||||
|
|
||||||
|
private void buildMaps() { |
||||||
|
for (Recipe r : this.getRecipeList()) { |
||||||
|
buildMapsFor(r); |
||||||
|
} |
||||||
|
// Now consolidate amounts and sort by
|
||||||
|
// shopcat/item/ingkey
|
||||||
|
optimizeIngredients(this.siList); |
||||||
|
|
||||||
|
this.siList.sort(new ShopclassComparator()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Run the ingredient list for the selected recipe and add |
||||||
|
* them to siList |
||||||
|
* |
||||||
|
* @param r |
||||||
|
* |
||||||
|
* @see #buildMaps() |
||||||
|
*/ |
||||||
|
private void buildMapsFor(Recipe r) { |
||||||
|
for (Ingredient ing : r.getIngredientHash()) { |
||||||
|
String ingkey = ing.getIngkey(); |
||||||
|
if (StringUtils.isBlank(ingkey)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
String shopCatName = ing.getShopCat() != null |
||||||
|
? ing.getShopCat().getShopcategory() |
||||||
|
: null; |
||||||
|
ShopIngredient sing = new ShopIngredient( |
||||||
|
ing.getAmount(), ing.getUnit(), |
||||||
|
ing.getItem(), ing.getIngkey(), shopCatName); |
||||||
|
siList.add(sing); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sort ShopIngredient list, then optimize it by |
||||||
|
* consolidating amounts where possible. |
||||||
|
* |
||||||
|
* @param victim List to optimize |
||||||
|
* |
||||||
|
* #TestedBy @see ShoppingListBeanTest |
||||||
|
*/ |
||||||
|
static void optimizeIngredients( |
||||||
|
List<ShopIngredient> victim) { |
||||||
|
victim.sort(null); |
||||||
|
for (int i = 0; i < (victim.size() - 1); i++) { |
||||||
|
ShopIngredient si = victim.get(i); |
||||||
|
ShopIngredient si2 = victim.get(i + 1); |
||||||
|
if (si.compareTo(si2) == 0) { |
||||||
|
si.setAmount(si.getAmount() + si2.getAmount()); |
||||||
|
victim.remove(si2); // reduces size()
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class ShopclassComparator |
||||||
|
implements Comparator<ShopIngredient> { |
||||||
|
|
||||||
|
@Override |
||||||
|
public int compare(ShopIngredient ing1, |
||||||
|
ShopIngredient ing2) { |
||||||
|
int i = 0; |
||||||
|
i = relate(ing1.getShopCat(), ing2.getShopCat()); |
||||||
|
if (i != 0) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
i = relate(ing1.getItem(), ing2.getItem()); |
||||||
|
if (i != 0) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
i = relate(ing1.getIngkey(), ing2.getIngkey()); |
||||||
|
if (i != 0) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
private int relate(String item2, String item3) { |
||||||
|
if ((item2 == null) && (item3 == null)) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
if (item2 == null) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
if (item3 == null) { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
return item2.compareTo(item3); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private List<Shopcat> shopcatList; |
||||||
|
|
||||||
|
public List<Shopcat> getShopcatList() { |
||||||
|
if (shopcatList == null) { |
||||||
|
shopcatList = loadShopcatList(); |
||||||
|
} |
||||||
|
return shopcatList; |
||||||
|
} |
||||||
|
|
||||||
|
@Inject |
||||||
|
ShopcatRepository shopcatRepository; |
||||||
|
|
||||||
|
private List<Shopcat> loadShopcatList() { |
||||||
|
return shopcatRepository |
||||||
|
.findAllByOrderByShopcategoryAsc(); |
||||||
|
} |
||||||
|
|
||||||
|
private Shopcat xeditShopcat = new Shopcat(); |
||||||
|
|
||||||
|
private String oldShopcategoryName; |
||||||
|
|
||||||
|
/** |
||||||
|
* @return the editShopcat |
||||||
|
*/ |
||||||
|
public Shopcat getEditShopcat() { |
||||||
|
return xeditShopcat; |
||||||
|
} |
||||||
|
|
||||||
|
public void doEditShopcat(int scId) { |
||||||
|
xeditShopcat = null; |
||||||
|
final List<Shopcat> scl = getShopcatList(); |
||||||
|
for (Shopcat sc : scl) { |
||||||
|
if (sc.getId() == scId) { |
||||||
|
xeditShopcat = sc; |
||||||
|
this.oldShopcategoryName = sc.getShopcategory(); |
||||||
|
if (sc.getPosition() == null) { |
||||||
|
sc.setPosition(0); |
||||||
|
} |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
log.error("SHOPCAT " + scId + " NOT FOUND"); |
||||||
|
} |
||||||
|
|
||||||
|
public void ajaxOnClickShopcatIngkey() { |
||||||
|
// Saves 1 shopcat/ingkey
|
||||||
|
this.shopcatRepository.save(xeditShopcat); |
||||||
|
this.shopcatList = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Updates all ingredient keys for shopcat name-change. |
||||||
|
* Note that once done, this cannot be undone! |
||||||
|
*/ |
||||||
|
public void ajaxOnClickShopcat() { |
||||||
|
this.shopcatRepository.UpdateShopcats( |
||||||
|
this.oldShopcategoryName, xeditShopcat.getShopcategory()); |
||||||
|
this.shopcatList = null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" |
||||||
|
xmlns:h="http://xmlns.jcp.org/jsf/html" |
||||||
|
xmlns:f="http://xmlns.jcp.org/jsf/core" |
||||||
|
xmlns:ui="http://java.sun.com/jsf/facelets" |
||||||
|
xmlns:p="http://primefaces.org/ui" |
||||||
|
> |
||||||
|
<h:head> |
||||||
|
<title>Shopping Category</title> |
||||||
|
<style type="text/css"> |
||||||
|
html { |
||||||
|
font-size: 14px; |
||||||
|
} |
||||||
|
</style> |
||||||
|
</h:head> |
||||||
|
<h:body> |
||||||
|
<ui:component> |
||||||
|
<h:form id="frmShopcat"> |
||||||
|
<p:panelGrid columns="1"> |
||||||
|
<p:dataTable id="tblShopcats" |
||||||
|
style="width: 600px" |
||||||
|
value="#{shoppingListBean.shopcatList}" |
||||||
|
sortBy="#{item.shopCat}" var="item" |
||||||
|
> |
||||||
|
<p:headerRow> |
||||||
|
<p:column colspan="4"> |
||||||
|
<h:outputText value="#{item.shopCat}" /> |
||||||
|
</p:column> |
||||||
|
</p:headerRow> |
||||||
|
</p:dataTable> |
||||||
|
<div>Ingredient key: |
||||||
|
#{editShopcatBean.ingkey}</div> |
||||||
|
<p:outputLabel for="@next" |
||||||
|
value="Category Name" |
||||||
|
/> |
||||||
|
<p:inputText id="ctlShopcat" |
||||||
|
value="#{editShopcatBean.shopcatName}" |
||||||
|
> |
||||||
|
</p:inputText> |
||||||
|
<h:outputText value="suggestion:" /> |
||||||
|
<p:selectOneMenu id="ctlShopcatMenu" |
||||||
|
value="#{editShopcatBean.shopcatSuggestion}" |
||||||
|
> |
||||||
|
<f:selectItems |
||||||
|
value="#{editShopcatBean.shopcatSuggestionList}" |
||||||
|
/> |
||||||
|
<p:ajax event="change" |
||||||
|
listener="#{editShopcatBean.ajaxShopcatSuggest}" |
||||||
|
update="ctlShopcat" |
||||||
|
/> |
||||||
|
</p:selectOneMenu> |
||||||
|
<p:panelGrid columns="2" style="width: 100%"> |
||||||
|
<p:commandButton id="scDlgOK" value="OK" |
||||||
|
style="width: 6em" |
||||||
|
action="#{recipeDetailBean.doUpdateShopcat}" |
||||||
|
update="form1:tabGroupClient:ingredientTable" |
||||||
|
oncomplete="PF('editShopcatDlg').hide()" |
||||||
|
/> |
||||||
|
<p:commandButton id="scDlgCan" |
||||||
|
value="Cancel" style="width: 6em" |
||||||
|
onclick="PF('editShopcatDlg').hide()" |
||||||
|
/> |
||||||
|
</p:panelGrid> |
||||||
|
</p:panelGrid> |
||||||
|
</h:form> |
||||||
|
</ui:component> |
||||||
|
</h:body> |
||||||
|
</html> |
@ -0,0 +1,198 @@ |
|||||||
|
<?xml version="1.0"?> |
||||||
|
<ui:composition template="/WEB-INF/layout/layout.xhtml" |
||||||
|
xmlns:h="http://xmlns.jcp.org/jsf/html" |
||||||
|
xmlns:f="http://xmlns.jcp.org/jsf/core" |
||||||
|
xmlns:ui="http://java.sun.com/jsf/facelets" |
||||||
|
xmlns:p="http://primefaces.org/ui" |
||||||
|
xmlns:c="http://xmlns.jcp.org/jstl" |
||||||
|
> |
||||||
|
<ui:define name="title">Gourmet Recipe Manager - Shopping</ui:define> |
||||||
|
<ui:define name="content"> |
||||||
|
<style> |
||||||
|
.recipeTitle { |
||||||
|
font-size: larger; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
|
||||||
|
.subtitle { |
||||||
|
font-size: large; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
|
||||||
|
.ui-panelgrid-cell { |
||||||
|
border-width: 0; |
||||||
|
border-style: none; |
||||||
|
} |
||||||
|
</style> |
||||||
|
<h:messages /> |
||||||
|
<h:form id="form1"> |
||||||
|
<p:dataTable id="tblRecipes" style="width: 600px" |
||||||
|
value="#{shoppingListBean.recipeList}" var="item" |
||||||
|
> |
||||||
|
<p:column headerText="Recipe"> |
||||||
|
<h:outputText value="#{item.title}" /> |
||||||
|
</p:column> |
||||||
|
</p:dataTable> |
||||||
|
<!-- ====== Ingredients ============================ --> |
||||||
|
<p:column id="ingredientsc" |
||||||
|
style="width: 25%; vertical-align: top;" |
||||||
|
> |
||||||
|
<p:dataTable id="tblShopIngredients" |
||||||
|
style="width: 600px; margin-top: 10px" |
||||||
|
value="#{shoppingListBean.ingredientList}" |
||||||
|
sortBy="#{item.shopCat}" var="item" |
||||||
|
> |
||||||
|
<f:facet name="header"> |
||||||
|
<h:outputText styleClass="subtitle" |
||||||
|
value="Ingredients" |
||||||
|
/> |
||||||
|
</f:facet> |
||||||
|
<p:headerRow> |
||||||
|
<p:column colspan="4"> |
||||||
|
<h:outputText value="#{item.shopCat}" /> |
||||||
|
</p:column> |
||||||
|
</p:headerRow> |
||||||
|
<p:column label="ingKey"> |
||||||
|
<h:outputText value="#{item.ingkey}" /> |
||||||
|
</p:column> |
||||||
|
<p:column label="Amt" |
||||||
|
style="width: 3em; text-align: right" |
||||||
|
> |
||||||
|
<h:outputText |
||||||
|
value="#{item.displayAmount}" |
||||||
|
/> |
||||||
|
</p:column> |
||||||
|
<p:column label="Units" style="width: 5em"> |
||||||
|
<h:outputText value="#{item.unit}" /> |
||||||
|
</p:column> |
||||||
|
<p:column label="Item" style="width: 20em"> |
||||||
|
<h:outputText value="#{item.item}" /> |
||||||
|
</p:column> |
||||||
|
</p:dataTable> |
||||||
|
</p:column> |
||||||
|
<p:commandButton id="doHome" value="Home" |
||||||
|
icon="ui-icon-home" ajax="false" immediate="true" |
||||||
|
action="main.jsf" |
||||||
|
/> |
||||||
|
<p:dataTable id="tblShopcats" style="width: 300px" |
||||||
|
value="#{shoppingListBean.shopcatList}" |
||||||
|
sortBy="#{item.shopcategory}" var="item" |
||||||
|
> |
||||||
|
<f:facet name="header"> |
||||||
|
<h:outputText |
||||||
|
value="Ingredient Keys/Shopping Categories" |
||||||
|
/> |
||||||
|
</f:facet> |
||||||
|
<p:headerRow> |
||||||
|
<p:column> |
||||||
|
<h:outputText id="ctlCatname" |
||||||
|
value="#{item.shopcategory}" |
||||||
|
/> |
||||||
|
</p:column> |
||||||
|
<p:column style="width: 5em"> |
||||||
|
<p:commandButton id="ctlEditCat" |
||||||
|
value="Rename" |
||||||
|
action="#{shoppingListBean.doEditShopcat(item.id)}" |
||||||
|
onclick="PF('dlgEditShopcat').show()" |
||||||
|
update="frmEscat:pnlData" |
||||||
|
/> |
||||||
|
</p:column> |
||||||
|
</p:headerRow> |
||||||
|
<p:column> |
||||||
|
<h:outputText value="#{item.ingkey}" |
||||||
|
onclick="clickIngkeyName()" |
||||||
|
/> |
||||||
|
</p:column> |
||||||
|
<p:column style="width: 5em"> |
||||||
|
<p:commandButton id="ctlEditIngkey" |
||||||
|
value="Move" |
||||||
|
action="#{shoppingListBean.doEditShopcat(item.id)}" |
||||||
|
onclick="PF('dlgEditIngkey').show()" |
||||||
|
update="frmIngkey:pnlData" |
||||||
|
/> |
||||||
|
</p:column> |
||||||
|
</p:dataTable> |
||||||
|
</h:form> |
||||||
|
<!-- --> |
||||||
|
<h:form id="frmEscat"> |
||||||
|
<p:dialog id="dlgEditShopcat" |
||||||
|
widgetVar="dlgEditShopcat" |
||||||
|
header="Edit/Rename Shopping Category" |
||||||
|
closeOnEscape="true" |
||||||
|
> |
||||||
|
<p:panelGrid id="pnlData" columns="2" |
||||||
|
styleClass="ui-panelgrid-blank" |
||||||
|
> |
||||||
|
<p:outputLabel for="@next" |
||||||
|
value="Shopping Category" |
||||||
|
/> |
||||||
|
<p:inputText id="ctlDlgShopcatName" |
||||||
|
label="Position" required="true" |
||||||
|
value="#{shoppingListBean.editShopcat.shopcategory}" |
||||||
|
/> |
||||||
|
<p:outputLabel for="@next" value="Position" /> |
||||||
|
<p:inputText id="ctlDlgShopcatPosition" |
||||||
|
type="number" required="true" size="3" |
||||||
|
value="#{shoppingListBean.editShopcat.position}" |
||||||
|
/> |
||||||
|
</p:panelGrid> |
||||||
|
<p:panelGrid columns="2" style="width: 100%" |
||||||
|
styleClass="ui-panelgrid-blank" |
||||||
|
> |
||||||
|
<p:commandButton id="scDlgOK" value="OK" |
||||||
|
style="width: 6em" |
||||||
|
action="#{shoppingListBean.ajaxOnClickShopcat}" |
||||||
|
update="form1:tblShopcats" |
||||||
|
process="@this pnlData" |
||||||
|
oncomplete="PF('dlgEditShopcat').hide()" |
||||||
|
/> |
||||||
|
<p:commandButton id="scDlgCan" value="Cancel" |
||||||
|
style="width: 6em" |
||||||
|
onclick="PF('dlgEditShopcat').hide()" |
||||||
|
/> |
||||||
|
</p:panelGrid> |
||||||
|
</p:dialog> |
||||||
|
</h:form> |
||||||
|
<!-- --> |
||||||
|
<h:form id="frmIngkey"> |
||||||
|
<p:dialog id="dlgEditIngkey" |
||||||
|
widgetVar="dlgEditIngkey" |
||||||
|
header="Edit/Rename Shopping Category for Ingredient Key" |
||||||
|
closeOnEscape="true" |
||||||
|
> |
||||||
|
<p:panelGrid id="pnlData" columns="2" |
||||||
|
styleClass="ui-panelgrid-blank" |
||||||
|
> |
||||||
|
<p:outputLabel for="@next" |
||||||
|
value="Ingredient Key" |
||||||
|
/> |
||||||
|
<h:outputText id="ctlDlgIngKeyIngkey" |
||||||
|
value="#{shoppingListBean.editShopcat.ingkey}" |
||||||
|
/> |
||||||
|
<p:outputLabel for="@next" |
||||||
|
value="Shopping Category" |
||||||
|
/> |
||||||
|
<p:inputText id="ctlDlgIngkeyShopcatName" |
||||||
|
label="Position" required="true" |
||||||
|
value="#{shoppingListBean.editShopcat.shopcategory}" |
||||||
|
/> |
||||||
|
</p:panelGrid> |
||||||
|
<p:panelGrid columns="2" style="width: 100%" |
||||||
|
styleClass="ui-panelgrid-blank" |
||||||
|
> |
||||||
|
<p:commandButton id="ingkDlgOK" value="OK" |
||||||
|
style="width: 6em" |
||||||
|
action="#{shoppingListBean.ajaxOnClickShopcatIngkey}" |
||||||
|
update="form1:tblShopcats" |
||||||
|
process="@this pnlData" |
||||||
|
oncomplete="PF('dlgEditIngkey').hide()" |
||||||
|
/> |
||||||
|
<p:commandButton id="ingkDlgCan" |
||||||
|
value="Cancel" style="width: 6em" |
||||||
|
onclick="PF('dlgEditIngkey').hide()" |
||||||
|
/> |
||||||
|
</p:panelGrid> |
||||||
|
</p:dialog> |
||||||
|
</h:form> |
||||||
|
</ui:define> |
||||||
|
</ui:composition> |
@ -0,0 +1,52 @@ |
|||||||
|
/** |
||||||
|
* Copyright (C) 2022, Tim Holloway |
||||||
|
* |
||||||
|
* Date written: Jan 12, 2022 |
||||||
|
* Author: Tim Holloway <timh@mousetech.com> |
||||||
|
*/ |
||||||
|
package com.mousetech.gourmetj; |
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeAll; |
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
import com.mousetech.gourmetj.ShopIngredient; |
||||||
|
import com.mousetech.gourmetj.persistence.model.Shopcat; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author timh |
||||||
|
* @since Jan 12, 2022 |
||||||
|
*/ |
||||||
|
class ShoppingListBeanTest { |
||||||
|
|
||||||
|
static List<ShopIngredient> testList; |
||||||
|
|
||||||
|
/** |
||||||
|
* @throws java.lang.Exception |
||||||
|
*/ |
||||||
|
@BeforeAll |
||||||
|
static void setUpBeforeClass() throws Exception { |
||||||
|
testList = new ArrayList<ShopIngredient>(); |
||||||
|
testList.add(new ShopIngredient(2.0d, "cup", |
||||||
|
"sugar", "sugar", "baking")); |
||||||
|
testList.add(new ShopIngredient(1.5, "tsp", |
||||||
|
"salt", "salt", "condiments")); |
||||||
|
testList.add(new ShopIngredient(0.5, "tsp", |
||||||
|
"pepper", "pepper", "condiments")); |
||||||
|
testList.add(new ShopIngredient(2.0d, "cup", |
||||||
|
"milk", "milk", "dairy")); |
||||||
|
testList.add(new ShopIngredient(0.75d, "cup", |
||||||
|
"sugar", "sugar", "baking")); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void test() { |
||||||
|
ShoppingListBean.optimizeIngredients(testList); |
||||||
|
assertEquals(4, testList.size()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue