diff --git a/src/main/java/com/andrewlalis/perfin/control/ProfilesViewController.java b/src/main/java/com/andrewlalis/perfin/control/ProfilesViewController.java index 842fde1..fbab444 100644 --- a/src/main/java/com/andrewlalis/perfin/control/ProfilesViewController.java +++ b/src/main/java/com/andrewlalis/perfin/control/ProfilesViewController.java @@ -21,8 +21,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import static com.andrewlalis.perfin.PerfinApp.router; @@ -92,6 +100,9 @@ public class ProfilesViewController { PerfinApp.instance.getHostServices().showDocument(Profile.getDir(profileName).toUri().toString()); }); buttonBox.getChildren().add(viewFilesButton); + Button backupButton = new Button("Backup"); + backupButton.setOnAction(event -> makeBackup(profileName)); + buttonBox.getChildren().add(backupButton); Button deleteButton = new Button("Delete"); deleteButton.setOnAction(event -> deleteProfile(profileName)); buttonBox.getChildren().add(deleteButton); @@ -117,6 +128,38 @@ public class ProfilesViewController { } } + private void makeBackup(String name) { + log.info("Making backup of profile \"{}\".", name); + final Path profileDir = Profile.getDir(name); + LocalDateTime now = LocalDateTime.now(); + Path backupFile = profileDir.resolve(String.format( + "backup_%04d-%02d-%02d_%02d-%02d-%02d.zip", + now.getYear(), now.getMonthValue(), now.getDayOfMonth(), + now.getHour(), now.getMinute(), now.getSecond() + )); + try { + ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(backupFile)); + Files.walkFileTree(profileDir, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Path relativeFile = profileDir.relativize(file); + if (relativeFile.toString().startsWith("backup_") || relativeFile.toString().equalsIgnoreCase("database.trace.db")) { + return FileVisitResult.CONTINUE; + } + out.putNextEntry(new ZipEntry(relativeFile.toString())); + byte[] bytes = Files.readAllBytes(file); + out.write(bytes, 0, bytes.length); + out.closeEntry(); + return FileVisitResult.CONTINUE; + } + }); + out.close(); + Popups.message(profilesVBox, "A new backup was created at " + backupFile.toAbsolutePath()); + } catch (IOException e) { + Popups.error(profilesVBox, e); + } + } + private void deleteProfile(String name) { boolean confirmA = Popups.confirm(profilesVBox, "Are you sure you want to delete the profile \"" + name + "\"? This will permanently delete ALL accounts, transactions, files, and other data for this profile, and it cannot be recovered."); if (confirmA) { diff --git a/src/main/java/com/andrewlalis/perfin/view/component/module/SpendingCategoryChartModule.java b/src/main/java/com/andrewlalis/perfin/view/component/module/SpendingCategoryChartModule.java new file mode 100644 index 0000000..a4d5d23 --- /dev/null +++ b/src/main/java/com/andrewlalis/perfin/view/component/module/SpendingCategoryChartModule.java @@ -0,0 +1,16 @@ +package com.andrewlalis.perfin.view.component.module; + +import javafx.scene.chart.PieChart; +import javafx.scene.layout.Pane; + +public class SpendingCategoryChartModule extends DashboardModule { + public SpendingCategoryChartModule(Pane parent) { + super(parent); + PieChart chart = new PieChart(); + } + + @Override + public void refreshContents() { + + } +}