Add experimental "Advanced Search" features, may incorporate into the main search interface yet...
This commit is contained in:
parent
a88ebc8e13
commit
2dbb3d944d
|
@ -3,17 +3,18 @@ package com.andrewlalis.perfin.control;
|
|||
import com.andrewlalis.javafx_scene_router.RouteSelectionListener;
|
||||
import com.andrewlalis.perfin.data.AccountRepository;
|
||||
import com.andrewlalis.perfin.data.TransactionRepository;
|
||||
import com.andrewlalis.perfin.data.TransactionVendorRepository;
|
||||
import com.andrewlalis.perfin.data.impl.JdbcDataSource;
|
||||
import com.andrewlalis.perfin.data.pagination.Page;
|
||||
import com.andrewlalis.perfin.data.pagination.PageRequest;
|
||||
import com.andrewlalis.perfin.data.pagination.Sort;
|
||||
import com.andrewlalis.perfin.data.search.JdbcTransactionSearcher;
|
||||
import com.andrewlalis.perfin.data.search.SearchFilter;
|
||||
import com.andrewlalis.perfin.data.util.DateUtil;
|
||||
import com.andrewlalis.perfin.data.util.Pair;
|
||||
import com.andrewlalis.perfin.model.Account;
|
||||
import com.andrewlalis.perfin.model.Profile;
|
||||
import com.andrewlalis.perfin.model.Transaction;
|
||||
import com.andrewlalis.perfin.model.TransactionVendor;
|
||||
import com.andrewlalis.perfin.view.BindingUtil;
|
||||
import com.andrewlalis.perfin.view.SceneUtil;
|
||||
import com.andrewlalis.perfin.view.component.AccountSelectionBox;
|
||||
|
@ -25,18 +26,16 @@ import javafx.beans.property.SimpleObjectProperty;
|
|||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.andrewlalis.perfin.PerfinApp.router;
|
||||
|
||||
|
@ -57,7 +56,15 @@ public class TransactionsViewController implements RouteSelectionListener {
|
|||
@FXML public BorderPane transactionsListBorderPane;
|
||||
@FXML public TextField searchField;
|
||||
@FXML public AccountSelectionBox filterByAccountComboBox;
|
||||
|
||||
@FXML public CheckBox advancedSearchFeaturesCheckBox;
|
||||
@FXML public VBox advancedSearchFeaturesVBox;
|
||||
@FXML public VBox advancedSearchAccountChoicesVBox;
|
||||
@FXML public VBox advancedSearchTagChoicesVBox;
|
||||
@FXML public VBox advancedSearchVendorChoicesVBox;
|
||||
|
||||
@FXML public VBox transactionsVBox;
|
||||
|
||||
private DataSourcePaginationControls paginationControls;
|
||||
|
||||
|
||||
|
@ -78,6 +85,15 @@ public class TransactionsViewController implements RouteSelectionListener {
|
|||
selectedTransaction.set(null);
|
||||
});
|
||||
|
||||
// Initialize advanced search feature toggling.
|
||||
BindingUtil.bindManagedAndVisible(filterByAccountComboBox.getParent(), advancedSearchFeaturesCheckBox.selectedProperty().not());
|
||||
BindingUtil.bindManagedAndVisible(advancedSearchFeaturesVBox, advancedSearchFeaturesCheckBox.selectedProperty());
|
||||
advancedSearchFeaturesCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
initializeAdvancedSearchFeatures();
|
||||
}
|
||||
});
|
||||
|
||||
this.paginationControls = new DataSourcePaginationControls(
|
||||
transactionsVBox.getChildren(),
|
||||
new DataSourcePaginationControls.PageFetcherFunction() {
|
||||
|
@ -124,6 +140,42 @@ public class TransactionsViewController implements RouteSelectionListener {
|
|||
});
|
||||
}
|
||||
|
||||
private void initializeAdvancedSearchFeatures() {
|
||||
Profile.getCurrent().dataSource().useRepoAsync(AccountRepository.class, repo -> {
|
||||
List<Account> allAccounts = repo.findAll(PageRequest.unpaged(Sort.asc("name"))).items();
|
||||
Platform.runLater(() -> {
|
||||
advancedSearchAccountChoicesVBox.getChildren().clear();
|
||||
for (Account account : allAccounts) {
|
||||
CheckBox checkBox = new CheckBox(account.getShortName());
|
||||
checkBox.setSelected(false);
|
||||
advancedSearchAccountChoicesVBox.getChildren().add(checkBox);
|
||||
}
|
||||
});
|
||||
});
|
||||
Profile.getCurrent().dataSource().useRepoAsync(TransactionRepository.class, repo -> {
|
||||
List<String> tags = repo.findAllTags();
|
||||
Platform.runLater(() -> {
|
||||
advancedSearchTagChoicesVBox.getChildren().clear();
|
||||
for (var tag : tags) {
|
||||
CheckBox checkBox = new CheckBox(tag);
|
||||
checkBox.setSelected(false);
|
||||
advancedSearchTagChoicesVBox.getChildren().add(checkBox);
|
||||
}
|
||||
});
|
||||
});
|
||||
Profile.getCurrent().dataSource().useRepoAsync(TransactionVendorRepository.class, repo -> {
|
||||
List<TransactionVendor> vendors = repo.findAll();
|
||||
Platform.runLater(() -> {
|
||||
advancedSearchVendorChoicesVBox.getChildren().clear();
|
||||
for (var vendor : vendors) {
|
||||
CheckBox checkBox = new CheckBox(vendor.getName());
|
||||
checkBox.setSelected(false);
|
||||
advancedSearchVendorChoicesVBox.getChildren().add(checkBox);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRouteSelected(Object context) {
|
||||
paginationControls.sorts.setAll(DEFAULT_SORTS);
|
||||
|
@ -162,31 +214,7 @@ public class TransactionsViewController implements RouteSelectionListener {
|
|||
}
|
||||
|
||||
@FXML public void exportTransactions() {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Export Transactions");
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("CSV Files", ".csv"));
|
||||
File file = fileChooser.showSaveDialog(detailPanel.getScene().getWindow());
|
||||
if (file != null) {
|
||||
try (
|
||||
var repo = Profile.getCurrent().dataSource().getTransactionRepository();
|
||||
var out = new PrintWriter(file, StandardCharsets.UTF_8)
|
||||
) {
|
||||
out.println("id,utc-timestamp,amount,currency,description");
|
||||
|
||||
List<Transaction> allTransactions = repo.findAll(PageRequest.unpaged(Sort.desc("timestamp"))).items();
|
||||
for (Transaction tx : allTransactions) {
|
||||
out.println("%d,%s,%s,%s,%s".formatted(
|
||||
tx.id,
|
||||
tx.getTimestamp().format(DateUtil.DEFAULT_DATETIME_FORMAT),
|
||||
tx.getAmount().toPlainString(),
|
||||
tx.getCurrency().getCurrencyCode(),
|
||||
tx.getDescription() == null ? "" : tx.getDescription()
|
||||
));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Popups.error(transactionsListBorderPane, e);
|
||||
}
|
||||
}
|
||||
Popups.message(transactionsListBorderPane, "Exporting transactions is not yet supported.");
|
||||
}
|
||||
|
||||
private List<SearchFilter> getCurrentSearchFilters() {
|
||||
|
|
|
@ -2,11 +2,8 @@
|
|||
|
||||
<?import com.andrewlalis.perfin.view.component.AccountSelectionBox?>
|
||||
<?import com.andrewlalis.perfin.view.component.PropertiesPane?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<BorderPane xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="com.andrewlalis.perfin.control.TransactionsViewController"
|
||||
|
@ -14,20 +11,43 @@
|
|||
<top>
|
||||
<HBox styleClass="std-padding,std-spacing">
|
||||
<Button text="Add Transaction" onAction="#addTransaction"/>
|
||||
<Button text="Export Transactions" onAction="#exportTransactions"/>
|
||||
<Button text="Export Transactions" onAction="#exportTransactions" disable="true"/>
|
||||
</HBox>
|
||||
</top>
|
||||
<center>
|
||||
<!-- The main page content is an HBox with a list of transactions on the
|
||||
left, and a detail panel on the right (which is hidden if no
|
||||
transaction is selected). -->
|
||||
<HBox>
|
||||
<BorderPane fx:id="transactionsListBorderPane" HBox.hgrow="ALWAYS">
|
||||
<top>
|
||||
<HBox styleClass="padding-extra,std-spacing">
|
||||
<TextField fx:id="searchField" promptText="Search"/>
|
||||
<VBox styleClass="padding-extra,std-spacing">
|
||||
<TextField fx:id="searchField" promptText="Search" maxWidth="300" prefWidth="300" minWidth="100"/>
|
||||
<PropertiesPane hgap="5" vgap="5">
|
||||
<Label text="Filter by Account"/>
|
||||
<AccountSelectionBox fx:id="filterByAccountComboBox" allowNone="true" showBalance="false"/>
|
||||
</PropertiesPane>
|
||||
</HBox>
|
||||
<CheckBox fx:id="advancedSearchFeaturesCheckBox" text="Advanced Search"/>
|
||||
<VBox fx:id="advancedSearchFeaturesVBox" styleClass="std-spacing">
|
||||
<Label text="Advanced search features shown here!"/>
|
||||
<PropertiesPane hgap="5" vgap="5">
|
||||
<Label text="Filter by Accounts"/>
|
||||
<ScrollPane maxHeight="100">
|
||||
<VBox fx:id="advancedSearchAccountChoicesVBox" styleClass="std-spacing"/>
|
||||
</ScrollPane>
|
||||
|
||||
<Label text="Filter by Tags"/>
|
||||
<ScrollPane maxHeight="100">
|
||||
<VBox fx:id="advancedSearchTagChoicesVBox" styleClass="std-spacing"/>
|
||||
</ScrollPane>
|
||||
|
||||
<Label text="Filter by Vendor"/>
|
||||
<ScrollPane maxHeight="100">
|
||||
<VBox fx:id="advancedSearchVendorChoicesVBox" styleClass="std-spacing"/>
|
||||
</ScrollPane>
|
||||
</PropertiesPane>
|
||||
</VBox>
|
||||
</VBox>
|
||||
</top>
|
||||
<center>
|
||||
<ScrollPane styleClass="tile-container-scroll">
|
||||
|
@ -35,6 +55,7 @@
|
|||
</ScrollPane>
|
||||
</center>
|
||||
</BorderPane>
|
||||
|
||||
<VBox fx:id="detailPanel"/>
|
||||
</HBox>
|
||||
</center>
|
||||
|
|
Loading…
Reference in New Issue