Updated popups to include owner.
This commit is contained in:
		
							parent
							
								
									4951b8720d
								
							
						
					
					
						commit
						da589807ef
					
				| 
						 | 
					@ -89,6 +89,7 @@ public class AccountViewController implements RouteSelectionListener {
 | 
				
			||||||
    @FXML
 | 
					    @FXML
 | 
				
			||||||
    public void archiveAccount() {
 | 
					    public void archiveAccount() {
 | 
				
			||||||
        boolean confirmResult = Popups.confirm(
 | 
					        boolean confirmResult = Popups.confirm(
 | 
				
			||||||
 | 
					                titleLabel,
 | 
				
			||||||
                "Are you sure you want to archive this account? It will no " +
 | 
					                "Are you sure you want to archive this account? It will no " +
 | 
				
			||||||
                        "longer show up in the app normally, and you won't be " +
 | 
					                        "longer show up in the app normally, and you won't be " +
 | 
				
			||||||
                        "able to add new transactions to it. You'll still be " +
 | 
					                        "able to add new transactions to it. You'll still be " +
 | 
				
			||||||
| 
						 | 
					@ -103,6 +104,7 @@ public class AccountViewController implements RouteSelectionListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @FXML public void unarchiveAccount() {
 | 
					    @FXML public void unarchiveAccount() {
 | 
				
			||||||
        boolean confirm = Popups.confirm(
 | 
					        boolean confirm = Popups.confirm(
 | 
				
			||||||
 | 
					                titleLabel,
 | 
				
			||||||
                "Are you sure you want to restore this account from its archived " +
 | 
					                "Are you sure you want to restore this account from its archived " +
 | 
				
			||||||
                        "status?"
 | 
					                        "status?"
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
| 
						 | 
					@ -115,6 +117,7 @@ public class AccountViewController implements RouteSelectionListener {
 | 
				
			||||||
    @FXML
 | 
					    @FXML
 | 
				
			||||||
    public void deleteAccount() {
 | 
					    public void deleteAccount() {
 | 
				
			||||||
        boolean confirm = Popups.confirm(
 | 
					        boolean confirm = Popups.confirm(
 | 
				
			||||||
 | 
					                titleLabel,
 | 
				
			||||||
                "Are you sure you want to permanently delete this account and " +
 | 
					                "Are you sure you want to permanently delete this account and " +
 | 
				
			||||||
                        "all data directly associated with it? This cannot be " +
 | 
					                        "all data directly associated with it? This cannot be " +
 | 
				
			||||||
                        "undone; deleted accounts are not recoverable at all. " +
 | 
					                        "undone; deleted accounts are not recoverable at all. " +
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,10 @@ public class BalanceRecordViewController implements RouteSelectionListener {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @FXML public void delete() {
 | 
					    @FXML public void delete() {
 | 
				
			||||||
        boolean confirm = Popups.confirm("Are you sure you want to delete this balance record? This may have an effect on the derived balance of your account, as shown in Perfin.");
 | 
					        boolean confirm = Popups.confirm(
 | 
				
			||||||
 | 
					                titleLabel,
 | 
				
			||||||
 | 
					                "Are you sure you want to delete this balance record? This may have an effect on the derived balance of your account, as shown in Perfin."
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        if (confirm) {
 | 
					        if (confirm) {
 | 
				
			||||||
            Profile.getCurrent().dataSource().useRepo(BalanceRecordRepository.class, repo -> repo.deleteById(balanceRecord.id));
 | 
					            Profile.getCurrent().dataSource().useRepo(BalanceRecordRepository.class, repo -> repo.deleteById(balanceRecord.id));
 | 
				
			||||||
            router.navigateBackAndClear();
 | 
					            router.navigateBackAndClear();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,7 @@ public class CreateBalanceRecordController implements RouteSelectionListener {
 | 
				
			||||||
        LocalDateTime localTimestamp = LocalDateTime.parse(timestampField.getText(), DateUtil.DEFAULT_DATETIME_FORMAT);
 | 
					        LocalDateTime localTimestamp = LocalDateTime.parse(timestampField.getText(), DateUtil.DEFAULT_DATETIME_FORMAT);
 | 
				
			||||||
        BigDecimal reportedBalance = new BigDecimal(balanceField.getText());
 | 
					        BigDecimal reportedBalance = new BigDecimal(balanceField.getText());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        boolean confirm = Popups.confirm("Are you sure that you want to record the balance of account\n%s\nas %s,\nas of %s?".formatted(
 | 
					        boolean confirm = Popups.confirm(timestampField, "Are you sure that you want to record the balance of account\n%s\nas %s,\nas of %s?".formatted(
 | 
				
			||||||
                account.getShortName(),
 | 
					                account.getShortName(),
 | 
				
			||||||
                CurrencyUtil.formatMoneyWithCurrencyPrefix(new MoneyValue(reportedBalance, account.getCurrency())),
 | 
					                CurrencyUtil.formatMoneyWithCurrencyPrefix(new MoneyValue(reportedBalance, account.getCurrency())),
 | 
				
			||||||
                localTimestamp.atZone(ZoneId.systemDefault()).format(DateUtil.DEFAULT_DATETIME_FORMAT_WITH_ZONE)
 | 
					                localTimestamp.atZone(ZoneId.systemDefault()).format(DateUtil.DEFAULT_DATETIME_FORMAT_WITH_ZONE)
 | 
				
			||||||
| 
						 | 
					@ -122,7 +122,7 @@ public class CreateBalanceRecordController implements RouteSelectionListener {
 | 
				
			||||||
                    CurrencyUtil.formatMoney(new MoneyValue(reportedBalance, account.getCurrency())),
 | 
					                    CurrencyUtil.formatMoney(new MoneyValue(reportedBalance, account.getCurrency())),
 | 
				
			||||||
                    CurrencyUtil.formatMoney(new MoneyValue(currentDerivedBalance, account.getCurrency()))
 | 
					                    CurrencyUtil.formatMoney(new MoneyValue(currentDerivedBalance, account.getCurrency()))
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            return Popups.confirm(msg);
 | 
					            return Popups.confirm(timestampField, msg);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,7 +117,7 @@ public class EditAccountController implements RouteSelectionListener {
 | 
				
			||||||
                BigDecimal initialBalance = new BigDecimal(initialBalanceField.getText().strip());
 | 
					                BigDecimal initialBalance = new BigDecimal(initialBalanceField.getText().strip());
 | 
				
			||||||
                List<Path> attachments = Collections.emptyList();
 | 
					                List<Path> attachments = Collections.emptyList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                boolean success = Popups.confirm("Are you sure you want to create this account?");
 | 
					                boolean success = Popups.confirm(accountNameField, "Are you sure you want to create this account?");
 | 
				
			||||||
                if (success) {
 | 
					                if (success) {
 | 
				
			||||||
                    long id = accountRepo.insert(type, number, name, currency);
 | 
					                    long id = accountRepo.insert(type, number, name, currency);
 | 
				
			||||||
                    balanceRepo.insert(LocalDateTime.now(ZoneOffset.UTC), id, initialBalance, currency, attachments);
 | 
					                    balanceRepo.insert(LocalDateTime.now(ZoneOffset.UTC), id, initialBalance, currency, attachments);
 | 
				
			||||||
| 
						 | 
					@ -138,7 +138,7 @@ public class EditAccountController implements RouteSelectionListener {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } catch (Exception e) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
            log.error("Failed to save (or update) account " + account.id, e);
 | 
					            log.error("Failed to save (or update) account " + account.id, e);
 | 
				
			||||||
            Popups.error("Failed to save the account: " + e.getMessage());
 | 
					            Popups.error(accountNameField, "Failed to save the account: " + e.getMessage());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,7 +203,7 @@ public class EditTransactionController implements RouteSelectionListener {
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            } catch (Exception e) {
 | 
					            } catch (Exception e) {
 | 
				
			||||||
                log.error("Failed to get repositories.", e);
 | 
					                log.error("Failed to get repositories.", e);
 | 
				
			||||||
                Popups.error("Failed to fetch account-specific data: " + e.getMessage());
 | 
					                Popups.error(container, "Failed to fetch account-specific data: " + e.getMessage());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,30 +1,65 @@
 | 
				
			||||||
package com.andrewlalis.perfin.control;
 | 
					package com.andrewlalis.perfin.control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javafx.scene.Node;
 | 
				
			||||||
 | 
					import javafx.scene.Scene;
 | 
				
			||||||
import javafx.scene.control.Alert;
 | 
					import javafx.scene.control.Alert;
 | 
				
			||||||
import javafx.scene.control.ButtonType;
 | 
					import javafx.scene.control.ButtonType;
 | 
				
			||||||
import javafx.stage.Modality;
 | 
					import javafx.stage.Modality;
 | 
				
			||||||
 | 
					import javafx.stage.Window;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Helper class for standardized popups and confirmation dialogs for the app.
 | 
					 * Helper class for standardized popups and confirmation dialogs for the app.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class Popups {
 | 
					public class Popups {
 | 
				
			||||||
    public static boolean confirm(String text) {
 | 
					    public static boolean confirm(Window owner, String text) {
 | 
				
			||||||
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION, text);
 | 
					        Alert alert = new Alert(Alert.AlertType.CONFIRMATION, text);
 | 
				
			||||||
 | 
					        alert.initOwner(owner);
 | 
				
			||||||
        alert.initModality(Modality.APPLICATION_MODAL);
 | 
					        alert.initModality(Modality.APPLICATION_MODAL);
 | 
				
			||||||
        var result = alert.showAndWait();
 | 
					        var result = alert.showAndWait();
 | 
				
			||||||
        return result.isPresent() && result.get() == ButtonType.OK;
 | 
					        return result.isPresent() && result.get() == ButtonType.OK;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void message(String text) {
 | 
					    public static boolean confirm(Node node, String text) {
 | 
				
			||||||
 | 
					        return confirm(getWindowFromNode(node), text);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void message(Window owner, String text) {
 | 
				
			||||||
        Alert alert = new Alert(Alert.AlertType.NONE, text);
 | 
					        Alert alert = new Alert(Alert.AlertType.NONE, text);
 | 
				
			||||||
 | 
					        alert.initOwner(owner);
 | 
				
			||||||
        alert.initModality(Modality.APPLICATION_MODAL);
 | 
					        alert.initModality(Modality.APPLICATION_MODAL);
 | 
				
			||||||
        alert.getButtonTypes().setAll(ButtonType.OK);
 | 
					        alert.getButtonTypes().setAll(ButtonType.OK);
 | 
				
			||||||
        alert.showAndWait();
 | 
					        alert.showAndWait();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void error(String text) {
 | 
					    public static void message(Node node, String text) {
 | 
				
			||||||
 | 
					        message(getWindowFromNode(node), text);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void error(Window owner, String text) {
 | 
				
			||||||
        Alert alert = new Alert(Alert.AlertType.WARNING, text);
 | 
					        Alert alert = new Alert(Alert.AlertType.WARNING, text);
 | 
				
			||||||
 | 
					        alert.initOwner(owner);
 | 
				
			||||||
        alert.initModality(Modality.APPLICATION_MODAL);
 | 
					        alert.initModality(Modality.APPLICATION_MODAL);
 | 
				
			||||||
        alert.showAndWait();
 | 
					        alert.showAndWait();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void error(Node node, String text) {
 | 
				
			||||||
 | 
					        error(getWindowFromNode(node), text);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void error(Window owner, Exception e) {
 | 
				
			||||||
 | 
					        error(owner, "An " + e.getClass().getSimpleName() + " occurred: " + e.getMessage());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void error(Node node, Exception e) {
 | 
				
			||||||
 | 
					        error(getWindowFromNode(node), e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static Window getWindowFromNode(Node n) {
 | 
				
			||||||
 | 
					        Window owner = null;
 | 
				
			||||||
 | 
					        Scene scene = n.getScene();
 | 
				
			||||||
 | 
					        if (scene != null) {
 | 
				
			||||||
 | 
					            owner = scene.getWindow();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return owner;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,10 +46,10 @@ public class ProfilesViewController {
 | 
				
			||||||
        String name = newProfileNameField.getText();
 | 
					        String name = newProfileNameField.getText();
 | 
				
			||||||
        boolean valid = Profile.validateName(name);
 | 
					        boolean valid = Profile.validateName(name);
 | 
				
			||||||
        if (valid && !ProfileLoader.getAvailableProfiles().contains(name)) {
 | 
					        if (valid && !ProfileLoader.getAvailableProfiles().contains(name)) {
 | 
				
			||||||
            boolean confirm = Popups.confirm("Are you sure you want to add a new profile named \"" + name + "\"?");
 | 
					            boolean confirm = Popups.confirm(profilesVBox, "Are you sure you want to add a new profile named \"" + name + "\"?");
 | 
				
			||||||
            if (confirm) {
 | 
					            if (confirm) {
 | 
				
			||||||
                if (openProfile(name, false)) {
 | 
					                if (openProfile(name, false)) {
 | 
				
			||||||
                    Popups.message("Created new profile \"" + name + "\" and loaded it.");
 | 
					                    Popups.message(profilesVBox, "Created new profile \"" + name + "\" and loaded it.");
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                newProfileNameField.clear();
 | 
					                newProfileNameField.clear();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -108,18 +108,18 @@ public class ProfilesViewController {
 | 
				
			||||||
            PerfinApp.profileLoader.load(name);
 | 
					            PerfinApp.profileLoader.load(name);
 | 
				
			||||||
            ProfilesStage.closeView();
 | 
					            ProfilesStage.closeView();
 | 
				
			||||||
            router.replace("accounts");
 | 
					            router.replace("accounts");
 | 
				
			||||||
            if (showPopup) Popups.message("The profile \"" + name + "\" has been loaded.");
 | 
					            if (showPopup) Popups.message(profilesVBox, "The profile \"" + name + "\" has been loaded.");
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } catch (ProfileLoadException e) {
 | 
					        } catch (ProfileLoadException e) {
 | 
				
			||||||
            Popups.error("Failed to load the profile: " + e.getMessage());
 | 
					            Popups.error(profilesVBox, "Failed to load the profile: " + e.getMessage());
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void deleteProfile(String name) {
 | 
					    private void deleteProfile(String name) {
 | 
				
			||||||
        boolean confirmA = Popups.confirm("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.");
 | 
					        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) {
 | 
					        if (confirmA) {
 | 
				
			||||||
            boolean confirmB = Popups.confirm("Press \"OK\" to confirm that you really want to delete the profile \"" + name + "\". There's no going back.");
 | 
					            boolean confirmB = Popups.confirm(profilesVBox, "Press \"OK\" to confirm that you really want to delete the profile \"" + name + "\". There's no going back.");
 | 
				
			||||||
            if (confirmB) {
 | 
					            if (confirmB) {
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    FileUtil.deleteDirRecursive(Profile.getDir(name));
 | 
					                    FileUtil.deleteDirRecursive(Profile.getDir(name));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,6 +72,7 @@ public class TransactionViewController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @FXML public void deleteTransaction() {
 | 
					    @FXML public void deleteTransaction() {
 | 
				
			||||||
        boolean confirm = Popups.confirm(
 | 
					        boolean confirm = Popups.confirm(
 | 
				
			||||||
 | 
					            titleLabel,
 | 
				
			||||||
            "Are you sure you want to delete this transaction? This will " +
 | 
					            "Are you sure you want to delete this transaction? This will " +
 | 
				
			||||||
            "permanently remove the transaction and its effects on any linked " +
 | 
					            "permanently remove the transaction and its effects on any linked " +
 | 
				
			||||||
            "accounts, as well as remove any attachments from storage within " +
 | 
					            "accounts, as well as remove any attachments from storage within " +
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -177,7 +177,7 @@ public class TransactionsViewController implements RouteSelectionListener {
 | 
				
			||||||
                    ));
 | 
					                    ));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } catch (Exception e) {
 | 
					            } catch (Exception e) {
 | 
				
			||||||
                Popups.error("An error occurred: " + e.getMessage());
 | 
					                Popups.error(transactionsListBorderPane, e);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,10 @@ import java.util.function.Consumer;
 | 
				
			||||||
 *     class maintains a static <em>current</em> profile that can be loaded and
 | 
					 *     class maintains a static <em>current</em> profile that can be loaded and
 | 
				
			||||||
 *     unloaded.
 | 
					 *     unloaded.
 | 
				
			||||||
 * </p>
 | 
					 * </p>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param name The name of the profile.
 | 
				
			||||||
 | 
					 * @param settings The profile's settings.
 | 
				
			||||||
 | 
					 * @param dataSource The profile's data source.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public record Profile(String name, Properties settings, DataSource dataSource) {
 | 
					public record Profile(String name, Properties settings, DataSource dataSource) {
 | 
				
			||||||
    private static final Logger log = LoggerFactory.getLogger(Profile.class);
 | 
					    private static final Logger log = LoggerFactory.getLogger(Profile.class);
 | 
				
			||||||
| 
						 | 
					@ -65,6 +69,7 @@ public record Profile(String name, Properties settings, DataSource dataSource) {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        currentProfileListeners.removeIf(ref -> ref.get() == null);
 | 
					        currentProfileListeners.removeIf(ref -> ref.get() == null);
 | 
				
			||||||
 | 
					        log.debug("Current profile set to {}.", current.name());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void whenLoaded(Consumer<Profile> consumer) {
 | 
					    public static void whenLoaded(Consumer<Profile> consumer) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
package com.andrewlalis.perfin.model;
 | 
					package com.andrewlalis.perfin.model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.andrewlalis.perfin.PerfinApp;
 | 
					import com.andrewlalis.perfin.PerfinApp;
 | 
				
			||||||
 | 
					import com.andrewlalis.perfin.control.Popups;
 | 
				
			||||||
import com.andrewlalis.perfin.data.DataSourceFactory;
 | 
					import com.andrewlalis.perfin.data.DataSourceFactory;
 | 
				
			||||||
import com.andrewlalis.perfin.data.ProfileLoadException;
 | 
					import com.andrewlalis.perfin.data.ProfileLoadException;
 | 
				
			||||||
import com.andrewlalis.perfin.data.util.FileUtil;
 | 
					import com.andrewlalis.perfin.data.util.FileUtil;
 | 
				
			||||||
| 
						 | 
					@ -43,6 +44,21 @@ public class ProfileLoader {
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            throw new ProfileLoadException("Failed to load profile settings.", e);
 | 
					            throw new ProfileLoadException("Failed to load profile settings.", e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            DataSourceFactory.SchemaStatus status = dataSourceFactory.getSchemaStatus(name);
 | 
				
			||||||
 | 
					            if (status == DataSourceFactory.SchemaStatus.NEEDS_MIGRATION) {
 | 
				
			||||||
 | 
					                boolean confirm = Popups.confirm(window, "The profile \"" + name + "\" has an outdated data schema and needs to be migrated to the latest version. Is this okay?");
 | 
				
			||||||
 | 
					                if (!confirm) {
 | 
				
			||||||
 | 
					                    throw new ProfileLoadException("User rejected migration.");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else if (status == DataSourceFactory.SchemaStatus.INCOMPATIBLE) {
 | 
				
			||||||
 | 
					                Popups.error(window, "The profile \"" + name + "\" has a data schema that's incompatible with this app.");
 | 
				
			||||||
 | 
					                throw new ProfileLoadException("Incompatible schema version.");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (IOException e) {
 | 
				
			||||||
 | 
					            throw new ProfileLoadException("Failed to get profile's schema status.", e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Popups.message(window, "Test!");
 | 
				
			||||||
        return new Profile(name, settings, dataSourceFactory.getDataSource(name));
 | 
					        return new Profile(name, settings, dataSourceFactory.getDataSource(name));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ import javafx.stage.Stage;
 | 
				
			||||||
import javafx.stage.StageStyle;
 | 
					import javafx.stage.StageStyle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.concurrent.CompletableFuture;
 | 
				
			||||||
import java.util.function.Consumer;
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -60,6 +61,10 @@ public class StartupSplashScreen extends Stage implements Consumer<String> {
 | 
				
			||||||
        return scene;
 | 
					        return scene;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Runs all tasks sequentially, invoking each one on the JavaFX main thread,
 | 
				
			||||||
 | 
					     * and quitting if there's any exception thrown.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private void runTasks() {
 | 
					    private void runTasks() {
 | 
				
			||||||
        Thread.ofVirtual().start(() -> {
 | 
					        Thread.ofVirtual().start(() -> {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
| 
						 | 
					@ -69,7 +74,16 @@ public class StartupSplashScreen extends Stage implements Consumer<String> {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            for (var task : tasks) {
 | 
					            for (var task : tasks) {
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    task.accept(this);
 | 
					                    CompletableFuture<Void> future = new CompletableFuture<>();
 | 
				
			||||||
 | 
					                    Platform.runLater(() -> {
 | 
				
			||||||
 | 
					                        try {
 | 
				
			||||||
 | 
					                            task.accept(this);
 | 
				
			||||||
 | 
					                            future.complete(null);
 | 
				
			||||||
 | 
					                        } catch (Exception e) {
 | 
				
			||||||
 | 
					                            future.completeExceptionally(e);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    future.join();
 | 
				
			||||||
                    Thread.sleep(500);
 | 
					                    Thread.sleep(500);
 | 
				
			||||||
                } catch (Exception e) {
 | 
					                } catch (Exception e) {
 | 
				
			||||||
                    accept("Startup failed: " + e.getMessage());
 | 
					                    accept("Startup failed: " + e.getMessage());
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue