diff --git a/pom.xml b/pom.xml index e6533e9..fcadf3a 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ com.andrewlalis javafx-scene-router - 1.5.1 + 1.6.0 diff --git a/src/main/java/com/andrewlalis/perfin/control/AccountViewController.java b/src/main/java/com/andrewlalis/perfin/control/AccountViewController.java index b41dc4a..2727486 100644 --- a/src/main/java/com/andrewlalis/perfin/control/AccountViewController.java +++ b/src/main/java/com/andrewlalis/perfin/control/AccountViewController.java @@ -94,8 +94,7 @@ public class AccountViewController implements RouteSelectionListener { ); if (confirmResult) { Profile.getCurrent().getDataSource().useAccountRepository(repo -> repo.archive(account.id)); - router.getHistory().clear(); - router.navigate("accounts"); + router.replace("accounts"); } } @@ -106,8 +105,7 @@ public class AccountViewController implements RouteSelectionListener { ); if (confirm) { Profile.getCurrent().getDataSource().useAccountRepository(repo -> repo.unarchive(account.id)); - router.getHistory().clear(); - router.navigate("accounts"); + router.replace("accounts"); } } @@ -122,8 +120,7 @@ public class AccountViewController implements RouteSelectionListener { ); if (confirm) { Profile.getCurrent().getDataSource().useAccountRepository(repo -> repo.delete(account)); - router.getHistory().clear(); - router.navigate("accounts"); + router.replace("accounts"); } } diff --git a/src/main/java/com/andrewlalis/perfin/control/EditAccountController.java b/src/main/java/com/andrewlalis/perfin/control/EditAccountController.java index 89c915d..3074aa9 100644 --- a/src/main/java/com/andrewlalis/perfin/control/EditAccountController.java +++ b/src/main/java/com/andrewlalis/perfin/control/EditAccountController.java @@ -124,8 +124,7 @@ public class EditAccountController implements RouteSelectionListener { // Once we create the new account, go to the account. Account newAccount = accountRepo.findById(id).orElseThrow(); - router.getHistory().clear(); - router.navigate("account", newAccount); + router.replace("account", newAccount); } } else { log.debug("Updating account {}", account.id); @@ -135,8 +134,7 @@ public class EditAccountController implements RouteSelectionListener { account.setCurrency(accountCurrencyComboBox.getValue()); accountRepo.update(account); Account updatedAccount = accountRepo.findById(account.id).orElseThrow(); - router.getHistory().clear(); - router.navigate("account", updatedAccount); + router.replace("account", updatedAccount); } } catch (Exception e) { log.error("Failed to save (or update) account " + account.id, e); diff --git a/src/main/java/com/andrewlalis/perfin/control/MainViewController.java b/src/main/java/com/andrewlalis/perfin/control/MainViewController.java index 1a55118..9e8e2fc 100644 --- a/src/main/java/com/andrewlalis/perfin/control/MainViewController.java +++ b/src/main/java/com/andrewlalis/perfin/control/MainViewController.java @@ -25,7 +25,7 @@ public class MainViewController { @FXML public void initialize() { AnchorPaneRouterView routerView = (AnchorPaneRouterView) router.getView(); - mainContainer.setCenter(routerView.getAnchorPane()); + mainContainer.setCenter(routerView.getPane()); // Set up a simple breadcrumb display in the top bar. BindingUtil.mapContent( @@ -76,13 +76,11 @@ public class MainViewController { } @FXML public void goToAccounts() { - router.getHistory().clear(); - router.navigate("accounts"); + router.replace("accounts"); } @FXML public void goToTransactions() { - router.getHistory().clear(); - router.navigate("transactions"); + router.replace("transactions"); } @FXML public void viewProfiles() { @@ -98,17 +96,14 @@ public class MainViewController { } @FXML public void helpViewHome() { - helpRouter.getHistory().clear(); - helpRouter.navigate("home"); + helpRouter.replace("home"); } @FXML public void helpViewAccounts() { - helpRouter.getHistory().clear(); - helpRouter.navigate("accounts"); + helpRouter.replace("accounts"); } @FXML public void helpViewTransactions() { - helpRouter.getHistory().clear(); - helpRouter.navigate("transactions"); + helpRouter.replace("transactions"); } } diff --git a/src/main/java/com/andrewlalis/perfin/control/ProfilesViewController.java b/src/main/java/com/andrewlalis/perfin/control/ProfilesViewController.java index edeb452..89d7aca 100644 --- a/src/main/java/com/andrewlalis/perfin/control/ProfilesViewController.java +++ b/src/main/java/com/andrewlalis/perfin/control/ProfilesViewController.java @@ -106,8 +106,7 @@ public class ProfilesViewController { try { Profile.load(name); ProfilesStage.closeView(); - router.getHistory().clear(); - router.navigate("accounts"); + router.replace("accounts"); if (showPopup) Popups.message("The profile \"" + name + "\" has been loaded."); return true; } catch (ProfileLoadException e) { diff --git a/src/main/java/com/andrewlalis/perfin/control/TransactionViewController.java b/src/main/java/com/andrewlalis/perfin/control/TransactionViewController.java index 4b56611..1c6155e 100644 --- a/src/main/java/com/andrewlalis/perfin/control/TransactionViewController.java +++ b/src/main/java/com/andrewlalis/perfin/control/TransactionViewController.java @@ -95,8 +95,7 @@ public class TransactionViewController { Profile.getCurrent().getDataSource().useTransactionRepository(repo -> { // TODO: Delete attachments first! repo.delete(transaction.id); - router.getHistory().clear(); - router.navigate("transactions"); + router.replace("transactions"); }); } } diff --git a/src/main/java/com/andrewlalis/perfin/data/AttachmentRepository.java b/src/main/java/com/andrewlalis/perfin/data/AttachmentRepository.java index 69cc2b4..34e4dd3 100644 --- a/src/main/java/com/andrewlalis/perfin/data/AttachmentRepository.java +++ b/src/main/java/com/andrewlalis/perfin/data/AttachmentRepository.java @@ -10,4 +10,5 @@ public interface AttachmentRepository extends AutoCloseable { Optional findById(long attachmentId); Optional findByIdentifier(String identifier); void deleteById(long attachmentId); + void deleteAllOrphans(); } diff --git a/src/main/java/com/andrewlalis/perfin/data/impl/JdbcAttachmentRepository.java b/src/main/java/com/andrewlalis/perfin/data/impl/JdbcAttachmentRepository.java index 2acdbc3..fec310a 100644 --- a/src/main/java/com/andrewlalis/perfin/data/impl/JdbcAttachmentRepository.java +++ b/src/main/java/com/andrewlalis/perfin/data/impl/JdbcAttachmentRepository.java @@ -5,6 +5,8 @@ import com.andrewlalis.perfin.data.ulid.UlidCreator; import com.andrewlalis.perfin.data.util.DbUtil; import com.andrewlalis.perfin.data.util.FileUtil; import com.andrewlalis.perfin.model.Attachment; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.UncheckedIOException; @@ -18,6 +20,8 @@ import java.util.List; import java.util.Optional; public record JdbcAttachmentRepository(Connection conn, Path contentDir) implements AttachmentRepository { + private static final Logger log = LoggerFactory.getLogger(JdbcAttachmentRepository.class); + @Override public Attachment insert(Path sourcePath) { String filename = sourcePath.getFileName().toString(); @@ -67,6 +71,41 @@ public record JdbcAttachmentRepository(Connection conn, Path contentDir) impleme } } + @Override + public void deleteAllOrphans() { + DbUtil.doTransaction(conn, () -> { + List orphans = DbUtil.findAll( + conn, + """ + SELECT * FROM attachment + WHERE + id NOT IN (SELECT attachment_id FROM transaction_attachment) AND + id NOT IN (SELECT attachment_id FROM balance_record_attachment)""", + JdbcAttachmentRepository::parseAttachment + ); + for (Attachment orphan : orphans) { + DbUtil.updateOne( + conn, + "DELETE FROM attachment WHERE id = ?", + List.of(orphan.id) + ); + Path filePath = orphan.getPath(contentDir); + try { + Files.deleteIfExists(filePath); + Path parentDir = filePath.getParent(); + try (var filesRemaining = Files.list(parentDir)) { + if (filesRemaining.findAny().isEmpty()) { + Files.delete(parentDir); + } + } + } catch (IOException e) { + log.warn("Failed to delete attachment at " + filePath + ".", e); + } + log.debug("Deleted orphan attachment with id {} at {}.", orphan.id, filePath); + } + }); + } + @Override public void close() throws Exception { conn.close(); diff --git a/src/main/java/com/andrewlalis/perfin/data/impl/JdbcTransactionRepository.java b/src/main/java/com/andrewlalis/perfin/data/impl/JdbcTransactionRepository.java index 9668aa0..fefa1e3 100644 --- a/src/main/java/com/andrewlalis/perfin/data/impl/JdbcTransactionRepository.java +++ b/src/main/java/com/andrewlalis/perfin/data/impl/JdbcTransactionRepository.java @@ -151,6 +151,7 @@ public record JdbcTransactionRepository(Connection conn, Path contentDir) implem @Override public void delete(long transactionId) { DbUtil.updateOne(conn, "DELETE FROM transaction WHERE id = ?", List.of(transactionId)); + new JdbcAttachmentRepository(conn, contentDir).deleteAllOrphans(); } @Override