I am going crazy because I am trying to pass by value an observable list of Part objects but I am somehow passing by reference, because every time I add a new Product, and try to pass a NEW list of parts specific for that instance of the Product that will in turn be added to an observable list. Somehow, I can not get it to have a new instance of observable list of parts but instead it is creating references, that, whenever I try to modify one list, it modifies the list for all of them. and if I create a new product, the new Product instances observable list of parts associated with it will then override all the previous product instances parts lists. I have tried everything I could find online for this issue but none of it seems to work. Can you please look over my code to see what I am doing wrong?
To save on putting in to much code, I will just put in addProduct, modifyProduct and Product classes, since I believe that is where the issue or issues are located. If anyone thinks I need more classes, I will edit to add.
addProduct Class
public class addProduct
{
private static Label error = new Label("");
private static TextField idT = new TextField();
private static TextField nameT = new TextField();
private static TextField invT = new TextField();
private static TextField priceT = new TextField();
private static TextField maxT = new TextField();
private static TextField minT = new TextField();
private static boolean pass = false;
private static ObservableList list;
//private static ObservableList adder = FXCollections.observableArrayList();
public static void displayAddProduct(Stage primaryStage, ObservableList list, ObservableList listParts)
{
addProduct.list = list;
Stage PrimaryStage = primaryStage;
Label addP = new Label("Add Product");
addP.setStyle("-fx-font-weight: bold;");
Label id = new Label("ID");
Label name = new Label("Name");
Label inv = new Label("Inv");
Label price = new Label("Price");
Label max = new Label("Max");
Label min = new Label("Min");
///////////////////////////////////
idT.setPrefWidth(140);
idT.setPromptText(String.valueOf("Auto Gen - Disabled"));
idT.setFocusTraversable(false);
nameT.setPrefWidth(140);
nameT.setText("");
nameT.requestFocus();
invT.setPrefWidth(60);
invT.setText(String.valueOf(""));
priceT.setPrefWidth(60);
priceT.setText(String.valueOf(""));
maxT.setPrefWidth(60);
maxT.setText(String.valueOf(""));
minT.setPrefWidth(60);
minT.setText(String.valueOf(""));
idT.setEditable(false);
//l2 = FXCollections.observableArrayList();
///////////////////////////////////
HBox hId = new HBox(id, idT);
hId.setSpacing(30);
HBox hName = new HBox(name, nameT);
hName.setSpacing(10);
HBox hInv = new HBox(inv, invT);
hInv.setSpacing(26);
HBox hPrice = new HBox(price, priceT);
hPrice.setSpacing(16);
HBox hMaxMin = new HBox(max, maxT, min, minT);
hMaxMin.setSpacing(20);
VBox labels = new VBox(hId, hName, hInv, hPrice, hMaxMin);
labels.setSpacing(10);
labels.setStyle("-fx-padding: 20;");
VBox left = new VBox(addP, labels, error);
labels.setAlignment(Pos.CENTER_LEFT);
left.setSpacing(10);
///////////////////////////////////
TableView<Part> tb1 = new TableView<>();
TableView<Part> tb2 = new TableView<>();
TableColumn pId = new TableColumn("Part ID");
TableColumn pName = new TableColumn("Part Name");
TableColumn iLvl = new TableColumn("Inventory Level");
TableColumn pCost = new TableColumn("Price/ Cost per Unit");
TableColumn pId2 = new TableColumn("Part ID");
TableColumn pName2 = new TableColumn("Part Name");
TableColumn iLvl2 = new TableColumn("Inventory Level");
TableColumn pCost2 = new TableColumn("Price/ Cost per Unit");
tb1.getColumns().addAll(pId, pName, iLvl, pCost);
tb2.getColumns().addAll(pId2, pName2, iLvl2, pCost2);
ObservableList l1 = listParts;
ObservableList l2 = FXCollections.observableArrayList();
tb1.setItems(l1); // This is the list of parts that I can pick and choose to add to tb2
// tb2 is the list of chosen products that will then be passed as its
tb2.setItems(l2); // own list of parts that are unique to each instance of Product.
///////////////////////////////////
pId.setCellValueFactory(new PropertyValueFactory<Product, Integer>("id"));
pName.setCellValueFactory(new PropertyValueFactory<Product, String>("name"));
pId2.setCellValueFactory(new PropertyValueFactory<Product, Integer>("id"));
pName2.setCellValueFactory(new PropertyValueFactory<Product, String>("name"));
iLvl.setCellValueFactory(new PropertyValueFactory<Product, Integer>("stock"));
pCost.setCellValueFactory(new PropertyValueFactory<Product, Double>("price"));
iLvl2.setCellValueFactory(new PropertyValueFactory<Product, Integer>("stock"));
pCost2.setCellValueFactory(new PropertyValueFactory<Product, Double>("price"));
///////////////////////////////////
TextField search = new TextField();
search.setPromptText("Search by Part ID or Name");
search.setPrefWidth(160);
Button add = new Button("Add");
add.setOnAction(e -> l2.add(tb1.getSelectionModel().getSelectedItem()));
Button remove = new Button("Remove Associated Part");
remove.setOnAction(e -> {Part selected = tb2.getSelectionModel().getSelectedItem();
alert(tb2, selected);
});
Button save = new Button("Save");
save.setOnAction(e -> {pass = addInfo(l2);
if(pass == true){
FXMain.displayMain(PrimaryStage);
}
});
save.setPrefWidth(50);
Button cancel = new Button("Cancel");
cancel.setOnAction(d -> FXMain.displayMain(PrimaryStage));
///////////////////////////////////
HBox hSearch = new HBox(search);
HBox hAdd = new HBox(add);
HBox hRemove = new HBox(remove);
HBox saveCancel = new HBox(save, cancel);
hSearch.setAlignment(Pos.BASELINE_RIGHT);
saveCancel.setSpacing(41);
VBox right = new VBox(hSearch, tb1,hAdd, tb2, hRemove, saveCancel);
hRemove.setAlignment(Pos.TOP_RIGHT);
hAdd.setAlignment(Pos.BASELINE_RIGHT);
hAdd.setStyle("-fx-padding: 0 40 0 0;");
saveCancel.setAlignment(Pos.CENTER_RIGHT);
right.setSpacing(10);
///////////////////////////////////
HBox fBox = new HBox(left, right);
fBox.setSpacing(70);
fBox.setStyle("-fx-border-style: solid inside;" +
"-fx-border-radius: 5;" +
"-fx-padding: 40;");
HBox sBox = new HBox(fBox);
sBox.setStyle("-fx-padding: 30 40 10 20;");
Scene scene = new Scene(sBox, 800, 520);
PrimaryStage.setScene(scene);
PrimaryStage.show();
}
private static boolean addInfo(ObservableList l2)
{
ObservableList pass;
pass = FXCollections.observableArrayList(l2);
int lastIndex = 0;
if(!list.isEmpty()){
Product last = (Product) list.get(list.size() - 1);
lastIndex = last.getId();
}
int intMax = 0, intMin = 0, intInv = 0, intMachine = 0, check1 = 0, check2 = 0;
double doubPrice = 0;
boolean nameCheck = false, priceCheck = false, restCheck = false;
String checkName = nameT.getText(), checkInv = invT.getText(), checkPrice = priceT.getText(), checkMax = maxT.getText(), checkMin = minT.getText();
error.setText("");
String forError = "";
//Inhouse last = (Inhouse) addList.get(addList.size() - 1);
if(!checkName.isEmpty())
{
nameCheck = true;
} else {
forError = forError + "Exception: No data in name field\n";
}
try{
intInv = Integer.parseInt(checkInv);
} catch (NumberFormatException e){
forError = forError + "Exception: Inventory is not an Integer\n";
}
try{
doubPrice = Double.parseDouble(checkPrice);
priceCheck = true;
} catch (NumberFormatException e) {
forError = forError + "Exception: Price is not a Double\n";
}
try {
intMax = Integer.parseInt(checkMax);
check1 = 1;
} catch (NumberFormatException e) {
forError = forError + "Exception: Max is not an Integer\n";
}
try{
intMin = Integer.parseInt(checkMin);
check2 = 1;
} catch (NumberFormatException e){
forError = forError + "Exception: Min is not an Integer\n";
}
if(check1 == 1 && check2 == 1)
{
if(intInv > intMax || intInv < intMin)
{
forError = forError + "Inv must be between Min and Max\n";
} else {
restCheck = true;
}
if(intMin > intMax)
{
forError = forError + "Exception: Min must be less than Max\n";
}
}
error.setText(forError);
if(nameCheck == true && priceCheck == true && restCheck == true)
{
list.add(new Product((lastIndex + 1), checkName, doubPrice, intInv, intMin, intMax, pass));
return true;
} else{
return false;
}
}
public static void alert(TableView table, Part selected){
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Associated Parts");
alert.setHeaderText("Do you want to remove this part?");
alert.setContentText("Remove");
Optional<ButtonType> result = alert.showAndWait();
if(result.get() == ButtonType.OK)
{
table.getItems().remove(selected);
}
}
}
ModifyProductClass
public class ModifyProduct
{
private static Label error = new Label("");
private static TextField idT = new TextField();
private static TextField nameT = new TextField();
private static TextField invT = new TextField();
private static TextField priceT = new TextField();
private static TextField maxT = new TextField();
private static TextField minT = new TextField();
private static boolean pass = false;
private static ObservableList list;
private static Product modify;
private static ObservableList l1;
private static ObservableList l2;
public static void displayModifyProduct(Stage primaryStage, ObservableList list, ObservableList listParts, Product modify)
{
ModifyProduct.modify = modify;
Stage PrimaryStage = primaryStage;
Label addP = new Label("Add Product");
addP.setStyle("-fx-font-weight: bold;");
Label id = new Label("ID");
Label name = new Label("Name");
Label inv = new Label("Inv");
Label price = new Label("Price");
Label max = new Label("Max");
Label min = new Label("Min");
///////////////////////////////////
idT.setPrefWidth(140);
idT.setPromptText(String.valueOf(modify.getId()));
idT.setFocusTraversable(false);
nameT.setPrefWidth(140);
nameT.setText(modify.getName());
invT.setPrefWidth(60);
invT.setText(String.valueOf(modify.getStock()));
priceT.setPrefWidth(60);
priceT.setText(String.valueOf(modify.getPrice()));
maxT.setPrefWidth(60);
maxT.setText(String.valueOf(modify.getMax()));
minT.setPrefWidth(60);
minT.setText(String.valueOf(modify.getMin()));
idT.setEditable(false);
///////////////////////////////////
HBox hId = new HBox(id, idT);
hId.setSpacing(30);
HBox hName = new HBox(name, nameT);
hName.setSpacing(10);
HBox hInv = new HBox(inv, invT);
hInv.setSpacing(26);
HBox hPrice = new HBox(price, priceT);
hPrice.setSpacing(16);
HBox hMaxMin = new HBox(max, maxT, min, minT);
hMaxMin.setSpacing(20);
VBox labels = new VBox(hId, hName, hInv, hPrice, hMaxMin);
labels.setSpacing(10);
labels.setStyle("-fx-padding: 20;");
VBox left = new VBox(addP, labels, error);
labels.setAlignment(Pos.CENTER_LEFT);
left.setSpacing(10);
///////////////////////////////////
TableView<Part> tb1 = new TableView<>();
TableView<Part> tb2 = new TableView<>();
TableColumn pId = new TableColumn("Part ID");
TableColumn pName = new TableColumn("Part Name");
TableColumn iLvl = new TableColumn("Inventory Level");
TableColumn pCost = new TableColumn("Price/ Cost per Unit");
TableColumn pId2 = new TableColumn("Part ID");
TableColumn pName2 = new TableColumn("Part Name");
TableColumn iLvl2 = new TableColumn("Inventory Level");
TableColumn pCost2 = new TableColumn("Price/ Cost per Unit");
tb1.getColumns().addAll(pId, pName, iLvl, pCost);
tb2.getColumns().addAll(pId2, pName2, iLvl2, pCost2);
l1 = listParts;
l2 = FXCollections.observableArrayList(modify.getList());
tb1.setItems(l1);
tb2.setItems(l2);
///////////////////////////////////
pId.setCellValueFactory(new PropertyValueFactory<Product, Integer>("id"));
pName.setCellValueFactory(new PropertyValueFactory<Product, String>("name"));
pId2.setCellValueFactory(new PropertyValueFactory<Product, Integer>("id"));
pName2.setCellValueFactory(new PropertyValueFactory<Product, String>("name"));
iLvl.setCellValueFactory(new PropertyValueFactory<Product, Integer>("stock"));
pCost.setCellValueFactory(new PropertyValueFactory<Product, Double>("price"));
iLvl2.setCellValueFactory(new PropertyValueFactory<Product, Integer>("stock"));
pCost2.setCellValueFactory(new PropertyValueFactory<Product, Double>("price"));
///////////////////////////////////
TextField search = new TextField();
search.setPromptText("Search by Part ID or Name");
search.setPrefWidth(160);
Button add = new Button("Add");
add.setOnAction(e -> l2.add(tb1.getSelectionModel().getSelectedItem()));
Button remove = new Button("Remove Associated Part");
remove.setOnAction(e -> {Part selected = tb2.getSelectionModel().getSelectedItem();
alert(tb2, selected);
});
Button save = new Button("Save");
save.setOnAction(e -> {pass = addInfo();
if(pass == true){
FXMain.displayMain(PrimaryStage);
}
});
save.setPrefWidth(50);
Button cancel = new Button("Cancel");
cancel.setOnAction(d -> FXMain.displayMain(PrimaryStage));
///////////////////////////////////
HBox hSearch = new HBox(search);
HBox hAdd = new HBox(add);
HBox hRemove = new HBox(remove);
HBox saveCancel = new HBox(save, cancel);
hSearch.setAlignment(Pos.BASELINE_RIGHT);
saveCancel.setSpacing(41);
VBox right = new VBox(hSearch, tb1,hAdd, tb2, hRemove, saveCancel);
hRemove.setAlignment(Pos.TOP_RIGHT);
hAdd.setAlignment(Pos.BASELINE_RIGHT);
hAdd.setStyle("-fx-padding: 0 40 0 0;");
saveCancel.setAlignment(Pos.CENTER_RIGHT);
right.setSpacing(10);
///////////////////////////////////
HBox fBox = new HBox(left, right);
fBox.setSpacing(70);
fBox.setStyle("-fx-border-style: solid inside;" +
"-fx-border-radius: 5;" +
"-fx-padding: 40;");
HBox sBox = new HBox(fBox);
sBox.setStyle("-fx-padding: 30 40 10 20;");
Scene scene = new Scene(sBox, 800, 520);
PrimaryStage.setScene(scene);
PrimaryStage.show();
}
private static boolean addInfo()
{
/**
Product last;
int lastIndex;
try{
last = (Product) list.get(list.size() - 1);
lastIndex = last.getId();
} catch(NumberFormatException e){
}
**/
int intMax = 0, intMin = 0, intInv = 0, intMachine = 0, check1 = 0, check2 = 0;
double doubPrice = 0;
boolean nameCheck = false, priceCheck = false, restCheck = false;
String checkName = nameT.getText(), checkInv = invT.getText(), checkPrice = priceT.getText(), checkMax = maxT.getText(), checkMin = minT.getText();
error.setText("");
String forError = "";
//Inhouse last = (Inhouse) addList.get(addList.size() - 1);
if(!checkName.isEmpty())
{
nameCheck = true;
} else {
forError = forError + "Exception: No data in name field\n";
}
try{
intInv = Integer.parseInt(checkInv);
} catch (NumberFormatException e){
forError = forError + "Exception: Inventory is not an Integer\n";
}
try{
doubPrice = Double.parseDouble(checkPrice);
priceCheck = true;
} catch (NumberFormatException e) {
forError = forError + "Exception: Price is not a Double\n";
}
try {
intMax = Integer.parseInt(checkMax);
check1 = 1;
} catch (NumberFormatException e) {
forError = forError + "Exception: Max is not an Integer\n";
}
try{
intMin = Integer.parseInt(checkMin);
check2 = 1;
} catch (NumberFormatException e){
forError = forError + "Exception: Min is not an Integer\n";
}
if(check1 == 1 && check2 == 1)
{
if(intInv > intMax || intInv < intMin)
{
forError = forError + "Inv must be between Min and Max\n";
} else {
restCheck = true;
}
if(intMin > intMax)
{
forError = forError + "Exception: Min must be less than Max\n";
}
}
error.setText(forError);
if(nameCheck == true && priceCheck == true && restCheck == true)
{
modify.setName(checkName);
modify.setPrice(doubPrice);
modify.setStock(intInv);
modify.setMax(intMax);
modify.setMin(intMin);
modify.setToList(l2);
l1 = FXCollections.observableArrayList();
l2 = FXCollections.observableArrayList();
idT.setText("");
nameT.setText("");
priceT.setText("");
minT.setText("");
maxT.setText("");
return true;
} else{
return false;
}
}
public static void alert(TableView table, Part selected){
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Associated Parts");
alert.setHeaderText("Do you want to remove this part?");
alert.setContentText("Remove");
Optional<ButtonType> result = alert.showAndWait();
if(result.get() == ButtonType.OK)
{
modify.removePart(table, selected);
}
}
}
Product
public class Product extends Part{
private static ObservableList data; // = FXCollections.observableArrayList();
public Product(int id, String name, double price, int stock, int min, int max)
{
super(id, name, price, stock, min, max);
}
public Product(int id, String name, double price, int stock, int min, int max, ObservableList firstData)
{
super(id, name, price, stock, min, max);
this.data = FXCollections.observableArrayList(firstData);
}
public void setToList(ObservableList addTo)
{
this.data = FXCollections.observableArrayList(addTo);
}
public ObservableList getList()
{
return this.data;
}
public void removePart(TableView table, Part part)
{
table.getItems().remove(part);
}
public boolean check()
{
if(data.isEmpty() == true)
{
return true;
} else {
return false;
}
}
}