Edit shopping category, mods to ingredient table edits

version2
Tim Holloway 2 years ago
parent e6817d7c2e
commit 200317d177
  1. 51
      src/main/java/com/mousetech/gourmetj/EditShopcatBean.java
  2. 215
      src/main/java/com/mousetech/gourmetj/RecipeDetailBean.java
  3. 2
      src/main/java/com/mousetech/gourmetj/persistence/dao/ShopcatRepository.java
  4. 4
      src/main/java/com/mousetech/gourmetj/persistence/model/Ingredient.java
  5. 5
      src/main/java/com/mousetech/gourmetj/persistence/service/RecipeService.java
  6. 18
      src/main/resources/META-INF/resources/WEB-INF/layout/layout.xhtml
  7. 46
      src/main/resources/META-INF/resources/detailEdit.xhtml
  8. 1
      src/main/resources/META-INF/resources/editShopcat.xhtml

@ -5,14 +5,12 @@ import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.primefaces.event.SelectEvent;
import com.mousetech.gourmetj.persistence.dao.ShopcatRepository;
import com.mousetech.gourmetj.persistence.model.Shopcat;
@Named
@ViewScoped
@ -34,6 +32,18 @@ public class EditShopcatBean implements Serializable {
@Inject
ShopcatRepository shopcatRepository;
/*
* Indicate if the shopcatname has been changed.
*/
private boolean changed = false;
/**
* @return the changed
*/
public boolean isChanged() {
return changed;
}
/**
* Default Constructor.
*/
@ -45,15 +55,20 @@ public class EditShopcatBean implements Serializable {
public void init() {
this.shopcatSuggestionList = this.shopcatRepository
.findDistinctCategoryNative();
// // Get ingkey from Flash scope
// ingkey = (String) JSFUtils.getFlash("ingkey");
// Shopcat scat = this.shopcatRepository
// .findShopcatByIngkey(ingkey);
// if (scat != null) {
// this.setShopcatName(scat.getShopcategory());
// }
}
/**
* Prepare for edit before the dialog is displayed.
*
* @param ingkey Ingredient key
* @param shopCat Previous shopping category for ingKey
*/
public void beginEdit(String ingkey, String shopCat) {
this.setIngkey(ingkey);
this.setShopcatName(shopCat);
this.changed = false;
}
/**
* @return the shopcatName
*/
@ -89,6 +104,11 @@ public class EditShopcatBean implements Serializable {
return ingkey;
}
/**
* Set the ingredient key.
*
* @param ingkey
*/
public void setIngkey(String ingkey) {
this.ingkey = ingkey;
}
@ -99,8 +119,17 @@ public class EditShopcatBean implements Serializable {
public List<String> getShopcatSuggestionList() {
return shopcatSuggestionList;
}
public void ajaxShopcatSuggest(AjaxBehaviorEvent event) {
this.shopcatName = this.shopcatSuggestion;
}
/**
* ValueChangeListener for shopcat editor.
*
* @param e Event, with new name in it.
*/
public void shopcatNameChanged(ValueChangeEvent e) {
this.changed = true;
}
}

@ -10,6 +10,7 @@ import java.util.Set;
import javax.annotation.PostConstruct;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.view.ViewScoped;
@ -203,6 +204,7 @@ public class RecipeDetailBean implements Serializable {
ingredients
.setWrappedData(new ArrayList<IngredientUI>(1));
}
log.info("Ingredient size="+ingredients.getRowCount());
return ingredients;
}
@ -224,7 +226,7 @@ public class RecipeDetailBean implements Serializable {
*/
if (this.recipe == null) {
Long rid =
//(Long) JSFUtils.getFlash("recipeID");
// (Long) JSFUtils.getFlash("recipeID");
userSession.getLastEdit();
if (rid != null) {
this.recipe = loadRecipe(rid);
@ -357,6 +359,7 @@ public class RecipeDetailBean implements Serializable {
public String doAddIngredient() {
this.addIngredientList(this.getIngredientText());
setIngredientText(""); // clear for next entry
updateSelectionStatus();
return null;
}
@ -376,7 +379,67 @@ public class RecipeDetailBean implements Serializable {
doAddIngredient();
}
public void ajaxMoveUp(AjaxBehaviorEvent event) {
// ===
/**
* Listen to the SELECT checkboxes on Ingredients and update
* the action button statuses.
*
* @param event notused
*/
public void ajaxSelectionListener(AjaxBehaviorEvent event) {
updateSelectionStatus();
}
private void updateSelectionStatus() {
List<IngredientUI> ingList = getWrappedIngredients();
final int ingCount = ingList.size();
boolean moveUpable = true;
boolean moveDownable = true;
boolean selectable = false;
for (int i = 0; i < ingCount; i++) {
boolean selected = ingList.get(i).isSelected();
if ((i == 0) && selected) {
moveUpable = false;
}
if ((i == (ingCount - 1)) && selected) {
moveDownable = false;
}
selectable |= selected;
}
this.setMoveUpAble(moveUpable && selectable);
this.setMoveDownAble(moveDownable && selectable);
this.setSelectable(selectable);
}
// ---
public void setMoveUpAble(boolean moveUpable) {
this.moveUpable = moveUpable;
}
public void setMoveDownAble(boolean moveDownable) {
this.moveDownable = moveDownable;
}
public void setSelectable(boolean selectable) {
this.selectable = selectable;
}
public boolean isMoveUpAble() {
return this.moveUpable;
}
public boolean isMoveDownAble() {
return this.moveDownable;
}
public boolean isSelectable() {
return this.selectable;
}
// ---
public void ajaxMoveUp() {
if (!isMoveUpAble()) {
JSFUtils.addErrorMessage("Cannot move up.");
return;
@ -393,6 +456,15 @@ public class RecipeDetailBean implements Serializable {
}
}
this.setDirty();
auditRows(rows);
}
private void auditRows(List<IngredientUI> rows) {
log.info("=== AUDIT ROWS ===");
for ( IngredientUI row : rows ) {
log.info((row.isSelected() ? "[X]" : "[ ]" ) +" ROW="+row);
}
log.info("=== DONE ===");
}
/**
@ -400,7 +472,7 @@ public class RecipeDetailBean implements Serializable {
*
* @param eventUnused
*/
public void ajaxMoveDown(AjaxBehaviorEvent event) {
public void ajaxMoveDown() {
if (!isMoveDownAble()) {
JSFUtils.addErrorMessage("Cannot move down.");
return;
@ -416,9 +488,10 @@ public class RecipeDetailBean implements Serializable {
rows.add(i, r);
}
}
auditRows(rows);
}
public void ajaxDeleteItems(AjaxBehaviorEvent event) {
public void ajaxDeleteItems() {
final List<IngredientUI> rows = getWrappedIngredients();
List<IngredientUI> selectedRows =
new ArrayList<IngredientUI>();
@ -433,61 +506,81 @@ public class RecipeDetailBean implements Serializable {
for (IngredientUI row : selectedRows) {
rows.remove(row);
}
auditRows(rows);
}
// =====
@Inject
EditShopcatBean editShopcatBean;
private boolean moveUpable;
private boolean moveDownable;
private boolean selectable;
/**
* Invoked when the "E"(dit" button for Ingkey shopping
* category has been clicked.
*
* @param item The item whose ingredient key will
* have its shopping category edited. Resets the dialog
* backing bean internal state.
*/
public void ajaxEditShopcat(IngredientUI item) {
// Map<String, Object> options = new HashMap<>();
// options.put("resizable", false);
// TODO: Reject if ingkey is empty/null
editShopcatBean.setIngkey(item.getIngkey());
editShopcatBean.setShopcatName(item.getShopCat());
// if ( ! StringUtils.isBlank(key) ) {
// PrimeFaces.current().dialog().openDynamic("editShopcat");
// }
editShopcatBean.beginEdit(item.getIngkey(),
item.getShopCat());
}
/**
* On "OK" for edit shopcat where shopcat has changed,
* update the shopcat Entity and the ingredients.
*/
public void doUpdateShopcat() {
final String key = editShopcatBean.getIngkey();
if ( StringUtils.isBlank(key)) {
if (StringUtils.isBlank(key)) {
return; // Do not set category if no ingKey
}
final String catname = editShopcatBean.getShopcatName();
Shopcat sc = this.recipeService
.findShopcatForIngredientKey(catname);
.findShopcatForIngredientKey(key);
if (sc == null) {
sc = new Shopcat();
sc.setIngkey(key);
sc.setShopcategory(catname);
} else {
if (catname.equals(sc.getShopcategory())) {
// No change. Do nothing.
return;
}
if ( StringUtils.equals(sc.getShopcategory(), catname) ) {
return; // No change
}
}
if ( StringUtils.isBlank(catname)) {
this.recipeService.deleteShopcat(sc);
} else {
sc.setShopcategory(catname);
/*
* Because the database does not have a UNIQUE
* constraint on ingkeys, we must delete old
* shopcat(s) for this key before adding (updating)
* the new shopcat.
*/
this.recipeService.deleteShopcatByIngKey(key);
if (! StringUtils.isBlank(catname)) {
this.recipeService.saveShopcat(sc);
}
updateDisplayedShopcats(key, sc);
}
/**
* When Shopcat name changes, update the Ingredients.
* In detailEdit, an AJAX "render" will then update
* the display. In recipeDetails, nothing actually shows.
* When Shopcat name changes, update the Ingredients. In
* detailEdit, an AJAX "render" will then update the display.
* In recipeDetails, nothing actually shows.
*/
private void updateDisplayedShopcats(String key, Shopcat sc) {
List<IngredientUI> ingList = this.getWrappedIngredients();
for (IngredientUI ingUI: ingList ) {
if ( key.equals(ingUI.getIngkey())) {
private void updateDisplayedShopcats(String key,
Shopcat sc) {
List<IngredientUI> ingList =
this.getWrappedIngredients();
for (IngredientUI ingUI : ingList) {
if (key.equals(ingUI.getIngkey())) {
ingUI.setShopCat(sc);
}
}
@ -521,6 +614,7 @@ public class RecipeDetailBean implements Serializable {
}
addIngredient(line);
}
updateSelectionStatus();
}
/**
@ -541,43 +635,6 @@ public class RecipeDetailBean implements Serializable {
ingredients.add(new IngredientUI(ing));
}
public boolean isSelectionActive() {
List<IngredientUI> rows = getWrappedIngredients();
for (IngredientUI row : rows) {
if (row.isSelected()) {
return true;
}
}
return false;
}
public void setSelectionActive(boolean value) {
// This is required by JBoss JSF, but the property is
// read-only.
}
public void setMoveUpAble() {
}
public void setMoveDownAble() {
}
public boolean isMoveUpAble() {
return true;
// TODO:
// if (isSelectionActive()) {
// List<IngredientUI> rows = getWrappedIngredients();
// return !rows.get(0).isSelected();
// }
// return false;
}
public boolean isMoveDownAble() {
return true;
}
// ===
/**
@ -695,16 +752,15 @@ public class RecipeDetailBean implements Serializable {
Shopcat scat = recipeService
.findShopcatForIngredientKey(ingKey);
if (scat == null) {
JSFUtils.addErrorMessage(
log.debug(
"No Shopping Category is defined for Ingredient Key "
+ ingKey);
//return false;
// return false;
}
ing.setShopCat(scat);
return true;
}
/**
* Parse out the comma-separated category text control and
* post the results as children of the recipe
@ -865,7 +921,6 @@ public class RecipeDetailBean implements Serializable {
public void ajaxUpdateShopcat(IngredientUI item) {
log.warn("SHOPCAT2 ");
updateShopcat(item);
;
}
// ***
@ -1002,9 +1057,9 @@ public class RecipeDetailBean implements Serializable {
long now = new java.util.Date().getTime();
return String.valueOf(now);
}
//*** Add Group
// *** Add Group
private String newGroupName;
/**
@ -1020,16 +1075,18 @@ public class RecipeDetailBean implements Serializable {
public void setNewGroupName(String newGroupName) {
this.newGroupName = newGroupName;
}
/**
* Add new group to bottom of model as AJAX operation.
*
* @return null
*/
public void doAddGroup() {
IngredientUI iui = new IngredientUI(null);
iui.setIngGroup(true);
iui.setItem(this.getNewGroupName());
List<IngredientUI> ingUIList = this.getWrappedIngredients();
List<IngredientUI> ingUIList =
this.getWrappedIngredients();
ingUIList.add(iui);
this.setNewGroupName(""); // Clear for next time!
}

@ -29,4 +29,6 @@ public interface ShopcatRepository
public List<String> findDistinctCategoryNative();
public Shopcat findShopcatByIngkey(String ingkey);
public void deleteByIngkey(String key);
}

@ -58,7 +58,7 @@ public class Ingredient implements Serializable, IngredientIF {
private String item;
@Column(name = "optional")
@NotNull
//@NotNull
private Integer optional;
@Column(name = "position")
@ -81,6 +81,8 @@ public class Ingredient implements Serializable, IngredientIF {
private String unit;
public Ingredient() {
// Attempt to remedy lack of constraints in DB
this.optional = 0;
}
@Override

@ -90,6 +90,11 @@ public class RecipeService implements Serializable {
}
public void deleteShopcatByIngKey(String key) {
shopcatRepository.deleteByIngkey(key);
}
public void saveShopcat(Shopcat sc) {
shopcatRepository.save(sc);
}

@ -47,12 +47,26 @@
style="z-index: 25000"
>
<p:commandButton id="cmdExpiredOK"
value="OK"
action="/main.jsf"
value="OK" action="/main.jsf"
oncomplete="PF('sessionExpiredConfirmation').hide()"
/>
</p:confirmDialog>
</h:form>
<!-- -->
<h:form id="frmOpErr">
<p:commandButton type="button"
onclick="PF('opError').show()"
/>
<p:confirmDialog
message="Session may have expired."
header="Error"
severity="alert" widgetVar="opError"
>
<p:commandButton value="OK"
oncomplete="PF('cd').hide()"
/>
</p:confirmDialog>
</h:form>
</h:body>
</f:view>
</ui:composition>

@ -100,7 +100,6 @@
max="10"
value="#{recipeDetailBean.recipe.preptime}"
>
<f:validator validatorId="com.mousetech.gourmetj.utils.TimeValidator"/>
<f:converter
converterId="com.mousetech.gourmetj.utils.TimeConverter"
/>
@ -110,9 +109,8 @@
/>
<p:inputText id="rcooktime"
max="10"
value="#{recipeDetailBean.recipe.cooktime}"
value="#{recipeDetailBean.recipe.cooktime}"
>
<f:validator validatorId="com.mousetech.gourmetj.utils.TimeValidator"/>
<f:converter
converterId="com.mousetech.gourmetj.utils.TimeConverter"
/>
@ -178,23 +176,17 @@
<p:commandButton value="Up"
disabled="#{not recipeDetailBean.moveUpAble}"
id="ctlUp"
>
<f:ajax
listener="#{recipeDetailBean.ajaxMoveUp}"
execute="ingredientTable"
render="ingredientTable"
/>
</p:commandButton>
actionListener="#{recipeDetailBean.ajaxMoveUp}"
update="ingredientTable"
onerror="PF('opError').show()"
/>
<p:commandButton value="Down"
disabled="#{not recipeDetailBean.moveDownAble}"
id="ctlDown"
>
<f:ajax
listener="#{recipeDetailBean.ajaxMoveDown}"
execute="ingredientTable"
render="ingredientTable"
/>
</p:commandButton>
onerror="PF('opError').show()"
actionListener="#{recipeDetailBean.ajaxMoveDown}"
update="ingredientTable"
/>
<p:commandButton
value="Add Group"
onclick="PF('addGroupDlg').show()"
@ -211,17 +203,14 @@
<p:commandButton
value="Delete"
id="ctlDelete"
disabled="not #{recipeDetailBean.selectionActive}"
>
<f:ajax
listener="#{recipeDetailBean.ajaxDeleteItems}"
immediate="true"
render="ingredientTable"
/>
</p:commandButton>
disabled="#{not recipeDetailBean.selectable}"
onerror="PF('opError').show()"
actionListener="#{recipeDetailBean.ajaxDeleteItems}"
update="ingredientTable"
/>
</h:panelGroup>
<p:dataTable id="ingredientTable"
style="width: 100%; height: 420px; margin-top: 8px"
style="width: 100%; height: 430px; margin-top: 8px"
value="#{recipeDetailBean.ingredients}"
scrollable="true"
scrollHeight="380" var="item"
@ -235,8 +224,8 @@
value="#{item.selected}"
>
<f:ajax
immediate="true"
render="pnlIngredients"
listener="#{recipeDetailBean.ajaxSelectionListener}"
render=":form1:tabGroupClient:ingButtons"
/>
</p:selectBooleanCheckbox>
</p:column>
@ -320,6 +309,7 @@
update="editShopcatDlg"
oncomplete="PF('editShopcatDlg').show()"
title="Edit the shopping category for ing. key"
disabled="#{empty item.ingkey}"
rendered="#{not item.ingGroup}"
/>
</p:column>

@ -26,6 +26,7 @@
value="Category Name" />
<p:inputText id="ctlShopcat"
value="#{editShopcatBean.shopcatName}"
valueChangeListener="#{editShopcatBean.shopcatNameChanged}"
>
</p:inputText>
<h:outputText

Loading…
Cancel
Save