Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#56 Kategorien: Verwaltungsansichten in MDV überführen #74

Merged
merged 2 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import timkodiert.budgetBook.view.ImportView;
import timkodiert.budgetBook.view.MonthlyOverview;
import timkodiert.budgetBook.view.View;
import timkodiert.budgetBook.view.category.CategoriesManageView;
import timkodiert.budgetBook.view.category.CategoryDetailView;
import timkodiert.budgetBook.view.fixed_turnover.FixedTurnoverDetailView;
import timkodiert.budgetBook.view.fixed_turnover.FixedTurnoverManageView;
import timkodiert.budgetBook.view.unique_expense.UniqueExpenseDetailView;
Expand Down Expand Up @@ -37,6 +39,8 @@ private void registerController() {
viewControllerMap.put(FixedTurnoverDetailView.class, viewComponent::getFixedTurnoverDetailView);
viewControllerMap.put(UniqueExpensesManageView.class, viewComponent::getUniqueExpensesManageView);
viewControllerMap.put(UniqueExpenseDetailView.class, viewComponent::getUniqueExpenseDetailView);
viewControllerMap.put(CategoriesManageView.class, viewComponent::getManageCategoriesView);
viewControllerMap.put(CategoryDetailView.class, viewComponent::getCategoryDetailView);
// Technische Ansichten
viewControllerMap.put(MigrationView.class, viewComponent::getMigrationView);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ public interface ServiceModule {

@Binds @Singleton PropertiesService bindPropertiesService(PropertiesServiceImpl impl);

@Binds @Singleton FXMLLoader bindFXMLLoader(BbFxmlLoader impl);
@Binds FXMLLoader bindFXMLLoader(BbFxmlLoader impl);
}
// @formatter:on
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
import timkodiert.budgetBook.view.AnnualOverviewView;
import timkodiert.budgetBook.view.ImportView;
import timkodiert.budgetBook.view.MainViewImpl;
import timkodiert.budgetBook.view.ManageCategoriesView;
import timkodiert.budgetBook.view.MonthlyOverview;
import timkodiert.budgetBook.view.NewCategoryView;
import timkodiert.budgetBook.view.category.CategoriesManageView;
import timkodiert.budgetBook.view.category.CategoryDetailView;
import timkodiert.budgetBook.view.fixed_turnover.FixedTurnoverDetailView;
import timkodiert.budgetBook.view.fixed_turnover.FixedTurnoverManageView;
import timkodiert.budgetBook.view.unique_expense.UniqueExpenseDetailView;
Expand All @@ -34,8 +34,8 @@ public interface ViewComponent {
// -----------------------------------
// Kategorien Ausgaben
// -----------------------------------
ManageCategoriesView getManageCategoriesView();
NewCategoryView getNewCategoryView();
CategoriesManageView getManageCategoriesView();
CategoryDetailView getCategoryDetailView();

// -----------------------------------
// Regelmäßige Umsätze
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,12 @@
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.MenuBar;
import javafx.scene.control.RadioMenuItem;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.jetbrains.annotations.Nullable;

Expand All @@ -29,16 +26,13 @@
import timkodiert.budgetBook.injector.ControllerFactory;
import timkodiert.budgetBook.injector.ViewComponent;
import timkodiert.budgetBook.properties.PropertiesService;
import timkodiert.budgetBook.util.StageBuilder;

import static timkodiert.budgetBook.view.FxmlResource.ANNUAL_OVERVIEW;
import static timkodiert.budgetBook.view.FxmlResource.IMPORT_VIEW;
import static timkodiert.budgetBook.view.FxmlResource.MAIN_VIEW;
import static timkodiert.budgetBook.view.FxmlResource.MANAGE_CATEGORIES_VIEW;
import static timkodiert.budgetBook.view.FxmlResource.MANAGE_REGULAR_TURNOVER_VIEW;
import static timkodiert.budgetBook.view.FxmlResource.MANAGE_UNIQUE_TURNOVER_VIEW;
import static timkodiert.budgetBook.view.FxmlResource.MONTHLY_OVERVIEW;
import static timkodiert.budgetBook.view.FxmlResource.NEW_CATEGORY_VIEW;

@Singleton
public class MainViewImpl implements Initializable, MainView {
Expand Down Expand Up @@ -147,34 +141,7 @@ public void openImportView(ActionEvent event) {

@FXML
private void openManageCategoriesView(ActionEvent event) {
try {
Stage stage = StageBuilder.create(languageManager)
.withModality(Modality.APPLICATION_MODAL)
.withOwner(this.primaryStage)
.withFXMLResource(MANAGE_CATEGORIES_VIEW.toString())
.withView(viewComponent.getManageCategoriesView())
.build();
stage.show();
} catch (Exception e) {
Alert alert = new Alert(AlertType.ERROR, languageManager.get("alert.viewCouldNotBeOpened"));
alert.showAndWait();
}
}

@FXML
private void openNewCategoryView(ActionEvent event) {
try {
Stage stage = StageBuilder.create(languageManager)
.withModality(Modality.APPLICATION_MODAL)
.withOwner(this.primaryStage)
.withFXMLResource(NEW_CATEGORY_VIEW.toString())
.withView(viewComponent.getNewCategoryView())
.build();
stage.show();
} catch (Exception e) {
Alert alert = new Alert(AlertType.ERROR, languageManager.get("alert.viewCouldNotBeOpened"));
alert.showAndWait();
}
loadViewPartial(FxmlResource.MANAGE_CATEGORY_VIEW);
}

@FXML
Expand Down
1 change: 0 additions & 1 deletion bb.application/src/main/resources/fxml/Main.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
<MenuItem mnemonicParsing="false" onAction="#openUniqueExpensesManageView" text="%menuItem.openUniqueExpensesView" />
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem mnemonicParsing="false" onAction="#openManageCategoriesView" text="%menuItem.manageCategoriesView" />
<MenuItem mnemonicParsing="false" onAction="#openNewCategoryView" text="%menuItem.openNewCategoryView" />
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem mnemonicParsing="false" onAction="#openSettingsView" text="%menuItem.openSettingsView" />
</items>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package timkodiert.budgetBook.domain.adapter;

import lombok.Getter;

import timkodiert.budgetBook.domain.model.Category;

public class CategoryAdapter implements Adapter<Category> {

@Getter
private final Category bean;

public CategoryAdapter(Category bean) {
this.bean = bean;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package timkodiert.budgetBook.domain.model;

import org.hibernate.annotations.GenericGenerator;

import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.hibernate.annotations.GenericGenerator;

@MappedSuperclass
@Getter
Expand All @@ -15,4 +14,8 @@ public abstract class BaseEntity implements ContentEquals {
@GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
protected int id;

public boolean isNew() {
return id <= 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package timkodiert.budgetBook.domain.model;

import static timkodiert.budgetBook.util.ObjectUtils.nvl;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
Expand All @@ -16,16 +14,19 @@
import jakarta.validation.constraints.NotBlank;
import javafx.scene.control.CheckBoxTreeItem;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

import timkodiert.budgetBook.domain.adapter.Adaptable;
import timkodiert.budgetBook.domain.adapter.CategoryAdapter;

import static timkodiert.budgetBook.util.ObjectUtils.nvl;

@Getter
@NoArgsConstructor
@RequiredArgsConstructor
@Entity
public class Category extends BaseEntity {
public class Category extends BaseEntity implements Adaptable<CategoryAdapter> {

@Setter
@NonNull
Expand Down Expand Up @@ -53,10 +54,27 @@ public class Category extends BaseEntity {
@Transient
private CheckBoxTreeItem<Category> treeItem = new CheckBoxTreeItem<>();

@Transient
private transient CategoryAdapter adapter;

public Category() {
initAdapter();
}

@Override
public void initAdapter() {
this.adapter = new CategoryAdapter(this);
}

public CheckBoxTreeItem<Category> asTreeItem() {
this.treeItem.setValue(this);
this.treeItem.getChildren().setAll(this.getChildren().stream().map(Category::asTreeItem).toList());
return this.treeItem;
CheckBoxTreeItem<Category> treeItem = new CheckBoxTreeItem<>();
treeItem.setValue(this);
treeItem.getChildren().setAll(this.getChildren().stream().map(Category::asTreeItem).toList());
return treeItem;
}

public boolean hasParent() {
return parent != null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package timkodiert.budgetBook.ui.helper;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.TreeItem;
Expand All @@ -12,31 +14,40 @@

public class CategoryTreeHelper {

private List<CheckBoxTreeItem<Category>> allTreeItems;
private final List<CheckBoxTreeItem<Category>> allTreeItems;

private CategoryTreeHelper(TreeView<Category> categoriesTreeView, List<Category> categories) {
allTreeItems = categories.stream().map(Category::asTreeItem).toList();
List<? extends TreeItem<Category>> roots = allTreeItems.stream()
.filter(ti -> ti.getValue().getParent() == null)
.toList();
private CategoryTreeHelper(TreeView<Category> categoriesTreeView, List<Category> categories, boolean checkboxCells) {
List<CheckBoxTreeItem<Category>> roots = categories.stream().filter(Predicate.not(Category::hasParent)).map(Category::asTreeItem).toList();
allTreeItems = roots.stream().flatMap(root -> identifyAllTreeItems(root).stream()).toList();
TreeItem<Category> root = new TreeItem<>(new Category("ROOT"));
root.getChildren().addAll(roots);
categoriesTreeView.setCellFactory(CheckBoxTreeCell.forTreeView());
if (checkboxCells) {
categoriesTreeView.setCellFactory(CheckBoxTreeCell.forTreeView());
}
categoriesTreeView.setRoot(root);
categoriesTreeView.setShowRoot(false);
}

private List<CheckBoxTreeItem<Category>> identifyAllTreeItems(CheckBoxTreeItem<Category> root) {
List<CheckBoxTreeItem<Category>> items = new ArrayList<>();
items.add(root);
root.getChildren().forEach(child -> items.addAll(identifyAllTreeItems((CheckBoxTreeItem<Category>) child)));
return items;
}

public void selectCategories(Categorizable entity) {
allTreeItems.forEach(ti -> ti.setSelected(entity.getCategories().contains(ti.getValue())));
}

public List<Category> getSelectedCategories() {
return allTreeItems.stream()
.filter(CheckBoxTreeItem::isSelected).map(TreeItem::getValue)
.toList();
return allTreeItems.stream().filter(CheckBoxTreeItem::isSelected).map(TreeItem::getValue).toList();
}

public static CategoryTreeHelper from(TreeView<Category> treeView, List<Category> categories) {
return new CategoryTreeHelper(treeView, categories);
return new CategoryTreeHelper(treeView, categories, true);
}

public static CategoryTreeHelper from(TreeView<Category> treeView, List<Category> categories, boolean checkboxCells) {
return new CategoryTreeHelper(treeView, categories, checkboxCells);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public enum FxmlResource {
IMPORT_VIEW("/fxml/Importer/ImportView.fxml", "stageTitle.importView"),
IMAGE_VIEW("/fxml/ImageView.fxml", null),
MONTH_YEAR_PICKER_WIDGET("/fxml/MonthYearPickerWidget.fxml", null),
MANAGE_CATEGORIES_VIEW("/fxml/ManageCategories.fxml", null),
MANAGE_CATEGORY_VIEW("/fxml/category/Manage.fxml", "stageTitle.mdv.categories"),
CATEGORY_DETAIL_VIEW("/fxml/category/Detail.fxml", null),
NEW_CATEGORY_VIEW("/fxml/NewCategory.fxml", null),
;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package timkodiert.budgetBook.view.mdv_base;

import java.net.URL;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.function.Supplier;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import org.jetbrains.annotations.Nullable;

import timkodiert.budgetBook.dialog.DialogFactory;
import timkodiert.budgetBook.domain.adapter.Adaptable;
import timkodiert.budgetBook.domain.adapter.Adapter;
import timkodiert.budgetBook.domain.model.BaseEntity;
import timkodiert.budgetBook.domain.repository.Repository;
import timkodiert.budgetBook.i18n.LanguageManager;

public abstract class BaseListManageView<T extends BaseEntity & Adaptable<A>, A extends Adapter<T>> extends BaseManageView<T, A> {

@FXML
protected TableView<A> entityTable;

protected final Repository<T> repository;
private final DialogFactory dialogFactory;

public BaseListManageView(Supplier<T> emptyEntityProducer,
Repository<T> repository,
FXMLLoader fxmlLoader,
DialogFactory dialogFactory,
LanguageManager languageManager) {
super(fxmlLoader, languageManager, repository, emptyEntityProducer);
this.repository = repository;
this.dialogFactory = dialogFactory;
}

@Override
public void initialize(URL location, ResourceBundle resources) {
super.initialize(location, resources);

entityTable.setRowFactory(tableView -> {
TableRow<A> row = new TableRow<>();
row.setOnMouseClicked(event -> {
if (event.getClickCount() == 1 && !row.isEmpty()) {
if (detailView.isDirty()) {
Alert alert = dialogFactory.buildConfirmationDialog();
Optional<ButtonType> result = alert.showAndWait();
if (result.get().equals(DialogFactory.CANCEL)) {
entityTable.getSelectionModel().select(detailView.getEntity().get().getAdapter());
return;
}
if (result.get().equals(DialogFactory.SAVE_CHANGES) && !detailView.save()) {
entityTable.getSelectionModel().select(detailView.getEntity().get().getAdapter());
return;
}
}

detailView.setEntity(row.getItem().getBean());
}
});
return row;
});

initControls();
}

@Override
protected void reloadTable(@Nullable T updatedEntity) {
entityTable.getItems().setAll(repository.findAll().stream().map(T::getAdapter).toList());
entityTable.sort();
}

}
Loading
Loading