GroceryListElement.java
package stud.ntnu.idatt1005.pantrypal.views.components;
import java.util.ArrayList;
import java.util.List;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import stud.ntnu.idatt1005.pantrypal.controllers.Observer;
import stud.ntnu.idatt1005.pantrypal.enums.ButtonEnum;
import stud.ntnu.idatt1005.pantrypal.models.Grocery;
import stud.ntnu.idatt1005.pantrypal.utils.FontPalette;
import stud.ntnu.idatt1005.pantrypal.views.Observable;
/**
* Class representing a shopping list element. This class implement the Observable interface
* and provides a visual representation of a grocery item in the shopping list.
* It includes a checkbox, text information about the grocery item, and a delete button.
*/
public class GroceryListElement implements Observable {
private final List<Observer> observers = new ArrayList<>();
/**
* The {@link BorderPane} containing the visual elements of the shopping list item.
* This includes a checkbox, text information about the grocery item, and a delete button.
*/
private final BorderPane pane = new BorderPane();
private final Grocery grocery;
/**
* Constructor for the shopping list element. It initializes the visual elements
* and sets up the necessary event handlers.
*/
private GroceryListElement(GroceryListElementBuilder builder) {
grocery = builder.grocery;
StackPane checkPane = builder.checkPane;
HBox textBox = builder.textBox;
textBox.setAlignment(Pos.CENTER);
Button deleteButton = createButton();
pane.setLeft(checkPane);
pane.setCenter(textBox);
pane.setRight(deleteButton);
pane.getStyleClass().add("shopping-list-element");
}
/**
* Retrieves the visual representation of the shopping list element.
*
* @return the {@link Pane} containing the visual elements of the shopping list item.
*/
public Pane getPane() {
return pane;
}
/**
* Creates a button element with the given text, variant, size and enum.
* When clicked the button will notify the observers with the given enum.
*
* @return the StyledButton with the specified properties.
*/
private StyledButton createButton() {
StyledButton newButton = new StyledButton(
"X", StyledButton.Variant.DELETE, StyledButton.Size.MEDIUM);
newButton.setOnAction(e -> notifyObservers(ButtonEnum.REMOVE));
return newButton;
}
@Override
public void addObserver(Observer observer) {
if (observer != null) {
if (!observers.contains(observer)) {
observers.add(observer);
}
} else {
throw new IllegalArgumentException("Observer cannot be null");
}
}
@Override
public void removeObserver(Observer observer) {
if (observer != null) {
observers.remove(observer);
} else {
throw new IllegalArgumentException("Observer cannot be null");
}
}
/**
* Notifies the observers with the given enum and grocery.
*
* @param buttonEnum the enum to be notified.
*/
protected void notifyObservers(ButtonEnum buttonEnum) {
List<Observer> observersCopy = new ArrayList<>(this.observers);
for (Observer observer : observersCopy) {
observer.update(buttonEnum, this.grocery);
}
}
/**
* A builder class representing a list element in the shopping list.
* This class provides a visual representation of a grocery item in the shopping list.
* It includes a checkbox, text information about the grocery item, and a delete button.
* This class also implements the Observable interface,
* allowing it to notify observers of changes.
*/
public static class GroceryListElementBuilder {
private final Grocery grocery;
private final StackPane checkPane = new StackPane();
private final HBox textBox = new HBox();
/**
* Constructor for the GroceryListElementBuilder.
*
* @param grocery the grocery item to be represented by the shopping list element.
* @throws IllegalArgumentException if the grocery item is null.
*/
public GroceryListElementBuilder(Grocery grocery) {
if (grocery != null) {
this.grocery = grocery;
} else {
throw new IllegalArgumentException("Grocery cannot be null");
}
}
/**
* Creates a new CheckBox and ads it to the GroceryListElementBuilder.
*
* @return a new GroceryListElementBuilder with the given grocery item.
*/
public GroceryListElementBuilder checkBox() {
CheckBox checkBox = new CheckBox("");
checkBox.setPadding(new Insets(10));
checkBox.setSelected(grocery.getChecked());
checkBox.setOnAction(event -> grocery.setChecked(checkBox.isSelected()));
checkPane.getChildren().add(checkBox);
return this;
}
/**
* Adds a text element to the GroceryListElementBuilder.
*
* @param text the text to be displayed in the text element.
* @return a new GroceryListElementBuilder with the given text.
*/
public GroceryListElementBuilder text(String text) {
Text newText = new Text(text);
newText.setFont(FontPalette.TEXT);
newText.setWrappingWidth(100);
StackPane textPane = new StackPane(newText);
textPane.setPadding(new Insets(0, 0, 0, 10));
textBox.getChildren().add(textPane);
return this;
}
/**
* Adds a quantity element to the GroceryListElementBuilder.
* The quantity element is a spinner that allows the user to
* change the quantity of the grocery item.
*
* @return a new GroceryListElementBuilder with the given quantity.
*/
public GroceryListElementBuilder quantity() {
Spinner<Integer> spinner = createSpinner();
spinner.setMaxWidth(100);
spinner.setMaxHeight(50);
spinner.setPadding(new Insets(0, 0, 0, 10));
textBox.getChildren().add(spinner);
return this;
}
/**
* Creates a spinner element with the given properties.
* The spinner element is a spinner that allows the user to
* change the quantity of the grocery item.
*
* @return a new Spinner element with the given properties.
*/
private Spinner<Integer> createSpinner() {
Spinner<Integer> spinner = new Spinner<>();
final Grocery finalGrocery = this.grocery;
SpinnerValueFactory.IntegerSpinnerValueFactory valueFactory =
new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 1000, finalGrocery.getQuantity());
valueFactory.setAmountToStepBy(1);
valueFactory.valueProperty().addListener((observable, oldValue, newValue) ->
finalGrocery.setQuantity(newValue)
);
spinner.setValueFactory(valueFactory);
spinner.setEditable(true);
return spinner;
}
/**
* Builds the GroceryListElement with the given properties.
*
* @return a new GroceryListElement with the given properties.
*/
public GroceryListElement build() {
return new GroceryListElement(this);
}
}
}