1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package Controllers;
21
22 import Exceptions.AccessException;
23 import Launchers.AddGroup;
24 import Utilities.*;
25 import Workers.LoadUGYWorker;
26 import javafx.application.Platform;
27 import javafx.collections.FXCollections;
28 import javafx.collections.ObservableList;
29 import javafx.event.ActionEvent;
30 import javafx.fxml.FXML;
31 import javafx.fxml.FXMLLoader;
32 import javafx.geometry.Insets;
33 import javafx.scene.Node;
34 import javafx.scene.control.*;
35 import javafx.scene.control.cell.CheckBoxTreeCell;
36 import javafx.scene.control.cell.ComboBoxTableCell;
37 import javafx.scene.control.cell.PropertyValueFactory;
38 import javafx.scene.control.cell.TextFieldTableCell;
39 import javafx.scene.input.MouseEvent;
40 import javafx.scene.layout.*;
41 import javafx.stage.FileChooser;
42 import javafx.stage.Window;
43 import javafx.util.Pair;
44 import org.apache.commons.lang3.RandomStringUtils;
45 import org.w3c.dom.Attr;
46 import org.w3c.dom.Document;
47 import org.w3c.dom.Element;
48 import org.w3c.dom.NodeList;
49
50 import javax.xml.parsers.DocumentBuilder;
51 import javax.xml.parsers.DocumentBuilderFactory;
52 import javax.xml.parsers.ParserConfigurationException;
53 import javax.xml.transform.*;
54 import javax.xml.transform.dom.DOMSource;
55 import javax.xml.transform.stream.StreamResult;
56 import java.io.*;
57 import java.math.BigDecimal;
58 import java.security.SecureRandom;
59 import java.sql.SQLException;
60 import java.time.LocalDate;
61 import java.util.*;
62 import java.util.regex.Pattern;
63
64
65
66 public class UsersGroupsAndYearsController {
67 @FXML
68 TabPane tabPane;
69 @FXML
70 TitledPane enabledUsersPane;
71 @FXML
72 TitledPane disabledUserPane;
73 @FXML
74 VBox groupVbox;
75 @FXML
76 VBox enabledUserVbox;
77 @FXML
78 ScrollPane enabledUsersScrollPane;
79 @FXML
80 TitledPane archivedUsersPane;
81 @FXML
82 VBox archivedUserVbox;
83 @FXML
84 ScrollPane archivedUsersScrollPane;
85 @FXML
86 ScrollPane disabledUsersScrollPane;
87 @FXML
88 ScrollPane groupScrollPane;
89 @FXML
90 VBox disabledUserVbox;
91 @FXML
92 TreeView<TreeItemPair<String, Pair<String, Object>>> summaryList;
93 @FXML
94 MenuButton userMenuBtn;
95 @FXML
96 SplitMenuButton addUserSplitBtn;
97 @FXML
98 MenuButton groupMenuBtn;
99 @FXML
100 Tab productsTab;
101 @FXML
102 Tab usersTab;
103 @FXML
104 Tab groupsTab;
105 Window parentWindow;
106 @FXML
107 private TableView<formattedProductProps> ProductTable;
108 @FXML
109 private TextField itemTb;
110 @FXML
111 private TextField sizeTb;
112 @FXML
113 private TextField rateTb;
114 @FXML
115 private TextField idTb;
116
117
118 private Map<String, Map<String, User>> cachedUsers = new HashMap<>();
119
120 private Map<String, ArrayList<Group>> cachedGroups = new HashMap<>();
121
122 private Collection<Year.category> rowsCats = new ArrayList<Year.category>();
123 private ObservableList<String> categoriesTb = FXCollections.observableArrayList();
124 @FXML
125 private ComboBox<String> categoriesCmbx;
126 private ObservableList<formattedProductProps> data = FXCollections.observableArrayList();
127 private Map<User, ArrayList<String>> checkedUsers = new HashMap();
128 private Map<Group, ArrayList<String>> checkedGroups = new HashMap();
129 private Map<User, User.STATUS> selectedUsers = new HashMap<User, User.STATUS>();
130 private ArrayList<Group> selectedGroups = new ArrayList<>();
131 private ArrayList<CheckBox> userPaneCheckboxes = new ArrayList<>();
132 private ArrayList<CheckBox> groupPaneCheckboxes = new ArrayList<>();
133 private Map<User, Node> allUsers = new HashMap();
134 private Map<Group, Node> allGroups = new HashMap();
135
136
137 private Map<User, Integer> groups = new HashMap<>();
138 private boolean isRightClick;
139 private String curYear = "";
140 public UsersGroupsAndYearsController() {
141
142 }
143
144
145
146
147 public void initUsersGroupsAndYears(Window parWindow) throws AccessException {
148 parentWindow = parWindow;
149 fillTreeView(null);
150
151 summaryList.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
152 if (event.isSecondaryButtonDown()) {
153 isRightClick = true;
154
155 }
156 if (event.getClickCount() == 2) {
157
158 Platform.runLater(() -> {
159 TreeItemPair<String, Pair<String, Object>> newValue = summaryList.getSelectionModel().getSelectedItem().getValue();
160 if (isRightClick) {
161
162 isRightClick = false;
163 } else if (newValue != null && !Objects.equals(newValue.getValue().getValue(), "RootNode")) {
164
165 switch (newValue.getValue().getKey()) {
166 case "Year":
167 openYear(newValue.getKey());
168 break;
169 case "Group":
170 String year = "";
171 if (summaryList.getSelectionModel().getSelectedItem().getParent().getValue().getValue().getKey().equals("Year")) {
172 year = summaryList.getSelectionModel().getSelectedItem().getParent().getValue().getKey();
173 } else if (summaryList.getSelectionModel().getSelectedItem().getParent().getParent().getValue().getValue().getKey().equals("Year")) {
174 year = summaryList.getSelectionModel().getSelectedItem().getParent().getParent().getValue().getKey();
175
176 }
177 openGroup((Group) newValue.getValue().getValue(), year);
178 break;
179 case "User":
180 year = "";
181 if (summaryList.getSelectionModel().getSelectedItem().getParent().getValue().getValue().getKey().equals("Year")) {
182 year = summaryList.getSelectionModel().getSelectedItem().getParent().getValue().getKey();
183 } else if (summaryList.getSelectionModel().getSelectedItem().getParent().getParent().getValue().getValue().getKey().equals("Year")) {
184 year = summaryList.getSelectionModel().getSelectedItem().getParent().getParent().getValue().getKey();
185
186 }
187 openUser((User) newValue.getValue().getValue(), year);
188
189 break;
190
191
192 }
193 }
194 });
195 }
196 });
197
198 summaryList.setCellFactory(p -> new TreeCellImpl());
199 }
200
201 private void fillTreeView(actionCallback cb) {
202
203 ProgressForm progDial = new ProgressForm();
204
205
206 LoadUGYWorker loadWorker = new LoadUGYWorker(this);
207
208 progDial.activateProgressBar(loadWorker);
209 loadWorker.setOnSucceeded(event -> {
210 summaryList.setRoot(loadWorker.getValue().getLeft());
211 cachedUsers = loadWorker.getValue().getMiddle();
212 cachedGroups = loadWorker.getValue().getRight();
213 progDial.getDialogStage().close();
214 if (cb != null) {
215 cb.doAction();
216 }
217 });
218 loadWorker.setOnFailed(event -> {
219 progDial.getDialogStage().close();
220
221 Throwable e = loadWorker.getException();
222
223 if (e instanceof SQLException) {
224 LogToFile.log((SQLException) e, Severity.SEVERE, CommonErrors.returnSqlMessage(((SQLException) loadWorker.getException())));
225
226 }
227 if (e instanceof InterruptedException) {
228 if (loadWorker.isCancelled()) {
229 LogToFile.log((InterruptedException) e, Severity.FINE, "Load process canceled.");
230
231 }
232 }
233
234
235 });
236
237
238 progDial.getDialogStage().show();
239 new Thread(loadWorker).start();
240 }
241
242 private void showTabs() {
243 productsTab.setDisable(false);
244 usersTab.setDisable(false);
245 groupsTab.setDisable(false);
246 }
247
248 private void hideTabs() {
249 productsTab.setDisable(true);
250 usersTab.setDisable(true);
251 groupsTab.setDisable(true);
252
253 }
254 private void openYear(String year) {
255 archivedUserVbox.getChildren().clear();
256 groupVbox.getChildren().clear();
257 disabledUserVbox.getChildren().clear();
258 enabledUserVbox.getChildren().clear();
259
260 curYear = year;
261 Year yearObj = new Year(year);
262
263 allUsers.clear();
264 allGroups.clear();
265 selectedUsers.clear();
266 userPaneCheckboxes.clear();
267 checkedUsers.clear();
268
269 cachedUsers.forEach((key, value) -> {
270 User user = value.getOrDefault(year, null);
271 User.STATUS status;
272
273 TitledPane userPane = new TitledPane();
274 if (user != null) {
275 if (user.getYears().contains(year)) {
276 status = User.STATUS.ENABLED;
277 enabledUserVbox.getChildren().add(userPane);
278 } else {
279 status = User.STATUS.ARCHIVED;
280 archivedUserVbox.getChildren().add(userPane);
281 }
282 } else {
283 status = User.STATUS.DISABLED;
284 user = value.get("DB");
285 disabledUserVbox.getChildren().add(userPane);
286
287 }
288 CheckBox selectedCheckBox = new CheckBox(user.getFullName() + " (" + user.getUserName() + ")");
289 selectedCheckBox.setMinSize(CheckBox.USE_PREF_SIZE, CheckBox.USE_PREF_SIZE);
290 User finalUser = user;
291 userPaneCheckboxes.add(selectedCheckBox);
292 selectedCheckBox.selectedProperty().addListener((ob, oldVal, newVal) -> {
293 if (newVal) {
294 if (!selectedUsers.containsKey(finalUser)) {
295 selectedUsers.put(finalUser, status);
296
297 }
298 } else {
299 if (selectedUsers.containsKey(finalUser)) {
300 selectedUsers.remove(finalUser, status);
301
302 }
303 }
304 });
305
306 Button editButton = new Button("Edit");
307 editButton.setMinSize(Button.USE_PREF_SIZE, Button.USE_PREF_SIZE);
308 editButton.setOnAction(event -> {
309 editUser(finalUser);
310 });
311 Button deleteBtn = new Button("Delete");
312 deleteBtn.setOnAction(event -> {
313 deleteUser(finalUser);
314 });
315 deleteBtn.getStyleClass().add("redBtn");
316 deleteBtn.setStyle("-fx-background-color: #ff4d4d");
317
318 Pane spacer = new Pane();
319 HBox.setHgrow(spacer, Priority.ALWAYS);
320 spacer.setMinSize(10, 1);
321 spacer.setMaxWidth(Double.MAX_VALUE);
322
323 VBox headerRoot = new VBox();
324 headerRoot.setFillWidth(true);
325 HBox header = new HBox();
326
327
328 header.minWidthProperty().bind(userPane.widthProperty().subtract(75));
329
330
331
332
333
334
335 header.getChildren().setAll(selectedCheckBox, spacer, deleteBtn, editButton);
336 HBox.setHgrow(spacer, Priority.ALWAYS);
337 spacer.setMinSize(10, 1);
338 userPane.setText(user.getFullName() + " (" + user.getUserName() + ")");
339 headerRoot.getChildren().setAll(header);
340 userPane.setGraphic(header);
341 userPane.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
342 userPane.setExpanded(false);
343
344
345
346 userPane.getStyleClass().add("informationPane");
347
348 VBox.setVgrow(userPane, Priority.ALWAYS);
349 FlowPane pane = new FlowPane();
350
351
352 ComboBox<TreeItemPair<String, Integer>> groupBox = new ComboBox<>();
353 TreeView<TreeItemPair<String, String>> yearTView;
354 CheckBoxTreeItem<TreeItemPair<String, String>> yearItem = new CheckBoxTreeItem<TreeItemPair<String, String>>(new TreeItemPair<>(year, ""));
355 User currentUser = user;
356 if (status != User.STATUS.DISABLED) {
357 cachedGroups.get(year).forEach(group -> {
358 CheckBoxTreeItem<TreeItemPair<String, String>> groupItem = new CheckBoxTreeItem<TreeItemPair<String, String>>(new TreeItemPair<>(group.getName(), ""));
359
360 group.getUsers().forEach(user2 -> {
361 CheckBoxTreeItem<TreeItemPair<String, String>> userItem = createUserTreeItem(new TreeItemPair<>(user2.getFullName(), user2.getUserName()), currentUser);
362 if (currentUser.getuManage().contains(user2.getUserName())) {
363 userItem.setSelected(true);
364 checkedUsers.computeIfPresent(currentUser, (k, v) -> {
365 if (!v.contains(user2.getUserName())) {
366
367 v.add(user2.getUserName());
368 }
369 return v;
370 });
371 checkedUsers.computeIfAbsent(currentUser, k -> {
372 ArrayList<String> v = new ArrayList();
373 v.add(user2.getUserName());
374 return v;
375 });
376
377
378
379
380
381
382
383
384
385
386
387 }
388 groupItem.getChildren().add(userItem);
389 });
390 yearItem.getChildren().add(groupItem);
391 try {
392 groupBox.getItems().add(new TreeItemPair<String, Integer>(group.getName(), group.getID()));
393 if (currentUser.getGroupId() == group.getID()) {
394 groupBox.getSelectionModel().selectLast();
395 } else if (currentUser.getGroupId() == 0) {
396 groupBox.getSelectionModel().selectFirst();
397
398 }
399
400 } catch (Group.GroupNotFoundException ignored) {
401 }
402
403 });
404
405 yearTView = new TreeView(yearItem);
406 yearTView.setPrefHeight(TreeView.USE_COMPUTED_SIZE);
407 yearTView.setMinHeight(70);
408 yearTView.setPrefWidth(TreeView.USE_COMPUTED_SIZE);
409 yearTView.getStyleClass().add("lightTreeView");
410 yearItem.setExpanded(true);
411 yearTView.setCellFactory(CheckBoxTreeCell.forTreeView());
412 yearTView.setFixedCellSize(35);
413
414 yearTView.expandedItemCountProperty().addListener((ob, oldVal, newVal) -> {
415 Platform.runLater(() -> {
416 yearTView.setPrefHeight(newVal.doubleValue() * (yearTView.getFixedCellSize()) + 10);
417 yearTView.setMinHeight(newVal.doubleValue() * (yearTView.getFixedCellSize()) + 10);
418
419 yearTView.refresh();
420 });
421
422 });
423 yearTView.refresh();
424 groupBox.getSelectionModel().selectedItemProperty().addListener(observable -> {
425
426 groups.put(currentUser, groupBox.getSelectionModel().getSelectedItem().getValue());
427 });
428 VBox.setVgrow(yearTView, Priority.ALWAYS);
429 VBox center = new VBox(10, new Label("Users to manage"), yearTView);
430 center.setFillWidth(true);
431
432 BorderPane contents = new BorderPane(center, new HBox(10, new Label("Group to be a part of"), groupBox), null, null, null);
433 contents.getStyleClass().add("containerPane");
434 contents.setStyle("-fx-border: 0; -fx-border-insets: 0");
435 contents.autosize();
436 userPane.setContent(contents);
437
438
439 groups.put(currentUser, groupBox.getSelectionModel().getSelectedItem().getValue());
440 }
441 allUsers.put(user, userPane);
442
443 });
444
445
446 cachedGroups.get(year).forEach(group -> {
447
448
449 TitledPane groupPane = new TitledPane();
450
451 Label titleLabel = new Label(group.getName());
452 titleLabel.setMinSize(CheckBox.USE_PREF_SIZE, CheckBox.USE_PREF_SIZE);
453
454 SplitMenuButton editButton = new SplitMenuButton();
455 editButton.setText("Edit");
456 editButton.setOnAction(event -> {
457 editGroup(group);
458 });
459 Button deleteBtn = new Button("Delete");
460 deleteBtn.setOnAction(event -> {
461 deleteGroup(group);
462
463 });
464 deleteBtn.getStyleClass().add("redBtn");
465 deleteBtn.setStyle("-fx-background-color: #ff4d4d");
466
467 MenuItem removeAllFromGroup = new MenuItem("Remove all From group");
468 removeAllFromGroup.setOnAction(event -> {
469 checkedGroups.forEach((grp, Users) -> {
470 Users.forEach(usrString -> {
471 User usr = new User(usrString, year, true);
472 usr.setGroupId(1);
473 usr.updateYear(year);
474 });
475 });
476 refresh(null);
477 });
478 editButton.getItems().add(removeAllFromGroup);
479 editButton.setMinSize(Button.USE_PREF_SIZE, Button.USE_PREF_SIZE);
480
481 Pane spacer = new Pane();
482 HBox.setHgrow(spacer, Priority.ALWAYS);
483 spacer.setMinSize(10, 1);
484 spacer.setMaxWidth(Double.MAX_VALUE);
485
486 VBox headerRoot = new VBox();
487 headerRoot.setFillWidth(true);
488 HBox header = new HBox();
489
490
491 header.minWidthProperty().bind(groupPane.widthProperty().subtract(75));
492
493
494
495
496
497
498 header.getChildren().setAll(titleLabel, spacer, deleteBtn, editButton);
499 HBox.setHgrow(spacer, Priority.ALWAYS);
500 spacer.setMinSize(10, 1);
501 headerRoot.getChildren().setAll(header);
502 groupPane.setGraphic(header);
503 groupPane.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
504 groupPane.setExpanded(false);
505
506
507
508 groupPane.getStyleClass().add("informationPane");
509
510 groupVbox.getChildren().add(groupPane);
511
512
513 CheckBoxTreeItem<TreeItemPair<String, String>> groupItem = createGroupTreeItem(new TreeItemPair<>(group.getName(), ""), group);
514 group.getUsers().forEach(user2 -> {
515 CheckBoxTreeItem<TreeItemPair<String, String>> userItem = createGroupTreeItem(new TreeItemPair<>(user2.getFullName(), user2.getUserName()), group);
516
517 groupItem.getChildren().add(userItem);
518 });
519
520
521 TreeView<TreeItemPair<String, String>> groupTvView = new TreeView(groupItem);
522 groupTvView.setShowRoot(false);
523 groupTvView.setPrefHeight(TreeView.USE_COMPUTED_SIZE);
524 groupTvView.setMinHeight(70);
525 groupTvView.setPrefWidth(TreeView.USE_COMPUTED_SIZE);
526 groupTvView.getStyleClass().add("lightTreeView");
527 groupItem.setExpanded(true);
528 groupTvView.setCellFactory(CheckBoxTreeCell.forTreeView());
529 groupTvView.setFixedCellSize(35);
530
531 groupTvView.expandedItemCountProperty().addListener((ob, oldVal, newVal) -> {
532 Platform.runLater(() -> {
533 groupTvView.setPrefHeight(newVal.doubleValue() * (groupTvView.getFixedCellSize()) + 10);
534 groupTvView.setMinHeight(newVal.doubleValue() * (groupTvView.getFixedCellSize()) + 10);
535
536 groupTvView.refresh();
537 });
538
539 });
540 groupTvView.refresh();
541
542 groupPane.setContent(new ScrollPane(groupTvView));
543 allGroups.put(group, groupPane);
544
545 });
546
547 initProductsTab();
548 showTabs();
549 }
550
551 private void openUser(User user, String year) {
552 openYear(year);
553
554
555 if (user.getYears().contains(year)) {
556
557 TitledPane userPane = (TitledPane) allUsers.get(user);
558 userPane.setExpanded(true);
559 enabledUsersPane.setExpanded(true);
560 double vvalue = userPane.getLayoutX() / (userPane.getHeight() - enabledUsersScrollPane.getHeight());
561
562 enabledUsersScrollPane.setVvalue(vvalue);
563 } else {
564 Year yearObj = new Year(year);
565 if (yearObj.getUsers().contains(user)) {
566 TitledPane userPane = (TitledPane) allUsers.get(user);
567 userPane.setExpanded(true);
568 archivedUsersPane.setExpanded(true);
569 double vvalue = userPane.getBoundsInParent().getMinY() / (userPane.getHeight() - archivedUsersScrollPane.getHeight());
570
571 archivedUsersScrollPane.setVvalue(vvalue);
572 } else {
573 TitledPane userPane = (TitledPane) allUsers.get(user);
574 userPane.setExpanded(true);
575 disabledUserPane.setExpanded(true);
576 double vvalue = userPane.getBoundsInParent().getMinY() / (userPane.getHeight() - disabledUsersScrollPane.getHeight());
577
578 disabledUsersScrollPane.setVvalue(vvalue);
579 }
580
581
582 }
583 tabPane.getSelectionModel().select(0);
584 }
585
586 private void openGroup(Group group, String year) {
587 openYear(year);
588
589
590 TitledPane groupPane = (TitledPane) allGroups.get(group);
591 groupPane.setExpanded(true);
592 double vvalue = groupPane.getBoundsInParent().getMinY() / (groupPane.getHeight() - disabledUsersScrollPane.getHeight());
593
594 groupScrollPane.setVvalue(vvalue);
595 tabPane.getSelectionModel().select(1);
596
597 }
598
599
600 @FXML
601 private void addSelectedUsersToGroup(ActionEvent event) {
602
603 Dialog<Group> dialog = new Dialog<>();
604 dialog.setTitle("Select Group");
605
606
607 ButtonType login = new ButtonType("Group", ButtonBar.ButtonData.OK_DONE);
608 dialog.getDialogPane().getButtonTypes().addAll(login, ButtonType.CANCEL);
609
610
611 GridPane grid = new GridPane();
612 grid.setHgap(10);
613 grid.setVgap(10);
614 grid.setPadding(new Insets(20, 150, 10, 10));
615
616 ComboBox<Group> groupComboBox = new ComboBox<>();
617 groupComboBox.getItems().addAll(Group.getGroupCollection(curYear));
618
619 grid.add(new Label("Group:"), 0, 0);
620 grid.add(groupComboBox, 1, 0);
621
622
623
624 javafx.scene.Node loginButton = dialog.getDialogPane().lookupButton(login);
625 loginButton.setDisable(true);
626
627
628
629 groupComboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> loginButton.setDisable(newValue == null));
630
631 dialog.getDialogPane().setContent(grid);
632
633
634 Platform.runLater(() -> groupComboBox.requestFocus());
635
636
637 dialog.setResultConverter(dialogButton -> {
638 if (dialogButton == login) {
639 return groupComboBox.getSelectionModel().getSelectedItem();
640 }
641 return null;
642 });
643
644 Optional<Group> result = dialog.showAndWait();
645
646 result.ifPresent(group -> {
647 Boolean alertDisabled = false;
648 selectedUsers.forEach((user, status) -> {
649 if (status != User.STATUS.DISABLED) {
650 try {
651 user.setGroupId(group.getID());
652 } catch (Group.GroupNotFoundException ignored) {
653 }
654 user.updateYear(curYear);
655 }
656
657 });
658 if (selectedUsers.containsValue(User.STATUS.DISABLED)) {
659 Alert alert = new Alert(Alert.AlertType.INFORMATION);
660 alert.setContentText("Operation applied. Disabled User(s) were skipped.");
661 alert.show();
662 }
663 selectedUsers.clear();
664 unselectAllUserPanes();
665 });
666
667
668 }
669
670 private void unselectAllUserPanes() {
671 userPaneCheckboxes.forEach(checkBox -> {
672 checkBox.setSelected(false);
673 });
674 }
675
676 private void unselectAllGroupUsers() {
677
678 }
679
680 @FXML
681 private void disableSelectedUsers(ActionEvent event) {
682 Optional<Group> returnGroup = Optional.empty();
683 Dialog<String> dialog = new Dialog<>();
684 dialog.setTitle("REMOVE USERS FROM YEAR?");
685 dialog.setHeaderText("This will delete ALL customers and data associated with these users for the selected year.");
686
687 ButtonType addGrp = new ButtonType("Remove", ButtonBar.ButtonData.OK_DONE);
688 dialog.getDialogPane().getButtonTypes().addAll(addGrp, ButtonType.CANCEL);
689
690
691 GridPane grid = new GridPane();
692 grid.setHgap(10);
693 grid.setVgap(10);
694 grid.setPadding(new Insets(20, 150, 10, 10));
695
696 TextField verifyUNameTF = new TextField();
697 char[] possibleCharacters = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-=").toCharArray();
698 String randomStr = RandomStringUtils.random(7, 0, possibleCharacters.length - 1, false, false, possibleCharacters, new SecureRandom());
699 grid.add(new Label("Please enter the verification code for confirmation:"), 0, 0);
700 grid.add(verifyUNameTF, 1, 0);
701 Label verificationCode = new Label(randomStr);
702 verificationCode.setStyle("-fx-font-size: 20px; -fx-font-weight: 600; -fx-color: black");
703 grid.add(new Label("Verification Code: "), 0, 1);
704 grid.add(verificationCode, 1, 1);
705
706
707
708 javafx.scene.Node deleteUserButton = dialog.getDialogPane().lookupButton(addGrp);
709 deleteUserButton.setDisable(true);
710 deleteUserButton.setStyle("fx-background-color: Red; fx-color: White");
711
712 verifyUNameTF.textProperty().addListener((observable, oldValue, newValue) -> {
713 if (Objects.equals(newValue, randomStr)) {
714 deleteUserButton.setDisable(false);
715 } else {
716 deleteUserButton.setDisable(true);
717 }
718 });
719
720 dialog.getDialogPane().setContent(grid);
721
722
723 Platform.runLater(() -> verifyUNameTF.requestFocus());
724
725
726 dialog.setResultConverter(dialogButton -> {
727 if (dialogButton == addGrp) {
728 return verifyUNameTF.getText();
729 }
730 return null;
731 });
732
733 Optional<String> result = dialog.showAndWait();
734 result.ifPresent(res -> {
735 if (res.equals(randomStr)) {
736 selectedUsers.forEach((user, status) -> {
737 user.deleteFromYear(curYear);
738
739 });
740 hideTabs();
741 openYear(curYear);
742 }
743 });
744 }
745
746 @FXML
747 private void archiveSelectedUsers(ActionEvent event) {
748 Optional<Group> returnGroup = Optional.empty();
749 Dialog<String> dialog = new Dialog<>();
750 dialog.setTitle("ARCHIVE SELECTED USERS?");
751 dialog.setHeaderText("Selected users will no longer have access to the selected year.");
752
753 ButtonType addGrp = new ButtonType("Archive", ButtonBar.ButtonData.OK_DONE);
754 dialog.getDialogPane().getButtonTypes().addAll(addGrp, ButtonType.CANCEL);
755
756
757 GridPane grid = new GridPane();
758 grid.setHgap(10);
759 grid.setVgap(10);
760 grid.setPadding(new Insets(20, 150, 10, 10));
761
762 TextField verifyUNameTF = new TextField();
763 char[] possibleCharacters = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-=").toCharArray();
764 String randomStr = RandomStringUtils.random(7, 0, possibleCharacters.length - 1, false, false, possibleCharacters, new SecureRandom());
765 grid.add(new Label("Please enter the verification code for confirmation:"), 0, 0);
766 grid.add(verifyUNameTF, 1, 0);
767 Label verificationCode = new Label(randomStr);
768 verificationCode.setStyle("-fx-font-size: 20px; -fx-font-weight: 600; -fx-color: black");
769 grid.add(new Label("Verification Code: "), 0, 1);
770 grid.add(verificationCode, 1, 1);
771
772
773
774 javafx.scene.Node deleteUserButton = dialog.getDialogPane().lookupButton(addGrp);
775 deleteUserButton.setDisable(true);
776 deleteUserButton.setStyle("fx-background-color: Red; fx-color: White");
777
778 verifyUNameTF.textProperty().addListener((observable, oldValue, newValue) -> {
779 if (Objects.equals(newValue, randomStr)) {
780 deleteUserButton.setDisable(false);
781 } else {
782 deleteUserButton.setDisable(true);
783 }
784 });
785
786 dialog.getDialogPane().setContent(grid);
787
788
789 Platform.runLater(() -> verifyUNameTF.requestFocus());
790
791
792 dialog.setResultConverter(dialogButton -> {
793 if (dialogButton == addGrp) {
794 return verifyUNameTF.getText();
795 }
796 return null;
797 });
798
799 Optional<String> result = dialog.showAndWait();
800 result.ifPresent(res -> {
801 if (res.equals(randomStr)) {
802 selectedUsers.forEach((user, status) -> {
803 Set<String> yrs = user.getYears();
804 yrs.remove(curYear);
805 user.setYears(yrs);
806 user.updateYear(curYear);
807
808 });
809 hideTabs();
810 openYear(curYear);
811 }
812 });
813 }
814
815 @FXML
816 private void enableSelectedUsers(ActionEvent event) {
817 selectedUsers.forEach((user, status) -> {
818 if (status == User.STATUS.DISABLED) {
819 ArrayList<String> uMan = new ArrayList<>();
820 uMan.add(user.getUserName());
821 user.setuManage(uMan);
822 Set<String> yrs = user.getYears();
823 yrs.add(curYear);
824 user.setYears(yrs);
825 user.updateYear(curYear);
826 } else if (status == User.STATUS.ARCHIVED) {
827 Set<String> yrs = user.getYears();
828 yrs.add(curYear);
829 user.setYears(yrs);
830 user.updateYear(curYear);
831 }
832 });
833 hideTabs();
834 openYear(curYear);
835 }
836
837 @FXML
838 private void addSelectedUsersToUser(ActionEvent event) {
839 Dialog<User> dialog = new Dialog<>();
840 dialog.setTitle("Select User as Manager");
841
842
843 ButtonType login = new ButtonType("Set Manager", ButtonBar.ButtonData.OK_DONE);
844 dialog.getDialogPane().getButtonTypes().addAll(login, ButtonType.CANCEL);
845
846
847 GridPane grid = new GridPane();
848 grid.setHgap(10);
849 grid.setVgap(10);
850 grid.setPadding(new Insets(20, 150, 10, 10));
851
852 ComboBox<User> groupComboBox = new ComboBox<>();
853 groupComboBox.getItems().addAll(new Year(curYear).getUsers());
854
855 grid.add(new Label("User:"), 0, 0);
856 grid.add(groupComboBox, 1, 0);
857
858
859
860 javafx.scene.Node loginButton = dialog.getDialogPane().lookupButton(login);
861 loginButton.setDisable(true);
862
863
864
865 groupComboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> loginButton.setDisable(newValue == null));
866
867 dialog.getDialogPane().setContent(grid);
868
869
870 Platform.runLater(() -> groupComboBox.requestFocus());
871
872
873 dialog.setResultConverter(dialogButton -> {
874 if (dialogButton == login) {
875 return groupComboBox.getSelectionModel().getSelectedItem();
876 }
877 return null;
878 });
879
880 Optional<User> result = dialog.showAndWait();
881
882 result.ifPresent(user -> {
883 Boolean alertDisabled = false;
884
885 ArrayList<String> uManage = user.getuManage();
886 selectedUsers.forEach((selectedUser, status) -> {
887 if (!uManage.contains(selectedUser.getUserName())) {
888 uManage.add(selectedUser.getUserName());
889 }
890 });
891 user.setuManage(uManage);
892
893
894 user.updateYear(curYear);
895
896
897 hideTabs();
898 openYear(curYear);
899 });
900 }
901
902 @FXML
903 private void cancelUser(ActionEvent event) {
904
905 }
906
907 private void deleteUser(User user) {
908 Optional<Group> returnGroup = Optional.empty();
909 Dialog<String> dialog = new Dialog<>();
910 dialog.setTitle("REMOVE USER FROM YEAR?");
911 dialog.setHeaderText("This will delete ALL customers and data associated with this user for the selected year.");
912
913 ButtonType addGrp = new ButtonType("Remove", ButtonBar.ButtonData.OK_DONE);
914 dialog.getDialogPane().getButtonTypes().addAll(addGrp, ButtonType.CANCEL);
915
916
917 GridPane grid = new GridPane();
918 grid.setHgap(10);
919 grid.setVgap(10);
920 grid.setPadding(new Insets(20, 150, 10, 10));
921
922 TextField verifyUNameTF = new TextField();
923 char[] possibleCharacters = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-=").toCharArray();
924 String randomStr = RandomStringUtils.random(7, 0, possibleCharacters.length - 1, false, false, possibleCharacters, new SecureRandom());
925 grid.add(new Label("Please enter the verification code for confirmation:"), 0, 0);
926 grid.add(verifyUNameTF, 1, 0);
927 Label verificationCode = new Label(randomStr);
928 verificationCode.setStyle("-fx-font-size: 20px; -fx-font-weight: 600; -fx-color: black");
929 grid.add(new Label("Verification Code: "), 0, 1);
930 grid.add(verificationCode, 1, 1);
931
932
933
934 javafx.scene.Node deleteUserButton = dialog.getDialogPane().lookupButton(addGrp);
935 deleteUserButton.setDisable(true);
936 deleteUserButton.setStyle("fx-background-color: Red; fx-color: White");
937
938 verifyUNameTF.textProperty().addListener((observable, oldValue, newValue) -> {
939 if (Objects.equals(newValue, randomStr)) {
940 deleteUserButton.setDisable(false);
941 } else {
942 deleteUserButton.setDisable(true);
943 }
944 });
945
946 dialog.getDialogPane().setContent(grid);
947
948
949 Platform.runLater(() -> verifyUNameTF.requestFocus());
950
951
952 dialog.setResultConverter(dialogButton -> {
953 if (dialogButton == addGrp) {
954 return verifyUNameTF.getText();
955 }
956 return null;
957 });
958
959 Optional<String> result = dialog.showAndWait();
960 result.ifPresent(res -> {
961 if (res.equals(randomStr)) {
962 user.deleteFromYear(curYear);
963 hideTabs();
964 openYear(curYear);
965 }
966 });
967 }
968
969 private void deleteGroup(Group group) {
970 Optional<Group> returnGroup = Optional.empty();
971 Dialog<String> dialog = new Dialog<>();
972 dialog.setTitle("Delete Group");
973 dialog.setHeaderText("This will move all the users to the ungrouped group.");
974
975 ButtonType addGrp = new ButtonType("Delete", ButtonBar.ButtonData.OK_DONE);
976 dialog.getDialogPane().getButtonTypes().addAll(addGrp, ButtonType.CANCEL);
977
978
979 GridPane grid = new GridPane();
980 grid.setHgap(10);
981 grid.setVgap(10);
982 grid.setPadding(new Insets(20, 150, 10, 10));
983
984 TextField verifyUNameTF = new TextField();
985 char[] possibleCharacters = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-=").toCharArray();
986 String randomStr = RandomStringUtils.random(7, 0, possibleCharacters.length - 1, false, false, possibleCharacters, new SecureRandom());
987 grid.add(new Label("Please enter the verification code for confirmation:"), 0, 0);
988 grid.add(verifyUNameTF, 1, 0);
989 Label verificationCode = new Label(randomStr);
990 verificationCode.setStyle("-fx-font-size: 20px; -fx-font-weight: 600; -fx-color: black");
991 grid.add(new Label("Verification Code: "), 0, 1);
992 grid.add(verificationCode, 1, 1);
993
994
995
996 javafx.scene.Node deleteUserButton = dialog.getDialogPane().lookupButton(addGrp);
997 deleteUserButton.setDisable(true);
998 deleteUserButton.setStyle("fx-background-color: Red; fx-color: White");
999
1000 verifyUNameTF.textProperty().addListener((observable, oldValue, newValue) -> {
1001 if (Objects.equals(newValue, randomStr)) {
1002 deleteUserButton.setDisable(false);
1003 } else {
1004 deleteUserButton.setDisable(true);
1005 }
1006 });
1007
1008 dialog.getDialogPane().setContent(grid);
1009
1010
1011 Platform.runLater(() -> verifyUNameTF.requestFocus());
1012
1013
1014 dialog.setResultConverter(dialogButton -> {
1015 if (dialogButton == addGrp) {
1016 return verifyUNameTF.getText();
1017 }
1018 return null;
1019 });
1020
1021 Optional<String> result = dialog.showAndWait();
1022 result.ifPresent(res -> {
1023 if (res.equals(randomStr)) {
1024 group.removeGroup();
1025 refresh(null);
1026 }
1027 });
1028 }
1029
1030 private void editUser(User user) {
1031 User oldUser = user;
1032 Dialog<Pair<Pair<String, Boolean>, Pair<String, String>>> dialog = new Dialog<>();
1033 dialog.setTitle("Edit User - " + user.toString());
1034
1035
1036 ButtonType login = new ButtonType("Edit", ButtonBar.ButtonData.OK_DONE);
1037 dialog.getDialogPane().getButtonTypes().addAll(login, ButtonType.CANCEL);
1038
1039
1040 GridPane grid = new GridPane();
1041 grid.setHgap(10);
1042 grid.setVgap(10);
1043 grid.setPadding(new Insets(20, 150, 10, 10));
1044
1045 TextField userNameTextField = new TextField();
1046 userNameTextField.setText(user.getUserName());
1047 userNameTextField.setEditable(false);
1048 TextField fullNameField = new TextField();
1049 fullNameField.setText(user.getFullName());
1050 PasswordField passwordField = new PasswordField();
1051 passwordField.setPromptText("Password");
1052 CheckBox adminCheckBox = new CheckBox("Admin?");
1053 adminCheckBox.setSelected(user.isAdmin());
1054
1055 grid.add(new Label("Username:"), 0, 0);
1056 grid.add(userNameTextField, 1, 0);
1057 grid.add(new Label("Full Name:"), 0, 1);
1058 grid.add(fullNameField, 1, 1);
1059 grid.add(new Label("Password:"), 0, 2);
1060 grid.add(passwordField, 1, 2);
1061 grid.add(adminCheckBox, 1, 3);
1062
1063
1064 dialog.getDialogPane().setContent(grid);
1065
1066
1067 Platform.runLater(() -> userNameTextField.requestFocus());
1068
1069
1070 dialog.setResultConverter(dialogButton -> {
1071 if (dialogButton == login) {
1072 return new Pair<Pair<String, Boolean>, Pair<String, String>>(new Pair<>(fullNameField.getText(), adminCheckBox.isSelected()), new Pair<>(userNameTextField.getText(), passwordField.getText()));
1073 }
1074 return null;
1075 });
1076
1077 Optional<Pair<Pair<String, Boolean>, Pair<String, String>>> result = dialog.showAndWait();
1078
1079 result.ifPresent(userInfo -> {
1080 Pattern p = Pattern.compile("[^a-zA-Z0-9]");
1081 String uName = userInfo.getValue().getKey();
1082 String pass = userInfo.getValue().getValue();
1083 String fName = userInfo.getKey().getKey();
1084 Boolean admin = userInfo.getKey().getValue();
1085 boolean hasSpecialChar = p.matcher(userInfo.getValue().getKey()).find();
1086 if (hasSpecialChar) {
1087 Alert alert = new Alert(Alert.AlertType.WARNING);
1088 alert.setTitle("");
1089 alert.setHeaderText("You have entered an invalid character in the username");
1090 alert.setContentText("Only Alphanumeric characters are aloud.");
1091 alert.show();
1092 } else {
1093 Set<String> years = new HashSet<>();
1094
1095 User.updateUser(uName, pass, fName, admin);
1096 user.setFullName(fName);
1097 user.setAdmin(admin);
1098 user.getYears().forEach(year -> {
1099 user.updateYear(year);
1100 });
1101 refresh(() -> {
1102 openUser(user, curYear);
1103 });
1104
1105
1106 ArrayList<ArrayList<String>> yearUsers = new ArrayList<>();
1107
1108
1109 }
1110
1111 });
1112
1113
1114 }
1115
1116 private void editGroup(Group group) {
1117 AddGroup.addGroup(curYear, group.getName(), (grp) -> {
1118 refresh(() -> {openGroup(grp, curYear);});
1119
1120 });
1121
1122 }
1123
1124 @FXML
1125 private void saveUsers(ActionEvent event) {
1126
1127 ArrayList<ArrayList<String>> yearUsers = new ArrayList<>();
1128 checkedUsers.forEach((user, userManage) -> {
1129 ArrayList<String> usersManage = new ArrayList<>();
1130
1131 userManage.forEach((uMan) -> {
1132 if (!uMan.isEmpty()) {
1133 usersManage.add(uMan);
1134
1135 }
1136 });
1137
1138 if (!usersManage.isEmpty()) {
1139
1140
1141 user.setuManage(usersManage);
1142 user.updateYear(curYear);
1143
1144 }
1145 });
1146 groups.forEach((user, groupId) -> {
1147 user.setGroupId(groupId);
1148 user.updateYear(curYear);
1149 });
1150
1151 refresh(null);
1152
1153 }
1154
1155 private void refresh(actionCallback cb) {
1156 hideTabs();
1157
1158 fillTreeView(() -> {
1159 openYear(curYear);
1160 if (cb != null) {
1161 cb.doAction();
1162 }
1163 });
1164 }
1165
1166 @FXML
1167 private void addSingleUser(ActionEvent event) {
1168 Dialog<Pair<Pair<String, Boolean>, Pair<String, String>>> dialog = new Dialog<>();
1169 dialog.setTitle("Add User");
1170
1171
1172 ButtonType login = new ButtonType("Add", ButtonBar.ButtonData.OK_DONE);
1173 dialog.getDialogPane().getButtonTypes().addAll(login, ButtonType.CANCEL);
1174
1175
1176 GridPane grid = new GridPane();
1177 grid.setHgap(10);
1178 grid.setVgap(10);
1179 grid.setPadding(new Insets(20, 150, 10, 10));
1180
1181 TextField userNameTextField = new TextField();
1182 userNameTextField.setPromptText("Username");
1183 TextField fullNameField = new TextField();
1184 fullNameField.setPromptText("Full Name");
1185 PasswordField passwordField = new PasswordField();
1186 passwordField.setPromptText("Password");
1187 CheckBox adminCheckBox = new CheckBox("Admin?");
1188
1189 grid.add(new Label("Username:"), 0, 0);
1190 grid.add(userNameTextField, 1, 0);
1191 grid.add(new Label("Full Name:"), 0, 1);
1192 grid.add(fullNameField, 1, 1);
1193 grid.add(new Label("Password:"), 0, 2);
1194 grid.add(passwordField, 1, 2);
1195 grid.add(adminCheckBox, 1, 3);
1196
1197
1198 javafx.scene.Node loginButton = dialog.getDialogPane().lookupButton(login);
1199 loginButton.setDisable(true);
1200
1201
1202 userNameTextField.textProperty().addListener((observable, oldValue, newValue) -> loginButton.setDisable(newValue.trim().isEmpty()));
1203
1204 dialog.getDialogPane().setContent(grid);
1205
1206
1207 Platform.runLater(() -> userNameTextField.requestFocus());
1208
1209
1210 dialog.setResultConverter(dialogButton -> {
1211 if (dialogButton == login) {
1212 return new Pair<Pair<String, Boolean>, Pair<String, String>>(new Pair<>(fullNameField.getText(), adminCheckBox.isSelected()), new Pair<>(userNameTextField.getText(), passwordField.getText()));
1213 }
1214 return null;
1215 });
1216
1217 Optional<Pair<Pair<String, Boolean>, Pair<String, String>>> result = dialog.showAndWait();
1218
1219 result.ifPresent(userInfo -> {
1220 Pattern p = Pattern.compile("[^a-zA-Z0-9]");
1221 String uName = userInfo.getValue().getKey();
1222 String pass = userInfo.getValue().getValue();
1223 String fName = userInfo.getKey().getKey();
1224 Boolean admin = userInfo.getKey().getValue();
1225 boolean hasSpecialChar = p.matcher(userInfo.getValue().getKey()).find();
1226 if (hasSpecialChar) {
1227 Alert alert = new Alert(Alert.AlertType.WARNING);
1228 alert.setTitle("");
1229 alert.setHeaderText("You have entered an invalid character in the username");
1230 alert.setContentText("Only Alphanumeric characters are aloud.");
1231 alert.show();
1232 } else {
1233 Set<String> years = new HashSet<>();
1234 User user = User.createUser(uName, pass, fName, admin);
1235 ArrayList<String> uMan = new ArrayList<>();
1236 uMan.add(uName);
1237 years.add(curYear);
1238 user.setuManage(uMan);
1239 user.setYears(years);
1240 user.setGroupId(1);
1241 user.updateYear(curYear);
1242 refresh(() -> {
1243 openUser(user, curYear);
1244
1245 });
1246
1247
1248
1249
1250
1251 ArrayList<ArrayList<String>> yearUsers = new ArrayList<>();
1252
1253
1254 }
1255
1256 });
1257
1258 }
1259
1260 @FXML
1261 private void addBulkUsers(ActionEvent event) {
1262
1263 }
1264
1265 @FXML
1266 private void addBulkGroups(ActionEvent event) {
1267
1268 }
1269
1270 @FXML
1271 private void addSingleGroup(ActionEvent event) {
1272 Group newGroup = AddGroup.addGroup(curYear, (grp -> {
1273 refresh(() -> {
1274 openGroup(grp, curYear);
1275
1276 });
1277 }));
1278
1279
1280
1281 }
1282
1283
1284 private String getCurrentYear() {
1285 return curYear;
1286 }
1287
1288
1289
1290
1291 private void initProductsTab() {
1292 boolean newYear = false;
1293 Year thisYear = new Year(getCurrentYear());
1294
1295
1296 categoriesCmbx.getItems().clear();
1297 categoriesTb.clear();
1298 categoriesTb.add("");
1299 String browse = "Add Category";
1300 rowsCats.clear();
1301 thisYear.getCategories().forEach((category) -> {
1302 categoriesTb.add(category.catName);
1303 rowsCats.add(category);
1304 });
1305
1306 categoriesTb.add(browse);
1307 categoriesCmbx.getItems().setAll(categoriesTb);
1308 ProductTable.getColumns().clear();
1309 ProductTable.getItems().clear();
1310 String[][] columnNames = {{"ID", "productID"}, {"Item", "productName"}, {"Size", "productSize"}, {"Price/Item", "productUnitPriceString"}};
1311
1312 {
1313 javafx.scene.control.TableColumn<formattedProductProps, String> idCol = new javafx.scene.control.TableColumn<>("ID");
1314 idCol.setCellValueFactory(new PropertyValueFactory<>("productID"));
1315 idCol.setCellFactory(TextFieldTableCell.forTableColumn());
1316 idCol.setOnEditCommit(t -> {
1317 t.getRowValue().productID.set(t.getNewValue());
1318 data.get(t.getTablePosition().getRow()).productID.set(t.getNewValue());
1319 t.getTableView().refresh();
1320 });
1321 ProductTable.getColumns().add(idCol);
1322
1323 }
1324 {
1325 javafx.scene.control.TableColumn<formattedProductProps, String> nameCol = new javafx.scene.control.TableColumn<>("Item");
1326 nameCol.setCellValueFactory(new PropertyValueFactory<>("productName"));
1327 nameCol.setCellFactory(TextFieldTableCell.forTableColumn());
1328 nameCol.setOnEditCommit(t -> {
1329 t.getRowValue().productName.set(t.getNewValue());
1330 data.get(t.getTablePosition().getRow()).productName.set(t.getNewValue());
1331 t.getTableView().refresh();
1332 });
1333 ProductTable.getColumns().add(nameCol);
1334
1335 }
1336 {
1337 javafx.scene.control.TableColumn<formattedProductProps, String> sizeCol = new javafx.scene.control.TableColumn<>("Size");
1338 sizeCol.setCellValueFactory(new PropertyValueFactory<>("productSize"));
1339 sizeCol.setCellFactory(TextFieldTableCell.forTableColumn());
1340 sizeCol.setOnEditCommit(t -> {
1341 t.getRowValue().productSize.set(t.getNewValue());
1342 data.get(t.getTablePosition().getRow()).productSize.set(t.getNewValue());
1343 t.getTableView().refresh();
1344 });
1345 ProductTable.getColumns().add(sizeCol);
1346
1347 }
1348 {
1349 javafx.scene.control.TableColumn<formattedProductProps, String> unitCostCol = new javafx.scene.control.TableColumn<>("Price/Item");
1350 unitCostCol.setCellValueFactory(new PropertyValueFactory<>("productUnitPriceString"));
1351 unitCostCol.setCellFactory(TextFieldTableCell.forTableColumn());
1352 unitCostCol.setOnEditCommit(t -> {
1353 try {
1354 BigDecimal unitPrice = new BigDecimal(t.getNewValue());
1355 t.getRowValue().productUnitPriceString.set(t.getNewValue());
1356 t.getRowValue().productUnitPrice.set(new BigDecimal(t.getNewValue()));
1357 data.get(t.getTablePosition().getRow()).productUnitPriceString.set(t.getNewValue());
1358 data.get(t.getTablePosition().getRow()).productUnitPrice.set(new BigDecimal(t.getNewValue()));
1359 t.getTableView().refresh();
1360 } catch (NumberFormatException e) {
1361 Alert alert = new Alert(Alert.AlertType.ERROR, "Invalid number");
1362 alert.setHeaderText("You have entered an invalid number.");
1363 alert.show();
1364 t.getRowValue().productUnitPriceString.set(t.getOldValue());
1365 }
1366
1367
1368 });
1369 ProductTable.getColumns().add(unitCostCol);
1370
1371 }
1372
1373
1374 javafx.scene.control.TableColumn<formattedProductProps, String> categoryColumn = new javafx.scene.control.TableColumn<>("Category");
1375 categoryColumn.setCellValueFactory(new PropertyValueFactory<>("productCategory"));
1376
1377 categoryColumn.setCellFactory(ComboBoxTableCell.forTableColumn(categoriesTb));
1378
1379 categoryColumn.setOnEditCommit(t -> {
1380 String newVal = catCmbxChanged(t.getNewValue());
1381
1382 t.getRowValue().productCategory.set(newVal);
1383 data.get(t.getTablePosition().getRow()).productCategory.set(newVal);
1384
1385 });
1386 ProductTable.getColumns().add(categoryColumn);
1387
1388 fillTable(getCurrentYear());
1389 productsTab.setDisable(false);
1390 }
1391
1392
1393 @FXML
1394 private void submit(ActionEvent event) {
1395
1396
1397 updateDb(getCurrentYear());
1398 Alert alert = new Alert(Alert.AlertType.INFORMATION, "Saved");
1399 alert.setHeaderText("Changes Saved.");
1400 alert.show();
1401
1402 }
1403
1404 @FXML
1405 private void tableFrmXML(ActionEvent event) {
1406 FileChooser chooser = new FileChooser();
1407 FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("XML files", "*.xml", "*.XML");
1408 chooser.getExtensionFilters().add(filter);
1409
1410 chooser.setSelectedExtensionFilter(filter);
1411
1412 File xmlFile = chooser.showOpenDialog(parentWindow);
1413 if (xmlFile != null) {
1414 String path = xmlFile.getAbsolutePath();
1415 createTable(path);
1416 }
1417 }
1418
1419 private void convert(String csvLoc, String xmlLoc) {
1420 List<String> headers = new ArrayList<>(5);
1421
1422
1423 File file = new File(csvLoc);
1424
1425 try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
1426
1427 DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
1428 DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
1429
1430 Document newDoc = domBuilder.newDocument();
1431
1432 Element rootElement = newDoc.createElement("LawnGarden");
1433 newDoc.appendChild(rootElement);
1434
1435 int line = 0;
1436
1437 String text;
1438 while ((text = reader.readLine()) != null) {
1439
1440 StringTokenizer st = new StringTokenizer(text, ";", false);
1441 String[] rowValues = new String[st.countTokens()];
1442 int index = 0;
1443 while (st.hasMoreTokens()) {
1444
1445 String next = st.nextToken();
1446 rowValues[index] = next;
1447 index++;
1448
1449 }
1450
1451
1452
1453 if (line == 0) {
1454 Collections.addAll(headers, rowValues);
1455 } else {
1456 Element rowElement = newDoc.createElement("Products");
1457 rootElement.appendChild(rowElement);
1458 Attr attr = newDoc.createAttribute("id");
1459 attr.setValue(Integer.toString(line - 1));
1460 rowElement.setAttributeNode(attr);
1461 for (int col = 0; col < headers.size(); col++) {
1462 String header = headers.get(col);
1463 String value;
1464
1465 if (col < rowValues.length) {
1466 value = rowValues[col].trim();
1467 } else {
1468
1469 value = "";
1470 }
1471
1472 Element curElement = newDoc.createElement(header);
1473 curElement.appendChild(newDoc.createTextNode(value));
1474 rowElement.appendChild(curElement);
1475 }
1476 }
1477 line++;
1478 }
1479
1480 OutputStreamWriter osw = null;
1481
1482 try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
1483 osw = new OutputStreamWriter(baos);
1484
1485 TransformerFactory tranFactory = TransformerFactory.newInstance();
1486 Transformer aTransformer = tranFactory.newTransformer();
1487 aTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
1488 aTransformer.setOutputProperty(OutputKeys.METHOD, "xml");
1489
1490 aTransformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
1491
1492 Source src = new DOMSource(newDoc);
1493 Result result = new StreamResult(osw);
1494 aTransformer.transform(src, result);
1495
1496 osw.flush();
1497
1498
1499 try (OutputStream outStream = new FileOutputStream(xmlLoc)) {
1500
1501 baos.writeTo(outStream);
1502 } catch (IOException e) {
1503 LogToFile.log(e, Severity.SEVERE, "Error writing XML file. Please try again.");
1504 }
1505
1506
1507 } catch (Exception exp) {
1508 LogToFile.log(exp, Severity.SEVERE, "Error writing XML file. Please try again.");
1509 } finally {
1510 try {
1511 if (osw != null) {
1512 osw.close();
1513 }
1514 } catch (IOException e) {
1515 LogToFile.log(e, Severity.SEVERE, "Error closing file. Please try again.");
1516 }
1517
1518 }
1519 } catch (Exception e) {
1520 LogToFile.log(e, Severity.SEVERE, "Error reading CSV file. Ensure the path exists, and the software has permission to read it.");
1521 }
1522 }
1523
1524 @FXML
1525 private void csvToXml(ActionEvent event) {
1526
1527 Dialog<Pair<String, String>> dialog = new Dialog<>();
1528 dialog.setTitle("CSV to XML conversion");
1529
1530
1531 ButtonType convertButtonType = new ButtonType("Convert", ButtonBar.ButtonData.OK_DONE);
1532 dialog.getDialogPane().getButtonTypes().addAll(convertButtonType, ButtonType.CANCEL);
1533
1534
1535 GridPane grid = new GridPane();
1536 grid.setHgap(10);
1537 grid.setVgap(10);
1538 grid.setPadding(new Insets(20, 150, 10, 10));
1539
1540 TextField csvLoc = new TextField();
1541 csvLoc.setPromptText("CSV file Location");
1542 TextField xmlLoc = new TextField();
1543 xmlLoc.setPromptText("XML Location");
1544 Button getCsvLoc = new Button("...");
1545 getCsvLoc.setOnAction(e -> {
1546 FileChooser chooser = new FileChooser();
1547 FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("CSV files", "*.csv", "*.CSV");
1548 chooser.getExtensionFilters().add(filter);
1549 chooser.setSelectedExtensionFilter(filter);
1550 File csv = chooser.showOpenDialog(grid.getScene().getWindow());
1551 if (csv != null) {
1552 String path = csv.getAbsolutePath();
1553 if (!path.toLowerCase().endsWith(".csv")) {
1554 path += ".csv";
1555 }
1556 csvLoc.setText(path);
1557 }
1558 });
1559 Button getXmlLoc = new Button("...");
1560 getXmlLoc.setOnAction(e -> {
1561 FileChooser chooser = new FileChooser();
1562 FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("XML files", "*.xml", "*.XML");
1563 chooser.getExtensionFilters().add(filter);
1564 chooser.setSelectedExtensionFilter(filter);
1565 File XML = chooser.showSaveDialog(grid.getScene().getWindow());
1566 if (XML != null) {
1567 String path = XML.getAbsolutePath();
1568 if (!path.toLowerCase().endsWith(".xml")) {
1569 path += ".xml";
1570 }
1571 xmlLoc.setText(path);
1572 }
1573 });
1574 grid.add(new Label("CSV file Location:"), 0, 0);
1575 grid.add(csvLoc, 1, 0);
1576 grid.add(getCsvLoc, 2, 0);
1577 grid.add(new Label("XML Location:"), 0, 1);
1578 grid.add(xmlLoc, 1, 1);
1579 grid.add(getXmlLoc, 2, 1);
1580
1581
1582
1583 javafx.scene.Node convertButton = dialog.getDialogPane().lookupButton(convertButtonType);
1584 convertButton.setDisable(true);
1585
1586
1587 csvLoc.textProperty().addListener((observable, oldValue, newValue) -> convertButton.setDisable(newValue.trim().isEmpty()));
1588
1589 dialog.getDialogPane().setContent(grid);
1590
1591
1592 Platform.runLater(() -> csvLoc.requestFocus());
1593
1594
1595 dialog.setResultConverter(dialogButton -> {
1596 if (dialogButton == convertButtonType) {
1597 return new Pair<>(csvLoc.getText(), xmlLoc.getText());
1598 }
1599 return null;
1600 });
1601
1602 Optional<Pair<String, String>> result = dialog.showAndWait();
1603
1604 result.ifPresent(fileLocations -> {
1605 convert(fileLocations.getKey(), fileLocations.getValue());
1606 createTable(fileLocations.getValue());
1607 });
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617 }
1618
1619 @FXML
1620 private void catCmbxChanged(ActionEvent event) {
1621 if (Objects.equals(categoriesCmbx.getSelectionModel().getSelectedItem(), "Add Category")) {
1622 Dialog<Pair<String, String>> dialog = new Dialog<>();
1623 dialog.setTitle("Add new category");
1624
1625
1626 ButtonType addCat = new ButtonType("Add", ButtonBar.ButtonData.OK_DONE);
1627 dialog.getDialogPane().getButtonTypes().addAll(addCat, ButtonType.CANCEL);
1628
1629
1630 GridPane grid = new GridPane();
1631 grid.setHgap(10);
1632 grid.setVgap(10);
1633 grid.setPadding(new Insets(20, 150, 10, 10));
1634
1635 TextField catName = new TextField();
1636 catName.setPromptText("Category Name");
1637 DatePicker catDate = new DatePicker(LocalDate.now());
1638 catDate.setPromptText("Category Due Date");
1639
1640 grid.add(new Label("Category Name:"), 0, 0);
1641 grid.add(catName, 1, 0);
1642 grid.add(new Label("Category Due Date:"), 0, 1);
1643 grid.add(catDate, 1, 1);
1644
1645
1646
1647 javafx.scene.Node addCatButton = dialog.getDialogPane().lookupButton(addCat);
1648 addCatButton.setDisable(true);
1649
1650
1651 catName.textProperty().addListener((observable, oldValue, newValue) -> addCatButton.setDisable(newValue.trim().isEmpty()));
1652
1653 dialog.getDialogPane().setContent(grid);
1654
1655
1656 Platform.runLater(() -> catName.requestFocus());
1657
1658
1659 dialog.setResultConverter(dialogButton -> {
1660 if (dialogButton == addCat) {
1661 return new Pair<String, String>(catName.getText(), catDate.getValue().toString());
1662 }
1663 return null;
1664 });
1665
1666 Optional<Pair<String, String>> result = dialog.showAndWait();
1667
1668 result.ifPresent(category -> {
1669 rowsCats.add(new Year.category(category.getKey(), category.getValue()));
1670 Platform.runLater(() -> refreshCmbx());
1671
1672 });
1673
1674
1675 }
1676
1677 }
1678
1679 private String catCmbxChanged(String newVal) {
1680 final Year.category newCat = new Year.category("", "");
1681 if (Objects.equals(newVal, "Add Category")) {
1682 Dialog<Pair<String, String>> dialog = new Dialog<>();
1683 dialog.setTitle("Add new category");
1684
1685
1686 ButtonType addCat = new ButtonType("Add", ButtonBar.ButtonData.OK_DONE);
1687 dialog.getDialogPane().getButtonTypes().addAll(addCat, ButtonType.CANCEL);
1688
1689
1690 GridPane grid = new GridPane();
1691 grid.setHgap(10);
1692 grid.setVgap(10);
1693 grid.setPadding(new Insets(20, 150, 10, 10));
1694
1695 TextField catName = new TextField();
1696 catName.setPromptText("Category Name");
1697 DatePicker catDate = new DatePicker(LocalDate.now());
1698 catDate.setPromptText("Category Due Date");
1699
1700 grid.add(new Label("Category Name:"), 0, 0);
1701 grid.add(catName, 1, 0);
1702 grid.add(new Label("Category Due Date:"), 0, 1);
1703 grid.add(catDate, 1, 1);
1704
1705
1706
1707 javafx.scene.Node addCatButton = dialog.getDialogPane().lookupButton(addCat);
1708 addCatButton.setDisable(true);
1709
1710
1711 catName.textProperty().addListener((observable, oldValue, newValue) -> addCatButton.setDisable(newValue.trim().isEmpty()));
1712
1713 dialog.getDialogPane().setContent(grid);
1714
1715
1716 Platform.runLater(() -> catName.requestFocus());
1717
1718
1719 dialog.setResultConverter(dialogButton -> {
1720 if (dialogButton == addCat) {
1721 return new Pair<String, String>(catName.getText(), catDate.getValue().toString());
1722 }
1723 return null;
1724 });
1725
1726 Optional<Pair<String, String>> result = dialog.showAndWait();
1727 result.ifPresent(category -> {
1728 newCat.catName = category.getKey();
1729 newCat.catDate = category.getValue();
1730 rowsCats.add(newCat);
1731 Platform.runLater(() -> refreshCmbx());
1732
1733 });
1734
1735
1736 }
1737
1738 return newCat.catName;
1739 }
1740
1741 @FXML
1742 private void addBtnPressed(ActionEvent event) {
1743 int count = ProductTable.getItems().size() + 1;
1744 data.add(new formattedProductProps(0, idTb.getText(), itemTb.getText(), sizeTb.getText(), new BigDecimal(rateTb.getText()), categoriesCmbx.getSelectionModel().getSelectedItem(), 0, BigDecimal.ZERO));
1745 ProductTable.setItems(data);
1746 }
1747
1748
1749
1750 private void refreshCmbx() {
1751 categoriesCmbx.getItems().clear();
1752 categoriesTb.clear();
1753 categoriesTb.add("");
1754 String browse = "Add Category";
1755
1756 rowsCats.forEach(cat -> categoriesTb.add(cat.catName));
1757
1758
1759 categoriesTb.add(browse);
1760 categoriesCmbx.getItems().setAll(categoriesTb);
1761
1762 }
1763
1764 private void updateDb(String year) {
1765 Year yearToUpdate = new Year(year);
1766 yearToUpdate.updateDb(year, ProductTable.getItems(), rowsCats);
1767 }
1768
1769
1770
1771
1772
1773
1774 private void createTable(String FLoc) {
1775 try {
1776
1777 File fXmlFile = new File(FLoc);
1778 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
1779 DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
1780 Document doc = dBuilder.parse(fXmlFile);
1781
1782
1783
1784 doc.getDocumentElement().normalize();
1785
1786
1787 NodeList nListCats = doc.getElementsByTagName("Categories");
1788
1789
1790
1791 for (int temp = 0; temp < nListCats.getLength(); temp++) {
1792
1793 org.w3c.dom.Node nNode = nListCats.item(temp);
1794
1795
1796 if ((int) nNode.getNodeType() == (int) org.w3c.dom.Node.ELEMENT_NODE) {
1797
1798 Element eElement = (Element) nNode;
1799 rowsCats.add(new Year.category(eElement.getElementsByTagName("CategoryName").item(0).getTextContent(), eElement.getElementsByTagName("CategoryDate").item(0).getTextContent()));
1800 }
1801 }
1802
1803 NodeList nList = doc.getElementsByTagName("Products");
1804
1805 Object[][] rows = new Object[nList.getLength()][5];
1806
1807 for (int temp = 0; temp < nList.getLength(); temp++) {
1808
1809 org.w3c.dom.Node nNode = nList.item(temp);
1810
1811
1812 if ((int) nNode.getNodeType() == (int) org.w3c.dom.Node.ELEMENT_NODE) {
1813
1814 Element eElement = (Element) nNode;
1815
1816
1817
1818 formattedProductProps prodProps = new formattedProductProps(0, eElement.getElementsByTagName(
1819 "ProductID").item(0).getTextContent(),
1820 eElement.getElementsByTagName("ProductName").item(0).getTextContent(),
1821 eElement.getElementsByTagName("Size").item(0).getTextContent(),
1822 new BigDecimal(eElement.getElementsByTagName("UnitCost").item(0).getTextContent()),
1823 (eElement.getElementsByTagName("Category").item(0) != null) ? eElement.getElementsByTagName("Category").item(0).getTextContent() : "",
1824 0,
1825 BigDecimal.ZERO
1826 );
1827 data.add(prodProps);
1828 ProductTable.setItems(data);
1829
1830 }
1831
1832
1833 }
1834 } catch (Exception e) {
1835 LogToFile.log(e, Severity.SEVERE, "Error Converting XML file to table. Please try again or contact support.");
1836 }
1837 refreshCmbx();
1838 }
1839
1840
1841
1842
1843
1844
1845 private void createXML(String SavePath) {
1846 try {
1847 DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
1848 DocumentBuilder docBuilder;
1849
1850 docBuilder = docFactory.newDocumentBuilder();
1851
1852
1853
1854 Document doc = docBuilder.newDocument();
1855
1856 Element rootElement = doc.createElement("LawnGarden");
1857 doc.appendChild(rootElement);
1858 Iterable<Year.category> caters;
1859 caters = rowsCats;
1860 int[] i = {0};
1861
1862 caters.forEach(cat -> {
1863 Element cats = doc.createElement("Categories");
1864 rootElement.appendChild(cats);
1865 Attr attr = doc.createAttribute("id");
1866 attr.setValue(Integer.toString(i[0]));
1867 cats.setAttributeNode(attr);
1868
1869
1870
1871 Element ProductID = doc.createElement("CategoryName");
1872 ProductID.appendChild(doc.createTextNode(cat.catName));
1873 cats.appendChild(ProductID);
1874
1875
1876 Element ProductName = doc.createElement("CategoryDate");
1877 ProductName.appendChild(doc.createTextNode(cat.catDate));
1878 cats.appendChild(ProductName);
1879 i[0]++;
1880 }
1881 );
1882
1883
1884
1885
1886
1887 for (int i2 = 0; i2 < ProductTable.getItems().size(); i2++) {
1888
1889 Element staff = doc.createElement("Products");
1890 rootElement.appendChild(staff);
1891 Attr attr = doc.createAttribute("id");
1892 attr.setValue(Integer.toString(i2));
1893 staff.setAttributeNode(attr);
1894
1895
1896 Element ProductID = doc.createElement("ProductID");
1897 ProductID.appendChild(doc.createTextNode(ProductTable.getItems().get(i2).getProductID()));
1898 staff.appendChild(ProductID);
1899
1900
1901 Element ProductName = doc.createElement("ProductName");
1902 ProductName.appendChild(doc.createTextNode(ProductTable.getItems().get(i2).getProductName()));
1903 staff.appendChild(ProductName);
1904
1905
1906 Element UnitCost = doc.createElement("UnitCost");
1907 UnitCost.appendChild(doc.createTextNode(ProductTable.getItems().get(i2).getProductUnitPrice().toPlainString()));
1908 staff.appendChild(UnitCost);
1909
1910
1911 Element Size = doc.createElement("Size");
1912 Size.appendChild(doc.createTextNode(ProductTable.getItems().get(i2).getProductSize()));
1913 staff.appendChild(Size);
1914
1915
1916
1917 String cat = (ProductTable.getItems().get(i2).getProductCategory() != null) ? ProductTable.getItems().get(i2).getProductCategory() : "";
1918 Element category = doc.createElement("Category");
1919 category.appendChild(doc.createTextNode(cat));
1920 staff.appendChild(category);
1921 }
1922
1923
1924
1925 TransformerFactory transformerFactory = TransformerFactory.newInstance();
1926 Transformer transformer = transformerFactory.newTransformer();
1927 Source source = new DOMSource(doc);
1928 Result result = new StreamResult(new FileOutputStream(SavePath));
1929
1930
1931
1932
1933 transformer.transform(source, result);
1934
1935
1936 } catch (ParserConfigurationException e) {
1937 LogToFile.log(e, Severity.SEVERE, "Error creating XML file: Parser error. Contact support.");
1938 } catch (TransformerException e) {
1939 LogToFile.log(e, Severity.SEVERE, "Error creating XML file: Parser Error. Contact support.");
1940 } catch (FileNotFoundException e) {
1941 LogToFile.log(e, Severity.SEVERE, "Error creating XML file: Error writing to file. Make sure the directory is readable by the software.");
1942 }
1943 }
1944
1945
1946
1947
1948 private void fillTable(String year) {
1949 Year yearInfo = new Year(year);
1950
1951 formattedProduct[] productArray = yearInfo.getAllProducts();
1952 Object[][] rows = new Object[productArray.length][6];
1953
1954
1955 int i = 0;
1956 for (formattedProduct productOrder : productArray) {
1957
1958 formattedProductProps prodProps = new formattedProductProps(productOrder.productKey, productOrder.productID, productOrder.productName, productOrder.productSize, productOrder.productUnitPrice, productOrder.productCategory, productOrder.orderedQuantity, productOrder.extendedCost);
1959 data.add(prodProps);
1960 i++;
1961 }
1962
1963 ProductTable.setItems(data);
1964
1965 }
1966
1967 @FXML
1968 private void tablefromDb(ActionEvent event) {
1969 fillTable(getCurrentYear());
1970 }
1971
1972 @FXML
1973 private void xmlFromTable(ActionEvent event) {
1974 FileChooser chooser = new FileChooser();
1975 FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("XML files", "*.xml", "*.XML");
1976 chooser.getExtensionFilters().add(filter);
1977 chooser.setSelectedExtensionFilter(filter);
1978 File XML = chooser.showSaveDialog(parentWindow);
1979 if (XML != null) {
1980 String path = XML.getAbsolutePath();
1981 if (!path.toLowerCase().endsWith(".xml")) {
1982 path += ".xml";
1983 }
1984 createXML(path);
1985 }
1986 }
1987
1988 private String arrayToCSV(Collection<String> array) {
1989 final String[] ret = {""};
1990 array.forEach(value -> {
1991 if (!ret[0].isEmpty()) {
1992 ret[0] = ret[0] + ", " + value;
1993 } else {
1994 ret[0] = value;
1995 }
1996 });
1997 return ret[0];
1998 }
1999
2000 private ContextMenu createContextMenu(TreeItem<TreeItemPair<String, Pair<String, Object>>> cell) {
2001 ContextMenu cm = new ContextMenu();
2002 ContextMenu cmContent = new ContextMenu();
2003 Pane newPane = null;
2004 FXMLLoader loader;
2005 Pane finalNewPane;
2006
2007 if (cell != null && cell.getValue() != null && !Objects.equals(cell.getValue().getValue().getKey(), "RootNode")) {
2008 switch (cell.getValue().getValue().getKey()) {
2009 case "Year":
2010 cmContent = createContextMenuContent(
2011
2012 () -> {
2013 openYear(cell.getValue().getKey());
2014
2015 }, null,
2016 null);
2017
2018 break;
2019 case "Group":
2020 cmContent = createContextMenuContent(
2021
2022 () -> {
2023 String year = "";
2024 if (cell.getParent().getValue().getValue().getKey().equals("Year")) {
2025 year = cell.getParent().getValue().getKey();
2026 } else if (cell.getParent().getParent().getValue().getValue().getKey().equals("Year")) {
2027 year = cell.getParent().getParent().getValue().getKey();
2028
2029 }
2030 openGroup((Group) cell.getValue().getValue().getValue(), year);
2031
2032 }, null, null);
2033 break;
2034 case "User":
2035 cmContent = createContextMenuContent(
2036
2037 () -> {
2038 String year = "";
2039 if (cell.getParent().getValue().getValue().getKey().equals("Year")) {
2040 year = cell.getParent().getValue().getKey();
2041 } else if (cell.getParent().getParent().getValue().getValue().getKey().equals("Year")) {
2042 year = cell.getParent().getParent().getValue().getKey();
2043
2044 }
2045 openUser((User) cell.getValue().getValue().getValue(), year);
2046
2047 }, null, null);
2048
2049 break;
2050
2051
2052 }
2053
2054
2055 }
2056 cm.getItems().addAll(cmContent.getItems());
2057 MenuItem refresh = new MenuItem("Refresh");
2058 refresh.setOnAction(event -> refresh(null));
2059 cm.getItems().add(refresh);
2060
2061 return cm;
2062 }
2063
2064 private <T> CheckBoxTreeItem<TreeItemPair<String, String>> createUserTreeItem(TreeItemPair<String, String> value, User user) {
2065
2066 CheckBoxTreeItem<TreeItemPair<String, String>> item = new CheckBoxTreeItem<TreeItemPair<String, String>>(value);
2067 if (!value.getValue().isEmpty()) {
2068 item.selectedProperty().addListener((obs, wasChecked, isNowChecked) -> {
2069 if (isNowChecked) {
2070 checkedUsers.computeIfPresent(user, (k, v) -> {
2071 if (!v.contains(value.getValue())) {
2072 v.add(value.getValue());
2073 }
2074 return v;
2075 });
2076 checkedUsers.computeIfAbsent(user, k -> {
2077 ArrayList<String> v = new ArrayList();
2078 v.add(value.getValue());
2079 return v;
2080 });
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091 } else {
2092 checkedUsers.compute(user, (k, v) -> {
2093 v.remove(value.getValue());
2094 return v;
2095 });
2096
2097
2098
2099
2100 }
2101
2102
2103 });
2104 }
2105
2106 return item;
2107 }
2108
2109 private <T> CheckBoxTreeItem<TreeItemPair<String, String>> createGroupTreeItem(TreeItemPair<String, String> value, Group group) {
2110
2111 CheckBoxTreeItem<TreeItemPair<String, String>> item = new CheckBoxTreeItem<TreeItemPair<String, String>>(value);
2112 if (!value.getValue().isEmpty()) {
2113 item.selectedProperty().addListener((obs, wasChecked, isNowChecked) -> {
2114 if (isNowChecked) {
2115 checkedGroups.computeIfPresent(group, (k, v) -> {
2116 if (!v.contains(value.getValue())) {
2117 v.add(value.getValue());
2118 }
2119 return v;
2120 });
2121 checkedGroups.computeIfAbsent(group, k -> {
2122 ArrayList<String> v = new ArrayList();
2123 v.add(value.getValue());
2124 return v;
2125 });
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136 } else {
2137 checkedGroups.compute(group, (k, v) -> {
2138 v.remove(value.getValue());
2139 return v;
2140 });
2141
2142
2143
2144
2145 }
2146
2147
2148 });
2149 }
2150
2151 return item;
2152 }
2153
2154 private ContextMenu createContextMenuContent(actionCallback open, actionCallback delete, actionCallback edit) {
2155 ContextMenu cm = new ContextMenu();
2156 if (open != null) {
2157 MenuItem openItem = new MenuItem("Open");
2158 openItem.setOnAction(event -> open.doAction());
2159 cm.getItems().add(openItem);
2160 }
2161
2162
2163 if (edit != null) {
2164 MenuItem openItem = new MenuItem("Edit");
2165 openItem.setOnAction(event -> edit.doAction());
2166 cm.getItems().add(openItem);
2167 }
2168 if (delete != null) {
2169 MenuItem openItem = new MenuItem("Delete");
2170 openItem.setOnAction(event -> delete.doAction());
2171 cm.getItems().add(openItem);
2172 }
2173 return cm;
2174 }
2175
2176 interface actionCallback {
2177 void doAction();
2178 }
2179
2180 abstract class AbstractTreeItem extends TreeItem {
2181
2182 protected abstract ContextMenu getMenu();
2183 }
2184
2185 public class contextTreeItem<K, V> extends AbstractTreeItem {
2186
2187
2188 public contextTreeItem(String key, Pair<String, String> value) {
2189 this.setValue(new TreeItemPair<>(key, value));
2190 }
2191
2192 public contextTreeItem(String key, String value) {
2193 this.setValue(new TreeItemPair<>(key, new Pair<String, String>(value, "")));
2194 }
2195
2196 public contextTreeItem(String key) {
2197 this.setValue(new TreeItemPair<>(key, null));
2198 }
2199
2200 @Override
2201 public ContextMenu getMenu() {
2202
2203 return createContextMenu(this);
2204 }
2205 }
2206
2207 private final class TreeCellImpl<K, V> extends TreeCell<TreeItemPair<String, Pair<String, String>>> {
2208
2209 @Override
2210 public void updateItem(TreeItemPair<String, Pair<String, String>> item, boolean empty) {
2211 super.updateItem(item, empty);
2212
2213 if (empty) {
2214 setText(null);
2215 setGraphic(null);
2216 } else {
2217 setText(getItem() == null ? "" : getItem().getKey());
2218 setGraphic(getTreeItem().getGraphic());
2219 setContextMenu(((AbstractTreeItem) getTreeItem()).getMenu());
2220 }
2221 }
2222 }
2223 }
2224