From 00d739401ab90f1f50e638b4e62aeafe1f7e01cc Mon Sep 17 00:00:00 2001 From: lantzelot-swe <75668734+lantzelot-swe@users.noreply.github.com> Date: Thu, 23 May 2024 16:30:03 +0200 Subject: [PATCH] fix: add, backup and restore db works --- src/main/java/se/lantz/db/DbConnector.java | 34 ++--- .../se/lantz/gui/DraggableTabbedPane.java | 52 ++++---- src/main/java/se/lantz/gui/MainPanel.java | 117 +++++++++++++++++- .../java/se/lantz/manager/BackupManager.java | 18 +-- .../java/se/lantz/model/MainViewModel.java | 43 +++++-- src/main/java/se/lantz/util/FileManager.java | 86 ++++++++----- 6 files changed, 256 insertions(+), 94 deletions(-) diff --git a/src/main/java/se/lantz/db/DbConnector.java b/src/main/java/se/lantz/db/DbConnector.java index 30d85a7..ee51a83 100644 --- a/src/main/java/se/lantz/db/DbConnector.java +++ b/src/main/java/se/lantz/db/DbConnector.java @@ -33,6 +33,7 @@ import se.lantz.util.GameListDataComparator; public class DbConnector { + public static String DB_FILE_NAME = "pcusb.db"; public static String DB_FILE = ""; private static final String COMMA = "\",\""; // @J- @@ -105,27 +106,32 @@ public class DbConnector columnList.add(DbConstants.DISK_4); columnList.add(DbConstants.DISK_5); columnList.add(DbConstants.DISK_6); - + for (String dbFolder : dbFolders) { setCurrentDbFolder(dbFolder); - //Check if databases file exists, if not create an empty db. - File dbFile = new File("./" + DB_FILE); - if (!dbFile.exists()) - { - createNewDb(); - logger.debug("Database {} missing, new db created.", dbFolder); - } - //To be backwards compatible with 1.0 db, update if missing - addLanguageAndDuplicateColumnsIfMissing(); - //To be backwards compatible with 2.8.2 db, update if missing - addDiskColumnsIfMissing(); + createDbIfMissing(dbFolder); } } - + + public void createDbIfMissing(String folderName) + { + //Check if databases file exists, if not create an empty db. + File dbFile = new File("./" + DB_FILE); + if (!dbFile.exists()) + { + createNewDb(); + logger.debug("Database {} missing, new db created.", folderName); + } + //To be backwards compatible with 1.0 db, update if missing + addLanguageAndDuplicateColumnsIfMissing(); + //To be backwards compatible with 2.8.2 db, update if missing + addDiskColumnsIfMissing(); + } + public static void setCurrentDbFolder(String dbFolder) { - DB_FILE = "./databases/" + dbFolder + "/pcusb.db"; + DB_FILE = "./databases/" + dbFolder + "/" + DB_FILE_NAME; } private void createNewDb() diff --git a/src/main/java/se/lantz/gui/DraggableTabbedPane.java b/src/main/java/se/lantz/gui/DraggableTabbedPane.java index b6e0a3d..7e2f572 100644 --- a/src/main/java/se/lantz/gui/DraggableTabbedPane.java +++ b/src/main/java/se/lantz/gui/DraggableTabbedPane.java @@ -14,10 +14,7 @@ import java.awt.image.BufferedImage; import javax.swing.JButton; import javax.swing.JFrame; -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; import javax.swing.JTabbedPane; -import javax.swing.SwingUtilities; public class DraggableTabbedPane extends JTabbedPane { @@ -32,14 +29,13 @@ public class DraggableTabbedPane extends JTabbedPane private ActionListener draggedTabListener = null; private ActionListener tabStructureChangedListener = null; + private boolean removingTab = false; public DraggableTabbedPane() { super(); - addMouseMotionListener(new MouseMotionAdapter() { - public void mouseDragged(MouseEvent e) { @@ -165,34 +161,31 @@ public class DraggableTabbedPane extends JTabbedPane // Need to repaint repaint(); } - - @Override - public void mouseClicked(MouseEvent e) - { - if (SwingUtilities.isRightMouseButton(e)) - { - - int tabNumber = getUI().tabForCoordinate(DraggableTabbedPane.this, e.getX(), 10); - - if (tabNumber > -1 && (tabNumber < getTabCount() - 1)) - { - JPopupMenu menu = new JPopupMenu(); - JMenuItem renameTabItem = new JMenuItem("Rename database"); - JMenuItem deleteTabItem = new JMenuItem("Delete database"); - menu.add(renameTabItem); - menu.add(deleteTabItem); - menu.show(DraggableTabbedPane.this, e.getX(), e.getY()); - } - } - } }); } + @Override + public void removeTabAt(int index) + { + //Select a proper tab after removing + if (getSelectedIndex() == getTabCount() - 2) + { + this.removingTab = true; + super.removeTabAt(index); + this.removingTab = false; + setSelectedIndex(getTabCount() - 2); + } + else + { + super.removeTabAt(index); + } + } + public void addTabDraggedListener(ActionListener listener) { draggedTabListener = listener; } - + public void addTabStructureChangedListener(ActionListener listener) { tabStructureChangedListener = listener; @@ -205,7 +198,7 @@ public class DraggableTabbedPane extends JTabbedPane draggedTabListener.actionPerformed(new ActionEvent(this, tabNumber, "inserted")); } } - + private void notifyTabStructureChangedListener() { if (tabStructureChangedListener != null) @@ -219,6 +212,11 @@ public class DraggableTabbedPane extends JTabbedPane return dragging; } + public boolean isRemovingTab() + { + return removingTab; + } + public int getPreviouslySelectedIndex() { return previouslySelectedIndex; diff --git a/src/main/java/se/lantz/gui/MainPanel.java b/src/main/java/se/lantz/gui/MainPanel.java index 0906c5b..7acb943 100644 --- a/src/main/java/se/lantz/gui/MainPanel.java +++ b/src/main/java/se/lantz/gui/MainPanel.java @@ -1,16 +1,24 @@ package se.lantz.gui; import java.awt.BorderLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import javax.swing.JComponent; +import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; import se.lantz.model.MainViewModel; import se.lantz.model.data.GameListData; +import se.lantz.util.ExceptionHandler; public class MainPanel extends JPanel { @@ -58,11 +66,11 @@ public class MainPanel extends JPanel //Update previous selected index once a tab is dragged to a new position tabbedPane.addTabDraggedListener(e -> previouslySelectedIndex = e.getID()); - //Update preferences when the tab structure changes (renamed, deleted, re-arranged) + //Update preferences when the tab positions changes tabbedPane.addTabStructureChangedListener(e -> updateTabOrderPreferences()); tabbedPane.addChangeListener(e -> { - if (!tabbedPane.isDragging()) + if (!tabbedPane.isRemovingTab() && !tabbedPane.isDragging()) { if (tabbedPane.getSelectedIndex() == uiModel.getAvailableDatabases().size()) { @@ -70,6 +78,7 @@ public class MainPanel extends JPanel tabbedPane.setSelectedIndex(previouslySelectedIndex); ignoreTabChange = false; String name = JOptionPane.showInputDialog(this, "Write a new name!"); + createNewTab(name); //Create a new empty one! return; } @@ -92,10 +101,114 @@ public class MainPanel extends JPanel repaint(); } }); + + tabbedPane.addMouseListener(new MouseAdapter() + { + + @Override + public void mouseClicked(MouseEvent e) + { + if (SwingUtilities.isRightMouseButton(e)) + { + int tabNumber = tabbedPane.getUI().tabForCoordinate(tabbedPane, e.getX(), 10); + + if (tabNumber > -1 && (tabNumber < tabbedPane.getTabCount() - 1)) + { + JPopupMenu menu = new JPopupMenu(); + JMenuItem renameTabItem = new JMenuItem("Rename database"); + renameTabItem.addActionListener(ev -> renameTab(tabNumber)); + JMenuItem deleteTabItem = new JMenuItem("Delete database"); + deleteTabItem.addActionListener(ev -> deleteTab(tabNumber)); + menu.add(renameTabItem); + menu.add(deleteTabItem); + menu.show(tabbedPane, e.getX(), e.getY()); + } + } + } + }); } return tabbedPane; } + private void renameTab(int tabIndex) + { + String oldName = tabbedPane.getTitleAt(tabIndex); + String newName = (String) JOptionPane.showInputDialog(this, + "Enter new name for \"" + oldName + "\"", + "Rename database", + JOptionPane.QUESTION_MESSAGE, + null, + null, + oldName); + if (newName != null) + { + try + { + uiModel.renameTab(oldName, newName); + tabbedPane.setTitleAt(tabIndex, newName); + updateTabOrderPreferences(); + } + catch (IOException e) + { + ExceptionHandler.handleException(e, "Could not rename database"); + } + } + } + + private void deleteTab(int tabIndex) + { + String selectedTab = tabbedPane.getTitleAt(tabIndex); + int answer = JOptionPane.showConfirmDialog(this, + "Are you sure you want to delete the " + selectedTab + + " database?\nIt will be removed completely from the databases folder.", + "Delete database", + JOptionPane.YES_NO_OPTION); + if (answer == JOptionPane.YES_OPTION) + { + try + { + uiModel.deleteTab(selectedTab); + tabbedPane.removeTabAt(tabIndex); + updateTabOrderPreferences(); + } + catch (IOException e) + { + ExceptionHandler.handleException(e, "Could not delete database"); + } + } + } + + private void createNewTab(String name) + { + //TODO: Check name here, do not add one with same name as existing, or null, or empty + if (name == null || name.isEmpty() || name.isBlank()) + { + //Do nothing + return; + } + List lowerCaseNames = + uiModel.getAvailableDatabases().stream().map(x -> x.toLowerCase()).collect(Collectors.toList()); + if (lowerCaseNames.contains(name.toLowerCase().trim())) + { + JOptionPane.showMessageDialog(this, + "A database with name " + name.trim() + " already exists", + "Duplicate db name", + JOptionPane.INFORMATION_MESSAGE); + return; + } + try + { + uiModel.addTab(name); + tabbedPane.insertTab(name, null, getNewContentPanel(null), null, tabbedPane.getTabCount() - 1); + tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 2); + updateTabOrderPreferences(); + } + catch (IOException e) + { + ExceptionHandler.handleException(e, "Could not create database"); + } + } + private void updateTabOrderPreferences() { List tabTitles = new ArrayList<>(); diff --git a/src/main/java/se/lantz/manager/BackupManager.java b/src/main/java/se/lantz/manager/BackupManager.java index d4fbaa4..3d5e39f 100644 --- a/src/main/java/se/lantz/manager/BackupManager.java +++ b/src/main/java/se/lantz/manager/BackupManager.java @@ -13,48 +13,50 @@ public class BackupManager { private static final Logger logger = LoggerFactory.getLogger(BackupManager.class); private MainViewModel uiModel; - + private String currentFolderName = ""; public BackupManager(MainViewModel uiModel) { this.uiModel = uiModel; } - + public String setupTargetFolderName() { DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"); LocalDateTime now = LocalDateTime.now(); //String for current date and time currentFolderName = dtf.format(now); + + currentFolderName = FileManager.getCurrentDbName() + "-" + currentFolderName; return currentFolderName; } - + public void backupDb() { FileManager.backupDb(currentFolderName); } - + public void backupCovers() { FileManager.backupCovers(currentFolderName); } - + public void backupScreens() { FileManager.backupScreens(currentFolderName); } - + public void backupGames() { FileManager.backupGames(currentFolderName); } - + public void backupExtraDisks() { FileManager.backupExtraDisks(currentFolderName); } - + public void backupSaves() { FileManager.backupSaves(currentFolderName); diff --git a/src/main/java/se/lantz/model/MainViewModel.java b/src/main/java/se/lantz/model/MainViewModel.java index bb2a19b..abf85da 100644 --- a/src/main/java/se/lantz/model/MainViewModel.java +++ b/src/main/java/se/lantz/model/MainViewModel.java @@ -43,7 +43,7 @@ import se.lantz.util.TextComponentSupport; public class MainViewModel extends AbstractModel { public static final String DB_TAB_ORDER = "dbTabOrder"; - + private static final Logger logger = LoggerFactory.getLogger(MainViewModel.class); DbConnector dbConnector; @@ -111,7 +111,7 @@ public class MainViewModel extends AbstractModel { ExceptionHandler.handleException(ex, "Could not read databases"); } - + if (availableDatabases.size() > 0) { //Read preferences for tab order @@ -120,23 +120,46 @@ public class MainViewModel extends AbstractModel if (tabOrder != null) { List preferencesOrder = Arrays.asList(tabOrder.split("\\s*,\\s*")); - - Collections.sort(availableDatabases, - Comparator.comparing(item -> preferencesOrder.indexOf(item))); + + Collections.sort(availableDatabases, Comparator.comparing(item -> preferencesOrder.indexOf(item))); } - + selectedDatabase = availableDatabases.get(0); FileManager.setCurrentDbFolder(selectedDatabase); DbConnector.setCurrentDbFolder(selectedDatabase); - } + } } - + public void updateDbTabPreferences(String prefValue) { Properties configuredProperties = FileManager.getConfiguredProperties(); configuredProperties.put(DB_TAB_ORDER, prefValue); } + public void renameTab(String oldName, String newName) throws IOException + { + Path source = Paths.get("./databases" + "/" + oldName); + Files.move(source, source.resolveSibling(newName)); + selectedDatabase = newName; + FileManager.setCurrentDbFolder(selectedDatabase); + DbConnector.setCurrentDbFolder(selectedDatabase); + } + + public void deleteTab(String dbName) throws IOException + { + availableDatabases.remove(dbName); + + Path source = Paths.get("./databases" + "/" + dbName); + + Files.walk(source).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); + } + + public void addTab(String name) throws IOException + { + FileManager.createNewDb(name); + availableDatabases.add(name); + } + public void setSavedStatesManager(SavedStatesManager savedStatesManager) { this.stateManager = savedStatesManager; @@ -1329,12 +1352,12 @@ public class MainViewModel extends AbstractModel { return this.currentGameDetails; } - + public List getAvailableDatabases() { return availableDatabases; } - + public void setCurrentDatabase(String database) { selectedDatabase = database; diff --git a/src/main/java/se/lantz/util/FileManager.java b/src/main/java/se/lantz/util/FileManager.java index 3facfaf..9e82315 100644 --- a/src/main/java/se/lantz/util/FileManager.java +++ b/src/main/java/se/lantz/util/FileManager.java @@ -70,11 +70,12 @@ public class FileManager public static BufferedImage infoSlotVic20Cover; private static String currentDbPath = "./"; + private static String currentDbName = ""; public static String GAMES = "./games/"; public static String SCREENS = "./screens/"; public static String COVERS = "./covers/"; public static String SAVES = "./saves/"; - private static String BACKUP = "./backup/"; + private static final String BACKUP = "./backup/"; public static String DISKS = "./extradisks/"; private static final Path TEMP_PATH = Paths.get("./temp"); @@ -131,18 +132,35 @@ public class FileManager { dbconnector = ref; } - + public static void setCurrentDbFolder(String dbFolder) { + currentDbName = dbFolder; currentDbPath = "./databases/" + dbFolder + "/"; GAMES = currentDbPath + "games/"; SCREENS = currentDbPath + "screens/"; COVERS = currentDbPath + "covers/"; SAVES = currentDbPath + "saves/"; - BACKUP = currentDbPath + "backup/"; DISKS = currentDbPath + "extradisks/"; } + public static void createNewDb(String name) throws IOException + { + setCurrentDbFolder(name); + Files.createDirectories(Paths.get(GAMES)); + Files.createDirectories(Paths.get(SCREENS)); + Files.createDirectories(Paths.get(COVERS)); + Files.createDirectories(Paths.get(SAVES)); + Files.createDirectories(Paths.get(DISKS)); + dbconnector.setCurrentDbFolder(name); + dbconnector.createDbIfMissing(name); + } + + public static String getCurrentDbName() + { + return currentDbName; + } + public static InputStream getMissingC64GameFile() throws URISyntaxException { return FileManager.class.getResourceAsStream("/se/lantz/MissingGame-C64.vsf.gz"); @@ -727,7 +745,7 @@ public class FileManager } else if (duplicateIndex > 9) { - newNameString = newNameString + "-" + duplicateIndex; + newNameString = newNameString + "-" + duplicateIndex; } logger.debug("Game title: \"{}\" ---- New fileName: \"{}\"", title, newNameString); @@ -970,9 +988,8 @@ public class FileManager } else { - gamePathString = SAVES + - SavedStatesManager.getGameFolderName(infoModel.getGamesFile(), infoModel.getTitle()) + "/" + - savedStatesModel.getState1File(); + gamePathString = SAVES + SavedStatesManager.getGameFolderName(infoModel.getGamesFile(), infoModel.getTitle()) + + "/" + savedStatesModel.getState1File(); } } break; @@ -985,9 +1002,8 @@ public class FileManager } else { - gamePathString = SAVES + - SavedStatesManager.getGameFolderName(infoModel.getGamesFile(), infoModel.getTitle()) + "/" + - savedStatesModel.getState2File(); + gamePathString = SAVES + SavedStatesManager.getGameFolderName(infoModel.getGamesFile(), infoModel.getTitle()) + + "/" + savedStatesModel.getState2File(); } break; case Save2: @@ -999,9 +1015,8 @@ public class FileManager } else { - gamePathString = SAVES + - SavedStatesManager.getGameFolderName(infoModel.getGamesFile(), infoModel.getTitle()) + "/" + - savedStatesModel.getState3File(); + gamePathString = SAVES + SavedStatesManager.getGameFolderName(infoModel.getGamesFile(), infoModel.getTitle()) + + "/" + savedStatesModel.getState3File(); } break; case Save3: @@ -1013,9 +1028,8 @@ public class FileManager } else { - gamePathString = SAVES + - SavedStatesManager.getGameFolderName(infoModel.getGamesFile(), infoModel.getTitle()) + "/" + - savedStatesModel.getState4File(); + gamePathString = SAVES + SavedStatesManager.getGameFolderName(infoModel.getGamesFile(), infoModel.getTitle()) + + "/" + savedStatesModel.getState4File(); } break; default: @@ -1381,24 +1395,30 @@ public class FileManager } return Boolean.parseBoolean(cropScreenshots); } - + public static boolean isShowCropDialogForCover() { if (showCropDialogForCover.isEmpty()) { - showCropDialogForCover = FileManager.getConfiguredProperties().getProperty(PreferencesModel.SHOW_CROP_DIALOG_FOR_COVER, "true"); + showCropDialogForCover = + FileManager.getConfiguredProperties().getProperty(PreferencesModel.SHOW_CROP_DIALOG_FOR_COVER, "true"); } return Boolean.parseBoolean(showCropDialogForCover); } + private static String getBackupFolderName(String targetFolderName) + { + return BACKUP + "/" + targetFolderName + "/"; + } + public static void backupDb(String targetFolderName) { - File outputFolder = new File(BACKUP + "/" + targetFolderName + "/"); + File outputFolder = new File(getBackupFolderName(targetFolderName)); try { - File dbFile = new File("./" + DbConnector.DB_FILE); + File dbFile = new File(DbConnector.DB_FILE); Files.createDirectories(outputFolder.toPath()); - Path targetFile = outputFolder.toPath().resolve(DbConnector.DB_FILE); + Path targetFile = outputFolder.toPath().resolve(DbConnector.DB_FILE_NAME); Files.copy(dbFile.toPath(), targetFile); } catch (IOException e) @@ -1409,7 +1429,7 @@ public class FileManager public static void backupScreens(String targetFolderName) { - File outputFolder = new File(BACKUP + "/" + targetFolderName + "/"); + File outputFolder = new File(getBackupFolderName(targetFolderName)); try { Files.createDirectories(outputFolder.toPath()); @@ -1424,7 +1444,7 @@ public class FileManager public static void backupCovers(String targetFolderName) { - File outputFolder = new File(BACKUP + "/" + targetFolderName + "/"); + File outputFolder = new File(getBackupFolderName(targetFolderName)); try { Files.createDirectories(outputFolder.toPath()); @@ -1439,7 +1459,7 @@ public class FileManager public static void backupGames(String targetFolderName) { - File outputFolder = new File(BACKUP + "/" + targetFolderName + "/"); + File outputFolder = new File(getBackupFolderName(targetFolderName)); try { Files.createDirectories(outputFolder.toPath()); @@ -1454,7 +1474,7 @@ public class FileManager public static void backupExtraDisks(String targetFolderName) { - File outputFolder = new File(BACKUP + "/" + targetFolderName + "/"); + File outputFolder = new File(getBackupFolderName(targetFolderName)); try { Files.createDirectories(outputFolder.toPath()); @@ -1469,7 +1489,7 @@ public class FileManager public static void backupSaves(String targetFolderName) { - File outputFolder = new File(BACKUP + "/" + targetFolderName + "/"); + File outputFolder = new File(getBackupFolderName(targetFolderName)); try { Files.createDirectories(outputFolder.toPath()); @@ -1583,10 +1603,10 @@ public class FileManager public static void restoreDb(String backupFolderName) { - File backupFolder = new File(BACKUP + "/" + backupFolderName + "/"); + File backupFolder = new File(getBackupFolderName(backupFolderName)); try { - Path backupFile = backupFolder.toPath().resolve(DbConnector.DB_FILE); + Path backupFile = backupFolder.toPath().resolve(DbConnector.DB_FILE_NAME); Path dbFile = new File("./" + DbConnector.DB_FILE).toPath(); Files.copy(backupFile, dbFile, StandardCopyOption.REPLACE_EXISTING); } @@ -1598,7 +1618,7 @@ public class FileManager public static void restoreCovers(String backupFolderName) { - File backupFolder = new File(BACKUP + "/" + backupFolderName + "/"); + File backupFolder = new File(getBackupFolderName(backupFolderName)); try { File coversDir = new File(COVERS); @@ -1613,7 +1633,7 @@ public class FileManager public static void restoreScreens(String backupFolderName) { - File backupFolder = new File(BACKUP + "/" + backupFolderName + "/"); + File backupFolder = new File(getBackupFolderName(backupFolderName)); try { File screensDir = new File(SCREENS); @@ -1628,7 +1648,7 @@ public class FileManager public static void restoreGames(String backupFolderName) { - File backupFolder = new File(BACKUP + "/" + backupFolderName + "/"); + File backupFolder = new File(getBackupFolderName(backupFolderName)); try { File gamesDir = new File(GAMES); @@ -1643,7 +1663,7 @@ public class FileManager public static void restoreExtraDisks(String backupFolderName) { - File backupFolder = new File(BACKUP + "/" + backupFolderName + "/"); + File backupFolder = new File(getBackupFolderName(backupFolderName)); try { File extradisksDir = new File(DISKS); @@ -1662,7 +1682,7 @@ public class FileManager public static void restoreSaves(String backupFolderName) { - File backupFolder = new File(BACKUP + "/" + backupFolderName + "/"); + File backupFolder = new File(getBackupFolderName(backupFolderName)); try { File savesDir = new File(SAVES);