diff --git a/src/de/deadlocker8/budgetmaster/logic/ReportItem.java b/src/de/deadlocker8/budgetmaster/logic/ReportItem.java new file mode 100644 index 0000000000000000000000000000000000000000..2090e787a5a3a8ae325f9964f317e10c1b9eceeb --- /dev/null +++ b/src/de/deadlocker8/budgetmaster/logic/ReportItem.java @@ -0,0 +1,93 @@ +package de.deadlocker8.budgetmaster.logic; + +public class ReportItem +{ + private int position; + private int amount; + private String date; + private Category category; + private String name; + private String description; + private boolean repeating; + + public ReportItem() + { + + } + + public int getPosition() + { + return position; + } + + public void setPosition(int position) + { + this.position = position; + } + + public int getAmount() + { + return amount; + } + + public void setAmount(int amount) + { + this.amount = amount; + } + + public String getDate() + { + return date; + } + + public void setDate(String date) + { + this.date = date; + } + + public Category getCategory() + { + return category; + } + + public void setCategory(Category category) + { + this.category = category; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getDescription() + { + return description; + } + + public void setDescription(String description) + { + this.description = description; + } + + public boolean getRepeating() + { + return repeating; + } + + public void setRepeating(boolean repeating) + { + this.repeating = repeating; + } + + @Override + public String toString() + { + return "ReportItem [position=" + position + ", amount=" + amount + ", date=" + date + ", category=" + category + ", name=" + name + ", description=" + description + ", isRepeating=" + repeating + "]"; + } +} \ No newline at end of file diff --git a/src/de/deadlocker8/budgetmaster/ui/Controller.java b/src/de/deadlocker8/budgetmaster/ui/Controller.java index e0a3a139f8e0af6e50177713bbd12ab5317d66d3..6fb76b59b6a8d3483c78be7158c5966a27715e7a 100644 --- a/src/de/deadlocker8/budgetmaster/ui/Controller.java +++ b/src/de/deadlocker8/budgetmaster/ui/Controller.java @@ -285,6 +285,7 @@ public class Controller homeController.refresh(); paymentController.refresh(); categoryController.refresh(); + reportController.refresh(); if(tabCharts.isSelected()) { chartController.refresh(); @@ -322,6 +323,7 @@ public class Controller tabPayments.setDisable(disable); tabCategories.setDisable(disable); tabCharts.setDisable(disable); + tabReports.setDisable(disable); buttonLeft.setDisable(disable); buttonRight.setDisable(disable); buttonToday.setDisable(disable); diff --git a/src/de/deadlocker8/budgetmaster/ui/ReportController.java b/src/de/deadlocker8/budgetmaster/ui/ReportController.java index b87e820ba59bbbcd130e9f52da94a5147e3b1ac4..9685ed3975fdb23991c4142eaaa753884621e093 100644 --- a/src/de/deadlocker8/budgetmaster/ui/ReportController.java +++ b/src/de/deadlocker8/budgetmaster/ui/ReportController.java @@ -1,35 +1,38 @@ package de.deadlocker8.budgetmaster.ui; import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; -import de.deadlocker8.budgetmaster.logic.Budget; -import de.deadlocker8.budgetmaster.logic.ExceptionHandler; import de.deadlocker8.budgetmaster.logic.FilterSettings; import de.deadlocker8.budgetmaster.logic.Helpers; -import de.deadlocker8.budgetmaster.logic.NormalPayment; import de.deadlocker8.budgetmaster.logic.Payment; -import de.deadlocker8.budgetmaster.logic.RepeatingPayment; import de.deadlocker8.budgetmaster.logic.RepeatingPaymentEntry; -import de.deadlocker8.budgetmaster.logic.ServerConnection; -import de.deadlocker8.budgetmaster.ui.cells.PaymentCell; +import de.deadlocker8.budgetmaster.logic.ReportItem; import fontAwesome.FontIcon; import fontAwesome.FontIconType; -import javafx.application.Platform; -import javafx.beans.value.ChangeListener; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; import javafx.beans.value.ObservableValue; -import javafx.event.EventHandler; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; +import javafx.geometry.Pos; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; -import javafx.scene.input.MouseEvent; +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableColumn.CellDataFeatures; +import javafx.scene.control.TableView; +import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.AnchorPane; +import javafx.scene.paint.Color; import javafx.stage.Modality; import javafx.stage.Stage; import javafx.util.Callback; @@ -37,20 +40,22 @@ import logger.Logger; public class ReportController implements Refreshable { - @FXML private AnchorPane anchorPaneMain; + @FXML private AnchorPane anchorPaneMain; @FXML private Label labelPayments; @FXML private Label labelFilterActive; @FXML private CheckBox checkBoxSplitTable; - @FXML private CheckBox checkBoxIncludeCharts; + @FXML private CheckBox checkBoxIncludeChart; + @FXML private CheckBox checkBoxDescending; @FXML private Button buttonFilter; @FXML private Button buttonGenerate; + @FXML private TableView<ReportItem> tableView; private Controller controller; public void init(Controller controller) { this.controller = controller; - + FontIcon iconFilter = new FontIcon(FontIconType.FILTER); iconFilter.setSize(18); iconFilter.setStyle("-fx-text-fill: white"); @@ -60,41 +65,300 @@ public class ReportController implements Refreshable iconPayment.setStyle("-fx-text-fill: white"); buttonGenerate.setGraphic(iconPayment); + checkBoxDescending.setSelected(true); + + initTable(); + // apply theme - anchorPaneMain.setStyle("-fx-background-color: #F4F4F4;"); - labelFilterActive.setStyle("-fx-text-fill: " + controller.getBundle().getString("color.text")); + anchorPaneMain.setStyle("-fx-background-color: #F4F4F4;"); + labelFilterActive.setStyle("-fx-text-fill: " + controller.getBundle().getString("color.text")); buttonFilter.setStyle("-fx-background-color: #2E79B9; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 16;"); buttonGenerate.setStyle("-fx-background-color: #2E79B9; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 16;"); + checkBoxSplitTable.setStyle("-fx-text-fill: " + controller.getBundle().getString("color.text") + "; -fx-font-size: 14;"); + checkBoxIncludeChart.setStyle("-fx-text-fill: " + controller.getBundle().getString("color.text") + "; -fx-font-size: 14;"); + checkBoxDescending.setStyle("-fx-text-fill: " + controller.getBundle().getString("color.text") + "; -fx-font-size: 14;"); refresh(); } - + + private void initTable() + { + Label labelPlaceholder = new Label("Keine Daten verfügbar"); + labelPlaceholder.setStyle("-fx-font-size: 16"); + tableView.setPlaceholder(labelPlaceholder); + + TableColumn<ReportItem, Integer> columnPosition = new TableColumn<>("Nr."); + columnPosition.setCellValueFactory(new PropertyValueFactory<ReportItem, Integer>("position")); + columnPosition.setStyle("-fx-alignment: CENTER;"); + CheckBox checkBoxPositions = new CheckBox(); + checkBoxPositions.setSelected(true); + checkBoxPositions.selectedProperty().addListener((a, b, c)->{ + String style = c ? "" : "-fx-background-color: salmon"; + columnPosition.setStyle(style); + }); + columnPosition.setGraphic(checkBoxPositions); + columnPosition.setSortable(false); + tableView.getColumns().add(columnPosition); + + TableColumn<ReportItem, String> columnDate = new TableColumn<>("Datum"); + columnDate.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ReportItem, String>, ObservableValue<String>>() + { + @Override + public ObservableValue<String> call(CellDataFeatures<ReportItem, String> param) + { + String dateString = param.getValue().getDate(); + try + { + DateFormat format = new SimpleDateFormat("dd-MM-yyyy"); + Date date = format.parse(dateString); + DateFormat finalFormat = new SimpleDateFormat("dd.MM.yy"); + dateString = finalFormat.format(date); + return new SimpleStringProperty(dateString); + } + catch(Exception e) + { + Logger.error(e); + return null; + } + } + }); + columnDate.setStyle("-fx-alignment: CENTER;"); + CheckBox checkBoxDate = new CheckBox(); + checkBoxDate.setSelected(true); + checkBoxDate.selectedProperty().addListener((a, b, c)->{ + String style = c ? "" : "-fx-background-color: salmon"; + columnDate.setStyle(style); + }); + columnDate.setGraphic(checkBoxDate); + columnDate.setSortable(false); + tableView.getColumns().add(columnDate); + + TableColumn<ReportItem, Boolean> columnIsRepeating = new TableColumn<>("Wiederholend"); + columnIsRepeating.setCellValueFactory(new PropertyValueFactory<ReportItem, Boolean>("repeating")); + columnIsRepeating.setCellFactory(new Callback<TableColumn<ReportItem, Boolean>, TableCell<ReportItem, Boolean>>() + { + @Override + public TableCell<ReportItem, Boolean> call(TableColumn<ReportItem, Boolean> param) + { + TableCell<ReportItem, Boolean> cell = new TableCell<ReportItem, Boolean>() + { + @Override + public void updateItem(Boolean item, boolean empty) + { + if(!empty) + { + FontIcon iconRepeating = new FontIcon(FontIconType.CALENDAR); + iconRepeating.setSize(16); + Color color = item ? Color.web("#212121") : Color.TRANSPARENT; + iconRepeating.setColor(color); + + Label labelRepeating = new Label(); + labelRepeating.setGraphic(iconRepeating); + labelRepeating.setStyle("-fx-font-weight: bold; -fx-font-size: 14; -fx-text-fill: #212121"); + labelRepeating.setAlignment(Pos.CENTER); + setGraphic(labelRepeating); + } + else + { + setGraphic(null); + } + } + }; + return cell; + } + }); + columnIsRepeating.setStyle("-fx-alignment: CENTER;"); + CheckBox checkBoxRepeating = new CheckBox(); + checkBoxRepeating.setSelected(true); + checkBoxRepeating.selectedProperty().addListener((a, b, c)->{ + String style = c ? "" : "-fx-background-color: salmon"; + columnIsRepeating.setStyle(style); + }); + columnIsRepeating.setGraphic(checkBoxRepeating); + columnIsRepeating.setSortable(false); + tableView.getColumns().add(columnIsRepeating); + + TableColumn<ReportItem, String> columnCategory = new TableColumn<>("Kategorie"); + columnCategory.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ReportItem, String>, ObservableValue<String>>() + { + @Override + public ObservableValue<String> call(CellDataFeatures<ReportItem, String> param) + { + String categoryName = param.getValue().getCategory().getName(); + if(categoryName.equals("NONE")) + { + categoryName = ""; + } + return new SimpleStringProperty(categoryName); + } + }); + columnCategory.setStyle("-fx-alignment: CENTER;"); + CheckBox checkBoxCategory = new CheckBox(); + checkBoxCategory.setSelected(true); + checkBoxCategory.selectedProperty().addListener((a, b, c)->{ + String style = c ? "" : "-fx-background-color: salmon"; + columnCategory.setStyle(style); + }); + columnCategory.setGraphic(checkBoxCategory); + columnCategory.setSortable(false); + tableView.getColumns().add(columnCategory); + + TableColumn<ReportItem, Integer> columnName = new TableColumn<>("Name"); + columnName.setCellValueFactory(new PropertyValueFactory<ReportItem, Integer>("name")); + columnName.setStyle("-fx-alignment: CENTER;"); + CheckBox checkBoxName = new CheckBox(); + checkBoxName.setSelected(true); + checkBoxName.selectedProperty().addListener((a, b, c)->{ + String style = c ? "" : "-fx-background-color: salmon"; + columnName.setStyle(style); + }); + columnName.setGraphic(checkBoxName); + columnName.setSortable(false); + tableView.getColumns().add(columnName); + + TableColumn<ReportItem, Integer> columnDescription = new TableColumn<>("Notiz"); + columnDescription.setCellValueFactory(new PropertyValueFactory<ReportItem, Integer>("description")); + columnDescription.setStyle("-fx-alignment: CENTER;"); + CheckBox checkBoxDescription = new CheckBox(); + checkBoxDescription.setSelected(true); + checkBoxDescription.selectedProperty().addListener((a, b, c)->{ + String style = c ? "" : "-fx-background-color: salmon"; + columnDescription.setStyle(style); + }); + columnDescription.setGraphic(checkBoxDescription); + columnDescription.setSortable(false); + tableView.getColumns().add(columnDescription); + + TableColumn<ReportItem, Integer> columnRating = new TableColumn<>("Bewertung"); + columnRating.setCellValueFactory(new PropertyValueFactory<ReportItem, Integer>("amount")); + columnRating.setCellFactory(new Callback<TableColumn<ReportItem, Integer>, TableCell<ReportItem, Integer>>() + { + @Override + public TableCell<ReportItem, Integer> call(TableColumn<ReportItem, Integer> param) + { + TableCell<ReportItem, Integer> cell = new TableCell<ReportItem, Integer>() + { + @Override + public void updateItem(Integer item, boolean empty) + { + if(!empty) + { + FontIcon iconRepeating = item > 0 ? new FontIcon(FontIconType.PLUS) : new FontIcon(FontIconType.MINUS); + iconRepeating.setSize(14); + iconRepeating.setColor(Color.web("#212121")); + + Label labelRepeating = new Label(); + labelRepeating.setGraphic(iconRepeating); + labelRepeating.setStyle("-fx-font-weight: bold; -fx-font-size: 14; -fx-text-fill: #212121"); + labelRepeating.setAlignment(Pos.CENTER); + setGraphic(labelRepeating); + } + else + { + setGraphic(null); + } + } + }; + return cell; + } + }); + columnRating.setStyle("-fx-alignment: CENTER;"); + CheckBox checkBoxRating = new CheckBox(); + checkBoxRating.setSelected(true); + checkBoxRating.selectedProperty().addListener((a, b, c)->{ + String style = c ? "" : "-fx-background-color: salmon"; + columnRating.setStyle(style); + }); + columnRating.setGraphic(checkBoxRating); + columnRating.setSortable(false); + tableView.getColumns().add(columnRating); + + TableColumn<ReportItem, String> columnAmount = new TableColumn<>("Betrag"); + columnAmount.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ReportItem, String>, ObservableValue<String>>() + { + @Override + public ObservableValue<String> call(CellDataFeatures<ReportItem, String> param) + { + StringProperty value = new SimpleStringProperty(); + double amount = param.getValue().getAmount() / 100.0; + value.set(String.valueOf(Helpers.NUMBER_FORMAT.format(amount).replace(".", ",")) + " " + controller.getSettings().getCurrency()); + return value; + } + }); + columnAmount.setStyle("-fx-alignment: CENTER;"); + CheckBox checkBoxAmount = new CheckBox(); + checkBoxAmount.setSelected(true); + checkBoxAmount.selectedProperty().addListener((a, b, c)->{ + String style = c ? "" : "-fx-background-color: salmon"; + columnAmount.setStyle(style); + }); + columnAmount.setGraphic(checkBoxAmount); + columnAmount.setSortable(false); + tableView.getColumns().add(columnAmount); + + tableView.setFixedCellSize(26); + } + public void filter() { -// try -// { -// FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/de/deadlocker8/budgetmaster/ui/FilterGUI.fxml")); -// Parent root = (Parent)fxmlLoader.load(); -// Stage newStage = new Stage(); -// newStage.initOwner(controller.getStage()); -// newStage.initModality(Modality.APPLICATION_MODAL); -// newStage.setTitle("Filter"); -// newStage.setScene(new Scene(root)); -// newStage.getIcons().add(controller.getIcon()); -// newStage.setResizable(false); -// FilterController newController = fxmlLoader.getController(); -// newController.init(newStage, controller, this, controller.getFilterSettings()); -// newStage.show(); -// } -// catch(IOException e) -// { -// Logger.error(e); -// } + try + { + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/de/deadlocker8/budgetmaster/ui/FilterGUI.fxml")); + Parent root = (Parent)fxmlLoader.load(); + Stage newStage = new Stage(); + newStage.initOwner(controller.getStage()); + newStage.initModality(Modality.APPLICATION_MODAL); + newStage.setTitle("Filter"); + newStage.setScene(new Scene(root)); + newStage.getIcons().add(controller.getIcon()); + newStage.setResizable(false); + FilterController newController = fxmlLoader.getController(); + newController.init(newStage, controller, controller.getFilterSettings()); + newStage.show(); + } + catch(IOException e) + { + Logger.error(e); + } + } + + private ArrayList<ReportItem> createReportItems(ArrayList<Payment> payments) + { + ArrayList<ReportItem> reportItems = new ArrayList<>(); + for(int i = 0; i < payments.size(); i++) + { + Payment currentPayment = payments.get(i); + ReportItem reportItem = new ReportItem(); + reportItem.setPosition(i + 1); + reportItem.setDate(currentPayment.getDate()); + reportItem.setAmount(currentPayment.getAmount()); + reportItem.setDescription(currentPayment.getDescription()); + reportItem.setName(currentPayment.getName()); + reportItem.setRepeating(currentPayment instanceof RepeatingPaymentEntry); + reportItem.setCategory(controller.getCategoryHandler().getCategory(currentPayment.getCategoryID())); + + reportItems.add(reportItem); + } + + return reportItems; } - + + private void refreshTableView() + { + tableView.getItems().clear(); + + ArrayList<Payment> payments = controller.getPaymentHandler().getPayments(); + if(payments != null) + { + ArrayList<ReportItem> reportItems = createReportItems(payments); + ObservableList<ReportItem> objectsForTable = FXCollections.observableArrayList(reportItems); + tableView.setItems(objectsForTable); + } + } + public void generate() { - + } public Controller getController() @@ -104,14 +368,16 @@ public class ReportController implements Refreshable @Override public void refresh() - { -// if(controller.getFilterSettings().equals(new FilterSettings())) -// { -// labelFilterActive.setVisible(false); -// } -// else -// { -// labelFilterActive.setVisible(true); -// } + { + if(controller.getFilterSettings().equals(new FilterSettings())) + { + labelFilterActive.setVisible(false); + } + else + { + labelFilterActive.setVisible(true); + } + + refreshTableView(); } } \ No newline at end of file diff --git a/src/de/deadlocker8/budgetmaster/ui/ReportTab.fxml b/src/de/deadlocker8/budgetmaster/ui/ReportTab.fxml index de540f17b628a9e151642a9f791ecbd224ffbd49..3d84c457b23c76a3cd270f30d242b6744b946507 100644 --- a/src/de/deadlocker8/budgetmaster/ui/ReportTab.fxml +++ b/src/de/deadlocker8/budgetmaster/ui/ReportTab.fxml @@ -41,11 +41,15 @@ <children> <CheckBox fx:id="checkBoxSplitTable" mnemonicParsing="false" text="Einnahmen und Ausgaben als getrennte Tabellen" /> <CheckBox fx:id="checkBoxIncludeChart" mnemonicParsing="false" text="Diagramm hinzufügen" /> + <CheckBox fx:id="checkBoxDescending" mnemonicParsing="false" text="Neuestes Datum zuerst" /> </children> </VBox> </children> </HBox> - <TableView fx:id="tableView" prefHeight="270.0" prefWidth="772.0" VBox.vgrow="ALWAYS" /> + <TableView fx:id="tableView" prefHeight="270.0" prefWidth="772.0" VBox.vgrow="ALWAYS"> + <columnResizePolicy> + <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> + </columnResizePolicy></TableView> <HBox alignment="CENTER" prefHeight="11.0" prefWidth="772.0"> <children> <VBox alignment="CENTER" spacing="10.0"> diff --git a/src/de/deadlocker8/budgetmaster/ui/cells/PaymentCell.java b/src/de/deadlocker8/budgetmaster/ui/cells/PaymentCell.java index e096c9a72a0c14fdabd8972136b64e235e739ac2..528e2f1c019da5b1827537452c0aeb5966e357e4 100644 --- a/src/de/deadlocker8/budgetmaster/ui/cells/PaymentCell.java +++ b/src/de/deadlocker8/budgetmaster/ui/cells/PaymentCell.java @@ -28,6 +28,7 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.paint.Color; import javafx.stage.Stage; +import logger.Logger; import tools.ConvertTo; public class PaymentCell extends ListCell<Payment> @@ -62,7 +63,7 @@ public class PaymentCell extends ListCell<Payment> } catch(ParseException e) { - e.printStackTrace(); + Logger.error(e); } Label labelDate = new Label(dateString); labelDate.setPrefHeight(HEIGHT);