View Javadoc
1   /*
2    * Copyright (c) Patrick Magauran 2018.
3    *   Licensed under the AGPLv3. All conditions of said license apply.
4    *       This file is part of ABOS.
5    *
6    *       ABOS is free software: you can redistribute it and/or modify
7    *       it under the terms of the GNU Affero General Public License as published by
8    *       the Free Software Foundation, either version 3 of the License, or
9    *       (at your option) any later version.
10   *
11   *       ABOS is distributed in the hope that it will be useful,
12   *       but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   *       GNU Affero General Public License for more details.
15   *
16   *       You should have received a copy of the GNU Affero General Public License
17   *       along with ABOS.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package ABOS.Derby;
21  
22  import javafx.application.Platform;
23  import javafx.collections.FXCollections;
24  import javafx.collections.ObservableList;
25  import javafx.event.ActionEvent;
26  import javafx.fxml.FXML;
27  import javafx.geometry.Insets;
28  import javafx.scene.control.*;
29  import javafx.scene.control.cell.ComboBoxTableCell;
30  import javafx.scene.control.cell.PropertyValueFactory;
31  import javafx.scene.control.cell.TextFieldTableCell;
32  import javafx.scene.layout.GridPane;
33  import javafx.stage.FileChooser;
34  import javafx.stage.Stage;
35  import javafx.stage.Window;
36  import javafx.util.Pair;
37  import org.w3c.dom.*;
38  
39  import javax.xml.parsers.DocumentBuilder;
40  import javax.xml.parsers.DocumentBuilderFactory;
41  import javax.xml.parsers.ParserConfigurationException;
42  import javax.xml.transform.*;
43  import javax.xml.transform.dom.DOMSource;
44  import javax.xml.transform.stream.StreamResult;
45  import java.io.*;
46  import java.math.BigDecimal;
47  import java.time.LocalDate;
48  import java.util.*;
49  
50  //import javax.swing.*;
51  //import javax.swing.border.EmptyBorder;
52  //import javax.swing.table.DefaultTableModel;
53  //import java.awt.*;
54  //import java.awt.*;
55  @SuppressWarnings("WeakerAccess")
56  
57  public class AddYearController {
58  
59      @FXML
60      private TextField yearText;
61      @FXML
62      private TableView<Product.formattedProductProps> ProductTable;
63      @FXML
64      private TextField itemTb;
65      @FXML
66      private TextField sizeTb;
67      @FXML
68      private TextField rateTb;
69      @FXML
70      private TextField idTb;
71      //private final JDialog parent;
72      private Collection<Year.category> rowsCats = new ArrayList<Year.category>();
73      @FXML
74      private CheckBox chkboxCreateDatabase;
75      private ObservableList<String> categoriesTb = FXCollections.observableArrayList();
76      @FXML
77      private ComboBox<String> categoriesCmbx;
78      //private DefaultTableModel tableModel;
79      private boolean newYear = false;
80      private ObservableList<Product.formattedProductProps> data = FXCollections.observableArrayList();
81      private Window parentWindow;
82  
83      public AddYearController() {}
84  
85      /**
86       * Create the dialog.
87       */
88  
89      @FXML
90      private void tableFrmXML(ActionEvent event) {
91          FileChooser chooser = new FileChooser();
92          FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("XML files", "*.xml", "*.XML");
93          chooser.getExtensionFilters().add(filter);
94  
95          chooser.setSelectedExtensionFilter(filter);
96  //        logoLoc.setText(chooser.showOpenDialog(settings).getAbsolutePath());
97          File xmlFile = chooser.showOpenDialog(parentWindow);
98          if (xmlFile != null) {
99              String path = xmlFile.getAbsolutePath();
100             createTable(path);
101         }
102     }
103 
104     private void convert(String csvLoc, String xmlLoc) {
105         List<String> headers = new ArrayList<>(5);
106 
107 
108         File file = new File(csvLoc);
109 
110         try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
111 
112             DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
113             DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
114 
115             Document newDoc = domBuilder.newDocument();
116             // Root element
117             Element rootElement = newDoc.createElement("LawnGarden");
118             newDoc.appendChild(rootElement);
119 
120             int line = 0;
121 
122             String text;
123             while ((text = reader.readLine()) != null) {
124 
125                 StringTokenizer st = new StringTokenizer(text, ";", false);
126                 String[] rowValues = new String[st.countTokens()];
127                 int index = 0;
128                 while (st.hasMoreTokens()) {
129 
130                     String next = st.nextToken();
131                     rowValues[index] = next;
132                     index++;
133 
134                 }
135 
136                 //String[] rowValues = text.split(",");
137 
138                 if (line == 0) { // Header row
139                     Collections.addAll(headers, rowValues);
140                 } else { // Data row
141                     Element rowElement = newDoc.createElement("Products");
142                     rootElement.appendChild(rowElement);
143                     Attr attr = newDoc.createAttribute("id");
144                     attr.setValue(Integer.toString(line - 1));
145                     rowElement.setAttributeNode(attr);
146                     for (int col = 0; col < headers.size(); col++) {
147                         String header = headers.get(col);
148                         String value;
149 
150                         if (col < rowValues.length) {
151                             value = rowValues[col].trim();
152                         } else {
153                             // ?? Default value
154                             value = "";
155                         }
156 
157                         Element curElement = newDoc.createElement(header);
158                         curElement.appendChild(newDoc.createTextNode(value));
159                         rowElement.appendChild(curElement);
160                     }
161                 }
162                 line++;
163             }
164 
165             OutputStreamWriter osw = null;
166 
167             try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
168                 osw = new OutputStreamWriter(baos);
169 
170                 TransformerFactory tranFactory = TransformerFactory.newInstance();
171                 Transformer aTransformer = tranFactory.newTransformer();
172                 aTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
173                 aTransformer.setOutputProperty(OutputKeys.METHOD, "xml");
174                 //aTransformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
175                 aTransformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
176 
177                 Source src = new DOMSource(newDoc);
178                 Result result = new StreamResult(osw);
179                 aTransformer.transform(src, result);
180 
181                 osw.flush();
182                 //System.out.println(new String(baos.toByteArray()));
183 
184                 try (OutputStream outStream = new FileOutputStream(xmlLoc)) {// writing bytes in to byte output stream
185 
186                     baos.writeTo(outStream);
187                 } catch (IOException e) {
188                     LogToFile.log(e, Severity.SEVERE, "Error writing XML file. Please try again.");
189                 }
190 
191 
192             } catch (Exception exp) {
193                 LogToFile.log(exp, Severity.SEVERE, "Error writing XML file. Please try again.");
194             } finally {
195                 try {
196                     if (osw != null) {
197                         osw.close();
198                     }
199                 } catch (IOException e) {
200                     LogToFile.log(e, Severity.SEVERE, "Error closing file. Please try again.");
201                 }
202 
203             }
204         } catch (Exception e) {
205             LogToFile.log(e, Severity.SEVERE, "Error reading CSV file. Ensure the path exists, and the software has permission to read it.");
206         }
207     }
208 
209     @FXML
210     private void csvToXml(ActionEvent event) {
211         // Create the custom dialog.
212         Dialog<Pair<String, String>> dialog = new Dialog<>();
213         dialog.setTitle("CSV to XML conversion");
214 
215 // Set the button types.
216         ButtonType convertButtonType = new ButtonType("Convert", ButtonBar.ButtonData.OK_DONE);
217         dialog.getDialogPane().getButtonTypes().addAll(convertButtonType, ButtonType.CANCEL);
218 
219 // Create the username and password labels and fields.
220         GridPane grid = new GridPane();
221         grid.setHgap(10);
222         grid.setVgap(10);
223         grid.setPadding(new Insets(20, 150, 10, 10));
224 
225         TextField csvLoc = new TextField();
226         csvLoc.setPromptText("CSV file Location");
227         TextField xmlLoc = new TextField();
228         xmlLoc.setPromptText("XML Location");
229         Button getCsvLoc = new Button("...");
230         getCsvLoc.setOnAction(e -> {
231             FileChooser chooser = new FileChooser();
232             FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("CSV files", "*.csv", "*.CSV");
233             chooser.getExtensionFilters().add(filter);
234             chooser.setSelectedExtensionFilter(filter);
235             File csv = chooser.showOpenDialog(grid.getScene().getWindow());
236             if (csv != null) {
237                 String path = csv.getAbsolutePath();
238                 if (!path.toLowerCase().endsWith(".csv")) {
239                     path += ".csv";
240                 }
241                 csvLoc.setText(path);
242             }
243         });
244         Button getXmlLoc = new Button("...");
245         getXmlLoc.setOnAction(e -> {
246             FileChooser chooser = new FileChooser();
247             FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("XML files", "*.xml", "*.XML");
248             chooser.getExtensionFilters().add(filter);
249             chooser.setSelectedExtensionFilter(filter);
250             File XML = chooser.showSaveDialog(grid.getScene().getWindow());
251             if (XML != null) {
252                 String path = XML.getAbsolutePath();
253                 if (!path.toLowerCase().endsWith(".xml")) {
254                     path += ".xml";
255                 }
256                 xmlLoc.setText(path);
257             }
258         });
259         grid.add(new Label("CSV file Location:"), 0, 0);
260         grid.add(csvLoc, 1, 0);
261         grid.add(getCsvLoc, 2, 0);
262         grid.add(new Label("XML Location:"), 0, 1);
263         grid.add(xmlLoc, 1, 1);
264         grid.add(getXmlLoc, 2, 1);
265 
266 
267 // Enable/Disable login button depending on whether a username was entered.
268         javafx.scene.Node convertButton = dialog.getDialogPane().lookupButton(convertButtonType);
269         convertButton.setDisable(true);
270 
271 // Do some validation (using the Java 8 lambda syntax).
272         csvLoc.textProperty().addListener((observable, oldValue, newValue) -> convertButton.setDisable(newValue.trim().isEmpty()));
273 
274         dialog.getDialogPane().setContent(grid);
275 
276 // Request focus on the username field by default.
277         Platform.runLater(() -> csvLoc.requestFocus());
278 
279 // Convert the result to a username-password-pair when the login button is clicked.
280         dialog.setResultConverter(dialogButton -> {
281             if (dialogButton == convertButtonType) {
282                 return new Pair<>(csvLoc.getText(), xmlLoc.getText());
283             }
284             return null;
285         });
286 
287         Optional<Pair<String, String>> result = dialog.showAndWait();
288 
289         result.ifPresent(fileLocations -> {
290             convert(fileLocations.getKey(), fileLocations.getValue());
291             createTable(fileLocations.getValue());
292         });
293 
294 
295 
296 
297 /*        CSV2XML csv = new CSV2XML(parent);
298         String xmlFile = csv.getXML();
299         if (!xmlFile.isEmpty()) {
300             createTable(xmlFile);
301         }*/
302     }
303 
304     @FXML
305     private void catCmbxChanged(ActionEvent event) {
306         if (Objects.equals(categoriesCmbx.getSelectionModel().getSelectedItem(), "Add Category")) {
307             Dialog<Pair<String, String>> dialog = new Dialog<>();
308             dialog.setTitle("Add new category");
309 
310 // Set the button types.
311             ButtonType addCat = new ButtonType("Add", ButtonBar.ButtonData.OK_DONE);
312             dialog.getDialogPane().getButtonTypes().addAll(addCat, ButtonType.CANCEL);
313 
314 // Create the username and password labels and fields.
315             GridPane grid = new GridPane();
316             grid.setHgap(10);
317             grid.setVgap(10);
318             grid.setPadding(new Insets(20, 150, 10, 10));
319 
320             TextField catName = new TextField();
321             catName.setPromptText("Category Name");
322             DatePicker catDate = new DatePicker(LocalDate.now());
323             catDate.setPromptText("Category Due Date");
324 
325             grid.add(new Label("Category Name:"), 0, 0);
326             grid.add(catName, 1, 0);
327             grid.add(new Label("Category Due Date:"), 0, 1);
328             grid.add(catDate, 1, 1);
329 
330 
331 // Enable/Disable login button depending on whether a username was entered.
332             javafx.scene.Node addCatButton = dialog.getDialogPane().lookupButton(addCat);
333             addCatButton.setDisable(true);
334 
335 // Do some validation (using the Java 8 lambda syntax).
336             catName.textProperty().addListener((observable, oldValue, newValue) -> addCatButton.setDisable(newValue.trim().isEmpty()));
337 
338             dialog.getDialogPane().setContent(grid);
339 
340 // Request focus on the username field by default.
341             Platform.runLater(() -> catName.requestFocus());
342 
343 // Convert the result to a username-password-pair when the login button is clicked.
344             dialog.setResultConverter(dialogButton -> {
345                 if (dialogButton == addCat) {
346                     return new Pair<String, String>(catName.getText(), catDate.getValue().toString());
347                 }
348                 return null;
349             });
350 
351             Optional<Pair<String, String>> result = dialog.showAndWait();
352 
353             result.ifPresent(category -> {
354                 rowsCats.add(new Year.category(category.getKey(), category.getValue()));
355                 refreshCmbx();
356 
357             });
358 
359 
360         }
361     }
362 
363     private void catCmbxChanged(String newVal) {
364         if (Objects.equals(newVal, "Add Category")) {
365             Dialog<Pair<String, String>> dialog = new Dialog<>();
366             dialog.setTitle("Add new category");
367 
368 // Set the button types.
369             ButtonType addCat = new ButtonType("Add", ButtonBar.ButtonData.OK_DONE);
370             dialog.getDialogPane().getButtonTypes().addAll(addCat, ButtonType.CANCEL);
371 
372 // Create the username and password labels and fields.
373             GridPane grid = new GridPane();
374             grid.setHgap(10);
375             grid.setVgap(10);
376             grid.setPadding(new Insets(20, 150, 10, 10));
377 
378             TextField catName = new TextField();
379             catName.setPromptText("Category Name");
380             DatePicker catDate = new DatePicker(LocalDate.now());
381             catDate.setPromptText("Category Due Date");
382 
383             grid.add(new Label("Category Name:"), 0, 0);
384             grid.add(catName, 1, 0);
385             grid.add(new Label("Category Due Date:"), 0, 1);
386             grid.add(catDate, 1, 1);
387 
388 
389 // Enable/Disable login button depending on whether a username was entered.
390             javafx.scene.Node addCatButton = dialog.getDialogPane().lookupButton(addCat);
391             addCatButton.setDisable(true);
392 
393 // Do some validation (using the Java 8 lambda syntax).
394             catName.textProperty().addListener((observable, oldValue, newValue) -> addCatButton.setDisable(newValue.trim().isEmpty()));
395 
396             dialog.getDialogPane().setContent(grid);
397 
398 // Request focus on the username field by default.
399             Platform.runLater(() -> catName.requestFocus());
400 
401 // Convert the result to a username-password-pair when the login button is clicked.
402             dialog.setResultConverter(dialogButton -> {
403                 if (dialogButton == addCat) {
404                     return new Pair<String, String>(catName.getText(), catDate.getValue().toString());
405                 }
406                 return null;
407             });
408 
409             Optional<Pair<String, String>> result = dialog.showAndWait();
410 
411             result.ifPresent(category -> {
412                 rowsCats.add(new Year.category(category.getKey(), category.getValue()));
413                 refreshCmbx();
414 
415             });
416 
417 
418         }
419     }
420 
421     @FXML
422     private void addBtnPressed(ActionEvent event) {
423         int count = ProductTable.getItems().size() + 1;
424         data.add(new Product.formattedProductProps(idTb.getText(), itemTb.getText(), sizeTb.getText(), rateTb.getText(), categoriesCmbx.getSelectionModel().getSelectedItem(), 0, BigDecimal.ZERO));
425         ProductTable.setItems(data);
426     }
427 
428     @FXML
429     private void submit(ActionEvent event) {
430         DbInt.getYears().forEach(year -> {
431             if (Objects.equals(year, yearText.getText())) {
432                 newYear = false;
433             }
434         });
435         if (chkboxCreateDatabase.isSelected() && newYear) {
436             CreateDb();
437         } else if (newYear) {
438             addYear();
439             updateDb(yearText.getText());
440         } else {
441             updateDb(yearText.getText());
442         }
443 
444         close();
445     }
446 
447     @FXML
448     private void cancel(ActionEvent event) {
449         close();
450     }
451 
452     private void close() {
453         Stage stage = (Stage) yearText.getScene().getWindow();
454         // do what you have to do
455         stage.close();
456     }
457 
458     public void initAddYear(Window parWindow) {
459         parentWindow = parWindow;
460         newYear = true;
461         chkboxCreateDatabase.setSelected(true);
462         yearText.setText(Integer.toString(Calendar.getInstance().get(Calendar.YEAR)));
463         categoriesTb.addAll("", "Add Category");
464         categoriesCmbx.getItems().setAll(categoriesTb);
465         String[][] columnNames = {{"ID", "productID"}, {"Item", "productName"}, {"Size", "productSize"}, {"Price/Item", "productUnitPrice"}};
466         for (String[] column : columnNames) {
467             TableColumn<Product.formattedProductProps, String> tbCol = new TableColumn<>(column[0]);
468             tbCol.setCellValueFactory(new PropertyValueFactory<>(column[1]));
469             tbCol.setCellFactory(TextFieldTableCell.forTableColumn());
470             ProductTable.getColumns().add(tbCol);
471         }
472         TableColumn<Product.formattedProductProps, String> categoryColumn = new TableColumn<>("Category");
473         categoryColumn.setCellValueFactory(new PropertyValueFactory<>("productCategory"));
474 
475         categoryColumn.setCellFactory(ComboBoxTableCell.forTableColumn(categoriesTb));
476 
477         categoryColumn.setOnEditCommit(t -> {
478             t.getRowValue().productCategory.set(t.getNewValue());
479             data.get(t.getTablePosition().getRow()).productCategory.set(t.getNewValue());
480             catCmbxChanged(t.getNewValue());
481         });
482         ProductTable.getColumns().add(categoryColumn);
483         //{"Category", "productCategory"}
484 
485 
486         //categoryColumn.setCellEditor(new DefaultCellEditor(categoriesTb));
487 
488 
489     }
490 
491     /**
492      * Create the dialog.
493      */
494     public void initAddYear(String year, Window parWindow) {
495         newYear = false;
496         parentWindow = parWindow;
497         Year thisYear = new Year(year);
498         yearText.setText(year);
499         yearText.setEditable(false);
500 
501         categoriesCmbx.getItems().clear();
502         categoriesTb.clear();
503         categoriesTb.add("");
504         String browse = "Add Category";
505         thisYear.getCategories().forEach((category) -> {
506             categoriesTb.add(category.catName);
507             rowsCats.add(category);
508         });
509 
510         categoriesTb.add(browse);
511         categoriesCmbx.getItems().setAll(categoriesTb);
512         String[][] columnNames = {{"ID", "productID"}, {"Item", "productName"}, {"Size", "productSize"}, {"Price/Item", "productUnitPrice"}};
513         for (String[] column : columnNames) {
514             TableColumn<Product.formattedProductProps, String> tbCol = new TableColumn<>(column[0]);
515             tbCol.setCellValueFactory(new PropertyValueFactory<>(column[1]));
516             tbCol.setCellFactory(TextFieldTableCell.forTableColumn());
517             ProductTable.getColumns().add(tbCol);
518         }
519         TableColumn<Product.formattedProductProps, String> categoryColumn = new TableColumn<>("Category");
520         categoryColumn.setCellValueFactory(new PropertyValueFactory<>("productCategory"));
521 
522         categoryColumn.setCellFactory(ComboBoxTableCell.forTableColumn(categoriesTb));
523 
524         categoryColumn.setOnEditCommit(t -> {
525             t.getRowValue().productCategory.set(t.getNewValue());
526             data.get(t.getTablePosition().getRow()).productCategory.set(t.getNewValue());
527             catCmbxChanged(t.getNewValue());
528 
529         });
530         ProductTable.getColumns().add(categoryColumn);
531         // boolean updateDb = true;
532         fillTable();
533 
534     }
535 
536     /*    public static void main(String... args) {
537             try {
538 
539                 Launchers.AddYear dialog = new Launchers.AddYear();
540                 dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
541                 dialog.setVisible(true);
542             } catch (RuntimeException e) {
543                 e.printStackTrace();
544             }
545         }*/
546     private void refreshCmbx() {
547         categoriesCmbx.getItems().clear();
548         categoriesTb.clear();
549         categoriesTb.add("");
550         String browse = "Add Category";
551 
552         rowsCats.forEach(cat -> categoriesTb.add(cat.catName));
553 
554 
555         categoriesTb.add(browse);
556         categoriesCmbx.getItems().setAll(categoriesTb);
557 
558     }
559 
560     /**
561      * Creates Database for the year specified.
562      */
563     private void CreateDb() {
564         Year yearToCreate = new Year(yearText.getText());
565         yearToCreate.CreateDb(ProductTable.getItems(), rowsCats);
566     }
567 
568     private void updateDb(String year) {
569         Year yearToUpdate = new Year(year);
570         yearToUpdate.updateDb(year, ProductTable.getItems(), rowsCats);
571     }
572 
573     private void addYear() {
574         Year yearToAdd = new Year(yearText.getText());
575         yearToAdd.addYear();
576     }
577 
578     /**
579      * Parses XML file to insert into products table on screen
580      *
581      * @param FLoc the location of the XML file
582      */
583     private void createTable(String FLoc) {
584         try {
585 
586             File fXmlFile = new File(FLoc);
587             DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
588             DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
589             Document doc = dBuilder.parse(fXmlFile);
590 
591             //optional, but recommended
592             //read this - http://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work
593             doc.getDocumentElement().normalize();
594 
595             //System.out.println("Root element :" + doc.getDocumentElement().getNodeName());
596             NodeList nListCats = doc.getElementsByTagName("Categories");
597 
598             // Collection<String[]> rowsCatsL = new ArrayList<>();
599 
600             for (int temp = 0; temp < nListCats.getLength(); temp++) {
601 
602                 Node nNode = nListCats.item(temp);
603 
604 
605                 if ((int) nNode.getNodeType() == (int) Node.ELEMENT_NODE) {
606 
607                     Element eElement = (Element) nNode;
608                     rowsCats.add(new Year.category(eElement.getElementsByTagName("CategoryName").item(0).getTextContent(), eElement.getElementsByTagName("CategoryDate").item(0).getTextContent()));
609                 }
610             }
611             //rowsCats = rowsCatsL;
612             NodeList nList = doc.getElementsByTagName("Products");
613 
614             Object[][] rows = new Object[nList.getLength()][5];
615 
616             for (int temp = 0; temp < nList.getLength(); temp++) {
617 
618                 Node nNode = nList.item(temp);
619 
620 
621                 if ((int) nNode.getNodeType() == (int) Node.ELEMENT_NODE) {
622 
623                     Element eElement = (Element) nNode;
624 
625 
626                     //String productID, String productName, String productSize, String productUnitPrice, String productCategory, int orderedQuantity, BigDecimal extendedCost
627                     Product.formattedProductProps prodProps = new Product.formattedProductProps(eElement.getElementsByTagName(
628                             "ProductID").item(0).getTextContent(),
629                             eElement.getElementsByTagName("ProductName").item(0).getTextContent(),
630                             eElement.getElementsByTagName("Size").item(0).getTextContent(),
631                             eElement.getElementsByTagName("UnitCost").item(0).getTextContent(),
632                             (eElement.getElementsByTagName("Category").item(0) != null) ? eElement.getElementsByTagName("Category").item(0).getTextContent() : "",
633                             0,
634                             BigDecimal.ZERO
635                     );
636                     data.add(prodProps);
637                     ProductTable.setItems(data);
638 
639                 }
640 
641 
642             }
643         } catch (Exception e) {
644             LogToFile.log(e, Severity.SEVERE, "Error Converting XML file to table. Please try again or contact support.");
645         }
646         refreshCmbx();
647     }
648 
649     /**
650      * Creates an XML file from the table
651      *
652      * @param SavePath Path to save the created XML file
653      */
654     private void createXML(String SavePath) {
655         try {
656             DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
657             DocumentBuilder docBuilder;
658 
659             docBuilder = docFactory.newDocumentBuilder();
660 
661 
662             // root elements
663             Document doc = docBuilder.newDocument();
664 
665             Element rootElement = doc.createElement("LawnGarden");
666             doc.appendChild(rootElement);
667             Iterable<Year.category> caters;
668             caters = rowsCats;
669             int[] i = {0};
670             //caters = getCategories(yearText.getText());
671             caters.forEach(cat -> {
672                         Element cats = doc.createElement("Categories");
673                         rootElement.appendChild(cats);
674                         Attr attr = doc.createAttribute("id");
675                         attr.setValue(Integer.toString(i[0]));
676                         cats.setAttributeNode(attr);
677 
678 
679                         //CateName elements
680                         Element ProductID = doc.createElement("CategoryName");
681                         ProductID.appendChild(doc.createTextNode(cat.catName));
682                         cats.appendChild(ProductID);
683 
684                         //CatDate elements
685                         Element ProductName = doc.createElement("CategoryDate");
686                         ProductName.appendChild(doc.createTextNode(cat.catDate));
687                         cats.appendChild(ProductName);
688                         i[0]++;
689                     }
690             );
691 
692             // staff elements
693 
694 
695             // set attribute to staff element
696             for (int i2 = 0; i2 < ProductTable.getItems().size(); i2++) {
697 
698                 Element staff = doc.createElement("Products");
699                 rootElement.appendChild(staff);
700                 Attr attr = doc.createAttribute("id");
701                 attr.setValue(Integer.toString(i2));
702                 staff.setAttributeNode(attr);
703 
704                 //ProductID elements
705                 Element ProductID = doc.createElement("ProductID");
706                 ProductID.appendChild(doc.createTextNode(ProductTable.getItems().get(i2).getProductID()));
707                 staff.appendChild(ProductID);
708 
709                 // Prodcut Name elements
710                 Element ProductName = doc.createElement("ProductName");
711                 ProductName.appendChild(doc.createTextNode(ProductTable.getItems().get(i2).getProductName()));
712                 staff.appendChild(ProductName);
713 
714                 // Unit COst elements
715                 Element UnitCost = doc.createElement("UnitCost");
716                 UnitCost.appendChild(doc.createTextNode(ProductTable.getItems().get(i2).getProductUnitPrice()));
717                 staff.appendChild(UnitCost);
718 
719                 // Size elements
720                 Element Size = doc.createElement("Size");
721                 Size.appendChild(doc.createTextNode(ProductTable.getItems().get(i2).getProductSize()));
722                 staff.appendChild(Size);
723 
724                 // Category elements
725 
726                 String cat = (ProductTable.getItems().get(i2).getProductCategory() != null) ? ProductTable.getItems().get(i2).getProductCategory() : "";
727                 Element category = doc.createElement("Category");
728                 category.appendChild(doc.createTextNode(cat));
729                 staff.appendChild(category);
730             }
731 
732 
733             // write the content into xml file
734             TransformerFactory transformerFactory = TransformerFactory.newInstance();
735             Transformer transformer = transformerFactory.newTransformer();
736             Source source = new DOMSource(doc);
737             Result result = new StreamResult(new FileOutputStream(SavePath));
738 
739             // Output to console for testing
740             // StreamResult result = new StreamResult(System.out);
741 
742             transformer.transform(source, result);
743 
744             //System.out.println("File saved!");
745         } catch (ParserConfigurationException e) {
746             LogToFile.log(e, Severity.SEVERE, "Error creating XML file: Parser error. Contact support.");
747         } catch (TransformerException e) {
748             LogToFile.log(e, Severity.SEVERE, "Error creating XML file: Parser Error. Contact support.");
749         } catch (FileNotFoundException e) {
750             LogToFile.log(e, Severity.SEVERE, "Error creating XML file: Error writing to file. Make sure the directory is readable by the software.");
751         }
752     }
753 
754     /**
755      * Fills the table from a DB table
756      */
757     private void fillTable() {
758         String year = yearText.getText();
759         Year yearInfo = new Year(year);
760 
761         Product.formattedProduct[] productArray = yearInfo.getAllProducts();
762         Object[][] rows = new Object[productArray.length][6];
763         // data = FXCollections.observableArrayList();
764 
765         int i = 0;
766         for (Product.formattedProduct productOrder : productArray) {
767             //String productID, String productName, String productSize, String productUnitPrice, String productCategory, int orderedQuantity, BigDecimal extendedCost
768             Product.formattedProductProps prodProps = new Product.formattedProductProps(productOrder.productID, productOrder.productName, productOrder.productSize, productOrder.productUnitPrice, productOrder.productCategory, productOrder.orderedQuantity, productOrder.extendedCost);
769             data.add(prodProps);
770             i++;
771         }
772 
773         ProductTable.setItems(data);
774 
775     }
776 
777     @FXML
778     private void tablefromDb(ActionEvent event) {
779 
780         fillTable();
781     }
782 
783     @FXML
784     private void xmlFromTable(ActionEvent event) {
785         FileChooser chooser = new FileChooser();
786         FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter("XML files", "*.xml", "*.XML");
787         chooser.getExtensionFilters().add(filter);
788         chooser.setSelectedExtensionFilter(filter);
789         File XML = chooser.showSaveDialog(parentWindow);
790         if (XML != null) {
791             String path = XML.getAbsolutePath();
792             if (!path.toLowerCase().endsWith(".xml")) {
793                 path += ".xml";
794             }
795             createXML(path);
796         }
797     }
798 
799 
800 }