diff --git a/.gitignore b/.gitignore index b83d222..7664c47 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target/ +./src/main/resources/res/config.properties diff --git a/.vs/AutoBackupProgram/FileContentIndex/4576e67e-939f-4ebe-b107-264fcfcd0806.vsidx b/.vs/BackupManager/FileContentIndex/4576e67e-939f-4ebe-b107-264fcfcd0806.vsidx similarity index 100% rename from .vs/AutoBackupProgram/FileContentIndex/4576e67e-939f-4ebe-b107-264fcfcd0806.vsidx rename to .vs/BackupManager/FileContentIndex/4576e67e-939f-4ebe-b107-264fcfcd0806.vsidx diff --git a/.vs/AutoBackupProgram/v17/.wsuo b/.vs/BackupManager/v17/.wsuo similarity index 100% rename from .vs/AutoBackupProgram/v17/.wsuo rename to .vs/BackupManager/v17/.wsuo diff --git a/.vs/AutoBackupProgram/v17/DocumentLayout.json b/.vs/BackupManager/v17/DocumentLayout.json similarity index 84% rename from .vs/AutoBackupProgram/v17/DocumentLayout.json rename to .vs/BackupManager/v17/DocumentLayout.json index 477eeb8..5621a32 100644 --- a/.vs/AutoBackupProgram/v17/DocumentLayout.json +++ b/.vs/BackupManager/v17/DocumentLayout.json @@ -1,6 +1,6 @@ { "Version": 1, - "WorkspaceRootPath": "D:\\Documents\\NetBeansProjects\\AutoBackupProgram\\", + "WorkspaceRootPath": "D:\\Documents\\NetBeansProjects\\BackupManager\\", "Documents": [], "DocumentGroupContainers": [ { diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite index 8fa7b15..5698f20 100644 Binary files a/.vs/slnx.sqlite and b/.vs/slnx.sqlite differ diff --git a/.vscode/launch.json b/.vscode/launch.json index 6df9e54..e26871b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,14 +14,14 @@ "type": "java", "name": "TranslationLoaderEnum", "request": "launch", - "mainClass": "com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum", + "mainClass": "backupmanager.Enums.TranslationLoaderEnum", "projectName": "BackupManager" }, { "type": "java", "name": "MainApp", "request": "launch", - "mainClass": "com.mycompany.autobackupprogram.MainApp", + "mainClass": "backupmanager.MainApp", "projectName": "BackupManager" } ] diff --git a/execute_background_service.bat b/execute_background_service.bat index 7b15388..eefc30a 100644 --- a/execute_background_service.bat +++ b/execute_background_service.bat @@ -1 +1 @@ -java -jar BackupManager-1.0-SNAPSHOT-jar-with-dependencies.jar --background \ No newline at end of file +java -jar ./target/BackupManager-1.0-SNAPSHOT-jar-with-dependencies.jar --background \ No newline at end of file diff --git a/nbactions.xml b/nbactions.xml index 6836511..3fd4ec4 100644 --- a/nbactions.xml +++ b/nbactions.xml @@ -13,7 +13,7 @@ ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} - com.mycompany.autobackupprogram.MainApp + backupmanager.MainApp java diff --git a/pom.xml b/pom.xml index ec025ab..bcb3098 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@ 4.0.0 - com.mycompany + backupmanager BackupManager 1.0-SNAPSHOT jar @@ -11,17 +11,21 @@ - - com.googlecode.json-simple - json-simple - 1.1.1 - - com.google.code.gson gson 2.8.9 + + com.fasterxml.jackson.core + jackson-databind + 2.15.2 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.15.2 + @@ -58,11 +62,55 @@ flatlaf 3.4.1 + + com.formdev + flatlaf-extras + 3.5.4 + org.netbeans.external AbsoluteLayout RELEASE220 + + + + com.itextpdf + kernel + 7.2.5 + jar + + + com.itextpdf + layout + 7.2.5 + jar + + + + + + org.slf4j + slf4j-api + 2.0.9 + + + + ch.qos.logback + logback-classic + 1.4.11 + + + + com.sun.mail + jakarta.mail + 2.0.1 + + + jakarta.activation + jakarta.activation-api + 2.1.0 + @@ -73,7 +121,7 @@ - com.mycompany.autobackupprogram.MainApp + backupmanager.MainApp diff --git a/src/main/java/backupmanager/BackupOperations.java b/src/main/java/backupmanager/BackupOperations.java new file mode 100644 index 0000000..29e1334 --- /dev/null +++ b/src/main/java/backupmanager/BackupOperations.java @@ -0,0 +1,395 @@ +package backupmanager; + +import java.awt.TrayIcon; +import java.io.File; +import java.io.FilenameFilter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.filechooser.FileSystemView; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.Entities.Backup; +import backupmanager.Entities.RunningBackups; +import backupmanager.Entities.TimeInterval; +import backupmanager.Entities.ZippingContext; +import backupmanager.Enums.BackupStatusEnum; +import backupmanager.Enums.ErrorTypes; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; +import backupmanager.GUI.BackupManagerGUI; +import static backupmanager.GUI.BackupManagerGUI.dateForfolderNameFormatter; +import static backupmanager.GUI.BackupManagerGUI.formatter; +import backupmanager.Managers.BackupManager; +import backupmanager.Managers.ExceptionManager; +import backupmanager.Services.ZippingThread; +import backupmanager.Table.TableDataManager; + +public class BackupOperations { + private static final Logger logger = LoggerFactory.getLogger(BackupOperations.class); + public static void SingleBackup(ZippingContext context) { + if (context.backup == null) throw new IllegalArgumentException("Backup cannot be null!"); + + logger.info("Event --> manual backup started"); + + try { + String temp = "\\"; + String path1 = context.backup.getInitialPath(); + String path2 = context.backup.getDestinationPath(); + + if(!CheckInputCorrect(context.backup.getBackupName(), path1, path2, context.trayIcon)) + return; + + if (context.progressBar != null) + context.progressBar.setVisible(true); + + LocalDateTime dateNow = LocalDateTime.now(); + String date = dateNow.format(dateForfolderNameFormatter); + String name1 = path1.substring(path1.length()-1, path1.length()-1); + + for(int i = path1.length() - 1; i >= 0; i--) { + if(path1.charAt(i) != temp.charAt(0)) name1 = path1.charAt(i) + name1; + else break; + } + + name1 = removeExtension(name1); + path2 = path2 + "\\" + name1 + " (Backup " + date + ")"; + + logger.info("date backup: " + date); + + ZippingThread.zipDirectory(path1, path2 + ".zip", context); + } catch (Exception ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + reEnableButtonsAndTable(context); + } + } + + public static String removeExtension(String fileName) { + int dotIndex = fileName.lastIndexOf('.'); + if (dotIndex > 0) { + return fileName.substring(0, dotIndex); + } + return fileName; + } + + private static void updateAfterBackup(String path1, String path2, ZippingContext context) { + if (context.backup == null) throw new IllegalArgumentException("Backup cannot be null!"); + if (path1 == null) throw new IllegalArgumentException("Initial path cannot be null!"); + if (path2 == null) throw new IllegalArgumentException("Destination path cannot be null!"); + + logger.info("Backup completed!"); + + reEnableButtonsAndTable(context); + + // next day backup update + if (context.backup.isAutoBackup() == true) { + TimeInterval time = context.backup.getTimeIntervalBackup(); + LocalDateTime nextDateBackup = BackupManager.getNexDateBackup(time); + context.backup.setNextDateBackup(nextDateBackup); + logger.info("Next date backup setted to: " + nextDateBackup); + } + context.backup.setLastBackup(LocalDateTime.now()); + context.backup.setBackupCount(context.backup.getBackupCount()+1); + + try { + List backups = BackupManager.getBackupList(); + + for (Backup b : backups) { + if (b.getBackupName().equals(context.backup.getBackupName())) { + b.UpdateBackup(context.backup); + break; + } + } + + BackupManager.updateBackup(context.backup); + + logger.info("Backup :\"" + context.backup.getBackupName() + "\" updated after the backup"); + + if (context.trayIcon != null) { + context.trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + context.backup.getBackupName() + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.SUCCESS_MESSAGE) + "\n" + TranslationCategory.GENERAL.getTranslation(TranslationKey.FROM) + ": " + path1 + "\n" + TranslationCategory.GENERAL.getTranslation(TranslationKey.TO) + ": " + path2, TrayIcon.MessageType.INFO); + } + } catch (IllegalArgumentException ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + } + + public static String pathSearchWithFileChooser(boolean allowFiles) { + logger.info("Event --> File chooser"); + + JFileChooser jfc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory()); + + if (allowFiles) + jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); + else + jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + int returnValue = jfc.showSaveDialog(null); + if (returnValue == JFileChooser.APPROVE_OPTION) { + File selectedFile = jfc.getSelectedFile(); + + if (selectedFile.isDirectory()) { + logger.info("You selected the directory: " + selectedFile); + } else if (selectedFile.isFile()) { + logger.info("You selected the file: " + selectedFile); + } + + return selectedFile.toString(); + } + + return null; + } + + public static boolean CheckInputCorrect(String backupName, String path1, String path2, TrayIcon trayIcon) { + //check if inputs are null + if(path1.length() == 0 || path2.length() == 0) { + setError(ErrorTypes.InputMissing, trayIcon, backupName); + return false; + } + + if (!Files.exists(Path.of(path1)) || !Files.exists(Path.of(path2))) { + setError(ErrorTypes.InputError, trayIcon, backupName); + return false; + } + + if (path1.equals(path2)) { + setError(ErrorTypes.SamePaths, trayIcon, backupName); + return false; + } + + return true; + } + + public static void interruptBackupProcess(ZippingContext context) { + logger.info("Event --> interrupt backup process"); + + ZippingThread.stopExecutorService(1); + if (ZippingThread.isInterrupted()) + reEnableButtonsAndTable(context); + + if (context.progressBar != null) + context.progressBar.dispose(); + } + + public static void reEnableButtonsAndTable(ZippingContext context) { + if (context.interruptBackupPopupItem != null) context.interruptBackupPopupItem.setEnabled(false); + if (context.deleteBackupPopupItem != null) context.deleteBackupPopupItem.setEnabled(true); + + // edit the backup running state + RunningBackups.updateBackupStatusAfterCompletition(context.backup.getBackupName()); + + if (BackupManagerGUI.backupTable != null) + TableDataManager.removeProgressInTheTableAndRestoreAsDefault(context.backup, formatter); + } + + public static void UpdateProgressPercentage(int value, String path1, String path2, ZippingContext context, String fileProcessed, int filesCopiedSoFar, int totalFilesCount) { + if (value == 0 || value == 25 || value == 50 || value == 75 || value == 100) + logger.info("Zipping progress: " + value + "%"); + + if (context.progressBar != null) { + context.progressBar.updateProgressBar(value, fileProcessed, filesCopiedSoFar, totalFilesCount); + } + + if (BackupManagerGUI.backupTable != null) { + TableDataManager.updateProgressBarPercentage(context.backup, value, formatter); + } + + // updating running backups file .json + RunningBackups running = RunningBackups.readBackupFromJSON(context.backup.getBackupName()); + if (running != null) { + running.progress = value; + RunningBackups.updateBackupToJSON(running); + }else { + RunningBackups.updateBackupToJSON(new RunningBackups(context.backup.getBackupName(), path2, value, BackupStatusEnum.Progress)); + } + + // if (value == 100) { + // RunningBackups.updateBackupToJSON(new RunningBackups(context.backup.getBackupName(), path2, value, BackupStatusEnum.Finished)); + // } else { + // RunningBackups.updateBackupToJSON(new RunningBackups(context.backup.getBackupName(), path2, value, BackupStatusEnum.Progress)); + // } + + if (value == 100) { + updateAfterBackup(path1, path2, context); + deleteOldBackupsIfNecessary(context.backup.getMaxBackupsToKeep(), path2); + } + } + + private static void deleteOldBackupsIfNecessary(int maxBackupsToKeep, String destinationPath) { + logger.info("Deleting old backups if necessary"); + + File folder = new File(destinationPath).getParentFile(); + String fileBackuppedToSearch = new File(destinationPath).getName(); + + // extract the file name (before the parentesis) + String baseName = fileBackuppedToSearch.substring(0, fileBackuppedToSearch.indexOf(" (Backup")); + + if (folder != null && folder.isDirectory()) { + // get current count + FilenameFilter filter = (dir, name) -> name.matches(baseName + " \\(Backup \\d{2}-\\d{2}-\\d{4} \\d{2}\\.\\d{2}\\.\\d{2}\\)\\.zip"); + File[] matchingFiles = folder.listFiles(filter); // getting files for that filter + + if (matchingFiles == null) { + logger.warn("Error during deleting old backups: none matching files"); + return; + } + + // check if the max is passed, and if it is, remove the oldest + if (matchingFiles.length > maxBackupsToKeep) { + logger.info("Found " + matchingFiles.length + " matching files, exceeding max allowed: " + maxBackupsToKeep); + + Arrays.sort(matchingFiles, (f1, f2) -> { + String datePattern = "\\(Backup (\\d{2}-\\d{2}-\\d{4} \\d{2}\\.\\d{2}\\.\\d{2})\\)\\.zip"; // regex aggiornata + + try { + // extracting dates from file names + String date1 = extractDateFromFileName(f1.getName(), datePattern); + String date2 = extractDateFromFileName(f2.getName(), datePattern); + + LocalDateTime dateTime1 = LocalDateTime.parse(date1, BackupManagerGUI.dateForfolderNameFormatter); + LocalDateTime dateTime2 = LocalDateTime.parse(date2, BackupManagerGUI.dateForfolderNameFormatter); + + return dateTime1.compareTo(dateTime2); + } catch (Exception e) { + logger.error("Error parsing dates: " + e.getMessage(), e); + return 0; + } + }); + + // delete older files + for (int i = 0; i < matchingFiles.length - maxBackupsToKeep; i++) { + File fileToDelete = matchingFiles[i]; + if (fileToDelete.delete()) { + logger.info("Deleted old backup: " + fileToDelete.getName()); + } else { + logger.warn("Failed to delete old backup: " + fileToDelete.getName()); + } + } + } + } else { + logger.warn("Destination path is not a directory: " + destinationPath); + } + } + + public static boolean deletePartialBackup(String filePath) { + logger.info("Attempting to delete partial backup: " + filePath); + + ZippingThread.stopExecutorService(1); + + if (filePath == null || filePath.isEmpty()) { + logger.warn("The file path is null or empty."); + return false; + } + + File file = new File(filePath); + + // Check if the file exists and is a valid file + if (file.exists()) { + if (file.isFile()) { + try { + if (file.delete()) { + logger.info("Partial backup deleted successfully: " + file.getName()); + return true; + } else { + logger.warn("Failed to delete partial backup (delete failed): " + file.getName()); + } + } catch (SecurityException e) { + logger.error("Security exception occurred while attempting to delete: " + file.getName(), e); + } catch (Exception e) { + logger.error("Unexpected error while attempting to delete: " + file.getName(), e); + } + } else { + logger.warn("The path points to a directory, not a file: " + filePath); + } + } else { + logger.warn("The file does not exist: " + filePath); + } + + return false; + } + + private static String extractDateFromFileName(String fileName, String pattern) throws Exception { + Pattern regex = Pattern.compile(pattern); + Matcher matcher = regex.matcher(fileName); + + if (matcher.find()) { + return matcher.group(1); + } + + throw new Exception("No date found in file name: " + fileName); + } + + public static void setError(ErrorTypes error, TrayIcon trayIcon, String backupName) { + switch (error) { + case InputMissing: + logger.warn("Input Missing!"); + if (trayIcon != null) { + trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_INPUT_MISSING), TrayIcon.MessageType.ERROR); + } else { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_INPUT_MISSING_GENERIC), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + break; + case InputError: + logger.warn("Input Error! One or both paths do not exist."); + if (trayIcon != null) { + trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_FILES_NOT_EXISTING), TrayIcon.MessageType.ERROR); + } else { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_PATH_NOT_EXISTING), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + break; + case SamePaths: + logger.warn("The initial path and destination path cannot be the same. Please choose different paths"); + if (trayIcon != null) { + trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_SAME_PATHS), TrayIcon.MessageType.ERROR); + } else { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_SAME_PATHS_GENERIC), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + break; + case ErrorCountingFiles: + logger.warn("Error during counting files in directory"); + if (trayIcon != null) { + trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_COUNTING_FILES), TrayIcon.MessageType.ERROR); + } else { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_COUNTING_FILES), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + break; + case ZippingGenericError: + logger.warn("Error during zipping directory"); + if (trayIcon != null) { + trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_ZIPPING_GENERIC), TrayIcon.MessageType.ERROR); + } else { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_ZIPPING_GENERIC), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + break; + case ZippingIOError: + logger.warn("I/O error occurred while zipping directory"); + if (trayIcon != null) { + trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_ZIPPING_IO), TrayIcon.MessageType.ERROR); + } else { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_ZIPPING_IO), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + break; + case ZippingSecurityError: + logger.warn("Security exception while zipping directory"); + if (trayIcon != null) { + trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_ZIPPING_SECURITY), TrayIcon.MessageType.ERROR); + } else { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_ZIPPING_SECURITY), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + break; + default: + throw new IllegalArgumentException("Error type not recognized: " + error); + } + } + +} diff --git a/src/main/java/backupmanager/Dialogs/BackupEntryDialog.form b/src/main/java/backupmanager/Dialogs/BackupEntryDialog.form new file mode 100644 index 0000000..33ea360 --- /dev/null +++ b/src/main/java/backupmanager/Dialogs/BackupEntryDialog.form @@ -0,0 +1,341 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/backupmanager/Dialogs/BackupEntryDialog.java b/src/main/java/backupmanager/Dialogs/BackupEntryDialog.java new file mode 100644 index 0000000..8d80627 --- /dev/null +++ b/src/main/java/backupmanager/Dialogs/BackupEntryDialog.java @@ -0,0 +1,694 @@ +package backupmanager.Dialogs; + +import static backupmanager.GUI.BackupManagerGUI.backupTable; + +import java.time.LocalDateTime; +import java.util.List; + +import javax.swing.JOptionPane; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.formdev.flatlaf.FlatClientProperties; + +import backupmanager.BackupOperations; +import backupmanager.Entities.Backup; +import backupmanager.Entities.RunningBackups; +import backupmanager.Entities.TimeInterval; +import backupmanager.Entities.ZippingContext; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; +import backupmanager.GUI.BackupManagerGUI; +import backupmanager.GUI.BackupProgressGUI; +import backupmanager.Json.JSONConfigReader; +import backupmanager.Managers.BackupManager; +import backupmanager.Services.ZippingThread; +import backupmanager.Table.BackupTable; + +public class BackupEntryDialog extends javax.swing.JDialog { + + private static final Logger logger = LoggerFactory.getLogger(BackupEntryDialog.class); + + private static final JSONConfigReader configReader = new JSONConfigReader(ConfigKey.CONFIG_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); + private String backupOnText; + private String backupOffText; + private Backup currentBackup; + private boolean closeOk; + private boolean create; + private TimeInterval timeInterval; + + public BackupEntryDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + + initializeDialog(); + setAutoBackupOff(); + this.create = true; + okButton.setText(TranslationCategory.GENERAL.getTranslation(TranslationKey.CREATE_BUTTON)); + } + + public BackupEntryDialog(java.awt.Frame parent, boolean modal, Backup currentBackup) { + super(parent, modal); + + this.currentBackup = currentBackup; + + initializeDialog(); + updateCurrentFiedsByBackup(currentBackup); + backupName.setText(currentBackup.getBackupName()); + backupName.setEditable(false); + backupName.setFocusable(false); + this.create = false; + this.timeInterval = currentBackup.getTimeIntervalBackup(); + okButton.setText(TranslationCategory.GENERAL.getTranslation(TranslationKey.SAVE_BUTTON)); + } + + private void initializeDialog() { + initComponents(); + + setCurrentBackupMaxBackupsToKeep(configReader.getMaxCountForSameBackup()); + this.closeOk = false; + + setSvgImages(); + setTranslations(); + } + + private void SetLastBackupLabel(LocalDateTime date) { + if (date != null) { + String dateStr = date.format(BackupManager.formatter); + dateStr = TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.LAST_BACKUP) + ": " + dateStr; + lastBackupLabel.setText(dateStr); + } + else lastBackupLabel.setText(""); + } + + private void updateCurrentFiedsByBackup(Backup backup) { + SetStartPathField(backup.getInitialPath()); + SetDestinationPathField(backup.getDestinationPath()); + SetLastBackupLabel(backup.getLastUpdateDate()); + setAutoBackupPreference(backup.isAutoBackup()); + setCurrentBackupNotes(backup.getNotes()); + setCurrentBackupMaxBackupsToKeep(backup.getMaxBackupsToKeep()); + + if (backup.getTimeIntervalBackup() != null) { + setAutoBackupOn(backup); + } else { + setAutoBackupOff(); + } + } + + private void openBackupActivationMessage(TimeInterval newtimeInterval) { + if (newtimeInterval == null) + throw new IllegalArgumentException("Time interval cannot be null"); + + // update current timeInterval with the new one + timeInterval = newtimeInterval; + + String startPath = GetStartPathField(); + String destinationPath = GetDestinationPathField(); + BackupManager.showMessageActivationAutoBackup(timeInterval, startPath, destinationPath); + } + + public void setAutoBackupPreference(boolean option) { + currentBackup.setAutoBackup(option); + + if (option) { + setAutoBackupOn(currentBackup); + } else { + disableAutoBackup(currentBackup); + } + } + + public Backup getBackup() { + if (!closeOk){ + return null; + } + + String initialPath = startPathField.getText(); + String destinationPath = destinationPathField.getText(); + String notes = backupNoteTextArea.getText(); + boolean autoBackup = toggleAutoBackup.isSelected(); + int maxBackupsToKeep = (int) maxBackupCountSpinner.getValue(); + + LocalDateTime nextDateBackup = null; + if (timeInterval != null){ + nextDateBackup = BackupManager.getNexDateBackup(timeInterval); + } + + if (!autoBackup) { + timeInterval = null; + nextDateBackup = null; + } + + if (currentBackup == null) { + String name = backupName.getText(); + LocalDateTime lastBackup = null; + LocalDateTime creationDate = LocalDateTime.now(); + LocalDateTime lastUpdateDate = creationDate; + int backupCount = 0; + return new Backup(name, initialPath, destinationPath, lastBackup, autoBackup, nextDateBackup, timeInterval, notes, creationDate, lastUpdateDate, backupCount, maxBackupsToKeep); + } else { + String name = currentBackup.getBackupName(); + LocalDateTime lastBackup = currentBackup.getLastBackup(); + LocalDateTime creationDate = currentBackup.getCreationDate(); + LocalDateTime lastUpdateDate = LocalDateTime.now(); + int backupCount = currentBackup.getBackupCount(); + return new Backup(name, initialPath, destinationPath, lastBackup, autoBackup, nextDateBackup, timeInterval, notes, creationDate, lastUpdateDate, backupCount, maxBackupsToKeep); + } + } + + public String GetStartPathField() { + return startPathField.getText(); + } + public String GetDestinationPathField() { + return destinationPathField.getText(); + } + public String GetNotesTextArea() { + return backupNoteTextArea.getText(); + } + public boolean GetAutomaticBackupPreference() { + return toggleAutoBackup.isSelected(); + } + public int GetMaxBackupsToKeep() { + return (int) maxBackupCountSpinner.getValue(); + } + public void SetStartPathField(String text) { + startPathField.setText(text); + } + public void SetDestinationPathField(String text) { + destinationPathField.setText(text); + } + + private void setCurrentBackupNotes(String notes) { + backupNoteTextArea.setText(notes); + } + + public void setCurrentBackupMaxBackupsToKeep(int maxBackupsCount) { + maxBackupCountSpinner.setValue(maxBackupsCount); + } + + public void SingleBackup(String path1, String path2, BackupTable backupTable) { + logger.info("Event --> single backup"); + + currentBackup.setInitialPath(path2); + + String temp = "\\"; + + //------------------------------INPUT CONTROL ERRORS------------------------------ + if (!BackupOperations.CheckInputCorrect(currentBackup.getBackupName(), path1, path2, null)) return; + + //------------------------------TO GET THE CURRENT DATE------------------------------ + LocalDateTime dateNow = LocalDateTime.now(); + + //------------------------------SET ALL THE VARIABLES------------------------------ + String name1; // folder name/initial file + String date = dateNow.format(BackupManager.dateForfolderNameFormatter); + + //------------------------------SET ALL THE STRINGS------------------------------ + name1 = path1.substring(path1.length()-1, path1.length()-1); + + for(int i=path1.length()-1; i>=0; i--) { + if(path1.charAt(i) != temp.charAt(0)) name1 = path1.charAt(i) + name1; + else break; + } + + name1 = BackupOperations.removeExtension(name1); + path2 = path2 + "\\" + name1 + " (Backup " + date + ")"; + + //------------------------------COPY THE FILE OR DIRECTORY------------------------------ + logger.info("date backup: " + date); + + BackupManagerGUI.progressBar = new BackupProgressGUI(path1, path2); + BackupManagerGUI.progressBar.setVisible(true); + + ZippingContext context = new ZippingContext(currentBackup, null, backupTable, BackupManagerGUI.progressBar, null, null); + ZippingThread.zipDirectory(path1, path2 + ".zip", context); + + //if current_file_opened is null it means they are not in a backup but it is a backup with no associated json file + if (currentBackup.getBackupName() != null && !currentBackup.getBackupName().isEmpty()) { + currentBackup.setInitialPath(GetStartPathField()); + currentBackup.setDestinationPath(GetDestinationPathField()); + currentBackup.setLastBackup(LocalDateTime.now()); + } + } + + private boolean toggleAutomaticBackup() { + Backup backup = BackupManager.toggleAutomaticBackup(currentBackup); + + if (backup != null) { + currentBackup = backup; + } + + if (backup.getTimeIntervalBackup() != null) { + timeInterval = backup.getTimeIntervalBackup(); + currentBackup.setNextDateBackup(BackupManager.getNexDateBackup(timeInterval)); + btnTimePicker.setToolTipText(timeInterval.toString()); + btnTimePicker.setEnabled(true); + setAutoBackupOn(currentBackup); + return true; + } + + setAutoBackupOff(); + return false; + } + + + private void setAutoBackupOn(Backup backup) { + toggleAutoBackup.setSelected(true); + toggleAutoBackup.setText(backupOnText); + + if (backup != null) + enableTimePickerButton(backup); + else + disableTimePickerButton(); + } + + private void setAutoBackupOff() { + toggleAutoBackup.setSelected(false); + toggleAutoBackup.setText(backupOffText); + disableTimePickerButton(); + } + + private void enableTimePickerButton(Backup backup) { + if (backup.getTimeIntervalBackup() != null) { + btnTimePicker.setToolTipText(backup.getTimeIntervalBackup().toString()); + btnTimePicker.setEnabled(true); + } else { + btnTimePicker.setEnabled(true); + } + } + + private void disableTimePickerButton() { + btnTimePicker.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.TIME_PICKER_TOOLTIP)); + btnTimePicker.setEnabled(false); + } + + private void disableAutoBackup(Backup backup) { + logger.info("Event --> auto backup disabled"); + + backup.setTimeIntervalBackup(null); + backup.setNextDateBackup(null); + backup.setAutoBackup(false); + backup.setLastUpdateDate(LocalDateTime.now()); + } + + private void maxBackupCountSpinnerChange() { + Integer backupCount = (Integer) maxBackupCountSpinner.getValue(); + + if (backupCount == null || backupCount < 1) { + maxBackupCountSpinner.setValue(1); + } else if (backupCount > 10) { + maxBackupCountSpinner.setValue(10); + } + } + + private void mouseWeel(java.awt.event.MouseWheelEvent evt) { + javax.swing.JSpinner spinner = (javax.swing.JSpinner) evt.getSource(); + int rotation = evt.getWheelRotation(); + + if (rotation < 0) { + spinner.setValue((Integer) spinner.getValue() + 1); + } else { + spinner.setValue((Integer) spinner.getValue() - 1); + } + } + + private void setSvgImages() { + btnPathSearch1.setSvgImage("res/img/folder.svg", 30, 30); + btnPathSearch2.setSvgImage("res/img/folder.svg", 30, 30); + btnTimePicker.setSvgImage("res/img/timer.svg", 30, 30); + } + + private void setTranslations() { + backupOnText = TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.AUTO_BACKUP_BUTTON_ON); + backupOffText = TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.AUTO_BACKUP_BUTTON_OFF); + btnPathSearch1.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.INITIAL_FILE_CHOOSER_TOOLTIP)); + btnPathSearch2.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.DESTINATION_FILE_CHOOSER_TOOLTIP)); + startPathField.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.INITIAL_PATH_TOOLTIP)); + destinationPathField.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.DESTINATION_PATH_TOOLTIP)); + backupNoteTextArea.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.NOTES_TOOLTIP)); + SingleBackup.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.SINGLE_BACKUP_BUTTON)); + SingleBackup.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.SINGLE_BACKUP_TOOLTIP)); + toggleAutoBackup.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.AUTO_BACKUP_BUTTON_OFF)); + toggleAutoBackup.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.AUTO_BACKUP_TOOLTIP)); + jLabel2.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.NOTES) + ":"); + lastBackupLabel.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.LAST_BACKUP) + ": "); + setTitle(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.PAGE_TITLE)); + startPathField.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.INITIAL_PATH_PLACEHOLDER)); + destinationPathField.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.DESTINATION_PATH_PLACEHOLDER)); + btnTimePicker.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.TIME_PICKER_TOOLTIP)); + maxBackupCountSpinner.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.MAX_BACKUPS_TO_KEEP_TOOLTIP) + "\n" + TranslationCategory.TIME_PICKER_DIALOG.getTranslation(TranslationKey.SPINNER_TOOLTIP)); + jLabel4.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.MAX_BACKUPS_TO_KEEP)); + closeButton.setText(TranslationCategory.GENERAL.getTranslation(TranslationKey.CLOSE_BUTTON)); + jLabel1.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.BACKUP_NAME)); + backupName.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.BACKUP_NAME_TOOLTIP)); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + startPathField = new javax.swing.JTextField(); + btnPathSearch1 = new backupmanager.svg.SVGButton(); + btnPathSearch2 = new backupmanager.svg.SVGButton(); + destinationPathField = new javax.swing.JTextField(); + jLabel2 = new javax.swing.JLabel(); + jScrollPane2 = new javax.swing.JScrollPane(); + backupNoteTextArea = new javax.swing.JTextArea(); + lastBackupLabel = new javax.swing.JLabel(); + SingleBackup = new javax.swing.JButton(); + toggleAutoBackup = new javax.swing.JToggleButton(); + btnTimePicker = new backupmanager.svg.SVGButton(); + maxBackupCountSpinner = new javax.swing.JSpinner(); + jLabel4 = new javax.swing.JLabel(); + closeButton = new javax.swing.JButton(); + okButton = new javax.swing.JButton(); + backupName = new javax.swing.JTextField(); + jLabel1 = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setResizable(false); + + startPathField.setToolTipText("(Required) Initial path"); + startPathField.setActionCommand("null"); + startPathField.setAlignmentX(0.0F); + startPathField.setAlignmentY(0.0F); + startPathField.setAutoscrolls(false); + startPathField.setMaximumSize(new java.awt.Dimension(465, 26)); + startPathField.setMinimumSize(new java.awt.Dimension(465, 26)); + startPathField.setPreferredSize(new java.awt.Dimension(465, 26)); + + btnPathSearch1.setToolTipText(""); + btnPathSearch1.setMaximumSize(new java.awt.Dimension(35, 35)); + btnPathSearch1.setMinimumSize(new java.awt.Dimension(35, 35)); + btnPathSearch1.setPreferredSize(new java.awt.Dimension(35, 35)); + btnPathSearch1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnPathSearch1ActionPerformed(evt); + } + }); + + btnPathSearch2.setToolTipText("Open file explorer"); + btnPathSearch2.setMaximumSize(new java.awt.Dimension(35, 35)); + btnPathSearch2.setMinimumSize(new java.awt.Dimension(35, 35)); + btnPathSearch2.setPreferredSize(new java.awt.Dimension(35, 35)); + btnPathSearch2.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnPathSearch2ActionPerformed(evt); + } + }); + + destinationPathField.setToolTipText("(Required) Destination path"); + destinationPathField.setActionCommand(""); + destinationPathField.setAlignmentX(0.0F); + destinationPathField.setAlignmentY(0.0F); + destinationPathField.setMaximumSize(new java.awt.Dimension(465, 26)); + destinationPathField.setMinimumSize(new java.awt.Dimension(465, 26)); + destinationPathField.setPreferredSize(new java.awt.Dimension(465, 26)); + + jLabel2.setText("notes:"); + + backupNoteTextArea.setColumns(20); + backupNoteTextArea.setRows(5); + backupNoteTextArea.setToolTipText("(Optional) Backup description"); + backupNoteTextArea.setMaximumSize(new java.awt.Dimension(232, 84)); + backupNoteTextArea.setMinimumSize(new java.awt.Dimension(232, 84)); + jScrollPane2.setViewportView(backupNoteTextArea); + + lastBackupLabel.setText("last backup: "); + + SingleBackup.setBackground(new java.awt.Color(51, 153, 255)); + SingleBackup.setForeground(new java.awt.Color(255, 255, 255)); + SingleBackup.setText("Single Backup"); + SingleBackup.setToolTipText("Perform the backup"); + SingleBackup.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + SingleBackup.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + SingleBackupActionPerformed(evt); + } + }); + + toggleAutoBackup.setText("Auto Backup"); + toggleAutoBackup.setToolTipText("Enable/Disable automatic backup"); + toggleAutoBackup.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); + toggleAutoBackup.setPreferredSize(new java.awt.Dimension(108, 27)); + toggleAutoBackup.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + toggleAutoBackupActionPerformed(evt); + } + }); + + btnTimePicker.setToolTipText("Time picker"); + btnTimePicker.setMaximumSize(new java.awt.Dimension(36, 36)); + btnTimePicker.setMinimumSize(new java.awt.Dimension(36, 36)); + btnTimePicker.setPreferredSize(new java.awt.Dimension(36, 36)); + btnTimePicker.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnTimePickerActionPerformed(evt); + } + }); + + maxBackupCountSpinner.setToolTipText("Maximum number of backups before removing the oldest."); + maxBackupCountSpinner.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + maxBackupCountSpinnerStateChanged(evt); + } + }); + maxBackupCountSpinner.addMouseWheelListener(new java.awt.event.MouseWheelListener() { + public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) { + maxBackupCountSpinnerMouseWheelMoved(evt); + } + }); + + jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + jLabel4.setText("Keep only last"); + + closeButton.setText("Close"); + closeButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + closeButtonActionPerformed(evt); + } + }); + + okButton.setText("Ok"); + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + backupName.setToolTipText("(Required) Backup name"); + backupName.setActionCommand("null"); + backupName.setAlignmentX(0.0F); + backupName.setAlignmentY(0.0F); + backupName.setAutoscrolls(false); + backupName.setMaximumSize(new java.awt.Dimension(465, 26)); + backupName.setMinimumSize(new java.awt.Dimension(465, 26)); + backupName.setPreferredSize(new java.awt.Dimension(465, 26)); + + jLabel1.setText("Backup name:"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(35, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(okButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(closeButton) + .addContainerGap()) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 469, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(destinationPathField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnPathSearch2, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 462, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lastBackupLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 461, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addGap(6, 6, 6) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(131, 131, 131) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(SingleBackup, javax.swing.GroupLayout.PREFERRED_SIZE, 188, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(toggleAutoBackup, javax.swing.GroupLayout.PREFERRED_SIZE, 188, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnTimePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addGroup(layout.createSequentialGroup() + .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 244, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(maxBackupCountSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(startPathField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 170, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(backupName, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnPathSearch1, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(15, 15, 15)))) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap(12, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(backupName, javax.swing.GroupLayout.DEFAULT_SIZE, 32, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(startPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnPathSearch1, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(destinationPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnPathSearch2, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 190, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(lastBackupLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(SingleBackup, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(toggleAutoBackup, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(btnTimePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(maxBackupCountSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel4)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(closeButton) + .addComponent(okButton)) + .addContainerGap()) + ); + + pack(); + setLocationRelativeTo(null); + }// //GEN-END:initComponents + + private void btnPathSearch1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPathSearch1ActionPerformed + logger.debug("File chooser: " + startPathField.getName() + ", files allowed: " + true); + String text = BackupOperations.pathSearchWithFileChooser(true); + if (text != null) { + startPathField.setText(text); + } + }//GEN-LAST:event_btnPathSearch1ActionPerformed + + private void btnPathSearch2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPathSearch2ActionPerformed + logger.debug("File chooser: " + destinationPathField.getName() + ", files allowed: " + false); + String text = BackupOperations.pathSearchWithFileChooser(false); + if (text != null) { + destinationPathField.setText(text); + } + }//GEN-LAST:event_btnPathSearch2ActionPerformed + + private void SingleBackupActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SingleBackupActionPerformed + List backups = RunningBackups.readBackupListFromJSON(); + if (backups.size() > 0) { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.WARNING_BACKUP_ALREADY_IN_PROGRESS_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.WARNING_GENERIC_TITLE), JOptionPane.WARNING_MESSAGE); + return; + } + + // update currentBackup + if (currentBackup == null) { + currentBackup = getBackup(); + } + + SingleBackup(startPathField.getText(), destinationPathField.getText(), backupTable); + }//GEN-LAST:event_SingleBackupActionPerformed + + private void toggleAutoBackupActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toggleAutoBackupActionPerformed + logger.info("Event --> Changing auto backup preference"); + toggleAutomaticBackup(); + }//GEN-LAST:event_toggleAutoBackupActionPerformed + + private void btnTimePickerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnTimePickerActionPerformed + TimeInterval timeInterval = BackupManager.openTimePicker(this, currentBackup.getTimeIntervalBackup()); + if (timeInterval == null) return; + + btnTimePicker.setToolTipText(timeInterval.toString()); + LocalDateTime nextDateBackup = BackupManager.getNexDateBackup(timeInterval); + + currentBackup.setTimeIntervalBackup(timeInterval); + currentBackup.setNextDateBackup(nextDateBackup); + currentBackup.setInitialPath(GetStartPathField()); + currentBackup.setDestinationPath(GetDestinationPathField()); + + openBackupActivationMessage(timeInterval); + }//GEN-LAST:event_btnTimePickerActionPerformed + + private void maxBackupCountSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_maxBackupCountSpinnerStateChanged + maxBackupCountSpinnerChange(); + }//GEN-LAST:event_maxBackupCountSpinnerStateChanged + + private void maxBackupCountSpinnerMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_maxBackupCountSpinnerMouseWheelMoved + mouseWeel(evt); + }//GEN-LAST:event_maxBackupCountSpinnerMouseWheelMoved + + private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed + this.dispose(); + }//GEN-LAST:event_closeButtonActionPerformed + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + closeOk = true; + + if (backupName.getText().isBlank() || destinationPathField.getText().isBlank() || startPathField.getText().isBlank()) { + return; + } + + currentBackup = getBackup(); + + if (create) { + if (Backup.getBackupByName(currentBackup.getBackupName()) != null) { + int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.DUPLICATED_BACKUP_NAME_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (response == JOptionPane.YES_OPTION) { + BackupManager.RemoveBackup(currentBackup.getBackupName()); + } else { + return; + } + } + BackupManager.newBackup(currentBackup); + } else { + BackupManager.updateBackup(currentBackup); + } + + this.dispose(); + }//GEN-LAST:event_okButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton SingleBackup; + private javax.swing.JTextField backupName; + private javax.swing.JTextArea backupNoteTextArea; + private backupmanager.svg.SVGButton btnPathSearch1; + private backupmanager.svg.SVGButton btnPathSearch2; + private backupmanager.svg.SVGButton btnTimePicker; + private javax.swing.JButton closeButton; + private javax.swing.JTextField destinationPathField; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel4; + private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JLabel lastBackupLabel; + private javax.swing.JSpinner maxBackupCountSpinner; + private javax.swing.JButton okButton; + private javax.swing.JTextField startPathField; + private javax.swing.JToggleButton toggleAutoBackup; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/java/backupmanager/Dialogs/EntryUserDialog.form b/src/main/java/backupmanager/Dialogs/EntryUserDialog.form new file mode 100644 index 0000000..528982c --- /dev/null +++ b/src/main/java/backupmanager/Dialogs/EntryUserDialog.form @@ -0,0 +1,122 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/backupmanager/Dialogs/EntryUserDialog.java b/src/main/java/backupmanager/Dialogs/EntryUserDialog.java new file mode 100644 index 0000000..ecc0ad5 --- /dev/null +++ b/src/main/java/backupmanager/Dialogs/EntryUserDialog.java @@ -0,0 +1,186 @@ +package backupmanager.Dialogs; + +import javax.swing.JOptionPane; + +import backupmanager.LimitDocument; +import backupmanager.Email.EmailValidator; +import backupmanager.Entities.User; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; + +public class EntryUserDialog extends javax.swing.JDialog { + + private User user; + + public EntryUserDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + + nameTextField.setDocument(new LimitDocument(20)); + surnameTextField.setDocument(new LimitDocument(20)); + emailTextField.setDocument(new LimitDocument(32)); + + user = null; + + setTranslactions(); + } + + private void setTranslactions() { + setTitle(TranslationCategory.USER_DIALOG.getTranslation(TranslationKey.USER_TITLE)); + nameLabel.setText(TranslationCategory.USER_DIALOG.getTranslation(TranslationKey.USER_NAME)); + surnameLabel.setText(TranslationCategory.USER_DIALOG.getTranslation(TranslationKey.USER_SURNAME)); + emailLabel.setText(TranslationCategory.USER_DIALOG.getTranslation(TranslationKey.USER_EMAIL)); + } + + public User getUser() { + return user; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + okBtn = new javax.swing.JButton(); + nameLabel = new javax.swing.JLabel(); + nameTextField = new javax.swing.JTextField(); + surnameLabel = new javax.swing.JLabel(); + surnameTextField = new javax.swing.JTextField(); + emailLabel = new javax.swing.JLabel(); + emailTextField = new javax.swing.JTextField(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle("Insert your data"); + setAlwaysOnTop(true); + setResizable(false); + + okBtn.setText("Ok"); + okBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okBtnActionPerformed(evt); + } + }); + + nameLabel.setText("Name"); + + nameTextField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + nameTextFieldKeyReleased(evt); + } + }); + + surnameLabel.setText("Surname"); + + surnameTextField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + surnameTextFieldKeyReleased(evt); + } + }); + + emailLabel.setText("Email"); + + emailTextField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyReleased(java.awt.event.KeyEvent evt) { + emailTextFieldKeyReleased(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(10, 10, 10) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(emailLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(surnameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 81, Short.MAX_VALUE) + .addComponent(nameLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(0, 128, Short.MAX_VALUE) + .addComponent(okBtn)) + .addComponent(surnameTextField, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(emailTextField) + .addComponent(nameTextField)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(nameLabel) + .addComponent(nameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(surnameLabel) + .addComponent(surnameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 39, Short.MAX_VALUE) + .addComponent(okBtn) + .addContainerGap()) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(emailLabel) + .addComponent(emailTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + ); + + pack(); + setLocationRelativeTo(null); + }// //GEN-END:initComponents + + private void okBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okBtnActionPerformed + String name = nameTextField.getText(); + String surname = surnameTextField.getText(); + String email = emailTextField.getText(); + + if (name.isEmpty() || surname.isEmpty() || email.isEmpty()) { + JOptionPane.showMessageDialog(this, TranslationCategory.USER_DIALOG.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_MISSING_DATA), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + return; + } else if (!EmailValidator.isValidEmail(email)) { + JOptionPane.showMessageDialog(this, TranslationCategory.USER_DIALOG.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_WRONG_EMAIL), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + return; + } + + // save user to the file + user = new User(name, surname, email); + + this.dispose(); + }//GEN-LAST:event_okBtnActionPerformed + + private void emailTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_emailTextFieldKeyReleased + if (evt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) { + okBtnActionPerformed(null); + } + }//GEN-LAST:event_emailTextFieldKeyReleased + + private void nameTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_nameTextFieldKeyReleased + if (evt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) { + surnameTextField.requestFocus(); + } + }//GEN-LAST:event_nameTextFieldKeyReleased + + private void surnameTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_surnameTextFieldKeyReleased + if (evt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) { + emailTextField.requestFocus(); + } + }//GEN-LAST:event_surnameTextFieldKeyReleased + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel emailLabel; + private javax.swing.JTextField emailTextField; + private javax.swing.JLabel nameLabel; + private javax.swing.JTextField nameTextField; + private javax.swing.JButton okBtn; + private javax.swing.JLabel surnameLabel; + private javax.swing.JTextField surnameTextField; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/java/com/mycompany/autobackupprogram/Dialogs/PreferencesDialog.form b/src/main/java/backupmanager/Dialogs/PreferencesDialog.form similarity index 100% rename from src/main/java/com/mycompany/autobackupprogram/Dialogs/PreferencesDialog.form rename to src/main/java/backupmanager/Dialogs/PreferencesDialog.form diff --git a/src/main/java/com/mycompany/autobackupprogram/Dialogs/PreferencesDialog.java b/src/main/java/backupmanager/Dialogs/PreferencesDialog.java similarity index 86% rename from src/main/java/com/mycompany/autobackupprogram/Dialogs/PreferencesDialog.java rename to src/main/java/backupmanager/Dialogs/PreferencesDialog.java index c7528ca..85826c5 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Dialogs/PreferencesDialog.java +++ b/src/main/java/backupmanager/Dialogs/PreferencesDialog.java @@ -1,29 +1,26 @@ -package com.mycompany.autobackupprogram.Dialogs; - -import com.mycompany.autobackupprogram.Logger; -import com.mycompany.autobackupprogram.Logger.LogLevel; -import com.mycompany.autobackupprogram.Entities.Preferences; -import com.mycompany.autobackupprogram.Enums.ConfigKey; -import com.mycompany.autobackupprogram.Enums.LanguagesEnum; -import com.mycompany.autobackupprogram.Enums.ThemesEnum; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationCategory; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationKey; -import com.mycompany.autobackupprogram.Managers.ThemeManager; -import static com.mycompany.autobackupprogram.GUI.BackupManagerGUI.OpenExceptionMessage; +package backupmanager.Dialogs; + +import backupmanager.Entities.Preferences; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.LanguagesEnum; +import backupmanager.Enums.ThemesEnum; +import backupmanager.Enums.TranslationLoaderEnum; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; +import backupmanager.Managers.ExceptionManager; +import backupmanager.Managers.ThemeManager; +import backupmanager.GUI.BackupManagerGUI; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.awt.Image; import java.io.IOException; import java.util.Arrays; - import javax.swing.ImageIcon; -import org.json.simple.parser.ParseException; - -import com.mycompany.autobackupprogram.GUI.BackupManagerGUI; - public class PreferencesDialog extends javax.swing.JDialog { - + private static final Logger logger = LoggerFactory.getLogger(PreferencesDialog.class); private final BackupManagerGUI mainGui; public PreferencesDialog(java.awt.Frame parent, boolean modal, BackupManagerGUI mainGui) { @@ -132,14 +129,14 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }// //GEN-END:initComponents private void themesComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_themesComboBoxActionPerformed - // TODO add your handling code here: + }//GEN-LAST:event_themesComboBoxActionPerformed private void applyBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_applyBtnActionPerformed String selectedLanguage = (String) languagesComboBox.getSelectedItem(); String selectedTheme = (String) themesComboBox.getSelectedItem(); - Logger.logMessage("Updating preferences -> Language: " + selectedLanguage + "; Theme: " + selectedTheme, LogLevel.INFO); + logger.info("Updating preferences -> Language: " + selectedLanguage + "; Theme: " + selectedTheme); try { // translactions @@ -152,11 +149,10 @@ private void applyBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRS ThemeManager.updateThemeDialog(this); // update globally - Preferences.updatePreferencesToJSON(); mainGui.reloadPreferences(); - } catch (IOException | ParseException ex) { - Logger.logMessage("An error occurred during applying preferences: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } catch (IOException ex) { + logger.error("An error occurred during applying preferences: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); } }//GEN-LAST:event_applyBtnActionPerformed diff --git a/src/main/java/com/mycompany/autobackupprogram/Dialogs/TimePicker.form b/src/main/java/backupmanager/Dialogs/TimePicker.form similarity index 100% rename from src/main/java/com/mycompany/autobackupprogram/Dialogs/TimePicker.form rename to src/main/java/backupmanager/Dialogs/TimePicker.form diff --git a/src/main/java/com/mycompany/autobackupprogram/Dialogs/TimePicker.java b/src/main/java/backupmanager/Dialogs/TimePicker.java similarity index 93% rename from src/main/java/com/mycompany/autobackupprogram/Dialogs/TimePicker.java rename to src/main/java/backupmanager/Dialogs/TimePicker.java index 7c848ee..46ab002 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Dialogs/TimePicker.java +++ b/src/main/java/backupmanager/Dialogs/TimePicker.java @@ -1,9 +1,9 @@ -package com.mycompany.autobackupprogram.Dialogs; +package backupmanager.Dialogs; -import com.mycompany.autobackupprogram.Enums.ConfigKey; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationCategory; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationKey; -import com.mycompany.autobackupprogram.Entities.TimeInterval; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; +import backupmanager.Entities.TimeInterval; import java.awt.Image; import javax.swing.ImageIcon; @@ -14,7 +14,7 @@ public class TimePicker extends javax.swing.JDialog { private TimeInterval timeInterval; private boolean closeOk; - public TimePicker(java.awt.Frame parent, TimeInterval timeInterval, boolean modal) { + public TimePicker(java.awt.Dialog parent, TimeInterval timeInterval, boolean modal) { super(parent, modal); closeOk = false; @@ -74,6 +74,12 @@ private boolean checkInputCorrectness() { Integer minutes = (Integer) minutesSpinner.getValue(); return (days != null && days >= 0 && hours != null && hours >= 0 && hours <= 23 && minutes != null && minutes >= 0 && minutes <= 59 && (days != 0 || hours != 0 || minutes != 0)); } + + private boolean checkShortTimeInterval() { + Integer days = (Integer) daysSpinner.getValue(); + Integer hours = (Integer) hoursSpinner.getValue(); + return (days == 0 && hours == 0); + } private void mouseWeel(java.awt.event.MouseWheelEvent evt) { javax.swing.JSpinner spinner = (javax.swing.JSpinner) evt.getSource(); @@ -246,12 +252,19 @@ private void minutesSpinnerMouseWheelMoved(java.awt.event.MouseWheelEvent evt) { private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed if (checkInputCorrectness()) { + + // check for small time interval setted + int response = JOptionPane.showConfirmDialog(this, TranslationCategory.DIALOGS.getTranslation(TranslationKey.WARNING_SHORT_TIME_INTERVAL_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.WARNING_GENERIC_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (response != JOptionPane.YES_OPTION) { + return; + } + timeInterval = new TimeInterval((int)daysSpinner.getValue(), (int)hoursSpinner.getValue(), (int)minutesSpinner.getValue()); closeOk = true; this.dispose(); } else { - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_WRONG_TIME_INTERVAL), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_WRONG_TIME_INTERVAL), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); } }//GEN-LAST:event_btnOkActionPerformed diff --git a/src/main/java/backupmanager/Email/EmailSender.java b/src/main/java/backupmanager/Email/EmailSender.java new file mode 100644 index 0000000..9d9a608 --- /dev/null +++ b/src/main/java/backupmanager/Email/EmailSender.java @@ -0,0 +1,158 @@ +package backupmanager.Email; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.Entities.User; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; +import backupmanager.Json.JsonUser; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.net.SMTPAppender; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.LinkedList; +import java.util.List; + +/** + * Utility class for sending emails through logback SMTPAppender. + */ +public class EmailSender { + + private static final Logger logger = LoggerFactory.getLogger(EmailSender.class); + + // Logger for sending critical error emails + private static final Logger emailErrorLogger = LoggerFactory.getLogger("EMAIL_ERROR_LOGGER"); + + // Logger for sending informational emails + private static final Logger emailInfoLogger = LoggerFactory.getLogger("EMAIL_INFO_LOGGER"); + + // Logger for sending confirmation email + private static final Logger emailConfirmationLogger = LoggerFactory.getLogger("EMAIL_CONFIRMATION_LOGGER"); + + /** + * Sends a critical error email. + * @param subject The email subject. + * @param body The email body. + */ + public static void sendErrorEmail(String subject, String body) { + User user = getCurrentUser(); + + if (user == null) { + logger.warn("User is null, using a default user for the email"); + user = User.getDefaultUser(); + } + + int rows = 300; + String emailMessage = String.format( + "Subject: %s\n\nUser: %s \nEmail: %s \nLanguage: %s \n\nHas encountered the following error:\n%s \n\nLast %d rows of the application.log file:\n%s", + subject, + user.getUserCompleteName(), + user.email, + user.language, + body, + rows, + getTextFromLogFile(rows) + ); + + emailErrorLogger.error(emailMessage); // Log the message as ERROR, triggering the SMTPAppender + + logger.info("Error email sent with subject: " + subject); + } + + /** + * Sends an informational email. + */ + public static void sendUserCreationEmail(User user) { + String userDetails = "New user registered. \n\nName: " + user.getUserCompleteName()+ "\nEmail: " + user.email + "\nLanguage: " + user.language; + + String emailMessage = "\n\n" + userDetails; + + // Should be info, but if you change it, it doesn't work + emailInfoLogger.error(emailMessage); // Log the message as INFO, triggering the SMTPAppender + + logger.info("User creation info email sent with user: " + user.toString()); + } + + /** + * Sends an informational email. + */ + public static void sendConfirmEmailToUser(User user) { + if (user == null) throw new IllegalArgumentException("User object cannot be null"); + + String subject = TranslationCategory.USER_DIALOG.getTranslation(TranslationKey.EMAIL_CONFIRMATION_SUBJECT); + String body = TranslationCategory.USER_DIALOG.getTranslation(TranslationKey.EMAIL_CONFIRMATION_BODY); + + // Assicurati di assegnare il risultato della sostituzione + body = body.replace("[UserName]", user.getUserCompleteName()); + body = body.replace("[SupportEmail]", ConfigKey.EMAIL.getValue()); + + String emailMessage = subject + "\n\n" + body; + + updateEmailRecipient(user.email); + + // Should be info, but if you change it, it doesn't work + emailConfirmationLogger.error(emailMessage); // Log the message as INFO, triggering the SMTPAppender + + logger.info("Confirmation registration email sent to the user: " + user.toString()); + } + + private static User getCurrentUser() { + try { + User user = JsonUser.readUserFromJson( + ConfigKey.USER_FILE_STRING.getValue(), + ConfigKey.CONFIG_DIRECTORY_STRING.getValue() + ); + + return user; + } catch (IOException e) { + logger.error("Unable to retrieve user details for the email: " + e.getMessage(), e); + } + + return null; + } + + public static String getTextFromLogFile(int rows) { + File file = new File(ConfigKey.LOG_DIRECTORY_STRING.getValue() + ConfigKey.LOG_FILE_STRING.getValue()); + + if (!file.exists() || !file.isFile() || file.length() == 0) { + return "Log file does not exist or is empty."; + } + + List lastLines = new LinkedList<>(); + + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + + while ((line = reader.readLine()) != null) { + if (lastLines.size() == rows) { + lastLines.remove(0); // remove the older + } + lastLines.add(line); + } + } catch (IOException e) { + logger.error("An error occurred during reading the log file for getting the last rows: " + e.getMessage(), e); + return "Error reading the log file."; + } + + return String.join("\n", lastLines); + } + + private static void updateEmailRecipient(String newRecipient) { + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + + //get the'appender SMTP + SMTPAppender smtpAppender = (SMTPAppender) context.getLogger("EMAIL_CONFIRMATION_LOGGER").getAppender("EMAIL_CONFIRMATION_LOGGER"); + + // if exists -> update + if (smtpAppender != null) { + smtpAppender.getToList().clear(); + smtpAppender.addTo(newRecipient); + } + } +} diff --git a/src/main/java/backupmanager/Email/EmailValidator.java b/src/main/java/backupmanager/Email/EmailValidator.java new file mode 100644 index 0000000..67534e3 --- /dev/null +++ b/src/main/java/backupmanager/Email/EmailValidator.java @@ -0,0 +1,22 @@ +package backupmanager.Email; + +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +public class EmailValidator { + + // regex pattern for validating email addresses + private static final String EMAIL_REGEX = + "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@" + + "(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"; + + private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX); + + public static boolean isValidEmail(String email) { + if (email == null) { + return false; + } + Matcher matcher = EMAIL_PATTERN.matcher(email); + return matcher.matches(); + } +} \ No newline at end of file diff --git a/src/main/java/com/mycompany/autobackupprogram/Entities/Backup.java b/src/main/java/backupmanager/Entities/Backup.java similarity index 64% rename from src/main/java/com/mycompany/autobackupprogram/Entities/Backup.java rename to src/main/java/backupmanager/Entities/Backup.java index dd033dd..35a700a 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Entities/Backup.java +++ b/src/main/java/backupmanager/Entities/Backup.java @@ -1,11 +1,21 @@ -package com.mycompany.autobackupprogram.Entities; +package backupmanager.Entities; +import java.io.IOException; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; -import com.mycompany.autobackupprogram.JSONConfigReader; -import com.mycompany.autobackupprogram.Enums.ConfigKey; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.Enums.ConfigKey; +import backupmanager.Json.JSONBackup; +import backupmanager.Json.JSONConfigReader; +import backupmanager.Managers.ExceptionManager; public class Backup { + private static final Logger logger = LoggerFactory.getLogger(Backup.class); private static final JSONConfigReader configReader = new JSONConfigReader(ConfigKey.CONFIG_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); private String _backupName; private String _initialPath; @@ -49,8 +59,13 @@ public Backup(String backupName, String initialPath, String destinationPath, Loc this._backupCount = backupCount; this._maxBackupsToKeep = maxBackupsToKeep; } + + public Backup(Backup backup) { + UpdateBackup(backup); + } - public void UpdateBackup(Backup backupUpdated) { + // make it final to avoid the warning (now this method cannot be overrided by the subclasses) + public final void UpdateBackup(Backup backupUpdated) { this._backupName = backupUpdated.getBackupName(); this._initialPath = backupUpdated.getInitialPath(); this._destinationPath = backupUpdated.getDestinationPath(); @@ -67,7 +82,59 @@ public void UpdateBackup(Backup backupUpdated) { @Override public String toString() { - return "[Name: "+_backupName + ", InitialPath: " + _initialPath + ", DestinationPath: " + _destinationPath + ", LastBackup: " + _lastBackup + ", IsAutoBackup: " + _autoBackup + ", NextDate: " + _nextDateBackup + ", Interval: " + (_timeIntervalBackup!=null ? _timeIntervalBackup.toString(): "")+", MaxBackupsToKeep: " + _maxBackupsToKeep + "]"; + return String.format("[Name: %s, InitialPath: %s, DestinationPath: %s, LastBackup: %s, IsAutoBackup: %s, NextDate: %s, Interval: %s, MaxBackupsToKeep: %d]", + _backupName, + _initialPath, + _destinationPath, + _lastBackup, + _autoBackup, + _nextDateBackup, + _timeIntervalBackup != null ? _timeIntervalBackup.toString() : "", + _maxBackupsToKeep + ); + } + + public String toCsvString() { + return String.format("%s,%s,%s,%s,%s,%s,%s,%d", + _backupName, + _initialPath, + _destinationPath, + _lastBackup != null ? _lastBackup.toString() : "", + _autoBackup, + _nextDateBackup != null ? _nextDateBackup.toString() : "", + _timeIntervalBackup != null ? _timeIntervalBackup.toString() : "", + _maxBackupsToKeep + ); + } + + public static Backup getBackupByName(List backups, String backupName) { + for (Backup backup : backups) { + if (backup.getBackupName().equals(backupName)) { + return backup; + } + } + return null; + } + + public static Backup getBackupByName(String backupName) { + List backups; + try { + backups = new JSONBackup().readBackupListFromJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile()); + for (Backup backup : backups) { + if (backup.getBackupName().equals(backupName)) { + return backup; + } + } + } catch (IOException ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + + return null; + } + + public static String getCSVHeader() { + return "BackupName,InitialPath,DestinationPath,LastBackup,IsAutoBackup,NextDate,Interval (gg.HH:mm),MaxBackupsToKeep"; } public String getBackupName() { @@ -131,9 +198,6 @@ public void setTimeIntervalBackup(TimeInterval timeIntervalBackup) { public void setNotes(String notes) { this._notes = notes; } - public void setCreationDate(LocalDateTime creationDate) { - this._creationDate = creationDate; - } public void setLastUpdateDate(LocalDateTime lastUpdateDate) { this._lastUpdateDate = lastUpdateDate; } diff --git a/src/main/java/com/mycompany/autobackupprogram/Entities/BackupList.java b/src/main/java/backupmanager/Entities/BackupList.java similarity index 51% rename from src/main/java/com/mycompany/autobackupprogram/Entities/BackupList.java rename to src/main/java/backupmanager/Entities/BackupList.java index b02c8f6..553571d 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Entities/BackupList.java +++ b/src/main/java/backupmanager/Entities/BackupList.java @@ -1,8 +1,8 @@ -package com.mycompany.autobackupprogram.Entities; +package backupmanager.Entities; public class BackupList { - private String directory; - private String file; + private final String directory; + private final String file; public BackupList(String directory, String file) { this.directory = directory; @@ -15,10 +15,4 @@ public String getDirectory() { public String getFile() { return file; } - public void setDirectory(String directory) { - this.directory = directory; - } - public void setFile(String file) { - this.file = file; - } } diff --git a/src/main/java/com/mycompany/autobackupprogram/Entities/Preferences.java b/src/main/java/backupmanager/Entities/Preferences.java similarity index 74% rename from src/main/java/com/mycompany/autobackupprogram/Entities/Preferences.java rename to src/main/java/backupmanager/Entities/Preferences.java index 3a53517..74c8688 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Entities/Preferences.java +++ b/src/main/java/backupmanager/Entities/Preferences.java @@ -1,4 +1,4 @@ -package com.mycompany.autobackupprogram.Entities; +package backupmanager.Entities; import java.io.FileNotFoundException; import java.io.FileReader; @@ -6,18 +6,22 @@ import java.io.IOException; import java.util.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.mycompany.autobackupprogram.Enums.ConfigKey; -import com.mycompany.autobackupprogram.Enums.LanguagesEnum; -import com.mycompany.autobackupprogram.Enums.ThemesEnum; -import static com.mycompany.autobackupprogram.GUI.BackupManagerGUI.OpenExceptionMessage; -import com.mycompany.autobackupprogram.Logger; -import com.mycompany.autobackupprogram.Logger.LogLevel; + +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.LanguagesEnum; +import backupmanager.Enums.ThemesEnum; +import backupmanager.Managers.ExceptionManager; public class Preferences { + private static final Logger logger = LoggerFactory.getLogger(Preferences.class); + private static LanguagesEnum language; private static ThemesEnum theme; private static BackupList backupList; @@ -31,14 +35,16 @@ public static void loadPreferencesFromJSON() { theme = getThemeFromJson(jsonObject); backupList = getBackupListFromJson(jsonObject); + logger.info("Preferences loaded from JSON file: language = " + language.getFileName() + ", theme = " + theme.getThemeName()); + updatePreferencesToJSON(); } catch (FileNotFoundException e) { - Logger.logMessage("Preferences file not found. Using default preferences.", Logger.LogLevel.WARN); + logger.error("Preferences file not found (Using default preferences): " + e.getMessage(), e); updatePreferencesToJSON(); // Create the JSON file with default preferences } catch (Exception ex) { - Logger.logMessage("An error occurred while loading preferences: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + logger.error("An error occurred while loading preferences: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); } } @@ -59,9 +65,11 @@ public static void updatePreferencesToJSON() { Gson gson = new Gson(); gson.toJson(jsonObject, writer); + logger.info("Preferences updated to JSON file: language = " + language.getFileName() + ", theme = " + theme.getThemeName()); + } catch (IOException ex) { - Logger.logMessage("An error occurred during updating preferences to json operation: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + logger.error("An error occurred during updating preferences to json operation: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); } } @@ -135,14 +143,14 @@ public static void setLanguage(String selectedLanguage) { for (LanguagesEnum lang : LanguagesEnum.values()) { if (lang.getLanguageName().equalsIgnoreCase(selectedLanguage)) { language = lang; - Logger.logMessage("Language set to: " + language.getLanguageName(), LogLevel.INFO); + logger.info("Language set to: " + language.getLanguageName()); return; } } - Logger.logMessage("Invalid language name: " + selectedLanguage, LogLevel.WARN); + logger.warn("Invalid language name: " + selectedLanguage); } catch (Exception ex) { - Logger.logMessage("An error occurred during setting language operation: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + logger.error("An error occurred during setting language operation: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); } } public static void setTheme(String selectedTheme) { @@ -150,14 +158,14 @@ public static void setTheme(String selectedTheme) { for (ThemesEnum t : ThemesEnum.values()) { if (t.getThemeName().equalsIgnoreCase(selectedTheme)) { theme = t; - Logger.logMessage("Theme set to: " + theme.getThemeName(), LogLevel.INFO); + logger.info("Theme set to: " + theme.getThemeName()); return; } } - Logger.logMessage("Invalid theme name: " + selectedTheme, LogLevel.WARN); + logger.warn("Invalid theme name: " + selectedTheme); } catch (Exception ex) { - Logger.logMessage("An error occurred during setting theme operation: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + logger.error("An error occurred during setting theme operation: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); } } } diff --git a/src/main/java/backupmanager/Entities/RunningBackups.java b/src/main/java/backupmanager/Entities/RunningBackups.java new file mode 100644 index 0000000..b0befc4 --- /dev/null +++ b/src/main/java/backupmanager/Entities/RunningBackups.java @@ -0,0 +1,203 @@ +package backupmanager.Entities; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; +import java.util.Random; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import backupmanager.BackupOperations; +import backupmanager.Enums.BackupStatusEnum; +import backupmanager.Enums.ConfigKey; + +// this class contains only the RunningBackups entity +// this entity is used to store the information of the backups that are currently running +// i use this object to know wich backups are currently running across the instances +public class RunningBackups { + private static final Logger logger = LoggerFactory.getLogger(RunningBackups.class); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public final String backupName; + public final String path; + public int progress; + public BackupStatusEnum status; + + public RunningBackups() { + this.backupName = null; + this.path = null; + this.progress = 0; + this.status = null; + } + + public RunningBackups(String backupName, String path, int progress, BackupStatusEnum status) { + this.backupName = backupName; + this.path = path; + this.progress = progress; + this.status = status; + } + + private static File getBackupFile() { + return new File(ConfigKey.CONFIG_DIRECTORY_STRING.getValue() + ConfigKey.RUNNING_BACKUPS_FILE_STRING.getValue()); + } + + public static synchronized List readBackupListFromJSON() { + File file = getBackupFile(); + int attempts = 5; + + for (int i = 0; i < attempts; i++) { + try { + if (!file.exists() || file.length() == 0) { + logger.warn("The backup file does not exist or is empty. Attempt " + (i + 1) + "/" + attempts); + Thread.sleep(new Random().nextInt(100, 150)); + continue; + } + + return objectMapper.readValue(file, new TypeReference>() {}); + } catch (IOException e) { + logger.error("Error while reading the file: " + e.getMessage(), e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + return new ArrayList<>(); + } + + public static RunningBackups readBackupFromJSON(String backupName) { + List backups = readBackupListFromJSON(); + + if (backups == null || backups.isEmpty()) return null; + + for (RunningBackups backup : backups) { + if (backup.backupName.equals(backupName)) { + return backup; + } + } + return null; // Return null if no backup with the specified name is found + } + + // the system is multi threading, it is possible that multiple threads call this method, so i need to use synchronized keyworl + public static synchronized void updateBackupToJSON(RunningBackups backup) { + List backups = readBackupListFromJSON(); + boolean updated = false; + + // Iterate through existing backups to update + for (ListIterator iterator = backups.listIterator(); iterator.hasNext(); ) { + RunningBackups currentBackup = iterator.next(); + if (currentBackup.backupName.equals(backup.backupName)) { + + if (backup.progress == 100) { + backup.status = BackupStatusEnum.Finished; + } else if (backup.status != null && backup.status != BackupStatusEnum.Terminated) { + backup.status = BackupStatusEnum.Progress; + } else { + backup.status = BackupStatusEnum.Terminated; + } + + logger.info("Backup '{}' updated with the status: {}", backup.backupName, backup.status); + + iterator.set(backup); + updated = true; + break; + } + } + + // If the backup wasn't found in the list, add it + if (!updated && backup.progress != 100) { + backup.status = BackupStatusEnum.Progress; + backups.add(backup); + + logger.info("Backup '{}' created with the status: {}", backup.backupName, backup.status); + } + + updateBackupsToJSON(backups); + } + + public static synchronized void updateBackupStatusAfterCompletition(String backupName) { + List backups = readBackupListFromJSON(); + boolean updated = false; + BackupStatusEnum status = BackupStatusEnum.Finished; + + for (RunningBackups backup : backups) { + if (backup.backupName.equals(backupName)) { + if (backup.progress == 100) { + backup.status = status; + } else { + status = BackupStatusEnum.Terminated; + backup.status = status; + cleanRunningBackupsFromJSON(backupName); // delete partial backup + } + + updated = true; + break; + } + } + + if (updated) { + updateBackupsToJSON(backups); + logger.info("Backup '{}' updated with the status: {}", backupName, status); + } else { + logger.warn("Backup '{}' didn't find. No status update", backupName); + } + } + + private static synchronized void updateBackupsToJSON(List backups) { + File file = getBackupFile(); + int attempts = 5; + + for (int i = 0; i < attempts; i++) { + try { + objectMapper.writeValue(file, backups); + return; + } catch (IOException e) { + logger.warn("Attempt " + (i + 1) + " to write failed: " + e.getMessage()); + try { + Thread.sleep(new Random().nextInt(100, 150)); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + + logger.error("Error: unable to write to JSON after " + attempts + " attempts."); + } + + public static synchronized void cleanRunningBackupsFromJSON(String backupName) { + List backups = readBackupListFromJSON(); + backups.removeIf(runningBackup -> + (runningBackup.progress != 100 && BackupOperations.deletePartialBackup(runningBackup.path)) || + (runningBackup.progress == 100 && runningBackup.backupName.equals(backupName)) + ); + + updateBackupsToJSON(backups); + } + + public static synchronized void deleteCompletedBackup(String backupName) { + List backups = readBackupListFromJSON(); + backups.removeIf(backup -> backup.backupName.equals(backupName) && (backup.status == BackupStatusEnum.Finished || backup.status == BackupStatusEnum.Terminated)); + + updateBackupsToJSON(backups); + } + + public static synchronized void deleteCompletedBackups() { + List backups = readBackupListFromJSON(); + backups.removeIf(backup -> backup.status == BackupStatusEnum.Finished || backup.status == BackupStatusEnum.Terminated); + + updateBackupsToJSON(backups); + } + + // remove all backups. I don't care the status, we have to delete everything + public static synchronized void deletePartialBackupsStuckedJSONFile() { + List backups = readBackupListFromJSON(); + backups.removeIf(backup -> BackupOperations.deletePartialBackup(backup.path)); + + updateBackupsToJSON(backups); + } +} diff --git a/src/main/java/com/mycompany/autobackupprogram/Entities/TimeInterval.java b/src/main/java/backupmanager/Entities/TimeInterval.java similarity index 77% rename from src/main/java/com/mycompany/autobackupprogram/Entities/TimeInterval.java rename to src/main/java/backupmanager/Entities/TimeInterval.java index 1ffa3b9..3ca7f70 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Entities/TimeInterval.java +++ b/src/main/java/backupmanager/Entities/TimeInterval.java @@ -1,4 +1,4 @@ -package com.mycompany.autobackupprogram.Entities; +package backupmanager.Entities; public class TimeInterval { private int days; @@ -58,20 +58,4 @@ public int getHours() { public int getMinutes() { return minutes; } - - public void setDays(int days) { - if (days < 0) throw new IllegalArgumentException("Days cannot be negative"); - this.days = days; - } - - public void setHours(int hours) { - if (hours < 0 || hours > 23) throw new IllegalArgumentException("Hours must be between 0 and 23"); - this.hours = hours; - } - - public void setMinutes(int minutes) { - if (minutes < 0 || minutes > 59) throw new IllegalArgumentException("Minutes must be between 0 and 59"); - this.minutes = minutes; - } - } diff --git a/src/main/java/backupmanager/Entities/User.java b/src/main/java/backupmanager/Entities/User.java new file mode 100644 index 0000000..4acab17 --- /dev/null +++ b/src/main/java/backupmanager/Entities/User.java @@ -0,0 +1,30 @@ +package backupmanager.Entities; + +import java.util.Locale; + +public class User { + public final String name; + public final String surname; + public final String email; // nullable + public final String language; + + public User(String name, String surname, String email) { + this.name = name; + this.surname = surname; + this.email = email; + this.language = Locale.getDefault().getDisplayName(); + } + + public String getUserCompleteName() { + return name + " " + surname; + } + + @Override + public String toString() { + return name + " " + surname + ", " + email + ", " + language; + } + + public static User getDefaultUser() { + return new User("Unregistered", "User", ""); + } +} diff --git a/src/main/java/backupmanager/Entities/ZippingContext.java b/src/main/java/backupmanager/Entities/ZippingContext.java new file mode 100644 index 0000000..6351072 --- /dev/null +++ b/src/main/java/backupmanager/Entities/ZippingContext.java @@ -0,0 +1,27 @@ +package backupmanager.Entities; + +import java.awt.TrayIcon; + +import javax.swing.JMenuItem; + +import backupmanager.GUI.BackupProgressGUI; +import backupmanager.Table.BackupTable; + +public class ZippingContext { + public Backup backup; + public TrayIcon trayIcon; + public BackupTable backupTable; + public BackupProgressGUI progressBar; + public JMenuItem interruptBackupPopupItem; + public JMenuItem deleteBackupPopupItem; + + public ZippingContext(Backup backup, TrayIcon trayIcon, BackupTable backupTable, BackupProgressGUI progressBar, + JMenuItem interruptBackupPopupItem, JMenuItem deleteBackupPopupItem) { + this.backup = backup; + this.trayIcon = trayIcon; + this.backupTable = backupTable; + this.progressBar = progressBar; + this.interruptBackupPopupItem = interruptBackupPopupItem; + this.deleteBackupPopupItem = deleteBackupPopupItem; + } +} diff --git a/src/main/java/backupmanager/Enums/BackupStatusEnum.java b/src/main/java/backupmanager/Enums/BackupStatusEnum.java new file mode 100644 index 0000000..71bbf4b --- /dev/null +++ b/src/main/java/backupmanager/Enums/BackupStatusEnum.java @@ -0,0 +1,8 @@ +package backupmanager.Enums; + +public enum BackupStatusEnum { + Progress, + Queue, + Finished, + Terminated +} \ No newline at end of file diff --git a/src/main/java/com/mycompany/autobackupprogram/Enums/ConfigKey.java b/src/main/java/backupmanager/Enums/ConfigKey.java similarity index 52% rename from src/main/java/com/mycompany/autobackupprogram/Enums/ConfigKey.java rename to src/main/java/backupmanager/Enums/ConfigKey.java index cfd3c85..eefb3ec 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Enums/ConfigKey.java +++ b/src/main/java/backupmanager/Enums/ConfigKey.java @@ -1,23 +1,32 @@ -package com.mycompany.autobackupprogram.Enums; +package backupmanager.Enums; import java.io.FileReader; import java.io.IOException; import java.util.EnumMap; import java.util.Map; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; public enum ConfigKey { LOG_FILE_STRING, + LOG_DIRECTORY_STRING, BACKUP_FILE_STRING, CONFIG_FILE_STRING, + RUNNING_BACKUPS_FILE_STRING, PREFERENCES_FILE_STRING, + USER_FILE_STRING, + PROPERTIES_FILE_STRING, + RESURCES_DIRECTORY_STRING, RES_DIRECTORY_STRING, LANGUAGES_DIRECTORY_STRING, CONFIG_DIRECTORY_STRING, - DONATE_PAGE_LINK, + DONATE, + DONATE_PAYPAL_LINK, + DONATE_BUYMEACOFFE_LINK, ISSUE_PAGE_LINK, INFO_PAGE_LINK, EMAIL, @@ -29,18 +38,18 @@ public enum ConfigKey { GUI_HEIGHT; private static final Map configValues = new EnumMap<>(ConfigKey.class); + private static final Logger logger = LoggerFactory.getLogger(ConfigKey.class); public static void loadFromJson(String filePath) { - JSONParser parser = new JSONParser(); try (FileReader reader = new FileReader(filePath)) { - JSONObject jsonObject = (JSONObject) parser.parse(reader); + JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); for (ConfigKey key : ConfigKey.values()) { - if (jsonObject.containsKey(key.name())) { - configValues.put(key, (String) jsonObject.get(key.name())); + if (jsonObject.has(key.name())) { + configValues.put(key, jsonObject.get(key.name()).getAsString()); } } - } catch (IOException | ParseException ex) { - ex.printStackTrace(); + } catch (IOException ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); } } diff --git a/src/main/java/backupmanager/Enums/ErrorTypes.java b/src/main/java/backupmanager/Enums/ErrorTypes.java new file mode 100644 index 0000000..b3ead29 --- /dev/null +++ b/src/main/java/backupmanager/Enums/ErrorTypes.java @@ -0,0 +1,11 @@ +package backupmanager.Enums; + +public enum ErrorTypes { + InputMissing, + InputError, + SamePaths, + ErrorCountingFiles, + ZippingIOError, + ZippingSecurityError, + ZippingGenericError +} diff --git a/src/main/java/com/mycompany/autobackupprogram/Enums/LanguagesEnum.java b/src/main/java/backupmanager/Enums/LanguagesEnum.java similarity index 92% rename from src/main/java/com/mycompany/autobackupprogram/Enums/LanguagesEnum.java rename to src/main/java/backupmanager/Enums/LanguagesEnum.java index 926dc8c..613e3c5 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Enums/LanguagesEnum.java +++ b/src/main/java/backupmanager/Enums/LanguagesEnum.java @@ -1,4 +1,4 @@ -package com.mycompany.autobackupprogram.Enums; +package backupmanager.Enums; public enum LanguagesEnum { ITA("Italiano", "ita.json"), diff --git a/src/main/java/com/mycompany/autobackupprogram/Enums/MenuItems.java b/src/main/java/backupmanager/Enums/MenuItems.java similarity index 75% rename from src/main/java/com/mycompany/autobackupprogram/Enums/MenuItems.java rename to src/main/java/backupmanager/Enums/MenuItems.java index 7989cb5..5da1dd8 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Enums/MenuItems.java +++ b/src/main/java/backupmanager/Enums/MenuItems.java @@ -1,10 +1,12 @@ -package com.mycompany.autobackupprogram.Enums; +package backupmanager.Enums; public enum MenuItems { BugReport, Preferences, Clear, Donate, + PaypalDonate, + BuymeacoffeeDonate, History, InfoPage, New, diff --git a/src/main/java/com/mycompany/autobackupprogram/Enums/ThemesEnum.java b/src/main/java/backupmanager/Enums/ThemesEnum.java similarity index 91% rename from src/main/java/com/mycompany/autobackupprogram/Enums/ThemesEnum.java rename to src/main/java/backupmanager/Enums/ThemesEnum.java index a88a741..814c5eb 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Enums/ThemesEnum.java +++ b/src/main/java/backupmanager/Enums/ThemesEnum.java @@ -1,4 +1,4 @@ -package com.mycompany.autobackupprogram.Enums; +package backupmanager.Enums; public enum ThemesEnum { INTELLIJ("Light"), diff --git a/src/main/java/com/mycompany/autobackupprogram/Enums/TranslationLoaderEnum.java b/src/main/java/backupmanager/Enums/TranslationLoaderEnum.java similarity index 77% rename from src/main/java/com/mycompany/autobackupprogram/Enums/TranslationLoaderEnum.java rename to src/main/java/backupmanager/Enums/TranslationLoaderEnum.java index 7a641f5..932327d 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Enums/TranslationLoaderEnum.java +++ b/src/main/java/backupmanager/Enums/TranslationLoaderEnum.java @@ -1,19 +1,21 @@ -package com.mycompany.autobackupprogram.Enums; - -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - -import com.mycompany.autobackupprogram.Logger; -import com.mycompany.autobackupprogram.Logger.LogLevel; +package backupmanager.Enums; import java.io.FileReader; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + public class TranslationLoaderEnum { + private static final Logger logger = LoggerFactory.getLogger(TranslationLoaderEnum.class); + public enum TranslationCategory { GENERAL("General"), MENU("Menu"), @@ -22,6 +24,7 @@ public enum TranslationCategory { BACKUP_LIST("BackupList"), TIME_PICKER_DIALOG("TimePickerDialog"), PREFERENCES_DIALOG("PreferencesDialog"), + USER_DIALOG("UserDialog"), PROGRESS_BACKUP_FRAME("ProgressBackupFrame"), TRAY_ICON("TrayIcon"), DIALOGS("Dialogs"); @@ -58,6 +61,8 @@ public enum TranslationKey { OK_BUTTON("OkButton", "Ok"), CANCEL_BUTTON("CancelButton", "Cancel"), APPLY_BUTTON("ApplyButton", "Apply"), + SAVE_BUTTON("SaveButton", "Save"), + CREATE_BUTTON("CreateButton", "Create"), // Menu FILE("File", "File"), @@ -95,6 +100,8 @@ public enum TranslationKey { AUTO_BACKUP_BUTTON_OFF("AutoBackupButtonOFF", "Auto Backup (OFF)"), INITIAL_PATH_PLACEHOLDER("InitialPathPlaceholder", "Initial path"), DESTINATION_PATH_PLACEHOLDER("DestinationPathPlaceholder", "Destination path"), + BACKUP_NAME("BackupName", "Backup name: "), + BACKUP_NAME_TOOLTIP("BackupNameTooltip", "(Required) Backup name"), INITIAL_PATH_TOOLTIP("InitialPathTooltip", "(Required) Initial path"), DESTINATION_PATH_TOOLTIP("DestinationPathTooltip", "(Required) Destination path"), INITIAL_FILE_CHOOSER_TOOLTIP("InitialFileChooserTooltip", "Open file explorer"), @@ -126,10 +133,14 @@ public enum TranslationKey { NOTES_DETAIL("NotesDetail", "Notes"), MAX_BACKUPS_TO_KEEP_DETAIL("MaxBackupsToKeepDetail", "MaxBackupsToKeep"), ADD_BACKUP_TOOLTIP("AddBackupTooltip", "Add new backup"), + EXPORT_AS("ExportAs", "Export as: "), + EXPORT_AS_PDF_TOOLTIP("ExportAsPdfTooltip", "Export as PDF"), + EXPORT_AS_CSV_TOOLTIP("ExportAsCsvTooltip", "Export as CSV"), RESEARCH_BAR_TOOLTIP("ResearchBarTooltip", "Research bar"), RESEARCH_BAR_PLACEHOLDER("ResearchBarPlaceholder", "Search..."), EDIT_POPUP("EditPopup", "Edit"), DELETE_POPUP("DeletePopup", "Delete"), + INTERRUPT_POPUP("InterruptPopup", "Interrupt"), DUPLICATE_POPUP("DuplicatePopup", "Duplicate"), RENAME_BACKUP_POPUP("RenameBackupPopup", "Rename backup"), OPEN_INITIAL_FOLDER_POPUP("OpenInitialFolderPopup", "Open initial path"), @@ -155,6 +166,16 @@ public enum TranslationKey { LANGUAGE("Language", "Language"), THEME("Theme", "Theme"), + // User dialog + USER_TITLE("UserTitle", "Insert your data"), + USER_NAME("Name", "Name"), + USER_SURNAME("Surname", "Surname"), + USER_EMAIL("Email", "Email"), + ERROR_MESSAGE_FOR_MISSING_DATA("ErrorMessageForMissingData", "Please fill in all the required fields."), + ERROR_MESSAGE_FOR_WRONG_EMAIL("ErrorMessageForWrongEmail", "The provided email address is invalid. Please provide a correct one."), + EMAIL_CONFIRMATION_SUBJECT("EmailConfirmationSubject", "Thank you for choosing Backup Manager!"), + EMAIL_CONFIRMATION_BODY("EmailConfirmationBody", "Hi [UserName],\n\nThank you for downloading and registering **Backup Manager**, your new tool for secure and efficient backup management!\n\nThis is an automated email sent to confirm your registration. We will contact you by email only to inform you about new releases or important updates of the application.\n\nIn the meantime, if you have any questions, need assistance, or have suggestions, we are always here for you. You can reach us at **[SupportEmail]**.\n\nThank you again for choosing Backup Manager, and enjoy managing your backups!\n\nBest regards,\nThe Backup Manager Team"), + // ProgressBackupFrame PROGRESS_BACKUP_TITLE("ProgressBackupTitle", "Backup in progress"), STATUS_COMPLETED("StatusCompleted", "Backup completed!"), @@ -169,6 +190,10 @@ public enum TranslationKey { // Dialogs ERROR_GENERIC_TITLE("ErrorGenericTitle", "Error"), + WARNING_GENERIC_TITLE("WarningGenericTitle", "Warning"), + WARNING_BACKUP_ALREADY_IN_PROGRESS_MESSAGE("WarningBackupAlreadyInProgressMessage", "There is already a backup in progress. It is not possible to perform parallel backups"), + WARNING_SHORT_TIME_INTERVAL_MESSAGE("WarningShortTimeIntervalMessage", "The selected time interval is very short. For optimal performance, we recommend setting it to at least one hour. Do you still want to proceed?"), + ERROR_MESSAGE_FOR_FOLDER_NOT_EXISTING("ErrorMessageForFolderNotExisting", "The folder does not exist or is invalid"), ERROR_MESSAGE_FOR_SAVING_FILE_WITH_PATHS_EMPTY("ErrorMessageForSavingFileWithPathsEmpty", "Unable to save the file. Both the initial and destination paths must be specified and cannot be empty"), BACKUP_SAVED_CORRECTLY_TITLE("BackupSavedCorrectlyTitle", "Backup saved"), @@ -215,6 +240,21 @@ public enum TranslationKey { ERROR_MESSAGE_SAME_PATHS_GENERIC("ErrorMessageForSamePaths", "The initial path and destination path cannot be the same. Please choose different paths!"), ERROR_MESSAGE_FOR_WRONG_FILE_EXTENSION_TITLE("ErrorMessageForWrongFileExtensionTitle", "Invalid File"), ERROR_MESSAGE_FOR_WRONG_FILE_EXTENSION_MESSAGE("ErrorMessageForWrongFileExtensionMessage", "Error: Please select a valid JSON file."), + ERROR_MESSAGE_COUNTING_FILES("ErrorMessageCountingFiles", "Error occurred while calculating files to back up."), + ERROR_MESSAGE_ZIPPING_GENERIC("ErrorMessageZippingGeneric", "Error occurred while zipping files."), + ERROR_MESSAGE_ZIPPING_IO("ErrorMessageZippingIO", "Error occurred while zipping files: I/O error."), + ERROR_MESSAGE_ZIPPING_SECURITY("ErrorMessageZippingSecurity", "Error occurred while zipping files: Security error."), + SUCCESS_GENERIC_TITLE( "SuccessGenericTitle", "Success"), + SUCCESSFULLY_EXPORTED_TO_CSV_MESSAGE("SuccessfullyExportedToCsvMessage", "Backups exported to CSV successfully!"), + SUCCESSFULLY_EXPORTED_TO_PDF_MESSAGE("SuccessfullyExportedToPdfMessage", "Backups exported to PDF successfully!"), + ERROR_MESSAGE_FOR_EXPORTING_TO_CSV("ErrorMessageForExportingToCsv", "Error exporting backups to CSV: "), + ERROR_MESSAGE_FOR_EXPORTING_TO_PDF("ErrorMessageForExportingToPdf", "Error exporting backups to PDF: "), + CSV_NAME_MESSAGE_INPUT("CsvNameMessageInput", "Enter the name of the CSV file."), + PDF_NAME_MESSAGE_INPUT("PdfNameMessageInput", "Enter the name of the PDF file."), + DUPLICATED_FILE_NAME_MESSAGE("DuplicatedFileNameMessage", "File already exists. Overwrite?"), + ERROR_MESSAGE_INVALID_FILENAME("ErrorMessageInvalidFilename", "Invalid file name. Use only alphanumeric characters, dashes, and underscores."), + CONFIRMATION_DELETION_TITLE("ConfirmationDeletionTitle", "Confirm Deletion"), + CONFIRMATION_DELETION_MESSAGE("ConfirmationDeletionMessage", "Are you sure you want to delete the selected rows?"), // InfoPage INFO_PAGE_DESCRIPTION("InfoPageDescription", "Backup automatic system for files with the option to schedule and make backups regularly."), @@ -262,20 +302,20 @@ public String toString() { } } - public static void loadTranslations(String filePath) throws IOException, ParseException { - JSONParser parser = new JSONParser(); - + public static void loadTranslations(String filePath) throws IOException { + Gson gson = new Gson(); + try (FileReader reader = new FileReader(filePath)) { - JSONObject jsonObject = (JSONObject) parser.parse(reader); - + JsonObject jsonObject = gson.fromJson(reader, JsonObject.class); + for (TranslationCategory category : TranslationCategory.values()) { - JSONObject categoryTranslations = (JSONObject) jsonObject.get(category.getCategoryName()); - + JsonObject categoryTranslations = jsonObject.getAsJsonObject(category.getCategoryName()); + if (categoryTranslations != null) { - for (Object keyObj : categoryTranslations.keySet()) { - String key = (String) keyObj; - String value = (String) categoryTranslations.get(key); - + for (Map.Entry entry : categoryTranslations.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue().getAsString(); + // Use fromKeyName to get the TranslationKey from the JSON key TranslationKey translationKey = TranslationKey.fromKeyName(key); if (translationKey != null) { @@ -283,30 +323,17 @@ public static void loadTranslations(String filePath) throws IOException, ParseEx String translationValue = (value != null && !value.isEmpty()) ? value : translationKey.getDefaultValue(); category.addTranslation(translationKey, translationValue); } else { - // If the key is not recognized in the enum, log it and use the default value - Logger.logMessage("Warning: Unrecognized key in JSON: " + key + ", using default value.", LogLevel.WARN); - category.addTranslation(translationKey, translationKey.getDefaultValue()); + logger.warn("Unrecognized key in JSON: " + key + ", using default value"); } } } } + } catch (Exception ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); } } - + public static String getTranslation(TranslationCategory category, TranslationKey key) { return category.translations.getOrDefault(key, key.getDefaultValue()); // Use default value if not found } - - // only for test - public static void main(String[] args) { - try { - loadTranslations("src/main/resources/res/languages/ita.json"); - - System.out.println(TranslationCategory.MENU.getTranslation(TranslationKey.FILE)); - System.out.println(TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE)); - - } catch (IOException | ParseException e) { - e.printStackTrace(); - } - } } diff --git a/src/main/java/backupmanager/GUI/BackupManagerGUI.form b/src/main/java/backupmanager/GUI/BackupManagerGUI.form new file mode 100644 index 0000000..670b9b9 --- /dev/null +++ b/src/main/java/backupmanager/GUI/BackupManagerGUI.form @@ -0,0 +1,549 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + </TableColumnModel> + </Property> + <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> + <Color id="Crosshair Cursor"/> + </Property> + <Property name="rowHeight" type="int" value="50"/> + <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor"> + <TableHeader reorderingAllowed="true" resizingAllowed="true"/> + </Property> + </Properties> + <Events> + <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="tableMouseClicked"/> + </Events> + </Component> + </SubComponents> + </Container> + <Component class="javax.swing.JLabel" name="detailsLabel"> + <Properties> + <Property name="verticalAlignment" type="int" value="1"/> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel3"> + <Properties> + <Property name="text" type="java.lang.String" value="Version 2.0.2"/> + </Properties> + </Component> + <Component class="backupmanager.svg.SVGButton" name="addBackupEntryButton"> + <Properties> + <Property name="toolTipText" type="java.lang.String" value="Add new backup"/> + <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> + <Dimension value="[32, 32]"/> + </Property> + <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> + <Dimension value="[32, 32]"/> + </Property> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="addBackupEntryButtonActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JLabel" name="jLabel1"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="Segoe UI" size="20" style="0"/> + </Property> + <Property name="text" type="java.lang.String" value="|"/> + <Property name="alignmentY" type="float" value="0.0"/> + </Properties> + </Component> + <Component class="javax.swing.JTextField" name="researchField"> + <Properties> + <Property name="toolTipText" type="java.lang.String" value="Research bar"/> + </Properties> + <AccessibilityProperties> + <Property name="AccessibleContext.accessibleName" type="java.lang.String" value=""/> + </AccessibilityProperties> + <Events> + <EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="researchFieldKeyTyped"/> + </Events> + </Component> + <Component class="javax.swing.JLabel" name="ExportLabel"> + <Properties> + <Property name="horizontalAlignment" type="int" value="4"/> + <Property name="text" type="java.lang.String" value="Export As:"/> + </Properties> + </Component> + <Component class="backupmanager.svg.SVGButton" name="exportAsCsvBtn"> + <Properties> + <Property name="toolTipText" type="java.lang.String" value="Export as .csv"/> + <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> + <Dimension value="[32, 32]"/> + </Property> + <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> + <Dimension value="[32, 32]"/> + </Property> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="exportAsCsvBtnActionPerformed"/> + </Events> + </Component> + <Component class="backupmanager.svg.SVGButton" name="exportAsPdfBtn"> + <Properties> + <Property name="toolTipText" type="java.lang.String" value="Export as .pdf"/> + <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> + <Dimension value="[32, 32]"/> + </Property> + <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> + <Dimension value="[32, 32]"/> + </Property> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="exportAsPdfBtnActionPerformed"/> + </Events> + </Component> + </SubComponents> +</Form> diff --git a/src/main/java/backupmanager/GUI/BackupManagerGUI.java b/src/main/java/backupmanager/GUI/BackupManagerGUI.java new file mode 100644 index 0000000..1283952 --- /dev/null +++ b/src/main/java/backupmanager/GUI/BackupManagerGUI.java @@ -0,0 +1,1160 @@ +package backupmanager.GUI; + +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import javax.swing.AbstractAction; +import javax.swing.ActionMap; +import javax.swing.ImageIcon; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumnModel; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.formdev.flatlaf.FlatClientProperties; + +import backupmanager.Managers.ImportExportManager; +import backupmanager.Dialogs.EntryUserDialog; +import backupmanager.Email.EmailSender; +import backupmanager.Entities.Backup; +import backupmanager.Entities.Preferences; +import backupmanager.Entities.RunningBackups; +import backupmanager.Entities.User; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.LanguagesEnum; +import backupmanager.Enums.MenuItems; +import backupmanager.Enums.TranslationLoaderEnum; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; +import backupmanager.Json.JSONBackup; +import backupmanager.Json.JSONConfigReader; +import backupmanager.Json.JsonUser; +import backupmanager.Managers.BackupManager; +import backupmanager.Managers.ExceptionManager; +import backupmanager.Managers.ThemeManager; +import backupmanager.Services.BackupObserver; +import backupmanager.Table.BackupTable; +import backupmanager.Table.BackupTableModel; +import backupmanager.Table.CheckboxCellRenderer; +import backupmanager.Table.StripedRowRenderer; +import backupmanager.Table.TableDataManager; + +/** + * @author Dennis Turco + */ +public final class BackupManagerGUI extends javax.swing.JFrame { + private static final Logger logger = LoggerFactory.getLogger(BackupManagerGUI.class); + public static final DateTimeFormatter dateForfolderNameFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH.mm.ss"); + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss"); + + private final BackupManager backupManager; + private final BackupObserver observer; + public static List<Backup> backups; + public static DefaultTableModel model; + public static BackupTable backupTable; + public static BackupTableModel tableModel; + public static BackupProgressGUI progressBar; + private Integer selectedRow; + private final String currentVersion; + + public BackupManagerGUI() { + ThemeManager.updateThemeFrame(this); + + initComponents(); + + currentVersion = ConfigKey.VERSION.getValue(); + + // logo application + Image icon = new ImageIcon(this.getClass().getResource(ConfigKey.LOGO_IMG.getValue())).getImage(); + this.setIconImage(icon); + + // load Menu items + initializeMenuItems(); + + // set app sizes + setScreenSize(); + + // icons + researchField.putClientProperty(FlatClientProperties.TEXT_FIELD_LEADING_ICON, new com.formdev.flatlaf.extras.FlatSVGIcon("res/img/search.svg", 16, 16)); + + // translations + setTranslations(); + + // first initialize the table, then start observer thread + initializeTable(); + observer = new BackupObserver(dateForfolderNameFormatter, 1000); + observer.start(); + + // disable interruption backup operation option + interruptBackupPopupItem.setEnabled(false); + + // set all svg images + setSvgImages(); + + checkForFirstAccess(); + + backupManager = new BackupManager(this); + + + // TODO: remove this + interruptBackupPopupItem.setVisible(false); + } + + private void checkForFirstAccess() { + logger.debug("Checking for first access"); + try { + User user = JsonUser.readUserFromJson(ConfigKey.USER_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); + + if (user != null) { + logger.info("Current user: " + user.toString()); + return; + } + + // set language based on PC language + setLanguageBasedOnPcLanguage(); + + // user creation + createUser(); + } catch (IOException e) { + logger.error("I/O error occurred during read user data: " + e.getMessage(), e); + JsonUser.writeUserToJson(User.getDefaultUser(), ConfigKey.USER_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); + } + } + + private void createUser() { + // first access + EntryUserDialog userDialog = new EntryUserDialog(this, true); + userDialog.setVisible(true); + User newUser = userDialog.getUser(); + + if (newUser == null) { + return; + } + + JsonUser.writeUserToJson(newUser, ConfigKey.USER_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); + + EmailSender.sendUserCreationEmail(newUser); + EmailSender.sendConfirmEmailToUser(newUser); + } + + private void setLanguageBasedOnPcLanguage() { + Locale defaultLocale = Locale.getDefault(); + String language = defaultLocale.getLanguage(); + + logger.info("Setting default language to: " + language); + + switch (language) { + case "en": + Preferences.setLanguage(LanguagesEnum.ENG); + break; + case "it": + Preferences.setLanguage(LanguagesEnum.ITA); + break; + case "es": + Preferences.setLanguage(LanguagesEnum.ESP); + break; + case "de": + Preferences.setLanguage(LanguagesEnum.DEU); + break; + case "fr": + Preferences.setLanguage(LanguagesEnum.FRA); + break; + default: + Preferences.setLanguage(LanguagesEnum.ENG); + } + + reloadPreferences(); + } + + public void showWindow() { + setVisible(true); + toFront(); + requestFocus(); + } + + private void setScreenSize() { + Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); + int width = Math.min((int) size.getWidth(), Integer.parseInt(ConfigKey.GUI_WIDTH.getValue())); + int height = Math.min((int) size.getHeight(), Integer.parseInt(ConfigKey.GUI_HEIGHT.getValue())); + + this.setSize(width,height); + } + + public void reloadPreferences() { + logger.info("Reloading preferences"); + + Preferences.updatePreferencesToJSON(); + + // load language + try { + TranslationLoaderEnum.loadTranslations(ConfigKey.LANGUAGES_DIRECTORY_STRING.getValue() + Preferences.getLanguage().getFileName()); + setTranslations(); + } catch (IOException ex) { + logger.error("An error occurred during reloading preferences operation: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + + // load theme + ThemeManager.updateThemeFrame(this); + ThemeManager.refreshPopup(TablePopup); + setSvgImages(); + } + + private void displayBackupList() { + BackupTableModel model = new BackupTableModel(getColumnTranslations(), 0); + + // Populate the model with backup data + for (Backup backup : backups) { + model.addRow(new Object[]{ + backup.getBackupName(), + backup.getInitialPath(), + backup.getDestinationPath(), + backup.getLastBackup() != null ? backup.getLastBackup().format(formatter) : "", + backup.isAutoBackup(), + backup.getNextDateBackup() != null ? backup.getNextDateBackup().format(formatter) : "", + backup.getTimeIntervalBackup() != null ? backup.getTimeIntervalBackup().toString() : "" + }); + } + + backupTable = new BackupTable(model); + + // Add key bindings using InputMap and ActionMap + InputMap inputMap = backupTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + ActionMap actionMap = backupTable.getActionMap(); + + // Handle Enter key + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "enterKey"); + actionMap.put("enterKey", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + int selectedRow = backupTable.getSelectedRow(); + if (selectedRow == -1) return; + + logger.debug("Enter key pressed on row: " + selectedRow); + backupManager.openBackup((String) backupTable.getValueAt(selectedRow, 0)); + + backupManager.openBackupEntryDialog(); + } + }); + + // Handle Delete key + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "deleteKey"); + actionMap.put("deleteKey", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + int[] selectedRows = backupTable.getSelectedRows(); + if (selectedRows.length == 0) return; + + logger.debug("Delete key pressed on rows: " + Arrays.toString(selectedRows)); + + int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_DELETION_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_DELETION_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (response != JOptionPane.YES_OPTION) { + return; + } + + for (int row : selectedRows) { + backupManager.deleteBackup(row, backups, backupTable, false); + } + } + }); + + // Apply renderers for each column + TableColumnModel columnModel = backupTable.getColumnModel(); + + for (int i = 0; i < columnModel.getColumnCount(); i++) { + if (i == 4) { + columnModel.getColumn(i).setCellRenderer(new CheckboxCellRenderer()); + columnModel.getColumn(i).setCellEditor(backupTable.getDefaultEditor(Boolean.class)); + } else { + columnModel.getColumn(i).setCellRenderer(new StripedRowRenderer()); + } + } + + // Add the existing mouse listener to the new table + backupTable.addMouseListener(new java.awt.event.MouseAdapter() { + @Override + public void mouseClicked(java.awt.event.MouseEvent evt) { + tableMouseClicked(evt); // Reuse the existing method + } + }); + + // Update the global model reference + BackupManagerGUI.model = model; + + // Replace the existing table in the GUI + JScrollPane scrollPane = (JScrollPane) table.getParent().getParent(); + table = backupTable; // Update the reference to the new table + scrollPane.setViewportView(table); // Replace the table in the scroll pane + } + + private void researchInTable() { + List<Backup> tempBackups = new ArrayList<>(); + + String research = researchField.getText(); + + for (Backup backup : backups) { + if (backup.getBackupName().contains(research) || + backup.getInitialPath().contains(research) || + backup.getDestinationPath().contains(research) || + (backup.getLastBackup() != null && backup.getLastBackup().toString().contains(research)) || + (backup.getNextDateBackup() != null && backup.getNextDateBackup().toString().contains(research)) || + (backup.getTimeIntervalBackup() != null && backup.getTimeIntervalBackup().toString().contains(research))) { + tempBackups.add(backup); + } + } + + TableDataManager.updateTableWithNewBackupList(tempBackups, formatter); + } + + /** + * This method is called from within the constructor to initialize the form. + * + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + TablePopup = new javax.swing.JPopupMenu(); + EditPoputItem = new javax.swing.JMenuItem(); + DeletePopupItem = new javax.swing.JMenuItem(); + interruptBackupPopupItem = new javax.swing.JMenuItem(); + DuplicatePopupItem = new javax.swing.JMenuItem(); + renamePopupItem = new javax.swing.JMenuItem(); + jSeparator1 = new javax.swing.JPopupMenu.Separator(); + OpenInitialFolderItem = new javax.swing.JMenuItem(); + OpenInitialDestinationItem = new javax.swing.JMenuItem(); + jSeparator3 = new javax.swing.JPopupMenu.Separator(); + Backup = new javax.swing.JMenu(); + RunBackupPopupItem = new javax.swing.JMenuItem(); + AutoBackupMenuItem = new javax.swing.JCheckBoxMenuItem(); + jSeparator2 = new javax.swing.JPopupMenu.Separator(); + jMenu4 = new javax.swing.JMenu(); + CopyBackupNamePopupItem = new javax.swing.JMenuItem(); + CopyInitialPathPopupItem = new javax.swing.JMenuItem(); + CopyDestinationPathPopupItem = new javax.swing.JMenuItem(); + jScrollPane1 = new javax.swing.JScrollPane(); + table = new javax.swing.JTable(); + detailsLabel = new javax.swing.JLabel(); + jLabel3 = new javax.swing.JLabel(); + addBackupEntryButton = new backupmanager.svg.SVGButton(); + jLabel1 = new javax.swing.JLabel(); + researchField = new javax.swing.JTextField(); + ExportLabel = new javax.swing.JLabel(); + exportAsCsvBtn = new backupmanager.svg.SVGButton(); + exportAsPdfBtn = new backupmanager.svg.SVGButton(); + jMenuBar1 = new javax.swing.JMenuBar(); + jMenu1 = new javax.swing.JMenu(); + MenuNew = new backupmanager.svg.SVGMenuItem(); + MenuSave = new backupmanager.svg.SVGMenuItem(); + MenuSaveWithName = new backupmanager.svg.SVGMenuItem(); + jSeparator4 = new javax.swing.JPopupMenu.Separator(); + MenuImport = new backupmanager.svg.SVGMenuItem(); + MenuExport = new backupmanager.svg.SVGMenuItem(); + jSeparator5 = new javax.swing.JPopupMenu.Separator(); + MenuClear = new backupmanager.svg.SVGMenuItem(); + MenuHistory = new backupmanager.svg.SVGMenuItem(); + jMenu2 = new javax.swing.JMenu(); + MenuPreferences = new backupmanager.svg.SVGMenuItem(); + MenuQuit = new backupmanager.svg.SVGMenuItem(); + jMenu3 = new javax.swing.JMenu(); + MenuWebsite = new backupmanager.svg.SVGMenuItem(); + MenuInfoPage = new backupmanager.svg.SVGMenuItem(); + MenuShare = new backupmanager.svg.SVGMenuItem(); + MenuDonate = new backupmanager.svg.SVGMenu(); + MenuPaypalDonate = new backupmanager.svg.SVGMenuItem(); + MenuBuyMeACoffeDonate = new backupmanager.svg.SVGMenuItem(); + jMenu5 = new javax.swing.JMenu(); + MenuBugReport = new backupmanager.svg.SVGMenuItem(); + MenuSupport = new backupmanager.svg.SVGMenuItem(); + + EditPoputItem.setText("Edit"); + EditPoputItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + EditPoputItemActionPerformed(evt); + } + }); + TablePopup.add(EditPoputItem); + + DeletePopupItem.setText("Delete"); + DeletePopupItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + DeletePopupItemActionPerformed(evt); + } + }); + TablePopup.add(DeletePopupItem); + + interruptBackupPopupItem.setText("Interrupt"); + interruptBackupPopupItem.setToolTipText(""); + interruptBackupPopupItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + interruptBackupPopupItemActionPerformed(evt); + } + }); + TablePopup.add(interruptBackupPopupItem); + + DuplicatePopupItem.setText("Duplicate"); + DuplicatePopupItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + DuplicatePopupItemActionPerformed(evt); + } + }); + TablePopup.add(DuplicatePopupItem); + + renamePopupItem.setText("Rename backup"); + renamePopupItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + renamePopupItemActionPerformed(evt); + } + }); + TablePopup.add(renamePopupItem); + TablePopup.add(jSeparator1); + + OpenInitialFolderItem.setText("Open initial folder"); + OpenInitialFolderItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + OpenInitialFolderItemActionPerformed(evt); + } + }); + TablePopup.add(OpenInitialFolderItem); + + OpenInitialDestinationItem.setText("Open destination folder"); + OpenInitialDestinationItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + OpenInitialDestinationItemActionPerformed(evt); + } + }); + TablePopup.add(OpenInitialDestinationItem); + TablePopup.add(jSeparator3); + + Backup.setText("Backup"); + + RunBackupPopupItem.setText("Run single backup"); + RunBackupPopupItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + RunBackupPopupItemActionPerformed(evt); + } + }); + Backup.add(RunBackupPopupItem); + + AutoBackupMenuItem.setSelected(true); + AutoBackupMenuItem.setText("Auto Backup"); + AutoBackupMenuItem.setToolTipText(""); + AutoBackupMenuItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + AutoBackupMenuItemActionPerformed(evt); + } + }); + Backup.add(AutoBackupMenuItem); + + TablePopup.add(Backup); + TablePopup.add(jSeparator2); + + jMenu4.setText("Copy text"); + + CopyBackupNamePopupItem.setText("Copy backup name"); + CopyBackupNamePopupItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + CopyBackupNamePopupItemActionPerformed(evt); + } + }); + jMenu4.add(CopyBackupNamePopupItem); + + CopyInitialPathPopupItem.setText("Copy initial path"); + CopyInitialPathPopupItem.setToolTipText(""); + CopyInitialPathPopupItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + CopyInitialPathPopupItemActionPerformed(evt); + } + }); + jMenu4.add(CopyInitialPathPopupItem); + + CopyDestinationPathPopupItem.setText("Copy destination path"); + CopyDestinationPathPopupItem.setToolTipText(""); + CopyDestinationPathPopupItem.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + CopyDestinationPathPopupItemActionPerformed(evt); + } + }); + jMenu4.add(CopyDestinationPathPopupItem); + + TablePopup.add(jMenu4); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle("Backup Manager"); + setMinimumSize(new java.awt.Dimension(750, 450)); + + table.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + + }, + new String [] { + "Backup name", "Initial path", "Destination path", "Last backup", "Auto backup", "Next date backup", "Days interval backup" + } + ) { + Class[] types = new Class [] { + java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Boolean.class, java.lang.String.class, java.lang.Integer.class + }; + boolean[] canEdit = new boolean [] { + false, false, false, false, false, false, false + }; + + public Class getColumnClass(int columnIndex) { + return types [columnIndex]; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return canEdit [columnIndex]; + } + }); + table.setCursor(new java.awt.Cursor(java.awt.Cursor.CROSSHAIR_CURSOR)); + table.setRowHeight(50); + table.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + tableMouseClicked(evt); + } + }); + jScrollPane1.setViewportView(table); + + detailsLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); + + jLabel3.setText("Version 2.0.2"); + + addBackupEntryButton.setToolTipText("Add new backup"); + addBackupEntryButton.setMaximumSize(new java.awt.Dimension(32, 32)); + addBackupEntryButton.setMinimumSize(new java.awt.Dimension(32, 32)); + addBackupEntryButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + addBackupEntryButtonActionPerformed(evt); + } + }); + + jLabel1.setFont(new java.awt.Font("Segoe UI", 0, 20)); // NOI18N + jLabel1.setText("|"); + jLabel1.setAlignmentY(0.0F); + + researchField.setToolTipText("Research bar"); + researchField.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyTyped(java.awt.event.KeyEvent evt) { + researchFieldKeyTyped(evt); + } + }); + + ExportLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + ExportLabel.setText("Export As:"); + + exportAsCsvBtn.setToolTipText("Export as .csv"); + exportAsCsvBtn.setMaximumSize(new java.awt.Dimension(32, 32)); + exportAsCsvBtn.setMinimumSize(new java.awt.Dimension(32, 32)); + exportAsCsvBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + exportAsCsvBtnActionPerformed(evt); + } + }); + + exportAsPdfBtn.setToolTipText("Export as .pdf"); + exportAsPdfBtn.setMaximumSize(new java.awt.Dimension(32, 32)); + exportAsPdfBtn.setMinimumSize(new java.awt.Dimension(32, 32)); + exportAsPdfBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + exportAsPdfBtnActionPerformed(evt); + } + }); + + jMenu1.setText("File"); + + MenuNew.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_DOWN_MASK)); + MenuNew.setText("New"); + MenuNew.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuNewActionPerformed(evt); + } + }); + jMenu1.add(MenuNew); + + MenuSave.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_DOWN_MASK)); + MenuSave.setText("Save"); + MenuSave.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuSaveActionPerformed(evt); + } + }); + jMenu1.add(MenuSave); + + MenuSaveWithName.setText("Save with name"); + MenuSaveWithName.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuSaveWithNameActionPerformed(evt); + } + }); + jMenu1.add(MenuSaveWithName); + jMenu1.add(jSeparator4); + + MenuImport.setText("Import backup list"); + MenuImport.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuImportActionPerformed(evt); + } + }); + jMenu1.add(MenuImport); + + MenuExport.setText("Export backup list"); + MenuExport.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuExportActionPerformed(evt); + } + }); + jMenu1.add(MenuExport); + jMenu1.add(jSeparator5); + + MenuClear.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_DOWN_MASK)); + MenuClear.setText("Clear"); + MenuClear.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuClearActionPerformed(evt); + } + }); + jMenu1.add(MenuClear); + + MenuHistory.setText("History"); + MenuHistory.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuHistoryActionPerformed(evt); + } + }); + jMenu1.add(MenuHistory); + + jMenuBar1.add(jMenu1); + + jMenu2.setText("Options"); + + MenuPreferences.setText("Preferences"); + MenuPreferences.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuPreferencesActionPerformed(evt); + } + }); + jMenu2.add(MenuPreferences); + + MenuQuit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.ALT_DOWN_MASK)); + MenuQuit.setText("Quit"); + MenuQuit.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuQuitActionPerformed(evt); + } + }); + jMenu2.add(MenuQuit); + + jMenuBar1.add(jMenu2); + + jMenu3.setText("About"); + + MenuWebsite.setText("Website"); + MenuWebsite.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuWebsiteActionPerformed(evt); + } + }); + jMenu3.add(MenuWebsite); + + MenuInfoPage.setText("Info"); + MenuInfoPage.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuInfoPageActionPerformed(evt); + } + }); + jMenu3.add(MenuInfoPage); + + MenuShare.setText("Share"); + MenuShare.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuShareActionPerformed(evt); + } + }); + jMenu3.add(MenuShare); + + MenuDonate.setText("Donate"); + + MenuPaypalDonate.setText("Paypal"); + MenuPaypalDonate.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuPaypalDonateActionPerformed(evt); + } + }); + MenuDonate.add(MenuPaypalDonate); + + MenuBuyMeACoffeDonate.setText("Buy me a coffe"); + MenuBuyMeACoffeDonate.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuBuyMeACoffeDonateActionPerformed(evt); + } + }); + MenuDonate.add(MenuBuyMeACoffeDonate); + + jMenu3.add(MenuDonate); + + jMenuBar1.add(jMenu3); + + jMenu5.setText("Help"); + + MenuBugReport.setText("Report a bug"); + MenuBugReport.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuBugReportActionPerformed(evt); + } + }); + jMenu5.add(MenuBugReport); + + MenuSupport.setText("Support"); + MenuSupport.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + MenuSupportActionPerformed(evt); + } + }); + jMenu5.add(MenuSupport); + + jMenuBar1.add(jMenu5); + + setJMenuBar(jMenuBar1); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1) + .addGroup(layout.createSequentialGroup() + .addComponent(addBackupEntryButton, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 9, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(researchField, javax.swing.GroupLayout.PREFERRED_SIZE, 321, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 209, Short.MAX_VALUE) + .addComponent(ExportLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 238, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(exportAsCsvBtn, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(exportAsPdfBtn, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(detailsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(addBackupEntryButton, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(researchField, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(ExportLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(exportAsCsvBtn, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 32, Short.MAX_VALUE) + .addComponent(exportAsPdfBtn, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 32, Short.MAX_VALUE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 377, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(detailsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jLabel3) + .addContainerGap()) + ); + + researchField.getAccessibleContext().setAccessibleName(""); + + pack(); + setLocationRelativeTo(null); + }// </editor-fold>//GEN-END:initComponents + + private void MenuQuitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuQuitActionPerformed + backupManager.menuItemQuit(observer); + }//GEN-LAST:event_MenuQuitActionPerformed + + private void MenuHistoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuHistoryActionPerformed + backupManager.menuItemHistory(); + }//GEN-LAST:event_MenuHistoryActionPerformed + + private void MenuClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuClearActionPerformed + }//GEN-LAST:event_MenuClearActionPerformed + + private void MenuSaveWithNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuSaveWithNameActionPerformed + }//GEN-LAST:event_MenuSaveWithNameActionPerformed + + private void MenuSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuSaveActionPerformed + }//GEN-LAST:event_MenuSaveActionPerformed + + private void MenuNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuNewActionPerformed + backupManager.menuItemNew(progressBar); + }//GEN-LAST:event_MenuNewActionPerformed + + private void EditPoputItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_EditPoputItemActionPerformed + backupManager.popupItemEditBackupName(selectedRow, backupTable, backups); + }//GEN-LAST:event_EditPoputItemActionPerformed + + private void DeletePopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_DeletePopupItemActionPerformed + backupManager.popupItemDelete(selectedRow, backups, backupTable); + }//GEN-LAST:event_DeletePopupItemActionPerformed + + private void researchFieldKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_researchFieldKeyTyped + researchInTable(); + }//GEN-LAST:event_researchFieldKeyTyped + + private void tableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tableMouseClicked + selectedRow = table.rowAtPoint(evt.getPoint()); // get index of the row + + if (selectedRow == -1) { // if clicked outside valid rows + table.clearSelection(); // deselect any selected row + detailsLabel.setText(""); // clear the label + } else { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + backupmanager.Entities.Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + logger.debug("Selected backup: " + backupName); + + // Handling right mouse button click + if (SwingUtilities.isRightMouseButton(evt)) { + logger.info("Right click on row: " + selectedRow); + AutoBackupMenuItem.setSelected(backup.isAutoBackup()); + table.setRowSelectionInterval(selectedRow, selectedRow); // select clicked row + TablePopup.show(evt.getComponent(), evt.getX(), evt.getY()); // show popup + + // check if the backup is running + if (RunningBackups.readBackupFromJSON(backupName) == null) { + DeletePopupItem.setEnabled(true); + interruptBackupPopupItem.setEnabled(false); + } else { + DeletePopupItem.setEnabled(false); + interruptBackupPopupItem.setEnabled(true); + } + } + + // Handling left mouse button double-click + else if (SwingUtilities.isLeftMouseButton(evt) && evt.getClickCount() == 2) { + logger.info("Double-click on row: " + selectedRow); + backupManager.openBackup(backupName); + } + + // Handling single left mouse button click + else if (SwingUtilities.isLeftMouseButton(evt)) { + String backupNameStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.BACKUP_NAME_DETAIL); + String initialPathStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.INITIAL_PATH_DETAIL); + String destinationPathStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.DESTINATION_PATH_DETAIL); + String lastBackupStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.LAST_BACKUP_DETAIL); + String nextBackupStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.NEXT_BACKUP_DATE_DETAIL); + String timeIntervalBackupStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.TIME_INTERVAL_DETAIL); + String creationDateStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.CREATION_DATE_DETAIL); + String lastUpdateDateStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.LAST_UPDATE_DATE_DETAIL); + String backupCountStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.BACKUP_COUNT_DETAIL); + String notesStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.NOTES_DETAIL); + String maxBackupsToKeepStr = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.MAX_BACKUPS_TO_KEEP_DETAIL); + + detailsLabel.setText( + "<html><b>" + backupNameStr + ":</b> " + backup.getBackupName() + ", " + + "<b>" + initialPathStr + ":</b> " + backup.getInitialPath() + ", " + + "<b>" + destinationPathStr + ":</b> " + backup.getDestinationPath() + ", " + + "<b>" + lastBackupStr + ":</b> " + (backup.getLastBackup() != null ? backup.getLastBackup().format(formatter) : "") + ", " + + "<b>" + nextBackupStr + ":</b> " + (backup.getNextDateBackup() != null ? backup.getNextDateBackup().format(formatter) : "_") + ", " + + "<b>" + timeIntervalBackupStr + ":</b> " + (backup.getTimeIntervalBackup() != null ? backup.getTimeIntervalBackup().toString() : "_") + ", " + + "<b>" + creationDateStr + ":</b> " + (backup.getCreationDate() != null ? backup.getCreationDate().format(formatter) : "_") + ", " + + "<b>" + lastUpdateDateStr + ":</b> " + (backup.getLastUpdateDate() != null ? backup.getLastUpdateDate().format(formatter) : "_") + ", " + + "<b>" + backupCountStr + ":</b> " + (backup.getBackupCount()) + ", " + + "<b>" + maxBackupsToKeepStr + ":</b> " + (backup.getMaxBackupsToKeep()) + ", " + + "<b>" + notesStr + ":</b> " + (backup.getNotes()) + + "</html>" + ); + } + } + }//GEN-LAST:event_tableMouseClicked + + private void DuplicatePopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_DuplicatePopupItemActionPerformed + backupManager.popupItemDuplicateBackup(selectedRow, backupTable, backups); + }//GEN-LAST:event_DuplicatePopupItemActionPerformed + + private void RunBackupPopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_RunBackupPopupItemActionPerformed + backupManager.popupItemRunBackup(selectedRow, backupTable, backups, interruptBackupPopupItem, RunBackupPopupItem); + }//GEN-LAST:event_RunBackupPopupItemActionPerformed + + private void CopyBackupNamePopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CopyBackupNamePopupItemActionPerformed + backupManager.popupItemCopyBackupName(selectedRow, backupTable, backups); + }//GEN-LAST:event_CopyBackupNamePopupItemActionPerformed + + private void CopyInitialPathPopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CopyInitialPathPopupItemActionPerformed + backupManager.popupItemCopyInitialPath(selectedRow, backupTable, backups); + }//GEN-LAST:event_CopyInitialPathPopupItemActionPerformed + + private void CopyDestinationPathPopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CopyDestinationPathPopupItemActionPerformed + backupManager.popupItemCopyDestinationPath(selectedRow, backupTable, backups); + }//GEN-LAST:event_CopyDestinationPathPopupItemActionPerformed + + private void AutoBackupMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AutoBackupMenuItemActionPerformed + backupManager.popupItemAutoBackup(selectedRow, backupTable, backups, AutoBackupMenuItem); + }//GEN-LAST:event_AutoBackupMenuItemActionPerformed + + private void OpenInitialFolderItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OpenInitialFolderItemActionPerformed + backupManager.popupItemOpenInitialPath(selectedRow, backupTable, backups); + }//GEN-LAST:event_OpenInitialFolderItemActionPerformed + + private void OpenInitialDestinationItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OpenInitialDestinationItemActionPerformed + backupManager.popupItemOpenDestinationPath(selectedRow, backupTable, backups); + }//GEN-LAST:event_OpenInitialDestinationItemActionPerformed + + private void renamePopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_renamePopupItemActionPerformed + backupManager.popupItemRenameBackup(selectedRow, backupTable, backups); + }//GEN-LAST:event_renamePopupItemActionPerformed + + private void MenuPaypalDonateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuPaypalDonateActionPerformed + backupManager.menuItemDonateViaPaypal(); + }//GEN-LAST:event_MenuPaypalDonateActionPerformed + + private void MenuBugReportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuBugReportActionPerformed + backupManager.menuItemBugReport(); + }//GEN-LAST:event_MenuBugReportActionPerformed + + private void MenuShareActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuShareActionPerformed + backupManager.menuItemShare(); + }//GEN-LAST:event_MenuShareActionPerformed + + private void MenuWebsiteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuWebsiteActionPerformed + backupManager.menuItemWebsite(); + }//GEN-LAST:event_MenuWebsiteActionPerformed + + private void MenuSupportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuSupportActionPerformed + backupManager.menuItemSupport(); + }//GEN-LAST:event_MenuSupportActionPerformed + + private void MenuInfoPageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuInfoPageActionPerformed + backupManager.menuItemInfoPage(); + }//GEN-LAST:event_MenuInfoPageActionPerformed + + private void MenuPreferencesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuPreferencesActionPerformed + backupManager.menuItemOpenPreferences(); + }//GEN-LAST:event_MenuPreferencesActionPerformed + + private void MenuImportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuImportActionPerformed + backups = backupManager.menuItemImportFromJson(); + }//GEN-LAST:event_MenuImportActionPerformed + + private void MenuExportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuExportActionPerformed + backupManager.menuItemExportToJson(); + }//GEN-LAST:event_MenuExportActionPerformed + + private void interruptBackupPopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interruptBackupPopupItemActionPerformed + backupManager.popupItemInterrupt(selectedRow, backupTable, backups, interruptBackupPopupItem, RunBackupPopupItem); + }//GEN-LAST:event_interruptBackupPopupItemActionPerformed + + private void exportAsCsvBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportAsCsvBtnActionPerformed + ImportExportManager.exportAsCSV(new ArrayList<>(backups), backupmanager.Entities.Backup.getCSVHeader()); + }//GEN-LAST:event_exportAsCsvBtnActionPerformed + + private void exportAsPdfBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportAsPdfBtnActionPerformed + ImportExportManager.exportAsPDF(new ArrayList<>(backups), backupmanager.Entities.Backup.getCSVHeader()); + }//GEN-LAST:event_exportAsPdfBtnActionPerformed + + private void addBackupEntryButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addBackupEntryButtonActionPerformed + backupManager.newBackup(progressBar); + }//GEN-LAST:event_addBackupEntryButtonActionPerformed + + private void MenuBuyMeACoffeDonateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuBuyMeACoffeDonateActionPerformed + backupManager.menuItemDonateViaBuymeacoffe(); + }//GEN-LAST:event_MenuBuyMeACoffeDonateActionPerformed + + private void setTranslations() { + // update table translations + if (backups != null) + displayBackupList(); + + // general + jLabel3.setText(TranslationCategory.GENERAL.getTranslation(TranslationKey.VERSION) + " " + currentVersion); + + // menu + jMenu1.setText(TranslationCategory.MENU.getTranslation(TranslationKey.FILE)); + jMenu2.setText(TranslationCategory.MENU.getTranslation(TranslationKey.OPTIONS)); + jMenu3.setText(TranslationCategory.MENU.getTranslation(TranslationKey.ABOUT)); + jMenu5.setText(TranslationCategory.MENU.getTranslation(TranslationKey.HELP)); + + // menu items + MenuBugReport.setText(TranslationCategory.MENU.getTranslation(TranslationKey.BUG_REPORT)); + MenuClear.setText(TranslationCategory.MENU.getTranslation(TranslationKey.CLEAR)); + MenuDonate.setText(TranslationCategory.MENU.getTranslation(TranslationKey.DONATE)); + MenuHistory.setText(TranslationCategory.MENU.getTranslation(TranslationKey.HISTORY)); + MenuInfoPage.setText(TranslationCategory.MENU.getTranslation(TranslationKey.INFO_PAGE)); + MenuNew.setText(TranslationCategory.MENU.getTranslation(TranslationKey.NEW)); + MenuQuit.setText(TranslationCategory.MENU.getTranslation(TranslationKey.QUIT)); + MenuSave.setText(TranslationCategory.MENU.getTranslation(TranslationKey.SAVE)); + MenuSaveWithName.setText(TranslationCategory.MENU.getTranslation(TranslationKey.SAVE_WITH_NAME)); + MenuPreferences.setText(TranslationCategory.MENU.getTranslation(TranslationKey.PREFERENCES)); + MenuImport.setText(TranslationCategory.MENU.getTranslation(TranslationKey.IMPORT)); + MenuExport.setText(TranslationCategory.MENU.getTranslation(TranslationKey.EXPORT)); + MenuShare.setText(TranslationCategory.MENU.getTranslation(TranslationKey.SHARE)); + MenuSupport.setText(TranslationCategory.MENU.getTranslation(TranslationKey.SUPPORT)); + MenuWebsite.setText(TranslationCategory.MENU.getTranslation(TranslationKey.WEBSITE)); + + // backup list + ExportLabel.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.EXPORT_AS)); + addBackupEntryButton.setToolTipText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.ADD_BACKUP_TOOLTIP)); + exportAsPdfBtn.setToolTipText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.EXPORT_AS_PDF_TOOLTIP)); + exportAsCsvBtn.setToolTipText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.EXPORT_AS_CSV_TOOLTIP)); + researchField.setToolTipText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.RESEARCH_BAR_TOOLTIP)); + researchField.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.RESEARCH_BAR_PLACEHOLDER)); + + // popup + CopyBackupNamePopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.COPY_BACKUP_NAME_POPUP)); + CopyDestinationPathPopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.COPY_DESTINATION_PATH_BACKUP)); + RunBackupPopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.SINGLE_BACKUP_POPUP)); + CopyInitialPathPopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.COPY_INITIAL_PATH_POPUP)); + DeletePopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.DELETE_POPUP)); + interruptBackupPopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.INTERRUPT_POPUP)); + DuplicatePopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.DUPLICATE_POPUP)); + EditPoputItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.EDIT_POPUP)); + OpenInitialDestinationItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.OPEN_DESTINATION_FOLDER_POPUP)); + OpenInitialFolderItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.OPEN_INITIAL_FOLDER_POPUP)); + renamePopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.RENAME_BACKUP_POPUP)); + jMenu4.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.COPY_TEXT_POPUP)); + AutoBackupMenuItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.AUTO_BACKUP_POPUP)); + Backup.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.BACKUP_POPUP)); + } + + private String[] getColumnTranslations() { + String[] columnNames = { + TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.BACKUP_NAME_COLUMN), + TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.INITIAL_PATH_COLUMN), + TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.DESTINATION_PATH_COLUMN), + TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.LAST_BACKUP_COLUMN), + TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.AUTOMATIC_BACKUP_COLUMN), + TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.NEXT_BACKUP_DATE_COLUMN), + TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.TIME_INTERVAL_COLUMN) + }; + return columnNames; + } + + private void initializeTable() { + try { + backups = JSONBackup.readBackupListFromJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile()); + displayBackupList(); + } catch (IOException ex) { + backups = null; + logger.error("An error occurred: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + } + + private void setSvgImages() { + exportAsCsvBtn.setSvgImage("res/img/csv.svg", 30, 30); + exportAsPdfBtn.setSvgImage("res/img/pdf.svg", 30, 30); + addBackupEntryButton.setSvgImage("res/img/add.svg", 30, 30); + MenuSave.setSvgImage("res/img/save.svg", 16, 16); + MenuSaveWithName.setSvgImage("res/img/save_as.svg", 16, 16); + MenuImport.setSvgImage("res/img/import.svg", 16, 16); + MenuExport.setSvgImage("res/img/export.svg", 16, 16); + MenuNew.setSvgImage("res/img/new_file.svg", 16, 16); + MenuBugReport.setSvgImage("res/img/bug.svg", 16, 16); + MenuClear.setSvgImage("res/img/clear.svg", 16, 16); + MenuHistory.setSvgImage("res/img/history.svg", 16, 16); + MenuDonate.setSvgImage("res/img/donate.svg", 16, 16); + MenuPaypalDonate.setSvgImage("res/img/paypal.svg", 16, 16); + MenuBuyMeACoffeDonate.setSvgImage("res/img/buymeacoffee.svg", 16, 16); + MenuPreferences.setSvgImage("res/img/settings.svg", 16, 16); + MenuShare.setSvgImage("res/img/share.svg", 16, 16); + MenuSupport.setSvgImage("res/img/support.svg", 16, 16); + MenuWebsite.setSvgImage("res/img/website.svg", 16, 16); + MenuQuit.setSvgImage("res/img/quit.svg", 16, 16); + MenuInfoPage.setSvgImage("res/img/info.svg", 16, 16); + } + + private void initializeMenuItems() { + JSONConfigReader config = new JSONConfigReader(ConfigKey.CONFIG_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); + MenuBugReport.setVisible(config.isMenuItemEnabled(MenuItems.BugReport.name())); + MenuPreferences.setVisible(config.isMenuItemEnabled(MenuItems.Preferences.name())); + MenuClear.setVisible(config.isMenuItemEnabled(MenuItems.Clear.name())); + MenuDonate.setVisible(config.isMenuItemEnabled(MenuItems.Donate.name())); + MenuPaypalDonate.setVisible(config.isMenuItemEnabled(MenuItems.PaypalDonate.name())); + MenuBuyMeACoffeDonate.setVisible(config.isMenuItemEnabled(MenuItems.BuymeacoffeeDonate.name())); + MenuHistory.setVisible(config.isMenuItemEnabled(MenuItems.History.name())); + MenuInfoPage.setVisible(config.isMenuItemEnabled(MenuItems.InfoPage.name())); + MenuNew.setVisible(config.isMenuItemEnabled(MenuItems.New.name())); + MenuQuit.setVisible(config.isMenuItemEnabled(MenuItems.Quit.name())); + MenuSave.setVisible(config.isMenuItemEnabled(MenuItems.Save.name())); + MenuSaveWithName.setVisible(config.isMenuItemEnabled(MenuItems.SaveWithName.name())); + MenuShare.setVisible(config.isMenuItemEnabled(MenuItems.Share.name())); + MenuSupport.setVisible(config.isMenuItemEnabled(MenuItems.Support.name())); + MenuWebsite.setVisible(config.isMenuItemEnabled(MenuItems.Website.name())); + MenuImport.setVisible(config.isMenuItemEnabled(MenuItems.Import.name())); + MenuExport.setVisible(config.isMenuItemEnabled(MenuItems.Export.name())); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JCheckBoxMenuItem AutoBackupMenuItem; + private javax.swing.JMenu Backup; + private javax.swing.JMenuItem CopyBackupNamePopupItem; + private javax.swing.JMenuItem CopyDestinationPathPopupItem; + private javax.swing.JMenuItem CopyInitialPathPopupItem; + private javax.swing.JMenuItem DeletePopupItem; + private javax.swing.JMenuItem DuplicatePopupItem; + private javax.swing.JMenuItem EditPoputItem; + private javax.swing.JLabel ExportLabel; + private backupmanager.svg.SVGMenuItem MenuBugReport; + private backupmanager.svg.SVGMenuItem MenuBuyMeACoffeDonate; + private backupmanager.svg.SVGMenuItem MenuClear; + private backupmanager.svg.SVGMenu MenuDonate; + private backupmanager.svg.SVGMenuItem MenuExport; + private backupmanager.svg.SVGMenuItem MenuHistory; + private backupmanager.svg.SVGMenuItem MenuImport; + private backupmanager.svg.SVGMenuItem MenuInfoPage; + private backupmanager.svg.SVGMenuItem MenuNew; + private backupmanager.svg.SVGMenuItem MenuPaypalDonate; + private backupmanager.svg.SVGMenuItem MenuPreferences; + private backupmanager.svg.SVGMenuItem MenuQuit; + private backupmanager.svg.SVGMenuItem MenuSave; + private backupmanager.svg.SVGMenuItem MenuSaveWithName; + private backupmanager.svg.SVGMenuItem MenuShare; + private backupmanager.svg.SVGMenuItem MenuSupport; + private backupmanager.svg.SVGMenuItem MenuWebsite; + private javax.swing.JMenuItem OpenInitialDestinationItem; + private javax.swing.JMenuItem OpenInitialFolderItem; + private javax.swing.JMenuItem RunBackupPopupItem; + private javax.swing.JPopupMenu TablePopup; + private backupmanager.svg.SVGButton addBackupEntryButton; + private javax.swing.JLabel detailsLabel; + private backupmanager.svg.SVGButton exportAsCsvBtn; + private backupmanager.svg.SVGButton exportAsPdfBtn; + private javax.swing.JMenuItem interruptBackupPopupItem; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel3; + private javax.swing.JMenu jMenu1; + private javax.swing.JMenu jMenu2; + private javax.swing.JMenu jMenu3; + private javax.swing.JMenu jMenu4; + private javax.swing.JMenu jMenu5; + private javax.swing.JMenuBar jMenuBar1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JPopupMenu.Separator jSeparator1; + private javax.swing.JPopupMenu.Separator jSeparator2; + private javax.swing.JPopupMenu.Separator jSeparator3; + private javax.swing.JPopupMenu.Separator jSeparator4; + private javax.swing.JPopupMenu.Separator jSeparator5; + private javax.swing.JMenuItem renamePopupItem; + private javax.swing.JTextField researchField; + private javax.swing.JTable table; + // End of variables declaration//GEN-END:variables +} \ No newline at end of file diff --git a/src/main/java/com/mycompany/autobackupprogram/GUI/BackupProgressGUI.form b/src/main/java/backupmanager/GUI/BackupProgressGUI.form similarity index 90% rename from src/main/java/com/mycompany/autobackupprogram/GUI/BackupProgressGUI.form rename to src/main/java/backupmanager/GUI/BackupProgressGUI.form index 3ca39e9..981a95b 100644 --- a/src/main/java/com/mycompany/autobackupprogram/GUI/BackupProgressGUI.form +++ b/src/main/java/backupmanager/GUI/BackupProgressGUI.form @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" ?> -<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo"> +<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo"> <NonVisualComponents> <Component class="javax.swing.JLabel" name="jLabel4"> <Properties> @@ -9,7 +9,7 @@ </Component> </NonVisualComponents> <Properties> - <Property name="defaultCloseOperation" type="int" value="3"/> + <Property name="defaultCloseOperation" type="int" value="0"/> <Property name="title" type="java.lang.String" value="Backup in progress"/> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[430, 175]"/> @@ -21,7 +21,7 @@ </Properties> <SyntheticProperties> <SyntheticProperty name="formSizePolicy" type="int" value="1"/> - <SyntheticProperty name="generateCenter" type="boolean" value="true"/> + <SyntheticProperty name="generateCenter" type="boolean" value="false"/> </SyntheticProperties> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> @@ -48,11 +48,12 @@ <Component id="closeButton" min="-2" max="-2" attributes="0"/> </Group> <Group type="102" attributes="0"> - <Group type="103" groupAlignment="0" max="-2" attributes="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="fileZippedLabel" min="-2" pref="415" max="-2" attributes="0"/> <Group type="102" attributes="0"> - <Group type="103" groupAlignment="1" max="-2" attributes="0"> - <Component id="loadingMessageLabel" alignment="0" max="32767" attributes="0"/> - <Component id="progressBar" alignment="0" pref="365" max="32767" attributes="0"/> + <Group type="103" groupAlignment="0" max="-2" attributes="0"> + <Component id="progressBar" pref="365" max="32767" attributes="0"/> + <Component id="loadingMessageLabel" max="32767" attributes="0"/> </Group> <EmptySpace min="-2" max="-2" attributes="0"/> <Component id="percentageLabel" min="-2" max="-2" attributes="0"/> @@ -74,7 +75,9 @@ <Component id="initialPathLabel" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="destinationPathLabel" min="-2" max="-2" attributes="0"/> - <EmptySpace pref="43" max="32767" attributes="0"/> + <EmptySpace pref="9" max="32767" attributes="0"/> + <Component id="fileZippedLabel" min="-2" pref="28" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> <Component id="loadingMessageLabel" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Group type="103" groupAlignment="0" max="-2" attributes="0"> @@ -109,7 +112,7 @@ </Component> <Component class="javax.swing.JLabel" name="percentageLabel"> <Properties> - <Property name="text" type="java.lang.String" value="100%"/> + <Property name="text" type="java.lang.String" value="0%"/> </Properties> </Component> <Component class="javax.swing.JButton" name="CancelButton"> @@ -148,5 +151,7 @@ </Property> </Properties> </Component> + <Component class="javax.swing.JLabel" name="fileZippedLabel"> + </Component> </SubComponents> </Form> diff --git a/src/main/java/com/mycompany/autobackupprogram/GUI/BackupProgressGUI.java b/src/main/java/backupmanager/GUI/BackupProgressGUI.java similarity index 80% rename from src/main/java/com/mycompany/autobackupprogram/GUI/BackupProgressGUI.java rename to src/main/java/backupmanager/GUI/BackupProgressGUI.java index 1cf9cfb..21fa566 100644 --- a/src/main/java/com/mycompany/autobackupprogram/GUI/BackupProgressGUI.java +++ b/src/main/java/backupmanager/GUI/BackupProgressGUI.java @@ -1,24 +1,23 @@ -package com.mycompany.autobackupprogram.GUI; +package backupmanager.GUI; -import com.mycompany.autobackupprogram.BackupOperations; -import com.mycompany.autobackupprogram.Enums.ConfigKey; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationCategory; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationKey; +import javax.swing.JOptionPane; import java.awt.Image; import javax.swing.ImageIcon; -import javax.swing.JOptionPane; -import javax.swing.WindowConstants; -public class BackupProgressGUI extends javax.swing.JFrame { +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; +import backupmanager.Services.ZippingThread; + + +public class BackupProgressGUI extends javax.swing.JDialog { public BackupProgressGUI(String initialPath, String destinationPath) { initComponents(); - - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - + // logo application - Image icon = new ImageIcon(this.getClass().getResource(ConfigKey.LOGO_IMG.getValue())).getImage(); - this.setIconImage(icon); + Image icon = new ImageIcon(this.getClass().getResource(ConfigKey.LOGO_IMG.getValue())).getImage(); + this.setIconImage(icon); initialPathLabel.setText(initialPath); destinationPathLabel.setText(destinationPath); @@ -28,14 +27,22 @@ public BackupProgressGUI(String initialPath, String destinationPath) { setTranslations(); } - public void UpdateProgressBar(int value) { + public void updateProgressBar(int value, String fileProcessed, int filesCopiedSoFar, int totalFilesCount) { + // editing the percentage progressBar.setValue(value); percentageLabel.setText(value + " %"); + // editing the current file zipped + fileZippedLabel.setText(fileProcessed); + + // edit the title with counts + setTitle(TranslationCategory.PROGRESS_BACKUP_FRAME.getTranslation(TranslationKey.PROGRESS_BACKUP_TITLE) + " - " + filesCopiedSoFar + "/" + totalFilesCount); + if (value == 100) { loadingMessageLabel.setText(TranslationCategory.PROGRESS_BACKUP_FRAME.getTranslation(TranslationKey.STATUS_COMPLETED)); closeButton.setEnabled(true); CancelButton.setEnabled(false); + fileZippedLabel.setText(""); this.setAlwaysOnTop(true); } } @@ -52,10 +59,11 @@ private void initComponents() { CancelButton = new javax.swing.JButton(); initialPathLabel = new javax.swing.JLabel(); destinationPathLabel = new javax.swing.JLabel(); + fileZippedLabel = new javax.swing.JLabel(); jLabel4.setText("jLabel4"); - setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); setTitle("Backup in progress"); setMaximumSize(new java.awt.Dimension(430, 175)); setMinimumSize(new java.awt.Dimension(430, 175)); @@ -70,7 +78,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { loadingMessageLabel.setText("loading..."); - percentageLabel.setText("100%"); + percentageLabel.setText("0%"); CancelButton.setText("Cancel"); CancelButton.addActionListener(new java.awt.event.ActionListener() { @@ -102,11 +110,12 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(closeButton)) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(fileZippedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 415, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(loadingMessageLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(progressBar, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 365, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 365, Short.MAX_VALUE) + .addComponent(loadingMessageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(percentageLabel)) .addComponent(initialPathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -121,7 +130,9 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addComponent(initialPathLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(destinationPathLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 43, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 9, Short.MAX_VALUE) + .addComponent(fileZippedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(loadingMessageLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) @@ -135,7 +146,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { ); pack(); - setLocationRelativeTo(null); }// </editor-fold>//GEN-END:initComponents private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed @@ -145,7 +155,7 @@ private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F private void CancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CancelButtonActionPerformed int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.INTERRUPT_BACKUP_PROCESS_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (response == JOptionPane.YES_OPTION) { - BackupOperations.StopCopyFiles(); + ZippingThread.stopExecutorService(1); this.dispose(); } }//GEN-LAST:event_CancelButtonActionPerformed @@ -161,6 +171,7 @@ private void setTranslations() { private javax.swing.JButton CancelButton; private javax.swing.JButton closeButton; private javax.swing.JLabel destinationPathLabel; + private javax.swing.JLabel fileZippedLabel; private javax.swing.JLabel initialPathLabel; private javax.swing.JLabel jLabel4; private javax.swing.JLabel loadingMessageLabel; diff --git a/src/main/java/backupmanager/Json/JSONBackup.java b/src/main/java/backupmanager/Json/JSONBackup.java new file mode 100644 index 0000000..045b55a --- /dev/null +++ b/src/main/java/backupmanager/Json/JSONBackup.java @@ -0,0 +1,200 @@ +package backupmanager.Json; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Type; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; + +import backupmanager.Entities.Backup; +import backupmanager.Entities.Preferences; +import backupmanager.Entities.TimeInterval; +import backupmanager.Managers.ExceptionManager; + +public class JSONBackup { + + private static final Logger logger = LoggerFactory.getLogger(JSONBackup.class); + + public static List<Backup> readBackupListFromJSON(String directoryPath, String filename) throws IOException { + List<Backup> backupList = new ArrayList<>(); + + // Check if the directory is correct, otherwise reset to default + File directory = new File(directoryPath); + if (!directory.exists() || !directory.isDirectory()) { + logger.warn("Directory of the backup list file doesn't exist (" + directoryPath + "), reset to default value."); + Preferences.setBackupList(Preferences.getDefaultBackupList()); + Preferences.updatePreferencesToJSON(); + directoryPath = Preferences.getBackupList().getDirectory(); + } + + String filePath = directoryPath + filename; + File file = new File(filePath); + + // Check if the file exists and is not empty + if (!file.exists()) { + file.createNewFile(); + logger.info("New backup list created with name: " + filePath); + } + if (file.length() == 0) { + try (FileWriter writer = new FileWriter(file)) { + writer.write("[]"); + logger.info("File initialized with empty JSON array: []"); + } catch (IOException e) { + logger.error("Error initializing file: " + e.getMessage(), e); + throw e; + } + } + + try (Reader reader = new FileReader(filePath)) { + JsonArray backupArray = JsonParser.parseReader(reader).getAsJsonArray(); + + for (JsonElement element : backupArray) { + JsonObject backupObj = element.getAsJsonObject(); + + String backupNameValue = getStringOrNull(backupObj, "backup_name"); + String startPathValue = getStringOrNull(backupObj, "start_path"); + String destinationPathValue = getStringOrNull(backupObj, "destination_path"); + String lastBackupStr = getStringOrNull(backupObj, "last_backup"); + String notesValue = getStringOrNull(backupObj, "notes"); + String creationDateStr = getStringOrNull(backupObj, "creation_date"); + String lastUpdateDateStr = getStringOrNull(backupObj, "last_update_date"); + int backupCountValue = backupObj.has("backup_count") ? backupObj.get("backup_count").getAsInt() : 0; + int maxBackupsToKeepValue = backupObj.has("max_backups_to_keep") ? backupObj.get("max_backups_to_keep").getAsInt() : 0; + + Boolean automaticBackupValue = backupObj.has("automatic_backup") && !backupObj.get("automatic_backup").isJsonNull() + ? backupObj.get("automatic_backup").getAsBoolean() + : null; + + String nextDateBackupStr = getStringOrNull(backupObj, "next_date_backup"); + String daysIntervalBackupStr = getStringOrNull(backupObj, "time_interval_backup"); + + LocalDateTime lastBackupValue = lastBackupStr != null ? LocalDateTime.parse(lastBackupStr) : null; + LocalDateTime nextDateBackupValue = nextDateBackupStr != null ? LocalDateTime.parse(nextDateBackupStr) : null; + LocalDateTime creationDateValue = creationDateStr != null ? LocalDateTime.parse(creationDateStr) : null; + LocalDateTime lastUpdateDateValue = lastUpdateDateStr != null ? LocalDateTime.parse(lastUpdateDateStr) : null; + + backupList.add(new Backup( + backupNameValue, + startPathValue, + destinationPathValue, + lastBackupValue, + automaticBackupValue, + nextDateBackupValue, + TimeInterval.getTimeIntervalFromString(daysIntervalBackupStr), + notesValue, + creationDateValue, + lastUpdateDateValue, + backupCountValue, + maxBackupsToKeepValue + )); + } + + } catch (IOException | JsonSyntaxException | NullPointerException ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + return backupList; + } + + // Helper method to safely retrieve a string or null + private static String getStringOrNull(JsonObject obj, String property) { + return obj.has(property) && !obj.get(property).isJsonNull() ? obj.get(property).getAsString() : null; + } + + public static void updateBackupListJSON(String directoryPath, String filename, List<Backup> backups) { + String filePath = directoryPath + filename; + + try (Writer writer = new FileWriter(filePath)) { + // Use Gson to convert the list of backups into a JSON array + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + JsonArray updatedBackupArray = new JsonArray(); + + for (Backup backup : backups) { + JsonObject backupObject = new JsonObject(); + backupObject.addProperty("backup_name", backup.getBackupName()); + backupObject.addProperty("start_path", backup.getInitialPath()); + backupObject.addProperty("destination_path", backup.getDestinationPath()); + backupObject.addProperty("last_backup", backup.getLastBackup() != null ? backup.getLastBackup().toString() : null); + backupObject.addProperty("automatic_backup", backup.isAutoBackup()); + backupObject.addProperty("next_date_backup", backup.getNextDateBackup() != null ? backup.getNextDateBackup().toString() : null); + backupObject.addProperty("time_interval_backup", backup.getTimeIntervalBackup() != null ? backup.getTimeIntervalBackup().toString() : null); + backupObject.addProperty("notes", backup.getNotes()); + backupObject.addProperty("creation_date", backup.getCreationDate() != null ? backup.getCreationDate().toString() : null); + backupObject.addProperty("last_update_date", backup.getLastUpdateDate() != null ? backup.getLastUpdateDate().toString() : null); + backupObject.addProperty("backup_count", backup.getBackupCount()); + backupObject.addProperty("max_backups_to_keep", backup.getMaxBackupsToKeep()); + + updatedBackupArray.add(backupObject); + } + + // Write the JSON array to the file + gson.toJson(updatedBackupArray, writer); + } catch (IOException ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + } + + public static void updateSingleBackupInJSON(String directoryPath, String filename, Backup updatedBackup) { + String filePath = directoryPath + filename; + + try (Reader reader = new FileReader(filePath)) { + // Parse JSON file into a list of Backup objects using Gson + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + Type listType = new TypeToken<List<JsonObject>>() {}.getType(); + List<JsonObject> backupList = gson.fromJson(reader, listType); + + // Find and update the specific backup + for (JsonObject backupObject : backupList) { + String backupName = backupObject.get("backup_name").getAsString(); + if (backupName.equals(updatedBackup.getBackupName())) { + backupObject.addProperty("start_path", updatedBackup.getInitialPath()); + backupObject.addProperty("destination_path", updatedBackup.getDestinationPath()); + backupObject.addProperty("last_backup", updatedBackup.getLastBackup() != null ? updatedBackup.getLastBackup().toString() : null); + backupObject.addProperty("automatic_backup", updatedBackup.isAutoBackup()); + backupObject.addProperty("next_date_backup", updatedBackup.getNextDateBackup() != null ? updatedBackup.getNextDateBackup().toString() : null); + backupObject.addProperty("time_interval_backup", updatedBackup.getTimeIntervalBackup() != null ? updatedBackup.getTimeIntervalBackup().toString() : null); + backupObject.addProperty("notes", updatedBackup.getNotes()); + backupObject.addProperty("creation_date", updatedBackup.getCreationDate() != null ? updatedBackup.getCreationDate().toString() : null); + backupObject.addProperty("last_update_date", updatedBackup.getLastUpdateDate() != null ? updatedBackup.getLastUpdateDate().toString() : null); + backupObject.addProperty("backup_count", updatedBackup.getBackupCount()); + backupObject.addProperty("max_backups_to_keep", updatedBackup.getMaxBackupsToKeep()); + break; + } + } + + // Write updated list back to the JSON file + try (Writer writer = new FileWriter(filePath)) { + gson.toJson(backupList, writer); + } catch (IOException ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + + } catch (IOException ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } catch (JsonSyntaxException ex) { + logger.error("Invalid JSON format: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + } +} \ No newline at end of file diff --git a/src/main/java/backupmanager/Json/JSONConfigReader.java b/src/main/java/backupmanager/Json/JSONConfigReader.java new file mode 100644 index 0000000..412f701 --- /dev/null +++ b/src/main/java/backupmanager/Json/JSONConfigReader.java @@ -0,0 +1,95 @@ +package backupmanager.Json; + +import java.io.FileReader; +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + + +public class JSONConfigReader { + private static final Logger logger = LoggerFactory.getLogger(JSONConfigReader.class); + + private final String filename; + private final String directoryPath; + private JsonObject config; + + public JSONConfigReader(String filename, String directoryPath) { + this.filename = filename; + this.directoryPath = directoryPath; + loadConfig(); // Load configuration at instantiation + } + + public boolean isMenuItemEnabled(String menuItem) { + if (config == null) { + logger.warn("Configuration not loaded. Cannot check menu items"); + return false; + } + + JsonObject menuService = config.getAsJsonObject("MenuItems"); + if (menuService != null) { + JsonElement isEnabled = menuService.get(menuItem); + return isEnabled != null && isEnabled.getAsBoolean(); + } + return true; // Default to true + } + public int getMaxCountForSameBackup() { + return getConfigValue("MaxCountForSameBackup", 1); // Default to 1 + } + + public int readCheckForBackupTimeInterval() throws IOException { + try { + JsonObject backupService = getBackupServiceConfig(); + JsonElement interval = backupService.get("value"); + + // if the interval is null, set to default of 5 minutes + int timeInterval = (interval != null) ? interval.getAsInt() : 5; + + logger.info("Time interval set to " + timeInterval + " minutes"); + return timeInterval; + } catch (NullPointerException e) { + logger.error("Error retrieving backup time interval, defaulting to 5 minutes: " + e.getMessage(), e); + return 5; // Default to 5 minutes + } + } + + private int getConfigValue(String key, int defaultValue) { + try { + JsonObject logService = getMaxCountForSameBackupConfig(); + JsonElement value = logService.get(key); + + return (value != null && value.isJsonPrimitive()) ? value.getAsInt() : defaultValue; + } catch (IOException | NullPointerException e) { + logger.error("Error retrieving config value for " + key + ": " + e.getMessage(), e); + return defaultValue; + } + } + + private void loadConfig() { + String filePath = directoryPath + filename; + try (FileReader reader = new FileReader(filePath)) { + Gson gson = new Gson(); + config = gson.fromJson(reader, JsonObject.class); + } catch (IOException e) { + logger.error("Failed to load configuration: " + e.getMessage(), e); + } + } + + private JsonObject getMaxCountForSameBackupConfig() throws IOException { + if (config == null) { + throw new IOException("Configuration not loaded."); + } + return config.getAsJsonObject("MaxCountForSameBackup"); + } + + private JsonObject getBackupServiceConfig() throws IOException { + if (config == null) { + throw new IOException("Configuration not loaded."); + } + return config.getAsJsonObject("BackupService"); + } +} \ No newline at end of file diff --git a/src/main/java/backupmanager/Json/JsonUser.java b/src/main/java/backupmanager/Json/JsonUser.java new file mode 100644 index 0000000..9008da2 --- /dev/null +++ b/src/main/java/backupmanager/Json/JsonUser.java @@ -0,0 +1,86 @@ +package backupmanager.Json; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.util.Arrays; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +import backupmanager.Entities.User; +import backupmanager.Managers.ExceptionManager; + +public class JsonUser { + private static final Logger logger = LoggerFactory.getLogger(JsonUser.class); + + public static User readUserFromJson(String filename, String directoryPath) throws IOException { + User user = null; + String filePath = directoryPath + File.separator + filename; + File file = new File(filePath); + + // Check if the file exists and is not empty + if (!file.exists() || file.length() == 0) { + logger.warn("User file doesn't exist or is empty"); + return null; + } + + try (Reader reader = new FileReader(filePath)) { + JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); + + // Check if "name" and "surname" fields are present and not empty + // I don't care if email is empty. This is not a probelm + String name = jsonObject.has("name") && !jsonObject.get("name").getAsString().isBlank() + ? jsonObject.get("name").getAsString() + : null; + String surname = jsonObject.has("surname") && !jsonObject.get("surname").getAsString().isBlank() + ? jsonObject.get("surname").getAsString() + : null; + String email = jsonObject.has("email") && !jsonObject.get("email").getAsString().isBlank() + ? jsonObject.get("email").getAsString() + : null; + + // Return null if either field is null + if (name == null || surname == null) { + logger.info("User data is incomplete: name or surname is missing"); + return null; + } + + // Create and return a User object + user = new User(name, surname, email); + return user; + } catch (JsonSyntaxException | NullPointerException ex) { + logger.error("An error occurred while parsing the user JSON: " + ex.getMessage(), ex); + return null; + } + } + + public static void writeUserToJson(User user, String filename, String directoryPath) { + String filePath = directoryPath + File.separator + filename; + File file = new File(filePath); + + try (FileWriter writer = new FileWriter(file)) { + Gson gson = new Gson(); + JsonObject jsonObject = new JsonObject(); + + // Populate the JSON object + jsonObject.addProperty("name", user.name != null ? user.name : ""); + jsonObject.addProperty("surname", user.surname != null ? user.surname : ""); + jsonObject.addProperty("email", user.email != null ? user.email : ""); + + // Write JSON to file + writer.write(gson.toJson(jsonObject)); + logger.info("User successfully written to JSON user file with data: " + user.toString()); + } catch (IOException ex) { + logger.error("An error occurred while writing the user JSON: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + } +} \ No newline at end of file diff --git a/src/main/java/backupmanager/LimitDocument.java b/src/main/java/backupmanager/LimitDocument.java new file mode 100644 index 0000000..ab83bd9 --- /dev/null +++ b/src/main/java/backupmanager/LimitDocument.java @@ -0,0 +1,23 @@ +package backupmanager; + +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.PlainDocument; + +public class LimitDocument extends PlainDocument { + private int limit; + + public LimitDocument(int limit) { + this.limit = limit; + } + + @Override + public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException { + if (str == null) return; + + // Controlla che la lunghezza attuale più la nuova non superi il limite + if ((getLength() + str.length()) <= limit) { + super.insertString(offset, str, attr); + } + } +} \ No newline at end of file diff --git a/src/main/java/backupmanager/MainApp.java b/src/main/java/backupmanager/MainApp.java new file mode 100644 index 0000000..e91deef --- /dev/null +++ b/src/main/java/backupmanager/MainApp.java @@ -0,0 +1,62 @@ +package backupmanager; + +import java.io.IOException; +import java.util.Arrays; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.Entities.Preferences; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.TranslationLoaderEnum; +import backupmanager.GUI.BackupManagerGUI; +import backupmanager.Managers.ExceptionManager; + +import backupmanager.Services.BackugrundService; + +public class MainApp { + private static final String CONFIG = "src/main/resources/res/config/config.json"; + private static final Logger logger = LoggerFactory.getLogger(MainApp.class); + + public static void main(String[] args) { + // load config keys + ConfigKey.loadFromJson(CONFIG); + + // load preferred language + try { + Preferences.loadPreferencesFromJSON(); + TranslationLoaderEnum.loadTranslations(ConfigKey.LANGUAGES_DIRECTORY_STRING.getValue() + Preferences.getLanguage().getFileName()); + } catch (IOException ex) { + logger.error("An error occurred during loading preferences: {}", ex.getMessage(), ex); + } + + boolean isBackgroundMode = args.length > 0 && args[0].equalsIgnoreCase("--background"); + + // check argument correction + if (!isBackgroundMode && args.length > 0) { + logger.error("Argument \"{}\" not valid!", args[0]); + throw new IllegalArgumentException("Argument passed is not valid!"); + } + + logger.info("Application started"); + logger.debug("Background mode: {}", isBackgroundMode); + + if (isBackgroundMode) { + logger.info("Backup service starting in the background"); + BackugrundService service = new BackugrundService(); + try { + service.startService(); + } catch (IOException ex) { + logger.error("An error occurred: {}", ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + } + else if (!isBackgroundMode) { + // GUI starting + javax.swing.SwingUtilities.invokeLater(() -> { + BackupManagerGUI gui = new BackupManagerGUI(); + gui.showWindow(); + }); + } + } +} diff --git a/src/main/java/backupmanager/Managers/BackupManager.java b/src/main/java/backupmanager/Managers/BackupManager.java new file mode 100644 index 0000000..58a1d1c --- /dev/null +++ b/src/main/java/backupmanager/Managers/BackupManager.java @@ -0,0 +1,553 @@ +package backupmanager.Managers; + +import java.awt.Desktop; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.io.File; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.BackupOperations; +import backupmanager.Dialogs.BackupEntryDialog; +import backupmanager.Dialogs.PreferencesDialog; +import backupmanager.Dialogs.TimePicker; +import backupmanager.Entities.Backup; +import backupmanager.Entities.Preferences; +import backupmanager.Entities.TimeInterval; +import backupmanager.Entities.ZippingContext; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; +import backupmanager.GUI.BackupManagerGUI; +import backupmanager.GUI.BackupProgressGUI; +import backupmanager.Json.JSONBackup; +import backupmanager.Services.BackupObserver; +import backupmanager.Table.BackupTable; +import backupmanager.Table.TableDataManager; + +public final class BackupManager { + private static final Logger logger = LoggerFactory.getLogger(BackupManager.class); + public static final DateTimeFormatter dateForfolderNameFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH.mm.ss"); + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss"); + + private final BackupManagerGUI main; + + public BackupManager(BackupManagerGUI main) { + this.main = main; + } + + private void renameBackup(List<Backup> backups, Backup backup) { + logger.info("Event --> backup renaming"); + + String backup_name = getBackupName(backups, backup.getBackupName(), false); + if (backup_name == null || backup_name.isEmpty()) return; + + backup.setBackupName(backup_name); + backup.setLastUpdateDate(LocalDateTime.now()); + updateBackupList(backups); + } + + public void openBackup(String backupName) { + logger.info("Event --> opening backup"); + + Backup backup = Backup.getBackupByName(backupName); + + BackupEntryDialog dialog = new BackupEntryDialog(main, false, backup); + dialog.setVisible(true); + } + + public void newBackup(BackupProgressGUI progressBar) { + logger.info("Event --> new backup"); + + BackupEntryDialog dialog = new BackupEntryDialog(main, false); + dialog.setVisible(true); + } + + public static void newBackup(Backup backup) { + List<Backup> backups = getBackupList(); + backups.add(backup); + updateBackupList(backups); + } + + public void deleteBackup(int selectedRow, List<Backup> backups, BackupTable backupTable, boolean isConfermationRequired) { + logger.info("Event --> deleting backup"); + + if (isConfermationRequired) { + int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_MESSAGE_BEFORE_DELETE_BACKUP), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (response != JOptionPane.YES_OPTION) { + return; + } + } + + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + RemoveBackup(backup.getBackupName(), backups); + } + + public void deleteBackup(int selectedRow, List<Backup> backups, BackupTable backupTable) { + logger.info("Event --> deleting backup"); + + if (selectedRow != -1) { + int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_MESSAGE_BEFORE_DELETE_BACKUP), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (response == JOptionPane.YES_OPTION) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(new ArrayList<>(backups), backupName); + + RemoveBackup(backup.getBackupName(), backups); + } + } + } + + public static void RemoveBackup(String backupName) { + List<Backup> backups = getBackupList(); + Backup backup = Backup.getBackupByName(backupName); + RemoveBackup(backup, backups); + } + + public static void RemoveBackup(String backupName, List<Backup> backups) { + Backup backup = Backup.getBackupByName(backupName); + RemoveBackup(backup, backups); + } + + public static void RemoveBackup(Backup backup, List<Backup> backups) { + logger.info("Event --> removing backup" + backupmanager.Entities.Backup.getBackupByName(backups, backup.getBackupName()).toString()); + + // backup list update + for (Backup back : backups) { + if (backup.getBackupName().equals(back.getBackupName())) { + backups.remove(back); + logger.info("Backup removed successfully: " + back.toString()); + break; + } + } + + updateBackupList(backups); + } + + public static void updateBackupList(List<Backup> backups) { + if (backups == null) throw new IllegalArgumentException("Backup list is null!"); + + logger.info("Updating backup list"); + + // update + JSONBackup.updateBackupListJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile(), backups); + + // get the new backup updated + backups = getBackupList(); + + if (BackupManagerGUI.model != null) + TableDataManager.updateTableWithNewBackupList(backups, formatter); + } + + public static void updateBackup(Backup updatedBackup) { + if (updatedBackup == null) throw new IllegalArgumentException("Backup is null!"); + + logger.info("Updating backup: " + updatedBackup.getBackupName()); + + JSONBackup.updateSingleBackupInJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile(), updatedBackup); + List<Backup> backups = getBackupList(); + + if (BackupManagerGUI.model != null) { + TableDataManager.updateTableWithNewBackupList(backups, formatter); + } + } + + private void OpenFolder(String path) { + logger.info("Event --> opening folder"); + + File folder = new File(path); + + // if the object is a file i want to obtain the folder that contains that file + if (folder.exists() && folder.isFile()) { + folder = folder.getParentFile(); + } + + if (folder.exists() && folder.isDirectory()) { + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + try { + desktop.open(folder); + } catch (IOException ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + } else { + logger.warn("Desktop not supported on this operating system"); + } + } else { + logger.warn("The folder does not exist or is invalid"); + + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_FOLDER_NOT_EXISTING), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + } + + private String getBackupName(List<Backup> backups, String oldName, boolean canOverwrite) { + while (true) { + String backupName = JOptionPane.showInputDialog(null, + TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_NAME_INPUT), oldName); + + // If the user cancels the operation + if (backupName == null || backupName.trim().isEmpty()) { + return null; + } + + Optional<Backup> existingBackup = backups.stream() + .filter(b -> b.getBackupName().equals(backupName)) + .findFirst(); + + if (existingBackup.isPresent()) { + if (canOverwrite) { + int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.DUPLICATED_BACKUP_NAME_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + + if (response == JOptionPane.YES_OPTION) { + backups.remove(existingBackup.get()); + return backupName; + } + } else { + logger.warn("Backup name '{}' is already in use", backupName); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_NAME_ALREADY_USED_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + } else { + return backupName; // Return valid name + } + } + } + + public void openBackupEntryDialog() { + BackupEntryDialog dialog = new BackupEntryDialog(main, false); + dialog.setVisible(true); + } + + public static LocalDateTime getNexDateBackup(TimeInterval timeInterval) { + return LocalDateTime.now() + .plusDays(timeInterval.getDays()) + .plusHours(timeInterval.getHours()) + .plusMinutes(timeInterval.getMinutes()); + } + + public static List<Backup> getBackupList() { + try { + List<Backup> backups = JSONBackup.readBackupListFromJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile()); + BackupManagerGUI.backups = backups; // i have to keep update also the backup list in the main panel + return backups; + } catch (IOException e) { + logger.error("An error occurred while trying to get the backup list from json file: " + e.getMessage(), e); + ExceptionManager.openExceptionMessage(e.getMessage(), Arrays.toString(e.getStackTrace())); + } catch (Exception e) { + logger.error("An error occurred: " + e.getMessage(), e); + } + + return null; + } + + // ################################################# Menu Items + + public void menuItemDonateViaBuymeacoffe() { + logger.info("Event --> buymeacoffe donation"); + WebsiteManager.openWebSite(ConfigKey.DONATE_BUYMEACOFFE_LINK.getValue()); + } + + public void menuItemDonateViaPaypal() { + logger.info("Event --> paypal donation"); + WebsiteManager.openWebSite(ConfigKey.DONATE_PAYPAL_LINK.getValue()); + } + + public void menuItemExportToJson() { + logger.info("Event --> exporting backup list"); + ImportExportManager.exportListToJson(); + } + + public List<Backup> menuItemImportFromJson() { + logger.info("Event --> importing backup list"); + return ImportExportManager.importListFromJson(main, formatter); + } + + public void menuItemOpenPreferences() { + logger.info("Event --> opening preferences dialog"); + PreferencesDialog prefs = new PreferencesDialog(main, true, main); + prefs.setVisible(true); + } + + public void menuItemInfoPage() { + logger.info("Event --> shard website"); + WebsiteManager.openWebSite(ConfigKey.INFO_PAGE_LINK.getValue()); + } + + public void menuItemSupport() { + logger.info("Event --> support"); + WebsiteManager.sendEmail(); + } + + public void menuItemWebsite() { + logger.info("Event --> shard website"); + WebsiteManager.openWebSite(ConfigKey.SHARD_WEBSITE.getValue()); + } + + public void menuItemShare() { + logger.info("Event --> share"); + + // pop-up message + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.SHARE_LINK_COPIED_MESSAGE)); + + // copy link to the clipboard + StringSelection stringSelectionObj = new StringSelection(ConfigKey.SHARE_LINK.getValue()); + Clipboard clipboardObj = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboardObj.setContents(stringSelectionObj, null); + } + + public void menuItemBugReport() { + logger.info("Event --> bug report"); + WebsiteManager.openWebSite(ConfigKey.ISSUE_PAGE_LINK.getValue()); + } + + public void menuItemNew(BackupProgressGUI progressBar) { + newBackup(progressBar); + } + + public void menuItemHistory() { + logger.info("Event --> history"); + try { + logger.debug("Opening log file with path: " + ConfigKey.LOG_DIRECTORY_STRING.getValue() + ConfigKey.LOG_FILE_STRING.getValue()); + new ProcessBuilder("notepad.exe", ConfigKey.LOG_DIRECTORY_STRING.getValue() + ConfigKey.LOG_FILE_STRING.getValue()).start(); + } catch (IOException e) { + logger.error("Error opening history file: " + e.getMessage(), e); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_OPEN_HISTORY_FILE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + } + + public void menuItemQuit(BackupObserver observer) { + logger.info("Event --> exit"); + observer.stop(); + System.exit(main.EXIT_ON_CLOSE); + } + + // returns the new time inteval + public static Backup toggleAutomaticBackup(Backup backup) { + logger.info("Event --> automatic backup"); + + if (backup.isAutoBackup()) { + int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_MESSAGE_CANCEL_AUTO_BACKUP), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + if (response != JOptionPane.YES_OPTION) { + return null; + } + + backup.setAutoBackup(false); + backup.setTimeIntervalBackup(null); + backup.setNextDateBackup(null); + backup.setLastUpdateDate(LocalDateTime.now()); + + logger.info("Automatic backup turned off"); + + updateBackup(backup); + return backup; + } + + if(!BackupOperations.CheckInputCorrect(backup.getBackupName(),backup.getInitialPath(), backup.getDestinationPath(), null)) return null; + + // if the file has not been saved you need to save it before setting the auto backup + if(!backup.isAutoBackup() || backup.getNextDateBackup() == null || backup.getTimeIntervalBackup() == null) { + if (backup.getBackupName() == null || backup.getBackupName().isEmpty()) return null; + + // message + TimeInterval timeInterval = openTimePicker(null, null); + if (timeInterval == null) return null; + + //set date for next backup + LocalDateTime nextDateBackup = getNexDateBackup(timeInterval); + + backup.setAutoBackup(true); + backup.setTimeIntervalBackup(timeInterval); + backup.setNextDateBackup(nextDateBackup); + backup.setLastUpdateDate(LocalDateTime.now()); + + logger.info("Automatic backup turned On and next date backup setted to {}", nextDateBackup); + + showMessageActivationAutoBackup(timeInterval, backup.getInitialPath(), backup.getDestinationPath()); + + updateBackup(backup); + return backup; + + } + + return null; + } + + public static TimeInterval openTimePicker(java.awt.Dialog parent, TimeInterval time) { + TimePicker picker = new TimePicker(parent, time, true); + picker.setVisible(true); + return picker.getTimeInterval(); + } + + public static void showMessageActivationAutoBackup(TimeInterval timeInterval, String startPath, String destinationPath) { + String from = TranslationCategory.GENERAL.getTranslation(TranslationKey.FROM); + String to = TranslationCategory.GENERAL.getTranslation(TranslationKey.TO); + String activated = TranslationCategory.DIALOGS.getTranslation(TranslationKey.AUTO_BACKUP_ACTIVATED_MESSAGE); + String setted = TranslationCategory.DIALOGS.getTranslation(TranslationKey.SETTED_EVERY_MESSAGE); + String days = TranslationCategory.DIALOGS.getTranslation(TranslationKey.DAYS_MESSAGE); + + JOptionPane.showMessageDialog(null, + activated + "\n\t" + from + ": " + startPath + "\n\t" + to + ": " + + destinationPath + setted + " " + timeInterval.toString() + days, + "AutoBackup", 1); + } + + + // ################################################# Popup items + public void popupItemInterrupt(int selectedRow, BackupTable backupTable, List<Backup> backups, JMenuItem interruptBackupPopupItem, JMenuItem RunBackupPopupItem) { + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + backupmanager.Entities.Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + ZippingContext context = new ZippingContext(backup, null, backupTable, BackupManagerGUI.progressBar, interruptBackupPopupItem, RunBackupPopupItem); + BackupOperations.interruptBackupProcess(context); + } + } + + public void popupItemRenameBackup(int selectedRow, BackupTable backupTable, List<Backup> backups) { + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + renameBackup(backups, backup); + } + } + + public void popupItemOpenDestinationPath(int selectedRow, BackupTable backupTable, List<Backup> backups) { + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + OpenFolder(backup.getDestinationPath()); + } + } + + public void popupItemOpenInitialPath(int selectedRow, BackupTable backupTable, List<Backup> backups) { + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + OpenFolder(backup.getInitialPath()); + } + } + + public void popupItemAutoBackup(int selectedRow, BackupTable backupTable, List<Backup> backups, JCheckBoxMenuItem autoBackupMenuItem) { + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + autoBackupMenuItem.setSelected(!backup.isAutoBackup()); + toggleAutomaticBackup(backup); + } + } + + public void popupItemCopyDestinationPath(int selectedRow, BackupTable backupTable, List<Backup> backups) { + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + StringSelection selection = new StringSelection(backup.getDestinationPath()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); + } + } + + public void popupItemCopyInitialPath(int selectedRow, BackupTable backupTable, List<Backup> backups) { + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + StringSelection selection = new StringSelection(backup.getInitialPath()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); + } + } + + public void popupItemCopyBackupName(int selectedRow, BackupTable backupTable, List<Backup> backups) { + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + StringSelection selection = new StringSelection(backup.getBackupName()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); + } + } + + public void popupItemRunBackup(int selectedRow, BackupTable backupTable, List<Backup> backups, JMenuItem interruptBackupPopupItem, JMenuItem RunBackupPopupItem) { + if (selectedRow != -1) { + + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + BackupManagerGUI.progressBar = new BackupProgressGUI(backup.getInitialPath(), backup.getDestinationPath()); + + ZippingContext context = new ZippingContext(backup, null, backupTable, BackupManagerGUI.progressBar, interruptBackupPopupItem, RunBackupPopupItem); + BackupOperations.SingleBackup(context); + } + } + + public void popupItemEditBackupName(int selectedRow, BackupTable backupTable, List<Backup> backups) { + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(new ArrayList<>(backups), backupName); + + logger.info("Edit row : " + selectedRow); + openBackup(backup.getBackupName()); + } + } + + public void popupItemDuplicateBackup(int selectedRow, BackupTable backupTable, List<Backup> backups) { + logger.info("Event --> duplicating backup"); + + if (selectedRow != -1) { + // get correct backup + String backupName = (String) backupTable.getValueAt(selectedRow, 0); + Backup backup = backupmanager.Entities.Backup.getBackupByName(backups, backupName); + + LocalDateTime dateNow = LocalDateTime.now(); + Backup newBackup = new Backup( + backup.getBackupName() + "_copy", + backup.getInitialPath(), + backup.getDestinationPath(), + null, + backup.isAutoBackup(), + backup.getNextDateBackup(), + backup.getTimeIntervalBackup(), + backup.getNotes(), + dateNow, + dateNow, + 0, + backup.getMaxBackupsToKeep() + ); + + backups.add(newBackup); + updateBackupList(backups); + } + } + + public void popupItemDelete(int selectedRow, List<Backup> backups, BackupTable backupTable) { + deleteBackup(selectedRow, backups, backupTable); + } +} diff --git a/src/main/java/backupmanager/Managers/ExceptionManager.java b/src/main/java/backupmanager/Managers/ExceptionManager.java new file mode 100644 index 0000000..c8b43d4 --- /dev/null +++ b/src/main/java/backupmanager/Managers/ExceptionManager.java @@ -0,0 +1,84 @@ +package backupmanager.Managers; + +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.datatransfer.StringSelection; + +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.Email.EmailSender; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; + +public class ExceptionManager { + private static final Logger logger = LoggerFactory.getLogger(ExceptionManager.class); + + public static void openExceptionMessage(String errorMessage, String stackTrace) { + Object[] options = {TranslationCategory.GENERAL.getTranslation(TranslationKey.CLOSE_BUTTON), TranslationCategory.DIALOGS.getTranslation(TranslationKey.EXCEPTION_MESSAGE_CLIPBOARD_BUTTON), TranslationCategory.DIALOGS.getTranslation(TranslationKey.EXCEPTION_MESSAGE_REPORT_BUTTON)}; + + if (errorMessage == null) { + errorMessage = ""; + } + + stackTrace = !errorMessage.isEmpty() ? errorMessage + "\n" + stackTrace : errorMessage + stackTrace; + + EmailSender.sendErrorEmail("Critical Error Report", stackTrace); + + String stackTraceMessage = TranslationCategory.DIALOGS.getTranslation(TranslationKey.EXCEPTION_MESSAGE_REPORT_MESSAGE) + "\n" + stackTrace; + + int choice; + + // Set a maximum width for the error message + final int MAX_WIDTH = 500; + + // Keep displaying the dialog until the "Close" option (index 0) is chosen + do { + if (stackTraceMessage.length() > 1500) { + stackTraceMessage = stackTraceMessage.substring(0, 1500) + "..."; + } + + // Create a JTextArea to hold the error message with line wrapping + JTextArea messageArea = new JTextArea(stackTraceMessage); + messageArea.setLineWrap(true); + messageArea.setWrapStyleWord(true); + messageArea.setEditable(false); + messageArea.setColumns(50); // Approximate width, adjust as necessary + + // Limit the maximum width + messageArea.setSize(new Dimension(MAX_WIDTH, Integer.MAX_VALUE)); + messageArea.setPreferredSize(new Dimension(MAX_WIDTH, messageArea.getPreferredSize().height)); + + // Put the JTextArea in a JScrollPane for scrollable display if needed + JScrollPane scrollPane = new JScrollPane(messageArea); + scrollPane.setPreferredSize(new Dimension(MAX_WIDTH, 300)); + + // Display the option dialog with the JScrollPane + String error = TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE); + choice = JOptionPane.showOptionDialog( + null, + scrollPane, // The JScrollPane containing the error message + error, // The error message/title + JOptionPane.DEFAULT_OPTION, // Option type (default option type) + JOptionPane.ERROR_MESSAGE, // Message type (error message icon) + null, // Icon (null means default icon) + options, // The options for the buttons + options[0] // The default option (Close) + ); + + if (choice == 1) { + StringSelection selection = new StringSelection(stackTrace); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); + logger.info("Error text has been copied to the clipboard"); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.EXCEPTION_MESSAGE_CLIPBOARD_MESSAGE)); + } else if (choice == 2) { + WebsiteManager.openWebSite(ConfigKey.ISSUE_PAGE_LINK.getValue()); + } + } while (choice == 1 || choice == 2); + } +} diff --git a/src/main/java/backupmanager/Managers/ImportExportManager.java b/src/main/java/backupmanager/Managers/ImportExportManager.java new file mode 100644 index 0000000..a5bcba9 --- /dev/null +++ b/src/main/java/backupmanager/Managers/ImportExportManager.java @@ -0,0 +1,240 @@ +package backupmanager.Managers; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.filechooser.FileNameExtensionFilter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.layout.Document; +import com.itextpdf.layout.element.Cell; +import com.itextpdf.layout.element.Paragraph; +import com.itextpdf.layout.element.Table; + +import backupmanager.BackupOperations; +import backupmanager.Entities.Backup; +import backupmanager.Entities.BackupList; +import backupmanager.Entities.Preferences; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; +import backupmanager.GUI.BackupManagerGUI; +import backupmanager.Json.JSONBackup; +import backupmanager.Table.TableDataManager; + +public class ImportExportManager { + + private static final Logger logger = LoggerFactory.getLogger(ImportExportManager.class); + + // return the Backup list. Null if the operations fail or cancelled by the user + public static List<Backup> importListFromJson(BackupManagerGUI main, DateTimeFormatter formatter) { + JFileChooser jfc = new JFileChooser(ConfigKey.RES_DIRECTORY_STRING.getValue()); + jfc.setFileSelectionMode(JFileChooser.FILES_ONLY); + + FileNameExtensionFilter jsonFilter = new FileNameExtensionFilter("JSON Files (*.json)", "json"); + jfc.setFileFilter(jsonFilter); + int returnValue = jfc.showSaveDialog(null); + + if (returnValue == JFileChooser.APPROVE_OPTION) { + File selectedFile = jfc.getSelectedFile(); + if (selectedFile.isFile() && selectedFile.getName().toLowerCase().endsWith(".json")) { + logger.info("File imported: " + selectedFile); + + Preferences.setBackupList(new BackupList(selectedFile.getParent()+File.separator, selectedFile.getName())); + Preferences.updatePreferencesToJSON(); + + try { + List<Backup> backups = JSONBackup.readBackupListFromJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile()); + TableDataManager.updateTableWithNewBackupList(backups, formatter); + JOptionPane.showMessageDialog(main, TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_LIST_CORRECTLY_IMPORTED_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_LIST_CORRECTLY_IMPORTED_TITLE), JOptionPane.INFORMATION_MESSAGE); + return backups; + } catch (IOException ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + } + } else { + JOptionPane.showMessageDialog(main, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_WRONG_FILE_EXTENSION_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_WRONG_FILE_EXTENSION_TITLE), JOptionPane.ERROR_MESSAGE); + } + } + + return null; + } + + public static void exportListToJson() { + Path desktopPath = Paths.get(System.getProperty("user.home"), "Desktop", Preferences.getBackupList().getFile()); + Path sourcePath = Paths.get(Preferences.getBackupList().getDirectory() + Preferences.getBackupList().getFile()); + + try { + Files.copy(sourcePath, desktopPath, StandardCopyOption.REPLACE_EXISTING); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_LIST_CORRECTLY_EXPORTED_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_LIST_CORRECTLY_EXPORTED_TITLE), JOptionPane.INFORMATION_MESSAGE); + } catch (java.nio.file.NoSuchFileException ex) { + logger.error("Source file not found: " + ex.getMessage()); + JOptionPane.showMessageDialog(null, "Error: The source file was not found.\nPlease check the file path.", "Export Error", JOptionPane.ERROR_MESSAGE); + } catch (java.nio.file.AccessDeniedException ex) { + logger.error("Access denied to desktop: " + ex.getMessage()); + JOptionPane.showMessageDialog(null, "Error: Access to the Desktop is denied.\nPlease check folder permissions and try again.","Export Error", JOptionPane.ERROR_MESSAGE); + } catch (IOException ex) { + logger.error("Unexpected error: " + ex.getMessage()); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + } + } + + public static void exportAsPDF(ArrayList<Backup> backups, String headers) { + logger.info("Exporting backups to PDF"); + + String path = BackupOperations.pathSearchWithFileChooser(false); + + if (path == null) { + logger.info("Exporting backups to PDF cancelled"); + return; + } + + String filename = JOptionPane.showInputDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.PDF_NAME_MESSAGE_INPUT)); + if (filename == null || filename.isEmpty()) { + logger.info("Exporting backups to PDF cancelled"); + return; + } + + // Validate filename + if (!filename.matches("[a-zA-Z0-9-_ ]+")) { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_INVALID_FILENAME), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + logger.info("Exporting backups to PDF cancelled due to invalid file name"); + return; + } + + // Build full path + String fullPath = Paths.get(path, filename + ".pdf").toString(); + + // Check if the file exists + File file = new File(fullPath); + if (file.exists()) { + int overwrite = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.DUPLICATED_FILE_NAME_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION); + if (overwrite != JOptionPane.YES_OPTION) { + logger.info("Exporting backups to PDF cancelled by user (file exists)"); + return; + } + } + + try { + // Initialize PDF writer + PdfWriter writer = new PdfWriter(fullPath); + PdfDocument pdfDoc = new PdfDocument(writer); + Document document = new Document(pdfDoc); + + // insert pdf title + document.add(new Paragraph(Preferences.getBackupList().getFile()).setFontSize(12f).setBold()); + + // Create table + String[] headerArray = headers.split(","); // Assuming headers are comma-separated + Table table = new Table(headerArray.length); + + // Add header cells + for (String header : headerArray) { + table.addCell(new Cell().add(new Paragraph(header.trim())).setFontSize(8f)); // Wrap the header in a Paragraph + } + + // Add backup data + if (backups != null && !backups.isEmpty()) { + for (Backup backup : backups) { + String[] data = backup.toCsvString().split(","); // Assuming backup data is comma-separated + for (String value : data) { + // new line every 25 characters + for (int i = 0; i < value.length(); i++) { + if (i % 25 == 0) { + value = value.substring(0, i) + "\n" + value.substring(i); + } + } + table.addCell(new Cell().add(new Paragraph(value.trim())).setFontSize(5f)); // Wrap the value in a Paragraph + } + } + } + + // Add table to document + document.add(table); + + // Close document + document.close(); + + // Notify success + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.SUCCESSFULLY_EXPORTED_TO_PDF_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.SUCCESS_GENERIC_TITLE), JOptionPane.INFORMATION_MESSAGE); + + } catch (IOException ex) { + logger.error("Error exporting backups to PDF: " + ex.getMessage(), ex); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_EXPORTING_TO_PDF) + ex.getMessage(), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } finally { + logger.info("Exporting backups to PDF finished"); + } + } + + public static void exportAsCSV(ArrayList<Backup> backups, String header) { + logger.info("Exporting backups to CSV"); + + String path = BackupOperations.pathSearchWithFileChooser(false); + + if (path == null) { + logger.info("Exporting backups to CSV cancelled"); + return; + } + + String filename = JOptionPane.showInputDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CSV_NAME_MESSAGE_INPUT)); + if (filename == null || filename.isEmpty()) { + logger.info("Exporting backups to CSV cancelled"); + return; + } + + // Validate filename + if (!filename.matches("[a-zA-Z0-9-_ ]+")) { + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_INVALID_FILENAME), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + logger.info("Exporting backups to CSV cancelled due to invalid file name"); + return; + } + + // Build full path + String fullPath = Paths.get(path, filename + ".csv").toString(); + + // Check if the file exists + File file = new File(fullPath); + if (file.exists()) { + int overwrite = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.DUPLICATED_FILE_NAME_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION); + if (overwrite != JOptionPane.YES_OPTION) { + logger.info("Exporting backups to CSV cancelled by user (file exists)"); + return; + } + } + + try (FileWriter writer = new FileWriter(fullPath)) { + // Prepare header row + if (header != null && !header.isEmpty()) { + writer.append(header).append("\n"); + } + + // Prepare data rows + if (backups != null && !backups.isEmpty()) { + for (Backup backup : backups) { + writer.append(backup.toCsvString()).append("\n"); + } + } + + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.SUCCESSFULLY_EXPORTED_TO_CSV_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.SUCCESS_GENERIC_TITLE), JOptionPane.INFORMATION_MESSAGE); + } catch (IOException ex) { + logger.error("Error exporting backups to CSV: " + ex.getMessage(), ex); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_EXPORTING_TO_CSV) + ex.getMessage(), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } finally { + logger.info("Exporting backups to CSV finished"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/mycompany/autobackupprogram/Managers/ThemeManager.java b/src/main/java/backupmanager/Managers/ThemeManager.java similarity index 89% rename from src/main/java/com/mycompany/autobackupprogram/Managers/ThemeManager.java rename to src/main/java/backupmanager/Managers/ThemeManager.java index 4ddb7ee..cdebba0 100644 --- a/src/main/java/com/mycompany/autobackupprogram/Managers/ThemeManager.java +++ b/src/main/java/backupmanager/Managers/ThemeManager.java @@ -1,15 +1,17 @@ -package com.mycompany.autobackupprogram.Managers; +package backupmanager.Managers; import java.awt.Component; import java.awt.Dialog; import java.awt.Frame; import java.util.Arrays; -import javax.swing.SwingUtilities; import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import static com.mycompany.autobackupprogram.GUI.BackupManagerGUI.OpenExceptionMessage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.formdev.flatlaf.FlatDarculaLaf; import com.formdev.flatlaf.FlatIntelliJLaf; @@ -21,14 +23,15 @@ import com.formdev.flatlaf.intellijthemes.FlatNordIJTheme; import com.formdev.flatlaf.intellijthemes.FlatSolarizedDarkIJTheme; import com.formdev.flatlaf.intellijthemes.FlatSolarizedLightIJTheme; -import com.mycompany.autobackupprogram.Entities.Preferences; -import com.mycompany.autobackupprogram.Logger; + +import backupmanager.Entities.Preferences; // https://www.formdev.com/flatlaf/#demo // https://www.formdev.com/flatlaf/themes/ // https://github.com/JFormDesigner/FlatLaf/tree/main/flatlaf-intellij-themes public class ThemeManager { + private static final Logger logger = LoggerFactory.getLogger(ThemeManager.class); public static void updateThemeFrame(Frame frame) { updateTheme(); @@ -97,8 +100,8 @@ private static void updateTheme() { } } catch (UnsupportedLookAndFeelException ex) { - Logger.logMessage("Error setting LookAndFeel: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); + logger.error("Error setting LookAndFeel: " + ex.getMessage(), ex); + ExceptionManager.openExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); } } } \ No newline at end of file diff --git a/src/main/java/backupmanager/Managers/WebsiteManager.java b/src/main/java/backupmanager/Managers/WebsiteManager.java new file mode 100644 index 0000000..a115ccb --- /dev/null +++ b/src/main/java/backupmanager/Managers/WebsiteManager.java @@ -0,0 +1,67 @@ +package backupmanager.Managers; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.awt.Desktop; +import javax.swing.JOptionPane; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.TranslationLoaderEnum.TranslationCategory; +import backupmanager.Enums.TranslationLoaderEnum.TranslationKey; + +public class WebsiteManager { + private static final Logger logger = LoggerFactory.getLogger(WebsiteManager.class); + + public static void openWebSite(String reportUrl) { + try { + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + if (desktop.isSupported(Desktop.Action.BROWSE)) { + desktop.browse(new URI(reportUrl)); + } + } + } catch (IOException | URISyntaxException e) { + logger.error("Failed to open the web page: " + e.getMessage(), e); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_OPENING_WEBSITE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + } + + public static void sendEmail() { + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + + if (desktop.isSupported(Desktop.Action.MAIL)) { + String subject = "Support - Backup Manager"; + String mailTo = "mailto:" + ConfigKey.EMAIL.getValue() + "?subject=" + encodeURI(subject); + + try { + URI uri = new URI(mailTo); + desktop.mail(uri); + } catch (IOException | URISyntaxException ex) { + logger.error("Failed to send email: " + ex.getMessage(), ex); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_UNABLE_TO_SEND_EMAIL), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + } else { + logger.warn("Mail action is unsupported in your system's desktop environment."); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_NOT_SUPPORTED_EMAIL), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + } else { + logger.warn("Desktop integration is unsupported on this system."); + JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_NOT_SUPPORTED_EMAIL_GENERIC), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); + } + } + + // Method to properly encode the URI with special characters (spaces, symbols, etc.) + private static String encodeURI(String value) { + try { + return java.net.URLEncoder.encode(value, "UTF-8").replace("+", "%20"); + } catch (IOException e) { + return value; // If encoding fails, return the original value + } + } +} + diff --git a/src/main/java/com/mycompany/autobackupprogram/BackupService.java b/src/main/java/backupmanager/Services/BackugrundService.java similarity index 60% rename from src/main/java/com/mycompany/autobackupprogram/BackupService.java rename to src/main/java/backupmanager/Services/BackugrundService.java index 7c3650d..01ee4ce 100644 --- a/src/main/java/com/mycompany/autobackupprogram/BackupService.java +++ b/src/main/java/backupmanager/Services/BackugrundService.java @@ -1,6 +1,13 @@ -package com.mycompany.autobackupprogram; - -import java.awt.*; +package backupmanager.Services; + +import java.awt.AWTException; +import java.awt.Frame; +import java.awt.Image; +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.SystemTray; +import java.awt.Toolkit; +import java.awt.TrayIcon; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -14,14 +21,23 @@ import javax.swing.JFrame; -import com.mycompany.autobackupprogram.Entities.Backup; -import com.mycompany.autobackupprogram.Entities.Preferences; -import com.mycompany.autobackupprogram.Enums.ConfigKey; -import com.mycompany.autobackupprogram.GUI.BackupManagerGUI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.BackupOperations; +import backupmanager.Entities.Backup; +import backupmanager.Entities.Preferences; +import backupmanager.Entities.RunningBackups; +import backupmanager.Entities.ZippingContext; +import backupmanager.Enums.ConfigKey; +import backupmanager.GUI.BackupManagerGUI; +import backupmanager.Json.JSONBackup; +import backupmanager.Json.JSONConfigReader; + +public class BackugrundService { + private static final Logger logger = LoggerFactory.getLogger(BackugrundService.class); -public class BackupService { private ScheduledExecutorService scheduler; - private final JSONAutoBackup json = new JSONAutoBackup(); private final JSONConfigReader jsonConfig = new JSONConfigReader(ConfigKey.CONFIG_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); private TrayIcon trayIcon = null; private BackupManagerGUI guiInstance = null; @@ -31,6 +47,9 @@ public void startService() throws IOException { createHiddenIcon(); } + // clear running backups json file (if last execution stopped brutally we have to delete the partial backups) + RunningBackups.deletePartialBackupsStuckedJSONFile(); + scheduler = Executors.newSingleThreadScheduledExecutor(); long interval = jsonConfig.readCheckForBackupTimeInterval(); scheduler.scheduleAtFixedRate(new BackupTask(), 0, interval, TimeUnit.MINUTES); @@ -39,10 +58,10 @@ public void startService() throws IOException { } public void stopService() { - Logger.logMessage("Stopping background service", Logger.LogLevel.DEBUG); + logger.debug("Stopping background service"); if (scheduler != null && !scheduler.isShutdown()) { scheduler.shutdownNow(); - Logger.logMessage("Background service stopped", Logger.LogLevel.INFO); + logger.info("Background service stopped"); } if (trayIcon != null) { SystemTray.getSystemTray().remove(trayIcon); @@ -52,7 +71,7 @@ public void stopService() { private void createHiddenIcon() { if (!SystemTray.isSupported()) { - Logger.logMessage("System tray is not supported!", Logger.LogLevel.WARN); + logger.warn("System tray is not supported!"); return; } @@ -72,9 +91,9 @@ private void createHiddenIcon() { try { tray.add(trayIcon); - Logger.logMessage("TrayIcon added", Logger.LogLevel.INFO); + logger.info("TrayIcon added"); } catch (AWTException e) { - Logger.logMessage("TrayIcon could not be added", Logger.LogLevel.ERROR, e); + logger.error("TrayIcon could not be added: " + e.getMessage(), e); } // Listener for click to tray icon @@ -93,7 +112,7 @@ public void mouseClicked(MouseEvent e) { } private void showMainGUI() { - Logger.logMessage("Showing the GUI", Logger.LogLevel.INFO); + logger.info("Showing the GUI"); if (guiInstance == null) { guiInstance = new BackupManagerGUI(); @@ -112,26 +131,39 @@ private void showMainGUI() { class BackupTask implements Runnable { @Override public void run() { - Logger.logMessage("Checking for automatic backup...", Logger.LogLevel.INFO); + logger.debug("Checking for automatic backup..."); try { - List<Backup> backups = json.ReadBackupListFromJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile()); - List<Backup> needsBackup = getBackupsToDo(backups); + List<Backup> backups = JSONBackup.readBackupListFromJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile()); + List<Backup> needsBackup = getBackupsToDo(backups, 1); if (needsBackup != null && !needsBackup.isEmpty()) { - Logger.logMessage("Start backup process.", Logger.LogLevel.INFO); + logger.info("Start backup process."); executeBackups(needsBackup); } else { - Logger.logMessage("No backup needed at this time.", Logger.LogLevel.INFO); + logger.debug("No backup needed at this time."); } } catch (IOException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); + logger.error("An error occurred: " + ex.getMessage(), ex); } } - private List<Backup> getBackupsToDo(List<Backup> backups) { + private List<Backup> getBackupsToDo(List<Backup> backups, int maxBackupsToAdd) { List<Backup> backupsToDo = new ArrayList<>(); + List<RunningBackups> runningBackups = RunningBackups.readBackupListFromJSON(); + for (Backup backup : backups) { - if (backup.getNextDateBackup() != null && backup.getNextDateBackup().isBefore(LocalDateTime.now())) { + + // i have to check that the backup is not running + boolean found = false; + for (RunningBackups running : runningBackups) { + if (backup.getBackupName().equals(running.backupName)){ + found = true; + break; + } + } + + if (!found && maxBackupsToAdd > 0 && backup.isAutoBackup() && backup.getNextDateBackup() != null && backup.getNextDateBackup().isBefore(LocalDateTime.now())) { backupsToDo.add(backup); + maxBackupsToAdd--; } } return backupsToDo; @@ -140,7 +172,8 @@ private List<Backup> getBackupsToDo(List<Backup> backups) { private void executeBackups(List<Backup> backups) { javax.swing.SwingUtilities.invokeLater(() -> { for (Backup backup : backups) { - BackupOperations.SingleBackup(backup, trayIcon, null, null, null); + ZippingContext context = new ZippingContext(backup, trayIcon, null, null, null, null); + BackupOperations.SingleBackup(context); } }); } diff --git a/src/main/java/backupmanager/Services/BackupObserver.java b/src/main/java/backupmanager/Services/BackupObserver.java new file mode 100644 index 0000000..46ef39a --- /dev/null +++ b/src/main/java/backupmanager/Services/BackupObserver.java @@ -0,0 +1,67 @@ +package backupmanager.Services; + +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.Entities.Backup; +import backupmanager.Entities.RunningBackups; +import backupmanager.Enums.BackupStatusEnum; +import backupmanager.Table.TableDataManager; + +/* + * I need a task that constantly checks if there are something running and i can't use a simple method calls instead because + * if a backup starts caused by the BackugroundService and we open the GUI, thre are 2 different instance of this program, + * so we need something like an observer that constantly checks if there are some backups in progress. + */ +public class BackupObserver { + private static final Logger logger = LoggerFactory.getLogger(BackupObserver.class); + + private final ScheduledExecutorService scheduler; + private final DateTimeFormatter formatter; + private final long millisecondsToWait; + + public BackupObserver(DateTimeFormatter formatter, int millisecondsToWait) { + this.millisecondsToWait = millisecondsToWait; + this.formatter = formatter; + this.scheduler = Executors.newSingleThreadScheduledExecutor(); // create single thread + } + + public void start() { + logger.info("Observer for running backups started"); + + RunningBackups.deleteCompletedBackups(); + + scheduler.scheduleAtFixedRate(() -> { + try { + List<RunningBackups> runningBackups = RunningBackups.readBackupListFromJSON(); + if (!runningBackups.isEmpty()) { + logger.debug("Observer has found a running backup"); + + for (RunningBackups backup : runningBackups) { + Backup backupEntity = Backup.getBackupByName(backup.backupName); + + if (backup.progress < 100 && backup.status == BackupStatusEnum.Progress) { + TableDataManager.updateProgressBarPercentage(backupEntity, backup.progress, formatter); + } else { + RunningBackups.deleteCompletedBackup(backup.backupName); + TableDataManager.removeProgressInTheTableAndRestoreAsDefault(backupEntity, formatter); + } + } + } + } catch (Exception ex) { + logger.error("An error occurred: " + ex.getMessage(), ex); + } + }, 0, millisecondsToWait, TimeUnit.MILLISECONDS); // run now and periodically + } + + public void stop() { + logger.info("Observer for running backups stopped"); + scheduler.shutdownNow(); + } +} diff --git a/src/main/java/backupmanager/Services/ZippingThread.java b/src/main/java/backupmanager/Services/ZippingThread.java new file mode 100644 index 0000000..3d4cf38 --- /dev/null +++ b/src/main/java/backupmanager/Services/ZippingThread.java @@ -0,0 +1,161 @@ +package backupmanager.Services; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.BackupOperations; +import backupmanager.Entities.ZippingContext; +import backupmanager.Enums.ErrorTypes; +import backupmanager.ZipFileVisitor; + +public class ZippingThread { + + private static final Logger logger = LoggerFactory.getLogger(ZippingThread.class); + private static ExecutorService executorService = Executors.newSingleThreadExecutor(); + + public static void zipDirectory(String sourceDirectoryPath, String targetZipPath, ZippingContext context) { + logger.info("Starting zipping process"); + + File sourceFile = new File(sourceDirectoryPath.trim()); + File targetFile = new File(targetZipPath.trim()); + + if (!sourceFile.exists()) { + handleError("Source directory does not exist: " + sourceDirectoryPath, ErrorTypes.ZippingIOError, context); + return; + } + + int totalFilesCount = sourceFile.isDirectory() ? countFilesInDirectory(sourceFile) : 1; + + AtomicInteger copiedFilesCount = new AtomicInteger(0); + + // Ensure the executor is not shut down before submitting a task + if (executorService.isShutdown() || executorService.isTerminated()) { + logger.warn("ExecutorService is terminated. Re-creating the executor..."); + executorService = Executors.newSingleThreadExecutor(); // Recreate the executor + } + + executorService.submit(() -> { + try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(targetZipPath))) { + Path sourceDir = Paths.get(sourceDirectoryPath); + + if (sourceFile.isFile()) { + addFileToZip(sourceDirectoryPath, targetZipPath, zipOut, sourceFile.toPath(), sourceFile.getName(), copiedFilesCount, totalFilesCount, context); + } else { + Files.walkFileTree(sourceDir, new ZipFileVisitor(sourceDir, targetFile, zipOut, copiedFilesCount, totalFilesCount, context)); + } + + } catch (IOException e) { + logger.error("I/O error occurred while zipping directory \"" + sourceDirectoryPath + "\"" + e.getMessage(), e); + handleError("I/O error occurred", ErrorTypes.ZippingIOError, context); + } finally { + finalizeProcess(context); + } + }); + } + + private static void handleError(String message, ErrorTypes errorType, ZippingContext context) { + logger.error(message); + BackupOperations.setError(errorType, context.trayIcon, null); + BackupOperations.reEnableButtonsAndTable(context); + } + + private static void finalizeProcess(ZippingContext context) { + logger.info("Finalizing zipping process"); + BackupOperations.reEnableButtonsAndTable(context); + } + + private static void addFileToZip(String sourceDirectoryPath, String destinationDirectoryPath, ZipOutputStream zipOut, Path file, String zipEntryName, AtomicInteger copiedFilesCount, int totalFilesCount, ZippingContext context) throws IOException { + if (zipEntryName == null || zipEntryName.isEmpty()) { + zipEntryName = file.getFileName().toString(); + } + zipOut.putNextEntry(new ZipEntry(zipEntryName)); + try (InputStream in = Files.newInputStream(file)) { + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) > 0) { + zipOut.write(buffer, 0, len); + } + } + zipOut.closeEntry(); + + int filesCopiedSoFar = copiedFilesCount.incrementAndGet(); + int actualProgress = (int) (((double) filesCopiedSoFar / totalFilesCount) * 100); + BackupOperations.UpdateProgressPercentage(actualProgress, sourceDirectoryPath, destinationDirectoryPath, context, zipEntryName, filesCopiedSoFar, totalFilesCount); + } + + private static int countFilesInDirectory(File directory) { + if (directory == null) { + logger.warn("Directory is null"); + return -1; + } + if (!directory.canRead()) { + logger.warn("Unable to read directory: " + directory.getAbsolutePath()); + return -1; + } + File[] files = directory.listFiles(); + if (files == null) { + logger.warn("Unable to list files for directory: " + directory.getAbsolutePath()); + return -1; + } + + int count = 0; + for (File file : files) { + if (file.isFile()) { + count++; + } else if (file.isDirectory()) { + count += countFilesInDirectory(file); // Recursively count files in subdirectories. + } + } + return count; + } + + /** + * Attempts to gracefully stop the given ExecutorService. + * + * @param executor The ExecutorService to shut down. + * @param timeout The maximum time to wait for termination, in seconds. + */ + public static void stopExecutorService(int timeout) { + logger.debug("Stopping zipping executor"); + + if (executorService == null || executorService.isShutdown()) { + logger.debug("executorService == null || executorService.isShutdown()"); + return; + } + + executorService.shutdown(); // Reject new tasks + try { + // Wait for ongoing tasks to complete + if (!executorService.awaitTermination(timeout, TimeUnit.SECONDS)) { + logger.warn("executorService did not terminate in the given time. Forcing shutdown..."); + executorService.shutdownNow(); // Forcefully stop remaining tasks + if (!executorService.awaitTermination(timeout, TimeUnit.SECONDS)) { + logger.warn("executorService did not terminate after forced shutdown"); + } + } + logger.info("Zipping executor stopped"); + } catch (InterruptedException e) { + logger.error("Shutdown process interrupted. Forcing shutdown... With message: " + e.getMessage(), e); + executorService.shutdownNow(); // Forcefully stop tasks on interruption + Thread.currentThread().interrupt(); // Preserve interrupted status + } + } + + public static boolean isInterrupted() { + return executorService.isShutdown() || executorService.isTerminated(); + } +} diff --git a/src/main/java/backupmanager/Table/BackupTable.java b/src/main/java/backupmanager/Table/BackupTable.java new file mode 100644 index 0000000..a819215 --- /dev/null +++ b/src/main/java/backupmanager/Table/BackupTable.java @@ -0,0 +1,53 @@ +package backupmanager.Table; + +import java.awt.Point; + +import javax.swing.JTable; +import javax.swing.event.TableModelEvent; +import javax.swing.table.TableModel; + +public class BackupTable extends JTable { + public BackupTable(TableModel model) { + super(model); + setRowHeight(35); + + //! TODO: I disable table sorting bacause indexes are not correct when is active + //setAutoCreateRowSorter(true); // Enable column sorting + + // Add the TableModelListener to handle updates + getModel().addTableModelListener(e -> { + if (e.getType() == TableModelEvent.UPDATE) { + int row = e.getFirstRow(); + int column = e.getColumn(); + int targetColumnIndex = 3; // Specify the target column index + + // Check if the value in the target column is 0, then set the StripedProgressBarRenderer + if (column == targetColumnIndex) { + Object value = getValueAt(row, column); + if (value instanceof Integer && (Integer) value == 0) { + getColumnModel().getColumn(targetColumnIndex).setCellRenderer(new ProgressBarRenderer()); + revalidate(); // Revalidate the table layout + repaint(); // Repaint the table to reflect the changes + } + } + } + }); + + // Make sure the table is focusable + setFocusable(true); + requestFocusInWindow(); + } + + @Override + public String getToolTipText(java.awt.event.MouseEvent e) { + Point point = e.getPoint(); + int row = rowAtPoint(point); + int col = columnAtPoint(point); + + if (col == 6) { + Object value = getValueAt(row, col); + return value != null ? "dd.HH:mm" : null; + } + return null; + } +} diff --git a/src/main/java/backupmanager/Table/BackupTableModel.java b/src/main/java/backupmanager/Table/BackupTableModel.java new file mode 100644 index 0000000..7d2e73f --- /dev/null +++ b/src/main/java/backupmanager/Table/BackupTableModel.java @@ -0,0 +1,19 @@ +package backupmanager.Table; + +import javax.swing.table.DefaultTableModel; + +public class BackupTableModel extends DefaultTableModel { + public BackupTableModel(Object[] columnNames, int rowCount) { + super(columnNames, rowCount); + } + + @Override + public Class<?> getColumnClass(int columnIndex) { + return columnIndex == 4 ? Boolean.class : super.getColumnClass(columnIndex); + } + + @Override + public boolean isCellEditable(int row, int column) { + return false; + } +} diff --git a/src/main/java/backupmanager/Table/CheckboxCellRenderer.java b/src/main/java/backupmanager/Table/CheckboxCellRenderer.java new file mode 100644 index 0000000..43f0dd7 --- /dev/null +++ b/src/main/java/backupmanager/Table/CheckboxCellRenderer.java @@ -0,0 +1,35 @@ +package backupmanager.Table; + +import java.awt.Color; +import java.awt.Component; +import javax.swing.JCheckBox; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +public class CheckboxCellRenderer extends DefaultTableCellRenderer { + private final JCheckBox checkBox = new JCheckBox(); + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (value instanceof Boolean aBoolean) { + checkBox.setSelected(aBoolean); + checkBox.setHorizontalAlignment(CENTER); + + if (row % 2 == 0) { + checkBox.setBackground(new Color(223, 222, 243)); + } else { + checkBox.setBackground(Color.WHITE); + } + + if (isSelected) { + checkBox.setBackground(table.getSelectionBackground()); + checkBox.setForeground(table.getSelectionForeground()); + } else { + checkBox.setForeground(Color.BLACK); + } + + return checkBox; + } + return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } +} diff --git a/src/main/java/backupmanager/Table/ProgressBarRenderer.java b/src/main/java/backupmanager/Table/ProgressBarRenderer.java new file mode 100644 index 0000000..5f08b81 --- /dev/null +++ b/src/main/java/backupmanager/Table/ProgressBarRenderer.java @@ -0,0 +1,38 @@ +package backupmanager.Table; + +import java.awt.Color; +import java.awt.Component; +import javax.swing.JProgressBar; +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +public class ProgressBarRenderer extends DefaultTableCellRenderer { + private final StripedRowRenderer stripedRowRenderer = new StripedRowRenderer(); + private final JProgressBar progressBar = new JProgressBar(0, 100); + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + // Delegate the striped row coloring logic to the StripedRowRenderer + Component c = stripedRowRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + // If the value is an Integer (assuming progress data), show the progress bar + if (value instanceof Integer) { + progressBar.setValue((Integer) value); + progressBar.setString((Integer) value + "%"); + progressBar.setStringPainted(true); + + // Set the progress bar background color based on the row (even/odd striped rows) + if (row % 2 == 0) { + progressBar.setBackground(new Color(223, 222, 243)); // Even row color for progress bar + } else { + progressBar.setBackground(Color.WHITE); // Odd row color for progress bar + } + + // Return the progress bar component instead of the default cell component + return progressBar; + } + + // Return the default (striped) component for non-progress values + return c; + } +} \ No newline at end of file diff --git a/src/main/java/backupmanager/Table/StripedRowRenderer.java b/src/main/java/backupmanager/Table/StripedRowRenderer.java new file mode 100644 index 0000000..1bfea4e --- /dev/null +++ b/src/main/java/backupmanager/Table/StripedRowRenderer.java @@ -0,0 +1,34 @@ +package backupmanager.Table; + +import java.awt.Color; +import java.awt.Component; + +import javax.swing.JTable; +import javax.swing.table.DefaultTableCellRenderer; + +public class StripedRowRenderer extends DefaultTableCellRenderer { + private final Color evenRowColor = new Color(223, 222, 243); + private final Color oddRowColor = Color.WHITE; + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + // Apply striped row colors + if (row % 2 == 0) { + c.setBackground(evenRowColor); + } else { + c.setBackground(oddRowColor); + } + + // Handle selection + if (isSelected) { + c.setBackground(table.getSelectionBackground()); + c.setForeground(table.getSelectionForeground()); + } else { + c.setForeground(Color.BLACK); + } + + return c; + } +} diff --git a/src/main/java/backupmanager/Table/TableDataManager.java b/src/main/java/backupmanager/Table/TableDataManager.java new file mode 100644 index 0000000..8e19978 --- /dev/null +++ b/src/main/java/backupmanager/Table/TableDataManager.java @@ -0,0 +1,106 @@ +package backupmanager.Table; + +import java.time.format.DateTimeFormatter; +import java.util.List; + +import javax.swing.SwingUtilities; +import javax.swing.table.TableColumnModel; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.Entities.Backup; +import backupmanager.GUI.BackupManagerGUI; + +public class TableDataManager { + + private static final Logger logger = LoggerFactory.getLogger(TableDataManager.class); + + public static void removeProgressInTheTableAndRestoreAsDefault(Backup backup, DateTimeFormatter formatter) { + if (backup == null) throw new IllegalArgumentException("Backup cannot be null"); + if (formatter == null) throw new IllegalArgumentException("Formatter cannot be null"); + + if (BackupManagerGUI.backupTable == null) { + return; + } + + // remove the progress bar renderer + BackupManagerGUI.backupTable.getColumnModel().getColumn(3).setCellRenderer(new StripedRowRenderer()); + + // Set last backup value in the table + BackupManagerGUI.backupTable.getModel().setValueAt( + backup.getLastBackup() != null ? backup.getLastBackup().format(formatter) : "", + TableDataManager.findBackupRowIndex(backup, BackupManagerGUI.backupTable), 3); + + BackupManagerGUI.backupTable.repaint(); // Repaints the whole table + BackupManagerGUI.backupTable.revalidate(); // Revalidates the table layout + } + + public static void updateProgressBarPercentage(Backup backup, int value, DateTimeFormatter formatter) { + if (backup == null) throw new IllegalArgumentException("Backup cannot be null"); + if (value < 0 || value > 100) throw new IllegalArgumentException("Value must be between 0 and 100"); + if (formatter == null) throw new IllegalArgumentException("Formatter cannot be null"); + + if (BackupManagerGUI.backupTable == null) { + return; + } + + SwingUtilities.invokeLater(() -> { + // Locate the row index of the backup in the table + int rowIndex = TableDataManager.findBackupRowIndex(backup, BackupManagerGUI.backupTable); + if (rowIndex != -1) { + TableColumnModel columnModel = BackupManagerGUI.backupTable.getColumnModel(); + int targetColumnIndex = 3; + + columnModel.getColumn(targetColumnIndex).setCellRenderer(new ProgressBarRenderer()); + + // Restore the original renderer after completion + if (value == 100) { + logger.debug("Restore the original renderer after completion"); + BackupManagerGUI.backupTable.getModel().setValueAt( + backup.getLastBackup() != null ? backup.getLastBackup().format(formatter) : "", + rowIndex, + targetColumnIndex + ); + } else { + // Update the value of the progress in the table + BackupManagerGUI.backupTable.getModel().setValueAt(value, rowIndex, targetColumnIndex); + } + + BackupManagerGUI.backupTable.repaint(); + } + }); + } + + public static void updateTableWithNewBackupList(List<Backup> updatedBackups, DateTimeFormatter formatter) { + logger.debug("updating backup list"); + + SwingUtilities.invokeLater(() -> { + BackupManagerGUI.model.setRowCount(0); + + for (Backup backup : updatedBackups) { + BackupManagerGUI.model.addRow(new Object[]{ + backup.getBackupName(), + backup.getInitialPath(), + backup.getDestinationPath(), + backup.getLastBackup() != null ? backup.getLastBackup().format(formatter) : "", + backup.isAutoBackup(), + backup.getNextDateBackup() != null ? backup.getNextDateBackup().format(formatter) : "", + backup.getTimeIntervalBackup() != null ? backup.getTimeIntervalBackup().toString() : "" + }); + } + }); + } + + private static int findBackupRowIndex(Backup backup, BackupTable table) { + if (backup == null) throw new IllegalArgumentException("Backup cannot be null"); + if (table == null) throw new IllegalArgumentException("Table cannot be null"); + + for (int i = 0; i < table.getRowCount(); i++) { + if (table.getValueAt(i, 0).equals(backup.getBackupName())) { // first column holds unique backup names + return i; + } + } + return -1; + } +} diff --git a/src/main/java/backupmanager/ZipFileVisitor.java b/src/main/java/backupmanager/ZipFileVisitor.java new file mode 100644 index 0000000..eadb32c --- /dev/null +++ b/src/main/java/backupmanager/ZipFileVisitor.java @@ -0,0 +1,91 @@ +package backupmanager; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +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.util.concurrent.atomic.AtomicInteger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import backupmanager.Entities.RunningBackups; +import backupmanager.Entities.ZippingContext; + +public class ZipFileVisitor extends SimpleFileVisitor<Path> { + private static final Logger logger = LoggerFactory.getLogger(ZipFileVisitor.class); + private final Path sourceDir; + private final File destinationDir; + private final ZipOutputStream zipOut; + private final AtomicInteger copiedFilesCount; + private final int totalFilesCount; + private final ZippingContext context; + + public ZipFileVisitor(Path sourceDir, File destinationDIr, ZipOutputStream zipOut, AtomicInteger copiedFilesCount, int totalFilesCount, ZippingContext context) { + this.sourceDir = sourceDir; + this.destinationDir = destinationDIr; + this.zipOut = zipOut; + this.copiedFilesCount = copiedFilesCount; + this.totalFilesCount = totalFilesCount; + this.context = context; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + if (Thread.currentThread().isInterrupted()) { + RunningBackups.updateBackupStatusAfterCompletition(context.backup.getBackupName()); + logger.info("Zipping process manually interrupted"); + return FileVisitResult.TERMINATE; + } + + String zipEntryName = sourceDir.relativize(dir).toString() + "/"; + logger.debug("Adding directory to zip: " + zipEntryName); + + zipOut.putNextEntry(new ZipEntry(zipEntryName)); + zipOut.closeEntry(); + + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (Thread.currentThread().isInterrupted()) { + RunningBackups.updateBackupStatusAfterCompletition(context.backup.getBackupName()); + logger.info("Zipping process manually interrupted"); + return FileVisitResult.TERMINATE; + } + + String zipEntryName = sourceDir.relativize(file).toString(); + logger.debug("Adding file to zip: " + zipEntryName); + + zipOut.putNextEntry(new ZipEntry(zipEntryName)); + + try (InputStream in = Files.newInputStream(file)) { + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) > 0) { + zipOut.write(buffer, 0, len); + } + } + + zipOut.closeEntry(); + + int filesCopiedSoFar = copiedFilesCount.incrementAndGet(); + int actualProgress = (int) (((double) filesCopiedSoFar / totalFilesCount) * 100); + BackupOperations.UpdateProgressPercentage(actualProgress, sourceDir.toString(), destinationDir.toString(), context, zipEntryName, filesCopiedSoFar, totalFilesCount); + + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + logger.error("Failed to visit file: " + file + ". Error: " + exc.getMessage(), exc); + return FileVisitResult.CONTINUE; + } +} diff --git a/src/main/java/backupmanager/svg/SVGButton.java b/src/main/java/backupmanager/svg/SVGButton.java new file mode 100644 index 0000000..f2176fc --- /dev/null +++ b/src/main/java/backupmanager/svg/SVGButton.java @@ -0,0 +1,21 @@ +package backupmanager.svg; + +import java.awt.Cursor; + +import javax.swing.JButton; + +import com.formdev.flatlaf.extras.FlatSVGIcon; + +public class SVGButton extends JButton { + + public SVGButton() { + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + + public void setSvgImage(String imagePath, int width, int height) { + if (imagePath == null) return; + + FlatSVGIcon svgIcon = SVGManager.applySvgColor(imagePath, width, height, getBackground()); + setIcon(svgIcon); + } +} diff --git a/src/main/java/backupmanager/svg/SVGManager.java b/src/main/java/backupmanager/svg/SVGManager.java new file mode 100644 index 0000000..275917f --- /dev/null +++ b/src/main/java/backupmanager/svg/SVGManager.java @@ -0,0 +1,35 @@ +package backupmanager.svg; + +import java.awt.Color; +import java.awt.Component; + +import com.formdev.flatlaf.extras.FlatSVGIcon; + +public class SVGManager extends Component { + + // to update dinamically the svg color + public static FlatSVGIcon applySvgColor(String svgImagePath, int svgWidth, int svgHeight, Color color) { + Color contrastColor = getContrastingColor(color); // get contstrasting color based of the bg color + FlatSVGIcon svgIcon = new FlatSVGIcon(svgImagePath, svgWidth, svgHeight); + + // color filter + svgIcon.setColorFilter(new FlatSVGIcon.ColorFilter() { + @Override + public Color filter(Color color) { + return contrastColor; // apply contrasting color + } + }); + + return svgIcon; + } + + public static Color getContrastingColor(Color bgColor) { + int brightness = (int) Math.sqrt( + bgColor.getRed() * bgColor.getRed() * 0.241 + + bgColor.getGreen() * bgColor.getGreen() * 0.691 + + bgColor.getBlue() * bgColor.getBlue() * 0.068 + ); + + return (brightness > 130) ? Color.BLACK : Color.WHITE; + } +} diff --git a/src/main/java/backupmanager/svg/SVGMenu.java b/src/main/java/backupmanager/svg/SVGMenu.java new file mode 100644 index 0000000..e73f68f --- /dev/null +++ b/src/main/java/backupmanager/svg/SVGMenu.java @@ -0,0 +1,14 @@ +package backupmanager.svg; + +import com.formdev.flatlaf.extras.FlatSVGIcon; +import javax.swing.JMenu; + +public class SVGMenu extends JMenu { + + public void setSvgImage(String imagePath, int width, int height) { + if (imagePath == null) return; + + FlatSVGIcon svgIcon = SVGManager.applySvgColor(imagePath, width, height, getBackground()); + setIcon(svgIcon); + } +} diff --git a/src/main/java/backupmanager/svg/SVGMenuItem.java b/src/main/java/backupmanager/svg/SVGMenuItem.java new file mode 100644 index 0000000..8a58886 --- /dev/null +++ b/src/main/java/backupmanager/svg/SVGMenuItem.java @@ -0,0 +1,15 @@ +package backupmanager.svg; + +import javax.swing.JMenuItem; + +import com.formdev.flatlaf.extras.FlatSVGIcon; + +public class SVGMenuItem extends JMenuItem { + + public void setSvgImage(String imagePath, int width, int height) { + if (imagePath == null) return; + + FlatSVGIcon svgIcon = SVGManager.applySvgColor(imagePath, width, height, getBackground()); + setIcon(svgIcon); + } +} diff --git a/src/main/java/com/mycompany/autobackupprogram/BackupOperations.java b/src/main/java/com/mycompany/autobackupprogram/BackupOperations.java deleted file mode 100644 index 979126c..0000000 --- a/src/main/java/com/mycompany/autobackupprogram/BackupOperations.java +++ /dev/null @@ -1,426 +0,0 @@ -package com.mycompany.autobackupprogram; - -import static com.mycompany.autobackupprogram.GUI.BackupManagerGUI.OpenExceptionMessage; -import static com.mycompany.autobackupprogram.GUI.BackupManagerGUI.dateForfolderNameFormatter; -import static com.mycompany.autobackupprogram.GUI.BackupManagerGUI.formatter; - -import java.awt.TrayIcon; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.time.LocalDateTime; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -import javax.swing.JButton; -import javax.swing.JOptionPane; -import javax.swing.JToggleButton; -import javax.swing.SwingUtilities; - -import com.mycompany.autobackupprogram.Entities.Backup; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationCategory; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationKey; -import com.mycompany.autobackupprogram.Entities.Preferences; -import com.mycompany.autobackupprogram.GUI.BackupManagerGUI; -import com.mycompany.autobackupprogram.GUI.BackupProgressGUI; -import com.mycompany.autobackupprogram.Entities.TimeInterval; -import com.mycompany.autobackupprogram.Logger.LogLevel; - -public class BackupOperations { - - private static final JSONAutoBackup JSON = new JSONAutoBackup(); - private static Thread zipThread; - - public static void SingleBackup(Backup backup, TrayIcon trayIcon, BackupProgressGUI progressBar, JButton singleBackupBtn, JToggleButton autoBackupBtn) { - if (backup == null) throw new IllegalArgumentException("Backup cannot be null!"); - - Logger.logMessage("Event --> automatic single backup started", Logger.LogLevel.INFO); - - if (singleBackupBtn != null) singleBackupBtn.setEnabled(false); - if (autoBackupBtn != null) autoBackupBtn.setEnabled(false); - - try { - String temp = "\\"; - String path1 = backup.getInitialPath(); - String path2 = backup.getDestinationPath(); - - if(!CheckInputCorrect(backup.getBackupName(), path1, path2, trayIcon)) return; - - LocalDateTime dateNow = LocalDateTime.now(); - String date = dateNow.format(dateForfolderNameFormatter); - String name1 = path1.substring(path1.length()-1, path1.length()-1); - - for(int i = path1.length() - 1; i >= 0; i--) { - if(path1.charAt(i) != temp.charAt(0)) name1 = path1.charAt(i) + name1; - else break; - } - - name1 = removeExtension(name1); - - path2 = path2 + "\\" + name1 + " (Backup " + date + ")"; - - zipDirectory(path1, path2+".zip", backup, trayIcon, progressBar, singleBackupBtn, autoBackupBtn); - } catch (IOException e) { - Logger.logMessage("Error during the backup operation: the initial path is incorrect!", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_INCORRECT_INITIAL_PATH), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - if (singleBackupBtn != null) singleBackupBtn.setEnabled(true); - if (autoBackupBtn != null) autoBackupBtn.setEnabled(true); - } catch (Exception ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - if (singleBackupBtn != null) singleBackupBtn.setEnabled(true); - if (autoBackupBtn != null) autoBackupBtn.setEnabled(true); - } - } - - public static String removeExtension(String fileName) { - int dotIndex = fileName.lastIndexOf('.'); - if (dotIndex > 0) { - return fileName.substring(0, dotIndex); - } - return fileName; - } - - private static void updateAfterBackup(String path1, String path2, Backup backup, TrayIcon trayIcon, JButton singleBackupBtn, JToggleButton autoBackupBtn) { - if (backup == null) throw new IllegalArgumentException("Backup cannot be null!"); - if (path1 == null) throw new IllegalArgumentException("Initial path cannot be null!"); - if (path2 == null) throw new IllegalArgumentException("Destination path cannot be null!"); - - LocalDateTime dateNow = LocalDateTime.now(); - - Logger.logMessage("Backup completed!", Logger.LogLevel.INFO); - - if (singleBackupBtn != null) singleBackupBtn.setEnabled(true); - if (autoBackupBtn != null) autoBackupBtn.setEnabled(true); - - // next day backup update - if (backup.isAutoBackup() == true) { - TimeInterval time = backup.getTimeIntervalBackup(); - LocalDateTime nextDateBackup = dateNow.plusDays(time.getDays()) - .plusHours(time.getHours()) - .plusMinutes(time.getMinutes()); - backup.setNextDateBackup(nextDateBackup); - Logger.logMessage("Next date backup setted to: " + nextDateBackup, Logger.LogLevel.INFO); - } - backup.setLastBackup(dateNow); - backup.setBackupCount(backup.getBackupCount()+1); - - try { - List<Backup> backups = JSON.ReadBackupListFromJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile()); - - for (Backup b : backups) { - if (b.getBackupName().equals(backup.getBackupName())) { - b.UpdateBackup(backup); - break; - } - } - - updateBackup(backups, backup); - - if (trayIcon != null) { - trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backup.getBackupName() + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.SUCCESS_MESSAGE) + "\n" + TranslationCategory.GENERAL.getTranslation(TranslationKey.FROM) + ": " + path1 + "\n" + TranslationCategory.GENERAL.getTranslation(TranslationKey.TO) + ": " + path2, TrayIcon.MessageType.INFO); - } - } catch (IllegalArgumentException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } catch (Exception e) { - Logger.logMessage("Error saving file", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_SAVING_FILE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - } - - public static boolean CheckInputCorrect(String backupName, String path1, String path2, TrayIcon trayIcon) { - //check if inputs are null - if(path1.length() == 0 || path2.length() == 0) { - Logger.logMessage("Input Missing!", Logger.LogLevel.WARN); - - if (trayIcon != null) { - trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_INPUT_MISSING), TrayIcon.MessageType.ERROR); - } else { - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_INPUT_MISSING_GENERIC), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - return false; - } - - if (!Files.exists(Path.of(path1)) || !Files.exists(Path.of(path2))) { - Logger.logMessage("Input Error! One or both paths do not exist.", Logger.LogLevel.WARN); - - if (trayIcon != null) { - trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_FILES_NOT_EXISTING), TrayIcon.MessageType.ERROR); - } else { - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_PATH_NOT_EXISTING), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - return false; - } - - if (path1.equals(path2)) { - Logger.logMessage("The initial path and destination path cannot be the same. Please choose different paths", Logger.LogLevel.WARN); - - if (trayIcon != null) { - trayIcon.displayMessage(TranslationCategory.GENERAL.getTranslation(TranslationKey.APP_NAME), TranslationCategory.GENERAL.getTranslation(TranslationKey.BACKUP) + ": " + backupName + TranslationCategory.TRAY_ICON.getTranslation(TranslationKey.ERROR_MESSAGE_SAME_PATHS), TrayIcon.MessageType.ERROR); - } else { - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_SAME_PATHS_GENERIC), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - return false; - } - - return true; - } - - public static void zipDirectory(String sourceDirectoryPath, String targetZipPath, Backup backup, TrayIcon trayIcon, BackupProgressGUI progressBar, JButton singleBackupBtn, JToggleButton autoBackupBtn) throws IOException { // Track copied files - Logger.logMessage("Starting zipping process", LogLevel.INFO); - - File file = new File(sourceDirectoryPath.trim()); - - int totalFilesCount = file.isDirectory() ? countFilesInDirectory(file) : 1; - AtomicInteger copiedFilesCount = new AtomicInteger(0); - - zipThread = new Thread(() -> { - Path sourceDir = Paths.get(sourceDirectoryPath); - String rootFolderName = sourceDir.getFileName().toString(); // Get the root folder name - - try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(targetZipPath))) { - if (file.isFile()) { - addFileToZip(sourceDirectoryPath, targetZipPath, zipOut, file.toPath(), file.getName(), copiedFilesCount, totalFilesCount, backup, trayIcon, progressBar, singleBackupBtn, autoBackupBtn); - } else { - Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (Thread.currentThread().isInterrupted()) { - Logger.logMessage("Zipping process manually interrupted", Logger.LogLevel.INFO); - if (singleBackupBtn != null) singleBackupBtn.setEnabled(true); - if (autoBackupBtn != null) autoBackupBtn.setEnabled(true); - return FileVisitResult.TERMINATE; // Stop if interrupted - } - - // Calculate the relative path inside the zip - Path targetFilePath = sourceDir.relativize(file); - String zipEntryName = rootFolderName + "/" + targetFilePath.toString(); - - // Create a new zip entry for the file - zipOut.putNextEntry(new ZipEntry(zipEntryName)); - - // Copy the file content to the zip output stream - try (InputStream in = Files.newInputStream(file)) { - byte[] buffer = new byte[1024]; - int len; - while ((len = in.read(buffer)) > 0) { - zipOut.write(buffer, 0, len); - } - } - - zipOut.closeEntry(); // Close the zip entry after the file is written - - // Update progress - int filesCopiedSoFar = copiedFilesCount.incrementAndGet(); - int actualProgress = (int) (((double) filesCopiedSoFar / totalFilesCount) * 100); - UpdateProgressPercentage(actualProgress, sourceDirectoryPath, targetZipPath, backup, trayIcon, progressBar, singleBackupBtn, autoBackupBtn); // Update progress percentage - - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - if (Thread.currentThread().isInterrupted()) { - Logger.logMessage("Zipping process manually interrupted", Logger.LogLevel.INFO); - if (singleBackupBtn != null) singleBackupBtn.setEnabled(true); - if (autoBackupBtn != null) autoBackupBtn.setEnabled(true); - return FileVisitResult.TERMINATE; // Stop if interrupted - } - - // case when the initial folder is empty - if (totalFilesCount == 0) { - UpdateProgressPercentage(100, sourceDirectoryPath, targetZipPath, backup, trayIcon, progressBar, singleBackupBtn, autoBackupBtn); - return FileVisitResult.TERMINATE; - } - - // Create directory entry in the zip if needed - Path targetDir = sourceDir.relativize(dir); - zipOut.putNextEntry(new ZipEntry(rootFolderName + "/" + targetDir.toString() + "/")); - zipOut.closeEntry(); - return FileVisitResult.CONTINUE; - } - }); - } - } catch (Exception ex) { - Logger.logMessage("An error occurred: " + ex.getMessage() , Logger.LogLevel.ERROR, ex); - ex.printStackTrace(); - } finally { - if (singleBackupBtn != null) singleBackupBtn.setEnabled(true); - if (autoBackupBtn != null) autoBackupBtn.setEnabled(true); - } - }); - - zipThread.start(); // Start the zipping thread - } - - private static void addFileToZip(String sourceDirectoryPath, String destinationDirectoryPath, ZipOutputStream zipOut, Path file, String zipEntryName, AtomicInteger copiedFilesCount, int totalFilesCount, Backup backup, TrayIcon trayIcon, BackupProgressGUI progressBar, JButton singleBackupBtn, JToggleButton autoBackupBtn) throws IOException { - if (zipEntryName == null || zipEntryName.isEmpty()) { - zipEntryName = file.getFileName().toString(); - } - zipOut.putNextEntry(new ZipEntry(zipEntryName)); - try (InputStream in = Files.newInputStream(file)) { - byte[] buffer = new byte[1024]; - int len; - while ((len = in.read(buffer)) > 0) { - zipOut.write(buffer, 0, len); - } - } - zipOut.closeEntry(); - - int filesCopiedSoFar = copiedFilesCount.incrementAndGet(); - int actualProgress = (int) (((double) filesCopiedSoFar / totalFilesCount) * 100); - UpdateProgressPercentage(actualProgress, sourceDirectoryPath, destinationDirectoryPath, backup, trayIcon, progressBar, singleBackupBtn, autoBackupBtn); - } - - public static void updateBackupList(List<Backup> backups) { - if (backups == null) throw new IllegalArgumentException("Backup list is null!"); - - JSON.UpdateBackupListJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile(), backups); - - if (BackupManagerGUI.model != null) - updateTableWithNewBackupList(backups); - } - - public static void updateBackup(List<Backup> backups, Backup updatedBackup) { - if (updatedBackup == null) throw new IllegalArgumentException("Backup is null!"); - - JSON.UpdateSingleBackupInJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile(), updatedBackup); - - if (BackupManagerGUI.model != null) - updateTableWithNewBackupList(backups); - } - - public static void UpdateProgressPercentage(int value, String path1, String path2, Backup backup, TrayIcon trayIcon, BackupProgressGUI progressBar, JButton singleBackupBtn, JToggleButton autoBackupBtn) { - if (value == 0 || value == 25 || value == 50 || value == 75 || value == 100) - Logger.logMessage("Progress: " + value, Logger.LogLevel.INFO); - - if (progressBar != null) - progressBar.UpdateProgressBar(value); - - if (value == 100) { - updateAfterBackup(path1, path2, backup, trayIcon, singleBackupBtn, autoBackupBtn); - - // delete - deleteOldBackupsIfNecessary(backup.getMaxBackupsToKeep(), path2); - } - } - - private static void deleteOldBackupsIfNecessary(int maxBackupsToKeep, String destinationPath) { - Logger.logMessage("Deleting old backups if necessary", LogLevel.INFO); - - File folder = new File(destinationPath).getParentFile(); - String fileBackuppedToSearch = new File(destinationPath).getName(); - - // extract the file name (before the parentesis) - String baseName = fileBackuppedToSearch.substring(0, fileBackuppedToSearch.indexOf(" (Backup")); - - if (folder != null && folder.isDirectory()) { - // get current count - FilenameFilter filter = (dir, name) -> name.matches(baseName + " \\(Backup \\d{2}-\\d{2}-\\d{4} \\d{2}\\.\\d{2}\\.\\d{2}\\)\\.zip"); - File[] matchingFiles = folder.listFiles(filter); // getting files for that filter - - if (matchingFiles == null) { - Logger.logMessage("Error during deleting old backups: none matching files", LogLevel.WARN); - return; - } - - // check if the max is passed, and if it is, remove the oldest - if (matchingFiles.length > maxBackupsToKeep) { - Logger.logMessage("Found " + matchingFiles.length + " matching files, exceeding max allowed: " + maxBackupsToKeep, LogLevel.INFO); - - Arrays.sort(matchingFiles, (f1, f2) -> { - String datePattern = "\\(Backup (\\d{2}-\\d{2}-\\d{4} \\d{2}\\.\\d{2}\\.\\d{2})\\)\\.zip"; // regex aggiornata - - try { - // extracting dates from file names - String date1 = extractDateFromFileName(f1.getName(), datePattern); - String date2 = extractDateFromFileName(f2.getName(), datePattern); - - LocalDateTime dateTime1 = LocalDateTime.parse(date1, BackupManagerGUI.dateForfolderNameFormatter); - LocalDateTime dateTime2 = LocalDateTime.parse(date2, BackupManagerGUI.dateForfolderNameFormatter); - - return dateTime1.compareTo(dateTime2); - } catch (Exception e) { - Logger.logMessage("Error parsing dates: " + e.getMessage(), LogLevel.ERROR); - return 0; - } - }); - - // delete older files - for (int i = 0; i < matchingFiles.length - maxBackupsToKeep; i++) { - File fileToDelete = matchingFiles[i]; - if (fileToDelete.delete()) { - Logger.logMessage("Deleted old backup: " + fileToDelete.getName(), LogLevel.INFO); - } else { - Logger.logMessage("Failed to delete old backup: " + fileToDelete.getName(), LogLevel.WARN); - } - } - } - } else { - Logger.logMessage("Destination path is not a directory: " + destinationPath, LogLevel.ERROR); - } - } - - private static String extractDateFromFileName(String fileName, String pattern) throws Exception { - Pattern regex = Pattern.compile(pattern); - Matcher matcher = regex.matcher(fileName); - - if (matcher.find()) { - return matcher.group(1); - } - - throw new Exception("No date found in file name: " + fileName); - } - - public static void updateTableWithNewBackupList(List<Backup> updatedBackups) { - Logger.logMessage("updating backup list", Logger.LogLevel.DEBUG); - - SwingUtilities.invokeLater(() -> { - BackupManagerGUI.model.setRowCount(0); - - for (Backup backup : updatedBackups) { - BackupManagerGUI.model.addRow(new Object[]{ - backup.getBackupName(), - backup.getInitialPath(), - backup.getDestinationPath(), - backup.getLastBackup() != null ? backup.getLastBackup().format(formatter) : "", - backup.isAutoBackup(), - backup.getNextDateBackup() != null ? backup.getNextDateBackup().format(formatter) : "", - backup.getTimeIntervalBackup() != null ? backup.getTimeIntervalBackup().toString() : "" - }); - } - }); - } - - private static int countFilesInDirectory(File directory) { - int count = 0; - - for (File file : directory.listFiles()) { - if (file.isFile()) { - count++; - } - if (file.isDirectory()) { - count += countFilesInDirectory(file); - } - } - return count; - } - - public static void StopCopyFiles() { - zipThread.interrupt(); - } -} diff --git a/src/main/java/com/mycompany/autobackupprogram/GUI/BackupManagerGUI.form b/src/main/java/com/mycompany/autobackupprogram/GUI/BackupManagerGUI.form deleted file mode 100644 index c8a47a2..0000000 --- a/src/main/java/com/mycompany/autobackupprogram/GUI/BackupManagerGUI.form +++ /dev/null @@ -1,946 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> - -<Form version="1.9" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo"> - <NonVisualComponents> - <Container class="javax.swing.JPopupMenu" name="TablePopup"> - - <Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout"> - <Property name="useNullLayout" type="boolean" value="true"/> - </Layout> - <SubComponents> - <MenuItem class="javax.swing.JMenuItem" name="EditPoputItem"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/pen.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Edit"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="EditPoputItemActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="DeletePopupItem"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/bin.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Delete"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="DeletePopupItemActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="DuplicatePopupItem"> - <Properties> - <Property name="text" type="java.lang.String" value="Duplicate"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="DuplicatePopupItemActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="renamePopupItem"> - <Properties> - <Property name="text" type="java.lang.String" value="Rename backup"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="renamePopupItemActionPerformed"/> - </Events> - </MenuItem> - <Component class="javax.swing.JPopupMenu$Separator" name="jSeparator1"> - </Component> - <MenuItem class="javax.swing.JMenuItem" name="OpenInitialFolderItem"> - <Properties> - <Property name="text" type="java.lang.String" value="Open initial folder"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="OpenInitialFolderItemActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="OpenInitialDestinationItem"> - <Properties> - <Property name="text" type="java.lang.String" value="Open destination folder"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="OpenInitialDestinationItemActionPerformed"/> - </Events> - </MenuItem> - <Component class="javax.swing.JPopupMenu$Separator" name="jSeparator3"> - </Component> - <Menu class="javax.swing.JMenu" name="Backup"> - <Properties> - <Property name="text" type="java.lang.String" value="Backup"/> - </Properties> - <SubComponents> - <MenuItem class="javax.swing.JMenuItem" name="RunBackupPopupItem"> - <Properties> - <Property name="text" type="java.lang.String" value="Run single backup"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="RunBackupPopupItemActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JCheckBoxMenuItem" name="AutoBackupMenuItem"> - <Properties> - <Property name="selected" type="boolean" value="true"/> - <Property name="text" type="java.lang.String" value="Auto Backup"/> - <Property name="toolTipText" type="java.lang.String" value=""/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="AutoBackupMenuItemActionPerformed"/> - </Events> - </MenuItem> - </SubComponents> - </Menu> - <Component class="javax.swing.JPopupMenu$Separator" name="jSeparator2"> - </Component> - <Menu class="javax.swing.JMenu" name="jMenu4"> - <Properties> - <Property name="text" type="java.lang.String" value="Copy text"/> - </Properties> - <SubComponents> - <MenuItem class="javax.swing.JMenuItem" name="CopyBackupNamePopupItem"> - <Properties> - <Property name="text" type="java.lang.String" value="Copy backup name"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="CopyBackupNamePopupItemActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="CopyInitialPathPopupItem"> - <Properties> - <Property name="text" type="java.lang.String" value="Copy initial path"/> - <Property name="toolTipText" type="java.lang.String" value=""/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="CopyInitialPathPopupItemActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="CopyDestinationPathPopupItem"> - <Properties> - <Property name="text" type="java.lang.String" value="Copy destination path"/> - <Property name="toolTipText" type="java.lang.String" value=""/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="CopyDestinationPathPopupItemActionPerformed"/> - </Events> - </MenuItem> - </SubComponents> - </Menu> - </SubComponents> - </Container> - <Menu class="javax.swing.JMenuBar" name="jMenuBar1"> - <SubComponents> - <Menu class="javax.swing.JMenu" name="jMenu1"> - <Properties> - <Property name="text" type="java.lang.String" value="File"/> - </Properties> - <SubComponents> - <MenuItem class="javax.swing.JMenuItem" name="MenuNew"> - <Properties> - <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor"> - <KeyStroke key="Ctrl+N"/> - </Property> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/add-file.png"/> - </Property> - <Property name="text" type="java.lang.String" value="New"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuNewActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuSave"> - <Properties> - <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor"> - <KeyStroke key="Ctrl+S"/> - </Property> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/diskette.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Save"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuSaveActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuSaveWithName"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/save.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Save with name"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuSaveWithNameActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator4"> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuImport"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/import.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Import backup list"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuImportActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuExport"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/export.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Export backup list"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuExportActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator5"> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuClear"> - <Properties> - <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor"> - <KeyStroke key="Ctrl+C"/> - </Property> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/clean.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Clear"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuClearActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuHistory"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/clock.png"/> - </Property> - <Property name="text" type="java.lang.String" value="History"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuHistoryActionPerformed"/> - </Events> - </MenuItem> - </SubComponents> - </Menu> - <Menu class="javax.swing.JMenu" name="jMenu2"> - <Properties> - <Property name="text" type="java.lang.String" value="Options"/> - </Properties> - <SubComponents> - <MenuItem class="javax.swing.JMenuItem" name="MenuPreferences"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/cogwheel.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Preferences"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuPreferencesActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuQuit"> - <Properties> - <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor"> - <KeyStroke key="Alt+F4"/> - </Property> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/remove.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Quit"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuQuitActionPerformed"/> - </Events> - </MenuItem> - </SubComponents> - </Menu> - <Menu class="javax.swing.JMenu" name="jMenu3"> - <Properties> - <Property name="text" type="java.lang.String" value="About"/> - </Properties> - <SubComponents> - <MenuItem class="javax.swing.JMenuItem" name="MenuWebsite"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/website.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Website"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuWebsiteActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuInfoPage"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/information.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Info"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuInfoPageActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuShare"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/share.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Share"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuShareActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuDonate"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/donation.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Donate"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuDonateActionPerformed"/> - </Events> - </MenuItem> - </SubComponents> - </Menu> - <Menu class="javax.swing.JMenu" name="jMenu5"> - <Properties> - <Property name="text" type="java.lang.String" value="Help"/> - </Properties> - <SubComponents> - <MenuItem class="javax.swing.JMenuItem" name="MenuBugReport"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/bug.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Report a bug"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuBugReportActionPerformed"/> - </Events> - </MenuItem> - <MenuItem class="javax.swing.JMenuItem" name="MenuSupport"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/help-desk.png"/> - </Property> - <Property name="text" type="java.lang.String" value="Support"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="MenuSupportActionPerformed"/> - </Events> - </MenuItem> - </SubComponents> - </Menu> - </SubComponents> - </Menu> - </NonVisualComponents> - <Properties> - <Property name="defaultCloseOperation" type="int" value="2"/> - <Property name="title" type="java.lang.String" value="Backup Manager"/> - <Property name="resizable" type="boolean" value="false"/> - </Properties> - <SyntheticProperties> - <SyntheticProperty name="menuBar" type="java.lang.String" value="jMenuBar1"/> - <SyntheticProperty name="formSizePolicy" type="int" value="1"/> - <SyntheticProperty name="generateCenter" type="boolean" value="true"/> - </SyntheticProperties> - <AuxValues> - <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> - <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> - <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> - <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> - <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> - </AuxValues> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="TabbedPane" alignment="1" max="32767" attributes="0"/> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="jLabel3" max="32767" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <Component id="TabbedPane" min="-2" pref="636" max="-2" attributes="0"/> - <EmptySpace type="separate" max="-2" attributes="0"/> - <Component id="jLabel3" min="-2" max="-2" attributes="0"/> - <EmptySpace pref="7" max="32767" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Container class="javax.swing.JTabbedPane" name="TabbedPane"> - - <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/> - <SubComponents> - <Container class="javax.swing.JPanel" name="jPanel1"> - <Properties> - <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[464, 472]"/> - </Property> - </Properties> - <Constraints> - <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription"> - <JTabbedPaneConstraints tabName="BackupEntry"> - <Property name="tabTitle" type="java.lang.String" value="BackupEntry"/> - </JTabbedPaneConstraints> - </Constraint> - </Constraints> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace min="-2" pref="248" max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" max="-2" attributes="0"> - <Group type="102" attributes="0"> - <Group type="103" groupAlignment="0" max="-2" attributes="0"> - <Component id="jLabel2" max="32767" attributes="0"/> - <Group type="102" attributes="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="destinationPathField" alignment="1" max="-2" attributes="0"/> - <Component id="startPathField" alignment="0" max="-2" attributes="0"/> - </Group> - <EmptySpace min="4" pref="4" max="-2" attributes="0"/> - </Group> - </Group> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="btnPathSearch2" min="-2" pref="34" max="-2" attributes="0"/> - </Group> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> - <Component id="btnPathSearch1" min="-2" pref="34" max="-2" attributes="0"/> - </Group> - </Group> - </Group> - <Group type="103" alignment="0" groupAlignment="1" attributes="0"> - <Component id="lastBackupLabel" min="-2" pref="461" max="-2" attributes="0"/> - <Component id="jScrollPane2" min="-2" pref="462" max="-2" attributes="0"/> - </Group> - <Component id="currentFileLabel" alignment="1" max="32767" attributes="0"/> - <Component id="txtTitle" alignment="0" min="-2" pref="466" max="-2" attributes="0"/> - </Group> - <EmptySpace pref="211" max="32767" attributes="0"/> - </Group> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="1" attributes="0"> - <Group type="102" attributes="0"> - <Component id="jLabel4" max="32767" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="maxBackupCountSpinner" min="-2" max="-2" attributes="0"/> - </Group> - <Group type="102" attributes="0"> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> - <Group type="103" groupAlignment="1" attributes="0"> - <Component id="SingleBackup" min="-2" pref="188" max="-2" attributes="0"/> - <Component id="toggleAutoBackup" min="-2" pref="188" max="-2" attributes="0"/> - </Group> - </Group> - </Group> - <EmptySpace max="-2" attributes="0"/> - <Component id="btnTimePicker" min="-2" pref="34" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="351" max="-2" attributes="0"/> - </Group> - <Group type="103" rootIndex="1" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> - <Component id="filler1" min="-2" max="-2" attributes="0"/> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> - </Group> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" pref="49" max="-2" attributes="0"/> - <Component id="txtTitle" min="-2" pref="58" max="-2" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="currentFileLabel" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="startPathField" min="-2" pref="31" max="-2" attributes="0"/> - <Component id="btnPathSearch1" min="-2" pref="31" max="-2" attributes="0"/> - </Group> - <EmptySpace max="32767" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="destinationPathField" min="-2" pref="31" max="-2" attributes="0"/> - <Component id="btnPathSearch2" min="-2" pref="31" max="-2" attributes="0"/> - </Group> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="jLabel2" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="jScrollPane2" min="-2" pref="190" max="-2" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="lastBackupLabel" min="-2" max="-2" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="SingleBackup" min="-2" pref="36" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="toggleAutoBackup" min="-2" pref="36" max="-2" attributes="0"/> - <Component id="btnTimePicker" alignment="0" min="-2" pref="31" max="-2" attributes="0"/> - </Group> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="maxBackupCountSpinner" alignment="3" min="-2" pref="31" max="-2" attributes="0"/> - <Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace min="-2" pref="20" max="-2" attributes="0"/> - </Group> - <Group type="103" rootIndex="1" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> - <Component id="filler1" min="-2" max="-2" attributes="0"/> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> - </Group> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JLabel" name="txtTitle"> - <Properties> - <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> - <Font name="Segoe UI" size="36" style="0"/> - </Property> - <Property name="horizontalAlignment" type="int" value="0"/> - <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> - <ComponentRef name="txtTitle"/> - </Property> - <Property name="text" type="java.lang.String" value="Backup Entry"/> - <Property name="toolTipText" type="java.lang.String" value=""/> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Default Cursor"/> - </Property> - <Property name="horizontalTextPosition" type="int" value="0"/> - </Properties> - </Component> - <Component class="javax.swing.JLabel" name="currentFileLabel"> - <Properties> - <Property name="text" type="java.lang.String" value="Current file: "/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="startPathField"> - <Properties> - <Property name="toolTipText" type="java.lang.String" value="(Required) Initial path"/> - <Property name="actionCommand" type="java.lang.String" value="null"/> - <Property name="alignmentX" type="float" value="0.0"/> - <Property name="alignmentY" type="float" value="0.0"/> - <Property name="autoscrolls" type="boolean" value="false"/> - <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[465, 26]"/> - </Property> - <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[465, 26]"/> - </Property> - <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[465, 26]"/> - </Property> - </Properties> - </Component> - <Component class="javax.swing.JButton" name="btnPathSearch1"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/folder.png"/> - </Property> - <Property name="toolTipText" type="java.lang.String" value="Open file explorer"/> - <Property name="borderPainted" type="boolean" value="false"/> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Hand Cursor"/> - </Property> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnPathSearch1ActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.JTextField" name="destinationPathField"> - <Properties> - <Property name="toolTipText" type="java.lang.String" value="(Required) Destination path"/> - <Property name="actionCommand" type="java.lang.String" value="<Not Set>"/> - <Property name="alignmentX" type="float" value="0.0"/> - <Property name="alignmentY" type="float" value="0.0"/> - <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[465, 26]"/> - </Property> - <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[465, 26]"/> - </Property> - <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[465, 26]"/> - </Property> - </Properties> - </Component> - <Component class="javax.swing.JButton" name="btnPathSearch2"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/folder.png"/> - </Property> - <Property name="toolTipText" type="java.lang.String" value="Open file explorer"/> - <Property name="borderPainted" type="boolean" value="false"/> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Hand Cursor"/> - </Property> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnPathSearch2ActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.JLabel" name="lastBackupLabel"> - <Properties> - <Property name="text" type="java.lang.String" value="last backup: "/> - </Properties> - </Component> - <Component class="javax.swing.JButton" name="SingleBackup"> - <Properties> - <Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> - <Color blue="ff" green="99" red="33" type="rgb"/> - </Property> - <Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> - <Color blue="ff" green="ff" red="ff" type="rgb"/> - </Property> - <Property name="text" type="java.lang.String" value="Single Backup"/> - <Property name="toolTipText" type="java.lang.String" value="Perform the backup"/> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Hand Cursor"/> - </Property> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="SingleBackupActionPerformed"/> - </Events> - </Component> - <Container class="javax.swing.JScrollPane" name="jScrollPane2"> - <AuxValues> - <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> - </AuxValues> - - <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> - <SubComponents> - <Component class="javax.swing.JTextArea" name="backupNoteTextArea"> - <Properties> - <Property name="columns" type="int" value="20"/> - <Property name="rows" type="int" value="5"/> - <Property name="toolTipText" type="java.lang.String" value="(Optional) Backup description"/> - <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[232, 84]"/> - </Property> - <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[232, 84]"/> - </Property> - </Properties> - </Component> - </SubComponents> - </Container> - <Component class="javax.swing.JLabel" name="jLabel2"> - <Properties> - <Property name="text" type="java.lang.String" value="notes:"/> - </Properties> - </Component> - <Component class="javax.swing.JButton" name="btnTimePicker"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/chronometer.png"/> - </Property> - <Property name="toolTipText" type="java.lang.String" value="time picker"/> - <Property name="borderPainted" type="boolean" value="false"/> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Hand Cursor"/> - </Property> - <Property name="enabled" type="boolean" value="false"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnTimePickerActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.JToggleButton" name="toggleAutoBackup"> - <Properties> - <Property name="text" type="java.lang.String" value="Auto Backup"/> - <Property name="toolTipText" type="java.lang.String" value="Enable/Disable automatic backup"/> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Hand Cursor"/> - </Property> - <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[108, 27]"/> - </Property> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="toggleAutoBackupActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.Box$Filler" name="filler1"> - <AuxValues> - <AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.RigidArea"/> - </AuxValues> - </Component> - <Component class="javax.swing.JLabel" name="jLabel4"> - <Properties> - <Property name="horizontalAlignment" type="int" value="4"/> - <Property name="text" type="java.lang.String" value="Keep only last"/> - </Properties> - </Component> - <Component class="javax.swing.JSpinner" name="maxBackupCountSpinner"> - <Properties> - <Property name="toolTipText" type="java.lang.String" value="Maximum number of backups before removing the oldest."/> - </Properties> - <Events> - <EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="maxBackupCountSpinnerStateChanged"/> - <EventHandler event="mouseWheelMoved" listener="java.awt.event.MouseWheelListener" parameters="java.awt.event.MouseWheelEvent" handler="maxBackupCountSpinnerMouseWheelMoved"/> - </Events> - </Component> - </SubComponents> - </Container> - <Container class="javax.swing.JPanel" name="jPanel2"> - <Constraints> - <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription"> - <JTabbedPaneConstraints tabName="BackupList"> - <Property name="tabTitle" type="java.lang.String" value="BackupList"/> - </JTabbedPaneConstraints> - </Constraint> - </Constraints> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="detailsPanel" alignment="0" max="32767" attributes="0"/> - <Component id="tablePanel" alignment="0" max="32767" attributes="0"/> - </Group> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace max="32767" attributes="0"/> - <Component id="tablePanel" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="detailsPanel" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Container class="javax.swing.JPanel" name="tablePanel"> - <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="tablePanelMouseClicked"/> - </Events> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <Component id="addBackupEntryButton" min="-2" pref="41" max="-2" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="jLabel1" min="-2" pref="9" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="researchField" min="-2" pref="321" max="-2" attributes="0"/> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> - </Group> - <Group type="102" alignment="0" attributes="0"> - <Component id="jScrollPane1" pref="950" max="32767" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - </Group> - </Group> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="addBackupEntryButton" min="-2" pref="34" max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="researchField" alignment="3" min="-2" pref="34" max="-2" attributes="0"/> - </Group> - </Group> - <EmptySpace min="-2" max="-2" attributes="0"/> - <Component id="jScrollPane1" pref="485" max="32767" attributes="0"/> - <EmptySpace min="-2" max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JButton" name="addBackupEntryButton"> - <Properties> - <Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> - <Color blue="0" green="0" red="0" type="rgb"/> - </Property> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/res/img/plus.png"/> - </Property> - <Property name="toolTipText" type="java.lang.String" value="Add new backup"/> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Hand Cursor"/> - </Property> - <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> - <Dimension value="[25, 25]"/> - </Property> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="addBackupEntryButtonActionPerformed"/> - </Events> - </Component> - <Container class="javax.swing.JScrollPane" name="jScrollPane1"> - <AuxValues> - <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> - </AuxValues> - - <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> - <SubComponents> - <Component class="javax.swing.JTable" name="table"> - <Properties> - <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor"> - <Table columnCount="7" rowCount="0"> - <Column editable="false" title="Backup name" type="java.lang.String"/> - <Column editable="false" title="Initial path" type="java.lang.String"/> - <Column editable="false" title="Destination path" type="java.lang.String"/> - <Column editable="false" title="Last backup" type="java.lang.String"/> - <Column editable="false" title="Auto backup" type="java.lang.Boolean"/> - <Column editable="false" title="Next date backup" type="java.lang.String"/> - <Column editable="false" title="Days interval backup" type="java.lang.Integer"/> - </Table> - </Property> - <Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor"> - <TableColumnModel selectionModel="0"> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> - <Title/> - <Editor/> - <Renderer/> - </Column> - </TableColumnModel> - </Property> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Crosshair Cursor"/> - </Property> - <Property name="rowHeight" type="int" value="50"/> - <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor"> - <TableHeader reorderingAllowed="true" resizingAllowed="true"/> - </Property> - </Properties> - <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="tableMouseClicked"/> - </Events> - </Component> - </SubComponents> - </Container> - <Component class="javax.swing.JLabel" name="jLabel1"> - <Properties> - <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> - <Font name="Segoe UI" size="20" style="0"/> - </Property> - <Property name="text" type="java.lang.String" value="|"/> - <Property name="alignmentY" type="float" value="0.0"/> - </Properties> - </Component> - <Component class="javax.swing.JTextField" name="researchField"> - <Properties> - <Property name="toolTipText" type="java.lang.String" value="Research bar"/> - </Properties> - <AccessibilityProperties> - <Property name="AccessibleContext.accessibleName" type="java.lang.String" value=""/> - </AccessibilityProperties> - <Events> - <EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="researchFieldKeyTyped"/> - </Events> - </Component> - </SubComponents> - </Container> - <Container class="javax.swing.JPanel" name="detailsPanel"> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="detailsLabel" max="32767" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <Component id="detailsLabel" min="-2" pref="78" max="-2" attributes="0"/> - <EmptySpace max="32767" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JLabel" name="detailsLabel"> - <Properties> - <Property name="verticalAlignment" type="int" value="1"/> - </Properties> - </Component> - </SubComponents> - </Container> - </SubComponents> - </Container> - </SubComponents> - </Container> - <Component class="javax.swing.JLabel" name="jLabel3"> - <Properties> - <Property name="text" type="java.lang.String" value="Version 2.0.2"/> - </Properties> - </Component> - </SubComponents> -</Form> diff --git a/src/main/java/com/mycompany/autobackupprogram/GUI/BackupManagerGUI.java b/src/main/java/com/mycompany/autobackupprogram/GUI/BackupManagerGUI.java deleted file mode 100644 index edbba3e..0000000 --- a/src/main/java/com/mycompany/autobackupprogram/GUI/BackupManagerGUI.java +++ /dev/null @@ -1,2273 +0,0 @@ -package com.mycompany.autobackupprogram.GUI; - -import com.mycompany.autobackupprogram.Entities.TimeInterval; -import com.formdev.flatlaf.FlatClientProperties; -import com.mycompany.autobackupprogram.BackupOperations; -import com.mycompany.autobackupprogram.Dialogs.PreferencesDialog; -import com.mycompany.autobackupprogram.JSONAutoBackup; -import com.mycompany.autobackupprogram.JSONConfigReader; -import com.mycompany.autobackupprogram.Logger; -import com.mycompany.autobackupprogram.Dialogs.TimePicker; -import com.mycompany.autobackupprogram.Entities.Backup; -import com.mycompany.autobackupprogram.Entities.BackupList; -import com.mycompany.autobackupprogram.Entities.Preferences; -import com.mycompany.autobackupprogram.Enums.ConfigKey; -import com.mycompany.autobackupprogram.Enums.MenuItems; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationCategory; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum.TranslationKey; -import com.mycompany.autobackupprogram.Logger.LogLevel; -import com.mycompany.autobackupprogram.Managers.ThemeManager; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Desktop; -import java.awt.Dimension; -import java.awt.HeadlessException; -import java.awt.Image; -import java.awt.Toolkit; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import javax.swing.ImageIcon; -import javax.swing.JCheckBox; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.JTextArea; -import javax.swing.JTextField; -import javax.swing.SwingUtilities; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.swing.filechooser.FileSystemView; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumnModel; - -import org.json.simple.parser.ParseException; - -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; - -/** - * @author Dennis Turco - */ -public class BackupManagerGUI extends javax.swing.JFrame { - private static final JSONConfigReader configReader = new JSONConfigReader(ConfigKey.CONFIG_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); - public static final DateTimeFormatter dateForfolderNameFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH.mm.ss"); - public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss"); - - public static Backup currentBackup; - private static List<Backup> backups; - private static JSONAutoBackup JSON; - public static DefaultTableModel model; - private BackupProgressGUI progressBar; - private boolean saveChanged; - private Integer selectedRow; - private String backupOnText; - private String backupOffText; - private String current_version; - - public BackupManagerGUI() { - ThemeManager.updateThemeFrame(this); - - initComponents(); - - current_version = ConfigKey.VERSION.getValue(); - - // logo application - Image icon = new ImageIcon(this.getClass().getResource(ConfigKey.LOGO_IMG.getValue())).getImage(); - this.setIconImage(icon); - - JSON = new JSONAutoBackup(); - currentBackup = new Backup(); - saveChanged = true; - - toggleAutoBackup.setText(toggleAutoBackup.isSelected() ? backupOnText : backupOffText); - - File file = new File(System.getProperty("os.name").toLowerCase().contains("win") ? "C:\\Windows\\System32" : "/root"); - if (file.canWrite()) { - Logger.logMessage("The application is running with administrator privileges.", Logger.LogLevel.DEBUG); - } else { - Logger.logMessage("The application does NOT have administrator privileges.", Logger.LogLevel.DEBUG); - } - - customListeners(); - - // load Menu items - JSONConfigReader config = new JSONConfigReader(ConfigKey.CONFIG_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); - MenuBugReport.setVisible(config.isMenuItemEnabled(MenuItems.BugReport.name())); - MenuPreferences.setVisible(config.isMenuItemEnabled(MenuItems.Preferences.name())); - MenuClear.setVisible(config.isMenuItemEnabled(MenuItems.Clear.name())); - MenuDonate.setVisible(config.isMenuItemEnabled(MenuItems.Donate.name())); - MenuHistory.setVisible(config.isMenuItemEnabled(MenuItems.History.name())); - MenuInfoPage.setVisible(config.isMenuItemEnabled(MenuItems.InfoPage.name())); - MenuNew.setVisible(config.isMenuItemEnabled(MenuItems.New.name())); - MenuQuit.setVisible(config.isMenuItemEnabled(MenuItems.Quit.name())); - MenuSave.setVisible(config.isMenuItemEnabled(MenuItems.Save.name())); - MenuSaveWithName.setVisible(config.isMenuItemEnabled(MenuItems.SaveWithName.name())); - MenuShare.setVisible(config.isMenuItemEnabled(MenuItems.Share.name())); - MenuSupport.setVisible(config.isMenuItemEnabled(MenuItems.Support.name())); - MenuWebsite.setVisible(config.isMenuItemEnabled(MenuItems.Website.name())); - MenuImport.setVisible(config.isMenuItemEnabled(MenuItems.Import.name())); - MenuExport.setVisible(config.isMenuItemEnabled(MenuItems.Export.name())); - - // set app size - setScreenSize(); - - // icons - researchField.putClientProperty(FlatClientProperties.TEXT_FIELD_LEADING_ICON, new javax.swing.ImageIcon(getClass().getResource("/res/img/search.png"))); - - // translations - setTranslations(); - - setCurrentBackupMaxBackupsToKeep(configReader.getMaxCountForSameBackup()); - } - - public void showWindow() { - setVisible(true); - toFront(); - requestFocus(); - } - - private void setScreenSize() { - Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); - int width = Math.min((int) size.getWidth(), Integer.parseInt(ConfigKey.GUI_WIDTH.getValue())); - int height = Math.min((int) size.getHeight(), Integer.parseInt(ConfigKey.GUI_HEIGHT.getValue())); - - this.setSize(width,height); - } - - private TimeInterval openTimePicker(TimeInterval time) { - TimePicker picker = new TimePicker(this, time, true); - picker.setVisible(true); - return picker.getTimeInterval(); - } - - private void openPreferences() { - Logger.logMessage("Event --> opening preferences dialog", LogLevel.INFO); - - PreferencesDialog prefs = new PreferencesDialog(this, true, this); - prefs.setVisible(true); - } - - public void reloadPreferences() { - Logger.logMessage("Reloading preferences", LogLevel.INFO); - - // load language - try { - TranslationLoaderEnum.loadTranslations(ConfigKey.LANGUAGES_DIRECTORY_STRING.getValue() + Preferences.getLanguage().getFileName()); - setTranslations(); - } catch (IOException | ParseException ex) { - Logger.logMessage("An error occurred during reloading preferences operation: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - - // load theme - ThemeManager.updateThemeFrame(this); - ThemeManager.refreshPopup(TablePopup); - } - - private void renameBackup(Backup backup) { - Logger.logMessage("Event --> backup renaming", Logger.LogLevel.INFO); - - String backup_name = getBackupName(false); - if (backup_name == null || backup_name.isEmpty()) return; - - backup.setBackupName(backup_name); - backup.setLastUpdateDate(LocalDateTime.now()); - BackupOperations.updateBackupList(backups); - } - - private void OpenFolder(String path) { - Logger.logMessage("Event --> opening folder", Logger.LogLevel.INFO); - - File folder = new File(path); - - // if the object is a file i want to obtain the folder that contains that file - if (folder.exists() && folder.isFile()) { - folder = folder.getParentFile(); - } - - if (folder.exists() && folder.isDirectory()) { - if (Desktop.isDesktopSupported()) { - Desktop desktop = Desktop.getDesktop(); - try { - desktop.open(folder); - } catch (IOException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - } else { - Logger.logMessage("Desktop not supported on this operating system", Logger.LogLevel.WARN); - } - } else { - Logger.logMessage("The folder does not exist or is invalid", Logger.LogLevel.WARN); - - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_FOLDER_NOT_EXISTING), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - } - - private void savedChanges(boolean saved) { - if (saved) { - setCurrentBackupName(currentBackup.getBackupName()); - saveChanged = true; - } else { - setCurrentBackupName(currentBackup.getBackupName() + "*"); - saveChanged = false; - } - } - - public void setAutoBackupPreference(boolean option) { - toggleAutoBackup.setSelected(option); - toggleAutoBackup.setText(toggleAutoBackup.isSelected() ? backupOnText : backupOffText); - currentBackup.setAutoBackup(option); - - if (!option) { - disableAutoBackup(currentBackup); - } - } - - public void setAutoBackupPreference(Backup backup, boolean option) { - backup.setAutoBackup(option); - if (backup.getBackupName().equals(currentBackup.getBackupName())) { - toggleAutoBackup.setSelected(option); - } - if (!option) { - disableAutoBackup(backup); - } - toggleAutoBackup.setText(toggleAutoBackup.isSelected() ? backupOnText : backupOffText); - } - - // it returns true if is correctly setted, false otherwise - public boolean AutomaticBackup() { - Logger.logMessage("Event --> automatic backup", Logger.LogLevel.INFO); - - if(!BackupOperations.CheckInputCorrect(currentBackup.getBackupName(),startPathField.getText(), destinationPathField.getText(), null)) return false; - - // if the file has not been saved you need to save it before setting the auto backup - if(currentBackup.isAutoBackup() == false || currentBackup.getNextDateBackup() == null || currentBackup.getTimeIntervalBackup() == null) { - if (currentBackup.getBackupName() == null || currentBackup.getBackupName().isEmpty()) SaveWithName(); - if (currentBackup.getBackupName() == null || currentBackup.getBackupName().isEmpty()) return false; - - // message - TimeInterval timeInterval = openTimePicker(null); - if (timeInterval == null) return false; - - //set date for next backup - LocalDateTime nextDateBackup = LocalDateTime.now().plusDays(timeInterval.getDays()) - .plusHours(timeInterval.getHours()) - .plusMinutes(timeInterval.getMinutes()); - - currentBackup.setTimeIntervalBackup(timeInterval); - currentBackup.setNextDateBackup(nextDateBackup); - btnTimePicker.setToolTipText(timeInterval.toString()); - btnTimePicker.setEnabled(true); - - Logger.logMessage("Event --> Next date backup setted to " + nextDateBackup, Logger.LogLevel.INFO); - - openBackupActivationMessage(timeInterval); - } - - currentBackup.setInitialPath(GetStartPathField()); - currentBackup.setDestinationPath(GetDestinationPathField()); - for (Backup b : backups) { - if (b.getBackupName().equals(currentBackup.getBackupName())) { - b.UpdateBackup(currentBackup); - break; - } - } - BackupOperations.updateBackupList(backups); - return true; - } - - public boolean AutomaticBackup(Backup backup) { - Logger.logMessage("Event --> automatic backup", Logger.LogLevel.INFO); - - if(!BackupOperations.CheckInputCorrect(backup.getBackupName(), backup.getInitialPath(), backup.getDestinationPath(), null)) return false; - - if(backup.isAutoBackup() == false || backup.getNextDateBackup() == null || backup.getTimeIntervalBackup() == null) { - // if the file has not been saved you need to save it before setting the auto backup - if (backup.getBackupName() == null || backup.getBackupName().isEmpty()) SaveWithName(); - if (backup.getBackupName() == null || backup.getBackupName().isEmpty()) return false; - - // message - TimeInterval timeInterval = openTimePicker(null); - if (timeInterval == null) return false; - - //set date for next backup - LocalDateTime nextDateBackup = LocalDateTime.now().plusDays(timeInterval.getDays()) - .plusHours(timeInterval.getHours()) - .plusMinutes(timeInterval.getMinutes()); - - backup.setTimeIntervalBackup(timeInterval); - backup.setNextDateBackup(nextDateBackup); - btnTimePicker.setToolTipText(timeInterval.toString()); - btnTimePicker.setEnabled(true); - - Logger.logMessage("Event --> Next date backup setted to " + nextDateBackup, Logger.LogLevel.INFO); - - openBackupActivationMessage(timeInterval); - } - - for (Backup b : backups) { - if (b.getBackupName().equals(backup.getBackupName())) { - b.UpdateBackup(backup); - break; - } - } - - // if the backup is currentBackup - if (currentBackup.getBackupName().equals(backup.getBackupName())) - currentBackup.UpdateBackup(backup); - - BackupOperations.updateBackupList(backups); - return true; - } - - private void openBackupActivationMessage(TimeInterval timeInterval) { - if (timeInterval == null) - throw new IllegalArgumentException("Time interval cannot be null"); - - String from = TranslationCategory.GENERAL.getTranslation(TranslationKey.FROM); - String to = TranslationCategory.GENERAL.getTranslation(TranslationKey.TO); - String activated = TranslationCategory.DIALOGS.getTranslation(TranslationKey.AUTO_BACKUP_ACTIVATED_MESSAGE); - String setted = TranslationCategory.DIALOGS.getTranslation(TranslationKey.SETTED_EVERY_MESSAGE); - String days = TranslationCategory.DIALOGS.getTranslation(TranslationKey.DAYS_MESSAGE); - - JOptionPane.showMessageDialog(null, - activated + "\n\t" + from + ": " + startPathField.getText() + "\n\t" + to + ": " - + destinationPathField.getText() + setted + " " + timeInterval.toString() + days, - "AutoBackup", 1); - } - - private void SaveWithName() { - Logger.logMessage("Event --> save with name", Logger.LogLevel.INFO); - - if (startPathField.getText().length() == 0 || destinationPathField.getText().length() == 0) { - Logger.logMessage("Unable to save the file. Both the initial and destination paths must be specified and cannot be empty", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_SAVING_FILE_WITH_PATHS_EMPTY), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - return; - } - - String backup_name = getBackupName(true); - - if (backup_name == null || backup_name.length() == 0) return; - - try { - LocalDateTime dateNow = LocalDateTime.now(); - Backup backup = new Backup ( - backup_name, - GetStartPathField(), - GetDestinationPathField(), - currentBackup.getLastBackup(), - currentBackup.isAutoBackup(), - currentBackup.getNextDateBackup(), - currentBackup.getTimeIntervalBackup(), - GetNotesTextArea(), - dateNow, - dateNow, - 0, - GetMaxBackupsToKeep() - ); - - backups.add(backup); - currentBackup = backup; - - BackupOperations.updateBackupList(backups); - Logger.logMessage("Backup '" + currentBackup.getBackupName() + "' saved successfully!", Logger.LogLevel.INFO); - JOptionPane.showMessageDialog(this, "Backup '" + currentBackup.getBackupName() + "' " + TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_SAVED_CORRECTLY_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_SAVED_CORRECTLY_TITLE), JOptionPane.INFORMATION_MESSAGE); - savedChanges(true); - } catch (IllegalArgumentException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } catch (HeadlessException ex) { - Logger.logMessage("Error saving backup", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_SAVING_BACKUP_MESSAGE), TranslationCategory.GENERAL.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - } - - private String getBackupName(boolean canOverwrite) { - String backup_name; - do { - - backup_name = JOptionPane.showInputDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_NAME_INPUT)); // pop-up message - for (Backup backup : backups) { - if (backup.getBackupName().equals(backup_name) && canOverwrite) { - int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.DUPLICATED_BACKUP_NAME_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); - if (response == JOptionPane.YES_OPTION) { - backups.remove(backup); - break; - } else { - backup_name = null; - } - } else if (backup.getBackupName().equals(backup_name)) { - Logger.logMessage("Error saving backup", Logger.LogLevel.WARN); - JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_NAME_ALREADY_USED_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE); - } - } - if (backup_name == null) return null; - } while (backup_name.equals("null") || backup_name.equals("null*")); - if (backup_name.isEmpty()) return null; - return backup_name; - } - - public void SingleBackup(String path1, String path2) { - Logger.logMessage("Event --> single backup", Logger.LogLevel.INFO); - - String temp = "\\"; - - //------------------------------INPUT CONTROL ERRORS------------------------------ - if(!BackupOperations.CheckInputCorrect(currentBackup.getBackupName(), path1, path2, null)) return; - - //------------------------------TO GET THE CURRENT DATE------------------------------ - LocalDateTime dateNow = LocalDateTime.now(); - - //------------------------------SET ALL THE VARIABLES------------------------------ - String name1; // folder name/initial file - String date = dateNow.format(dateForfolderNameFormatter); - - //------------------------------SET ALL THE STRINGS------------------------------ - name1 = path1.substring(path1.length()-1, path1.length()-1); - - for(int i=path1.length()-1; i>=0; i--) { - if(path1.charAt(i) != temp.charAt(0)) name1 = path1.charAt(i) + name1; - else break; - } - - name1 = BackupOperations.removeExtension(name1); - - path2 = path2 + "\\" + name1 + " (Backup " + date + ")"; - - //------------------------------COPY THE FILE OR DIRECTORY------------------------------ - Logger.logMessage("date backup: " + date, Logger.LogLevel.INFO); - - try { - progressBar = new BackupProgressGUI(path1, path2); - progressBar.setVisible(true); - - SingleBackup.setEnabled(false); - toggleAutoBackup.setEnabled(false); - - BackupOperations.zipDirectory(path1, path2+".zip", currentBackup, null, progressBar, SingleBackup, toggleAutoBackup); - - //if current_file_opened is null it means they are not in a backup but it is a backup with no associated json file - if (currentBackup.getBackupName() != null && !currentBackup.getBackupName().isEmpty()) { - currentBackup.setInitialPath(GetStartPathField()); - currentBackup.setDestinationPath(GetDestinationPathField()); - currentBackup.setLastBackup(LocalDateTime.now()); - - } - - } catch (IOException e) { - Logger.logMessage("Error during the backup operation: the initial path is incorrect!", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_INCORRECT_INITIAL_PATH), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - } - - private void setCurrentBackupName(String name) { - currentFileLabel.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.CURRENT_FILE) + ": " + name); - } - - private void setCurrentBackupNotes(String notes) { - backupNoteTextArea.setText(notes); - } - - public void setCurrentBackupMaxBackupsToKeep(int maxBackupsCount) { - maxBackupCountSpinner.setValue(maxBackupsCount); - } - - public void setStringToText() { - try { - String last_date = LocalDateTime.now().format(formatter); - lastBackupLabel.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.LAST_BACKUP) + last_date); - } catch(Exception ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - } - - public void setTextValues() { - try { - updateCurrentFiedsByBackup(currentBackup); - } catch (IllegalArgumentException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - setAutoBackupPreference(currentBackup.isAutoBackup()); - } - - private void customListeners() { - startPathField.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - somethingHasChanged(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - somethingHasChanged(); - } - - @Override - public void changedUpdate(DocumentEvent e) {} - }); - - destinationPathField.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - somethingHasChanged(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - somethingHasChanged(); - } - - @Override - public void changedUpdate(DocumentEvent e) {} - }); - - backupNoteTextArea.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - somethingHasChanged(); - } - - @Override - public void removeUpdate(DocumentEvent e) { - somethingHasChanged(); - } - - @Override - public void changedUpdate(DocumentEvent e) {} - }); - } - - private void somethingHasChanged() { - boolean backupNameNotNull = currentBackup.getBackupName() != null; - boolean pathsOrNotesChanged = - !startPathField.getText().equals(currentBackup.getInitialPath()) || - !destinationPathField.getText().equals(currentBackup.getDestinationPath()) || - !backupNoteTextArea.getText().equals(currentBackup.getNotes()); - - if (backupNameNotNull && !pathsOrNotesChanged) { - savedChanges(true); - } else { - savedChanges(false); - } - } - - public String GetStartPathField() { - return startPathField.getText(); - } - public String GetDestinationPathField() { - return destinationPathField.getText(); - } - public String GetNotesTextArea() { - return backupNoteTextArea.getText(); - } - public boolean GetAutomaticBackupPreference() { - return toggleAutoBackup.isSelected(); - } - public int GetMaxBackupsToKeep() { - return (int) maxBackupCountSpinner.getValue(); - } - public void SetStartPathField(String text) { - startPathField.setText(text); - } - public void SetDestinationPathField(String text) { - destinationPathField.setText(text); - } - public void SetLastBackupLabel(LocalDateTime date) { - if (date != null) { - String dateStr = date.format(formatter); - dateStr = TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.LAST_BACKUP) + ": " + dateStr; - lastBackupLabel.setText(dateStr); - } - else lastBackupLabel.setText(""); - } - - public static void OpenExceptionMessage(String errorMessage, String stackTrace) { - Object[] options = {TranslationCategory.GENERAL.getTranslation(TranslationKey.CLOSE_BUTTON), TranslationCategory.DIALOGS.getTranslation(TranslationKey.EXCEPTION_MESSAGE_CLIPBOARD_BUTTON), TranslationCategory.DIALOGS.getTranslation(TranslationKey.EXCEPTION_MESSAGE_REPORT_BUTTON)}; - - if (errorMessage == null) { - errorMessage = ""; - } - stackTrace = !errorMessage.isEmpty() ? errorMessage + "\n" + stackTrace : errorMessage + stackTrace; - String stackTraceMessage = TranslationCategory.DIALOGS.getTranslation(TranslationKey.EXCEPTION_MESSAGE_REPORT_MESSAGE) + "\n" + stackTrace; - - int choice; - - // Set a maximum width for the error message - final int MAX_WIDTH = 500; - - // Keep displaying the dialog until the "Close" option (index 0) is chosen - do { - if (stackTraceMessage.length() > 1500) { - stackTraceMessage = stackTraceMessage.substring(0, 1500) + "..."; - } - - // Create a JTextArea to hold the error message with line wrapping - JTextArea messageArea = new JTextArea(stackTraceMessage); - messageArea.setLineWrap(true); - messageArea.setWrapStyleWord(true); - messageArea.setEditable(false); - messageArea.setColumns(50); // Approximate width, adjust as necessary - - // Limit the maximum width - messageArea.setSize(new Dimension(MAX_WIDTH, Integer.MAX_VALUE)); - messageArea.setPreferredSize(new Dimension(MAX_WIDTH, messageArea.getPreferredSize().height)); - - // Put the JTextArea in a JScrollPane for scrollable display if needed - JScrollPane scrollPane = new JScrollPane(messageArea); - scrollPane.setPreferredSize(new Dimension(MAX_WIDTH, 300)); - - // Display the option dialog with the JScrollPane - String error = TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE); - choice = JOptionPane.showOptionDialog( - null, - scrollPane, // The JScrollPane containing the error message - error, // The error message/title - JOptionPane.DEFAULT_OPTION, // Option type (default option type) - JOptionPane.ERROR_MESSAGE, // Message type (error message icon) - null, // Icon (null means default icon) - options, // The options for the buttons - options[0] // The default option (Close) - ); - - if (choice == 1) { - StringSelection selection = new StringSelection(stackTrace); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); - Logger.logMessage("Error text has been copied to the clipboard", Logger.LogLevel.INFO); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.EXCEPTION_MESSAGE_CLIPBOARD_MESSAGE)); - } else if (choice == 2) { - openWebSite(ConfigKey.ISSUE_PAGE_LINK.getValue()); - } - } while (choice == 1 || choice == 2); - } - - private static void openWebSite(String reportUrl) { - try { - if (Desktop.isDesktopSupported()) { - Desktop desktop = Desktop.getDesktop(); - if (desktop.isSupported(Desktop.Action.BROWSE)) { - desktop.browse(new URI(reportUrl)); - } - } - } catch (IOException | URISyntaxException e) { - Logger.logMessage("Failed to open the web page. Please try again", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_OPENING_WEBSITE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - } - - private void displayBackupList(List<Backup> backups) { - String backupName = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.BACKUP_NAME_COLUMN); - String initialPath = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.INITIAL_PATH_COLUMN); - String destinationPath = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.DESTINATION_PATH_COLUMN); - String lastBackup = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.LAST_BACKUP_COLUMN); - String automaticBackup = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.AUTOMATIC_BACKUP_COLUMN); - String nextBackupDate = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.NEXT_BACKUP_DATE_COLUMN); - String timeInterval = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.TIME_INTERVAL_COLUMN); - model = new DefaultTableModel(new Object[]{backupName, initialPath, destinationPath, lastBackup, automaticBackup, nextBackupDate, timeInterval}, 0) { - - @Override - public Class<?> getColumnClass(int columnIndex) { - if (columnIndex == 4) { - return Boolean.class; - } - return super.getColumnClass(columnIndex); - } - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - }; - - table.setModel(model); - - for (int i = 0; i < backups.size(); i++) { - Backup backup = backups.get(i); - - if (i >= model.getRowCount()) { - model.addRow(new Object[]{"", "", "", "", "", "", ""}); - } - - model.setValueAt(backup.getBackupName(), i, 0); - model.setValueAt(backup.getInitialPath(), i, 1); - model.setValueAt(backup.getDestinationPath(), i, 2); - model.setValueAt(backup.getLastBackup() != null ? backup.getLastBackup().format(formatter) : "", i, 3); - model.setValueAt(backup.isAutoBackup(), i, 4); - model.setValueAt(backup.getNextDateBackup() != null ? backup.getNextDateBackup().format(formatter) : "", i, 5); - model.setValueAt(backup.getTimeIntervalBackup() != null ? backup.getTimeIntervalBackup().toString() : "", i, 6); - } - - DefaultTableCellRenderer renderer = new DefaultTableCellRenderer() { - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - - if (row % 2 == 0) { - c.setBackground(new Color(223, 222, 243)); - } else { - c.setBackground(Color.WHITE); - } - - if (isSelected) { - c.setBackground(table.getSelectionBackground()); - c.setForeground(table.getSelectionForeground()); - } else { - c.setForeground(Color.BLACK); - } - - return c; - } - }; - - TableCellRenderer checkboxRenderer = new DefaultTableCellRenderer() { - private final JCheckBox checkBox = new JCheckBox(); - - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - if (value instanceof Boolean aBoolean) { - checkBox.setSelected(aBoolean); - checkBox.setHorizontalAlignment(CENTER); - - if (row % 2 == 0) { - checkBox.setBackground(new Color(223, 222, 243)); - } else { - checkBox.setBackground(Color.WHITE); - } - - if (isSelected) { - checkBox.setBackground(table.getSelectionBackground()); - checkBox.setForeground(table.getSelectionForeground()); - } else { - checkBox.setForeground(Color.BLACK); - } - - return checkBox; - } - return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - } - }; - - TableColumnModel columnModel = table.getColumnModel(); - for (int i = 0; i < columnModel.getColumnCount(); i++) { - columnModel.getColumn(i).setCellRenderer(renderer); - } - - columnModel.getColumn(4).setCellRenderer(checkboxRenderer); - columnModel.getColumn(4).setCellEditor(table.getDefaultEditor(Boolean.class)); - } - - // Method to properly encode the URI with special characters (spaces, symbols, etc.) - private static String encodeURI(String value) { - try { - return java.net.URLEncoder.encode(value, "UTF-8").replace("+", "%20"); - } catch (IOException e) { - return value; // If encoding fails, return the original value - } - } - - public boolean Clear(boolean canMessageAppear) { - Logger.logMessage("Event --> clear", Logger.LogLevel.INFO); - - if (canMessageAppear && ((!saveChanged && !currentBackup.getBackupName().isEmpty()) || (!startPathField.getText().isEmpty() || !destinationPathField.getText().isEmpty() || !backupNoteTextArea.getText().isEmpty()))) { - int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_MESSAGE_FOR_CLEAR), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); - if (response != JOptionPane.YES_OPTION) { - return false; - } - } - - saveChanged = false; - setCurrentBackupName(""); - startPathField.setText(""); - destinationPathField.setText(""); - lastBackupLabel.setText(""); - backupNoteTextArea.setText(""); - maxBackupCountSpinner.setValue(configReader.getMaxCountForSameBackup()); - - return true; - } - - private void RemoveBackup(String backupName) { - Logger.logMessage("Event --> removing backup", Logger.LogLevel.INFO); - - // backup list update - for (Backup backup : backups) { - if (backupName.equals(backup.getBackupName())) { - backups.remove(backup); - break; - } - } - - BackupOperations.updateBackupList(backups); - } - - private void saveFile() { - Logger.logMessage("Event --> saving backup", Logger.LogLevel.INFO); - - if (startPathField.getText().length() == 0 || destinationPathField.getText().length() == 0) { - Logger.logMessage("Unable to save the file. Both the initial and destination paths must be specified and cannot be empty", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_SAVING_FILE_WITH_PATHS_EMPTY), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - return; - } - - if (currentBackup.getBackupName() == null || currentBackup.getBackupName().isEmpty()) { - SaveWithName(); - } - - try { - currentBackup.setInitialPath(GetStartPathField()); - currentBackup.setDestinationPath(GetDestinationPathField()); - currentBackup.setNotes(GetNotesTextArea()); - currentBackup.setMaxBackupsToKeep(GetMaxBackupsToKeep()); - - LocalDateTime dateNow = LocalDateTime.now(); - currentBackup.setLastUpdateDate(dateNow); - - for (Backup b : backups) { - if (b.getBackupName().equals(currentBackup.getBackupName())) { - b.UpdateBackup(currentBackup); - break; - } - } - BackupOperations.updateBackupList(backups); - savedChanges(true); - } catch (IllegalArgumentException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - } - - private void OpenBackup(String backupName) { - Logger.logMessage("Event --> opening backup", Logger.LogLevel.INFO); - - // if canges are not saved and if something has been written - if (!saveChanged && (startPathField.getText().length() != 0 || destinationPathField.getText().length() != 0 || backupNoteTextArea.getText().length() != 0)) { - int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_MESSAGE_FOR_UNSAVED_CHANGES), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); - if (response == JOptionPane.YES_OPTION) { - saveFile(); - } else if (response == JOptionPane.CANCEL_OPTION) { - return; - } - } - - try { - for(Backup backup : backups) { - if (backup.getBackupName().equals(backupName)) { - currentBackup = backup; - break; - } - } - - updateCurrentFiedsByBackup(currentBackup); - backupNoteTextArea.setEnabled(true); - savedChanges(true); - } catch (IllegalArgumentException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - } - - private void pathSearchWithFileChooser(JTextField textField, boolean allowFiles) { - JFileChooser jfc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory()); - - if (allowFiles) - jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); - else - jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - - int returnValue = jfc.showSaveDialog(null); - if (returnValue == JFileChooser.APPROVE_OPTION) { - File selectedFile = jfc.getSelectedFile(); - - if (selectedFile.isDirectory()) { - Logger.logMessage("You selected the directory: " + selectedFile, Logger.LogLevel.INFO); - } else if (selectedFile.isFile()) { - Logger.logMessage("You selected the file: " + selectedFile, Logger.LogLevel.INFO); - } - - textField.setText(selectedFile.toString()); - } - savedChanges(false); - } - - private void researchInTable() { - List<Backup> tempBackups = new ArrayList<>(); - - String research = researchField.getText(); - - for (Backup backup : backups) { - if (backup.getBackupName().contains(research) || - backup.getInitialPath().contains(research) || - backup.getDestinationPath().contains(research) || - (backup.getLastBackup() != null && backup.getLastBackup().toString().contains(research)) || - (backup.getNextDateBackup() != null && backup.getNextDateBackup().toString().contains(research)) || - (backup.getTimeIntervalBackup() != null && backup.getTimeIntervalBackup().toString().contains(research))) { - tempBackups.add(backup); - } - } - - BackupOperations.updateTableWithNewBackupList(tempBackups); - } - - private void updateCurrentFiedsByBackup(Backup backup) { - SetStartPathField(backup.getInitialPath()); - SetDestinationPathField(backup.getDestinationPath()); - SetLastBackupLabel(backup.getLastUpdateDate()); - setAutoBackupPreference(backup.isAutoBackup()); - setCurrentBackupName(backup.getBackupName()); - setCurrentBackupNotes(backup.getNotes()); - setCurrentBackupMaxBackupsToKeep(backup.getMaxBackupsToKeep()); - - if (backup.getTimeIntervalBackup() != null) { - btnTimePicker.setToolTipText(backup.getTimeIntervalBackup().toString()); - btnTimePicker.setEnabled(true); - } else { - btnTimePicker.setToolTipText(""); - btnTimePicker.setEnabled(false); - } - } - - private void NewBackup() { - Logger.logMessage("Event --> new backup", Logger.LogLevel.INFO); - - if (!saveChanged) { - int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_MESSAGE_FOR_UNSAVED_CHANGES), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); - if (response == JOptionPane.YES_OPTION) { - saveFile(); - } else if (response == JOptionPane.CANCEL_OPTION) { - return; - } - } - - if (!Clear(false)) { - return; - } - currentBackup = new Backup(); - currentBackup.setAutoBackup(false); - currentBackup.setBackupName(""); - currentBackup.setMaxBackupsToKeep(configReader.getMaxCountForSameBackup()); - - // basic auto enable is disabled - setAutoBackupPreference(currentBackup.isAutoBackup()); - - // I remove the current open backup - setCurrentBackupName("untitled*"); - } - - private void disableAutoBackup(Backup backup) { - Logger.logMessage("Event --> auto backup disabled", Logger.LogLevel.INFO); - - backup.setTimeIntervalBackup(null); - backup.setNextDateBackup(null); - backup.setAutoBackup(false); - backup.setLastUpdateDate(LocalDateTime.now()); - BackupOperations.updateBackupList(backups); - - // if the backup is the current backup i have to update the main panel - if (backup.getBackupName().equals(currentBackup.getBackupName())) { - btnTimePicker.setToolTipText(""); - btnTimePicker.setEnabled(false); - } - } - - private void maxBackupCountSpinnerChange() { - Integer backupCount = (Integer) maxBackupCountSpinner.getValue(); - - if (backupCount == null || backupCount < 1) { - maxBackupCountSpinner.setValue(1); - } else if (backupCount > 10) { - maxBackupCountSpinner.setValue(10); - } - } - - private void mouseWeel(java.awt.event.MouseWheelEvent evt) { - javax.swing.JSpinner spinner = (javax.swing.JSpinner) evt.getSource(); - int rotation = evt.getWheelRotation(); - - if (rotation < 0) { - spinner.setValue((Integer) spinner.getValue() + 1); - } else { - spinner.setValue((Integer) spinner.getValue() - 1); - } - - if ((int) spinner.getValue() != currentBackup.getMaxBackupsToKeep()) - savedChanges(false); - else - savedChanges(true); - } - - /** - * This method is called from within the constructor to initialize the form. - * - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents - private void initComponents() { - - TablePopup = new javax.swing.JPopupMenu(); - EditPoputItem = new javax.swing.JMenuItem(); - DeletePopupItem = new javax.swing.JMenuItem(); - DuplicatePopupItem = new javax.swing.JMenuItem(); - renamePopupItem = new javax.swing.JMenuItem(); - jSeparator1 = new javax.swing.JPopupMenu.Separator(); - OpenInitialFolderItem = new javax.swing.JMenuItem(); - OpenInitialDestinationItem = new javax.swing.JMenuItem(); - jSeparator3 = new javax.swing.JPopupMenu.Separator(); - Backup = new javax.swing.JMenu(); - RunBackupPopupItem = new javax.swing.JMenuItem(); - AutoBackupMenuItem = new javax.swing.JCheckBoxMenuItem(); - jSeparator2 = new javax.swing.JPopupMenu.Separator(); - jMenu4 = new javax.swing.JMenu(); - CopyBackupNamePopupItem = new javax.swing.JMenuItem(); - CopyInitialPathPopupItem = new javax.swing.JMenuItem(); - CopyDestinationPathPopupItem = new javax.swing.JMenuItem(); - TabbedPane = new javax.swing.JTabbedPane(); - jPanel1 = new javax.swing.JPanel(); - txtTitle = new javax.swing.JLabel(); - currentFileLabel = new javax.swing.JLabel(); - startPathField = new javax.swing.JTextField(); - btnPathSearch1 = new javax.swing.JButton(); - destinationPathField = new javax.swing.JTextField(); - btnPathSearch2 = new javax.swing.JButton(); - lastBackupLabel = new javax.swing.JLabel(); - SingleBackup = new javax.swing.JButton(); - jScrollPane2 = new javax.swing.JScrollPane(); - backupNoteTextArea = new javax.swing.JTextArea(); - jLabel2 = new javax.swing.JLabel(); - btnTimePicker = new javax.swing.JButton(); - toggleAutoBackup = new javax.swing.JToggleButton(); - filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0)); - jLabel4 = new javax.swing.JLabel(); - maxBackupCountSpinner = new javax.swing.JSpinner(); - jPanel2 = new javax.swing.JPanel(); - tablePanel = new javax.swing.JPanel(); - addBackupEntryButton = new javax.swing.JButton(); - jScrollPane1 = new javax.swing.JScrollPane(); - table = new javax.swing.JTable(); - jLabel1 = new javax.swing.JLabel(); - researchField = new javax.swing.JTextField(); - detailsPanel = new javax.swing.JPanel(); - detailsLabel = new javax.swing.JLabel(); - jLabel3 = new javax.swing.JLabel(); - jMenuBar1 = new javax.swing.JMenuBar(); - jMenu1 = new javax.swing.JMenu(); - MenuNew = new javax.swing.JMenuItem(); - MenuSave = new javax.swing.JMenuItem(); - MenuSaveWithName = new javax.swing.JMenuItem(); - jSeparator4 = new javax.swing.JPopupMenu.Separator(); - MenuImport = new javax.swing.JMenuItem(); - MenuExport = new javax.swing.JMenuItem(); - jSeparator5 = new javax.swing.JPopupMenu.Separator(); - MenuClear = new javax.swing.JMenuItem(); - MenuHistory = new javax.swing.JMenuItem(); - jMenu2 = new javax.swing.JMenu(); - MenuPreferences = new javax.swing.JMenuItem(); - MenuQuit = new javax.swing.JMenuItem(); - jMenu3 = new javax.swing.JMenu(); - MenuWebsite = new javax.swing.JMenuItem(); - MenuInfoPage = new javax.swing.JMenuItem(); - MenuShare = new javax.swing.JMenuItem(); - MenuDonate = new javax.swing.JMenuItem(); - jMenu5 = new javax.swing.JMenu(); - MenuBugReport = new javax.swing.JMenuItem(); - MenuSupport = new javax.swing.JMenuItem(); - - EditPoputItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/pen.png"))); // NOI18N - EditPoputItem.setText("Edit"); - EditPoputItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - EditPoputItemActionPerformed(evt); - } - }); - TablePopup.add(EditPoputItem); - - DeletePopupItem.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/bin.png"))); // NOI18N - DeletePopupItem.setText("Delete"); - DeletePopupItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - DeletePopupItemActionPerformed(evt); - } - }); - TablePopup.add(DeletePopupItem); - - DuplicatePopupItem.setText("Duplicate"); - DuplicatePopupItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - DuplicatePopupItemActionPerformed(evt); - } - }); - TablePopup.add(DuplicatePopupItem); - - renamePopupItem.setText("Rename backup"); - renamePopupItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - renamePopupItemActionPerformed(evt); - } - }); - TablePopup.add(renamePopupItem); - TablePopup.add(jSeparator1); - - OpenInitialFolderItem.setText("Open initial folder"); - OpenInitialFolderItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - OpenInitialFolderItemActionPerformed(evt); - } - }); - TablePopup.add(OpenInitialFolderItem); - - OpenInitialDestinationItem.setText("Open destination folder"); - OpenInitialDestinationItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - OpenInitialDestinationItemActionPerformed(evt); - } - }); - TablePopup.add(OpenInitialDestinationItem); - TablePopup.add(jSeparator3); - - Backup.setText("Backup"); - - RunBackupPopupItem.setText("Run single backup"); - RunBackupPopupItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - RunBackupPopupItemActionPerformed(evt); - } - }); - Backup.add(RunBackupPopupItem); - - AutoBackupMenuItem.setSelected(true); - AutoBackupMenuItem.setText("Auto Backup"); - AutoBackupMenuItem.setToolTipText(""); - AutoBackupMenuItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - AutoBackupMenuItemActionPerformed(evt); - } - }); - Backup.add(AutoBackupMenuItem); - - TablePopup.add(Backup); - TablePopup.add(jSeparator2); - - jMenu4.setText("Copy text"); - - CopyBackupNamePopupItem.setText("Copy backup name"); - CopyBackupNamePopupItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - CopyBackupNamePopupItemActionPerformed(evt); - } - }); - jMenu4.add(CopyBackupNamePopupItem); - - CopyInitialPathPopupItem.setText("Copy initial path"); - CopyInitialPathPopupItem.setToolTipText(""); - CopyInitialPathPopupItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - CopyInitialPathPopupItemActionPerformed(evt); - } - }); - jMenu4.add(CopyInitialPathPopupItem); - - CopyDestinationPathPopupItem.setText("Copy destination path"); - CopyDestinationPathPopupItem.setToolTipText(""); - CopyDestinationPathPopupItem.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - CopyDestinationPathPopupItemActionPerformed(evt); - } - }); - jMenu4.add(CopyDestinationPathPopupItem); - - TablePopup.add(jMenu4); - - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - setTitle("Backup Manager"); - setResizable(false); - - jPanel1.setMaximumSize(new java.awt.Dimension(464, 472)); - - txtTitle.setFont(new java.awt.Font("Segoe UI", 0, 36)); // NOI18N - txtTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); - txtTitle.setLabelFor(txtTitle); - txtTitle.setText("Backup Entry"); - txtTitle.setToolTipText(""); - txtTitle.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); - txtTitle.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - - currentFileLabel.setText("Current file: "); - - startPathField.setToolTipText("(Required) Initial path"); - startPathField.setActionCommand("null"); - startPathField.setAlignmentX(0.0F); - startPathField.setAlignmentY(0.0F); - startPathField.setAutoscrolls(false); - startPathField.setMaximumSize(new java.awt.Dimension(465, 26)); - startPathField.setMinimumSize(new java.awt.Dimension(465, 26)); - startPathField.setPreferredSize(new java.awt.Dimension(465, 26)); - - btnPathSearch1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/folder.png"))); // NOI18N - btnPathSearch1.setToolTipText("Open file explorer"); - btnPathSearch1.setBorderPainted(false); - btnPathSearch1.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); - btnPathSearch1.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnPathSearch1ActionPerformed(evt); - } - }); - - destinationPathField.setToolTipText("(Required) Destination path"); - destinationPathField.setActionCommand("<Not Set>"); - destinationPathField.setAlignmentX(0.0F); - destinationPathField.setAlignmentY(0.0F); - destinationPathField.setMaximumSize(new java.awt.Dimension(465, 26)); - destinationPathField.setMinimumSize(new java.awt.Dimension(465, 26)); - destinationPathField.setPreferredSize(new java.awt.Dimension(465, 26)); - - btnPathSearch2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/folder.png"))); // NOI18N - btnPathSearch2.setToolTipText("Open file explorer"); - btnPathSearch2.setBorderPainted(false); - btnPathSearch2.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); - btnPathSearch2.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnPathSearch2ActionPerformed(evt); - } - }); - - lastBackupLabel.setText("last backup: "); - - SingleBackup.setBackground(new java.awt.Color(51, 153, 255)); - SingleBackup.setForeground(new java.awt.Color(255, 255, 255)); - SingleBackup.setText("Single Backup"); - SingleBackup.setToolTipText("Perform the backup"); - SingleBackup.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); - SingleBackup.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - SingleBackupActionPerformed(evt); - } - }); - - backupNoteTextArea.setColumns(20); - backupNoteTextArea.setRows(5); - backupNoteTextArea.setToolTipText("(Optional) Backup description"); - backupNoteTextArea.setMaximumSize(new java.awt.Dimension(232, 84)); - backupNoteTextArea.setMinimumSize(new java.awt.Dimension(232, 84)); - jScrollPane2.setViewportView(backupNoteTextArea); - - jLabel2.setText("notes:"); - - btnTimePicker.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/chronometer.png"))); // NOI18N - btnTimePicker.setToolTipText("time picker"); - btnTimePicker.setBorderPainted(false); - btnTimePicker.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); - btnTimePicker.setEnabled(false); - btnTimePicker.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnTimePickerActionPerformed(evt); - } - }); - - toggleAutoBackup.setText("Auto Backup"); - toggleAutoBackup.setToolTipText("Enable/Disable automatic backup"); - toggleAutoBackup.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); - toggleAutoBackup.setPreferredSize(new java.awt.Dimension(108, 27)); - toggleAutoBackup.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - toggleAutoBackupActionPerformed(evt); - } - }); - - jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); - jLabel4.setText("Keep only last"); - - maxBackupCountSpinner.setToolTipText("Maximum number of backups before removing the oldest."); - maxBackupCountSpinner.addChangeListener(new javax.swing.event.ChangeListener() { - public void stateChanged(javax.swing.event.ChangeEvent evt) { - maxBackupCountSpinnerStateChanged(evt); - } - }); - maxBackupCountSpinner.addMouseWheelListener(new java.awt.event.MouseWheelListener() { - public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) { - maxBackupCountSpinnerMouseWheelMoved(evt); - } - }); - - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(248, 248, 248) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(destinationPathField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(startPathField, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(4, 4, 4))) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnPathSearch2, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() - .addGap(2, 2, 2) - .addComponent(btnPathSearch1, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)))) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lastBackupLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 461, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 462, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(currentFileLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(txtTitle, javax.swing.GroupLayout.PREFERRED_SIZE, 466, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(211, Short.MAX_VALUE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(maxBackupCountSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(SingleBackup, javax.swing.GroupLayout.PREFERRED_SIZE, 188, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(toggleAutoBackup, javax.swing.GroupLayout.PREFERRED_SIZE, 188, javax.swing.GroupLayout.PREFERRED_SIZE)))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnTimePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(351, 351, 351)) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(49, 49, 49) - .addComponent(txtTitle, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(currentFileLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(startPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnPathSearch1, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(destinationPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnPathSearch2, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 190, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(lastBackupLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(SingleBackup, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(toggleAutoBackup, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnTimePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(maxBackupCountSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel4)) - .addGap(20, 20, 20)) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - ); - - TabbedPane.addTab("BackupEntry", jPanel1); - - tablePanel.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - tablePanelMouseClicked(evt); - } - }); - - addBackupEntryButton.setForeground(new java.awt.Color(0, 0, 0)); - addBackupEntryButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/plus.png"))); // NOI18N - addBackupEntryButton.setToolTipText("Add new backup"); - addBackupEntryButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); - addBackupEntryButton.setPreferredSize(new java.awt.Dimension(25, 25)); - addBackupEntryButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - addBackupEntryButtonActionPerformed(evt); - } - }); - - table.setModel(new javax.swing.table.DefaultTableModel( - new Object [][] { - - }, - new String [] { - "Backup name", "Initial path", "Destination path", "Last backup", "Auto backup", "Next date backup", "Days interval backup" - } - ) { - Class[] types = new Class [] { - java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Boolean.class, java.lang.String.class, java.lang.Integer.class - }; - boolean[] canEdit = new boolean [] { - false, false, false, false, false, false, false - }; - - public Class getColumnClass(int columnIndex) { - return types [columnIndex]; - } - - public boolean isCellEditable(int rowIndex, int columnIndex) { - return canEdit [columnIndex]; - } - }); - table.setCursor(new java.awt.Cursor(java.awt.Cursor.CROSSHAIR_CURSOR)); - table.setRowHeight(50); - table.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - tableMouseClicked(evt); - } - }); - jScrollPane1.setViewportView(table); - - jLabel1.setFont(new java.awt.Font("Segoe UI", 0, 20)); // NOI18N - jLabel1.setText("|"); - jLabel1.setAlignmentY(0.0F); - - researchField.setToolTipText("Research bar"); - researchField.addKeyListener(new java.awt.event.KeyAdapter() { - public void keyTyped(java.awt.event.KeyEvent evt) { - researchFieldKeyTyped(evt); - } - }); - - javax.swing.GroupLayout tablePanelLayout = new javax.swing.GroupLayout(tablePanel); - tablePanel.setLayout(tablePanelLayout); - tablePanelLayout.setHorizontalGroup( - tablePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(tablePanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(tablePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(tablePanelLayout.createSequentialGroup() - .addComponent(addBackupEntryButton, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 9, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(researchField, javax.swing.GroupLayout.PREFERRED_SIZE, 321, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(tablePanelLayout.createSequentialGroup() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 950, Short.MAX_VALUE) - .addContainerGap()))) - ); - tablePanelLayout.setVerticalGroup( - tablePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(tablePanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(tablePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(addBackupEntryButton, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(tablePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) - .addComponent(researchField, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE) - .addContainerGap()) - ); - - researchField.getAccessibleContext().setAccessibleName(""); - - detailsLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); - - javax.swing.GroupLayout detailsPanelLayout = new javax.swing.GroupLayout(detailsPanel); - detailsPanel.setLayout(detailsPanelLayout); - detailsPanelLayout.setHorizontalGroup( - detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, detailsPanelLayout.createSequentialGroup() - .addContainerGap() - .addComponent(detailsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - ); - detailsPanelLayout.setVerticalGroup( - detailsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(detailsPanelLayout.createSequentialGroup() - .addComponent(detailsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 78, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); - jPanel2.setLayout(jPanel2Layout); - jPanel2Layout.setHorizontalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(detailsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(tablePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - ); - jPanel2Layout.setVerticalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(tablePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(detailsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) - ); - - TabbedPane.addTab("BackupList", jPanel2); - - jLabel3.setText("Version 2.0.2"); - - jMenu1.setText("File"); - - MenuNew.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_N, java.awt.event.InputEvent.CTRL_DOWN_MASK)); - MenuNew.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/add-file.png"))); // NOI18N - MenuNew.setText("New"); - MenuNew.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuNewActionPerformed(evt); - } - }); - jMenu1.add(MenuNew); - - MenuSave.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_DOWN_MASK)); - MenuSave.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/diskette.png"))); // NOI18N - MenuSave.setText("Save"); - MenuSave.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuSaveActionPerformed(evt); - } - }); - jMenu1.add(MenuSave); - - MenuSaveWithName.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/save.png"))); // NOI18N - MenuSaveWithName.setText("Save with name"); - MenuSaveWithName.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuSaveWithNameActionPerformed(evt); - } - }); - jMenu1.add(MenuSaveWithName); - jMenu1.add(jSeparator4); - - MenuImport.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/import.png"))); // NOI18N - MenuImport.setText("Import backup list"); - MenuImport.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuImportActionPerformed(evt); - } - }); - jMenu1.add(MenuImport); - - MenuExport.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/export.png"))); // NOI18N - MenuExport.setText("Export backup list"); - MenuExport.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuExportActionPerformed(evt); - } - }); - jMenu1.add(MenuExport); - jMenu1.add(jSeparator5); - - MenuClear.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_DOWN_MASK)); - MenuClear.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/clean.png"))); // NOI18N - MenuClear.setText("Clear"); - MenuClear.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuClearActionPerformed(evt); - } - }); - jMenu1.add(MenuClear); - - MenuHistory.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/clock.png"))); // NOI18N - MenuHistory.setText("History"); - MenuHistory.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuHistoryActionPerformed(evt); - } - }); - jMenu1.add(MenuHistory); - - jMenuBar1.add(jMenu1); - - jMenu2.setText("Options"); - - MenuPreferences.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/cogwheel.png"))); // NOI18N - MenuPreferences.setText("Preferences"); - MenuPreferences.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuPreferencesActionPerformed(evt); - } - }); - jMenu2.add(MenuPreferences); - - MenuQuit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.ALT_DOWN_MASK)); - MenuQuit.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/remove.png"))); // NOI18N - MenuQuit.setText("Quit"); - MenuQuit.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuQuitActionPerformed(evt); - } - }); - jMenu2.add(MenuQuit); - - jMenuBar1.add(jMenu2); - - jMenu3.setText("About"); - - MenuWebsite.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/website.png"))); // NOI18N - MenuWebsite.setText("Website"); - MenuWebsite.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuWebsiteActionPerformed(evt); - } - }); - jMenu3.add(MenuWebsite); - - MenuInfoPage.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/information.png"))); // NOI18N - MenuInfoPage.setText("Info"); - MenuInfoPage.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuInfoPageActionPerformed(evt); - } - }); - jMenu3.add(MenuInfoPage); - - MenuShare.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/share.png"))); // NOI18N - MenuShare.setText("Share"); - MenuShare.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuShareActionPerformed(evt); - } - }); - jMenu3.add(MenuShare); - - MenuDonate.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/donation.png"))); // NOI18N - MenuDonate.setText("Donate"); - MenuDonate.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuDonateActionPerformed(evt); - } - }); - jMenu3.add(MenuDonate); - - jMenuBar1.add(jMenu3); - - jMenu5.setText("Help"); - - MenuBugReport.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/bug.png"))); // NOI18N - MenuBugReport.setText("Report a bug"); - MenuBugReport.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuBugReportActionPerformed(evt); - } - }); - jMenu5.add(MenuBugReport); - - MenuSupport.setIcon(new javax.swing.ImageIcon(getClass().getResource("/res/img/help-desk.png"))); // NOI18N - MenuSupport.setText("Support"); - MenuSupport.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - MenuSupportActionPerformed(evt); - } - }); - jMenu5.add(MenuSupport); - - jMenuBar1.add(jMenu5); - - setJMenuBar(jMenuBar1); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(TabbedPane, javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(TabbedPane, javax.swing.GroupLayout.PREFERRED_SIZE, 636, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(jLabel3) - .addContainerGap(7, Short.MAX_VALUE)) - ); - - pack(); - setLocationRelativeTo(null); - }// </editor-fold>//GEN-END:initComponents - - private void MenuQuitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuQuitActionPerformed - Logger.logMessage("Event --> exit", Logger.LogLevel.INFO); - System.exit(EXIT_ON_CLOSE); - }//GEN-LAST:event_MenuQuitActionPerformed - - private void MenuHistoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuHistoryActionPerformed - Logger.logMessage("Event --> history", Logger.LogLevel.INFO); - try { - new ProcessBuilder("notepad.exe", ConfigKey.RES_DIRECTORY_STRING.getValue() + ConfigKey.LOG_FILE_STRING.getValue()).start(); - } catch (IOException e) { - Logger.logMessage("Error opening history file.", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_OPEN_HISTORY_FILE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - }//GEN-LAST:event_MenuHistoryActionPerformed - - private void MenuClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuClearActionPerformed - Clear(true); - }//GEN-LAST:event_MenuClearActionPerformed - - private void MenuSaveWithNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuSaveWithNameActionPerformed - SaveWithName(); - }//GEN-LAST:event_MenuSaveWithNameActionPerformed - - private void MenuSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuSaveActionPerformed - saveFile(); - }//GEN-LAST:event_MenuSaveActionPerformed - - private void MenuNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuNewActionPerformed - NewBackup(); - }//GEN-LAST:event_MenuNewActionPerformed - - private void SingleBackupActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SingleBackupActionPerformed - SingleBackup(startPathField.getText(), destinationPathField.getText()); - }//GEN-LAST:event_SingleBackupActionPerformed - - private void EditPoputItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_EditPoputItemActionPerformed - if (selectedRow != -1) { - Logger.logMessage("Edit row : " + selectedRow, Logger.LogLevel.INFO); - OpenBackup(backups.get(selectedRow).getBackupName()); - TabbedPane.setSelectedIndex(0); - } - }//GEN-LAST:event_EditPoputItemActionPerformed - - private void DeletePopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_DeletePopupItemActionPerformed - Logger.logMessage("Event --> deleting backup", Logger.LogLevel.INFO); - - if (selectedRow != -1) { - int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_MESSAGE_BEFORE_DELETE_BACKUP), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); - if (response == JOptionPane.YES_OPTION) { - RemoveBackup(backups.get(selectedRow).getBackupName()); - } - } - }//GEN-LAST:event_DeletePopupItemActionPerformed - - private void addBackupEntryButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addBackupEntryButtonActionPerformed - TabbedPane.setSelectedIndex(0); - NewBackup(); - }//GEN-LAST:event_addBackupEntryButtonActionPerformed - - private void researchFieldKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_researchFieldKeyTyped - researchInTable(); - }//GEN-LAST:event_researchFieldKeyTyped - - private void tableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tableMouseClicked - selectedRow = table.rowAtPoint(evt.getPoint()); // get index of the row - - if (selectedRow == -1) { // if clicked outside valid rows - table.clearSelection(); // deselect any selected row - detailsLabel.setText(""); // clear the label - } else { - // Handling right mouse button click - if (SwingUtilities.isRightMouseButton(evt)) { - AutoBackupMenuItem.setSelected(backups.get(selectedRow).isAutoBackup()); - table.setRowSelectionInterval(selectedRow, selectedRow); // select clicked row - TablePopup.show(evt.getComponent(), evt.getX(), evt.getY()); // show popup - } - - // Handling left mouse button double-click - else if (SwingUtilities.isLeftMouseButton(evt) && evt.getClickCount() == 2) { - Logger.logMessage("Edit row : " + selectedRow, Logger.LogLevel.INFO); - OpenBackup(backups.get(selectedRow).getBackupName()); - TabbedPane.setSelectedIndex(0); - } - - // Handling single left mouse button click - else if (SwingUtilities.isLeftMouseButton(evt)) { - String backupName = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.BACKUP_NAME_DETAIL); - String initialPath = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.INITIAL_PATH_DETAIL); - String destinationPath = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.DESTINATION_PATH_DETAIL); - String lastBackup = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.LAST_BACKUP_DETAIL); - String nextBackup = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.NEXT_BACKUP_DATE_DETAIL); - String timeIntervalBackup = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.TIME_INTERVAL_DETAIL); - String creationDate = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.CREATION_DATE_DETAIL); - String lastUpdateDate = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.LAST_UPDATE_DATE_DETAIL); - String backupCount = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.BACKUP_COUNT_DETAIL); - String notes = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.NOTES_DETAIL); - String maxBackupsToKeep = TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.MAX_BACKUPS_TO_KEEP_DETAIL); - - detailsLabel.setText( - "<html><b>" + backupName + ":</b> " + backups.get(selectedRow).getBackupName() + ", " + - "<b>" + initialPath + ":</b> " + backups.get(selectedRow).getInitialPath() + ", " + - "<b>" + destinationPath + ":</b> " + backups.get(selectedRow).getDestinationPath() + ", " + - "<b>" + lastBackup + ":</b> " + (backups.get(selectedRow).getLastBackup() != null ? backups.get(selectedRow).getLastBackup().format(formatter) : "") + ", " + - "<b>" + nextBackup + ":</b> " + (backups.get(selectedRow).getNextDateBackup() != null ? backups.get(selectedRow).getNextDateBackup().format(formatter) : "_") + ", " + - "<b>" + timeIntervalBackup + ":</b> " + (backups.get(selectedRow).getTimeIntervalBackup() != null ? backups.get(selectedRow).getTimeIntervalBackup().toString() : "_") + ", " + - "<b>" + creationDate + ":</b> " + (backups.get(selectedRow).getCreationDate() != null ? backups.get(selectedRow).getCreationDate().format(formatter) : "_") + ", " + - "<b>" + lastUpdateDate + ":</b> " + (backups.get(selectedRow).getLastUpdateDate() != null ? backups.get(selectedRow).getLastUpdateDate().format(formatter) : "_") + ", " + - "<b>" + backupCount + ":</b> " + (backups.get(selectedRow).getBackupCount()) + ", " + - "<b>" + maxBackupsToKeep + ":</b> " + (backups.get(selectedRow).getMaxBackupsToKeep()) + ", " + - "<b>" + notes + ":</b> " + (backups.get(selectedRow).getNotes()) + - "</html>" - ); - } - } - }//GEN-LAST:event_tableMouseClicked - - private void tablePanelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tablePanelMouseClicked - table.clearSelection(); // deselect any selected row - detailsLabel.setText(""); // clear the label - }//GEN-LAST:event_tablePanelMouseClicked - - private void DuplicatePopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_DuplicatePopupItemActionPerformed - Logger.logMessage("Event --> duplicating backup", Logger.LogLevel.INFO); - - if (selectedRow != -1) { - Backup backup = backups.get(selectedRow); - LocalDateTime dateNow = LocalDateTime.now(); - Backup newBackup = new Backup( - backup.getBackupName() + "_copy", - backup.getInitialPath(), - backup.getDestinationPath(), - null, - backup.isAutoBackup(), - backup.getNextDateBackup(), - backup.getTimeIntervalBackup(), - backup.getNotes(), - dateNow, - dateNow, - 0, - backup.getMaxBackupsToKeep() - ); - - backups.add(newBackup); - BackupOperations.updateBackupList(backups); - } - }//GEN-LAST:event_DuplicatePopupItemActionPerformed - - private void RunBackupPopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_RunBackupPopupItemActionPerformed - if (selectedRow != -1) { - - Backup backup = backups.get(selectedRow); - - progressBar = new BackupProgressGUI(backup.getInitialPath(), backup.getDestinationPath()); - progressBar.setVisible(true); - BackupOperations.SingleBackup(backup, null, progressBar, SingleBackup, toggleAutoBackup); - - // if the backup is currentBackup - if (currentBackup.getBackupName().equals(backup.getBackupName())) - currentBackup.UpdateBackup(backup); - } - }//GEN-LAST:event_RunBackupPopupItemActionPerformed - - private void CopyBackupNamePopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CopyBackupNamePopupItemActionPerformed - if (selectedRow != -1) { - StringSelection selection = new StringSelection(backups.get(selectedRow).getBackupName()); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); - } - }//GEN-LAST:event_CopyBackupNamePopupItemActionPerformed - - private void CopyInitialPathPopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CopyInitialPathPopupItemActionPerformed - if (selectedRow != -1) { - StringSelection selection = new StringSelection(backups.get(selectedRow).getInitialPath()); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); - } - }//GEN-LAST:event_CopyInitialPathPopupItemActionPerformed - - private void CopyDestinationPathPopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CopyDestinationPathPopupItemActionPerformed - if (selectedRow != -1) { - StringSelection selection = new StringSelection(backups.get(selectedRow).getDestinationPath()); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); - } - }//GEN-LAST:event_CopyDestinationPathPopupItemActionPerformed - - private void AutoBackupMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AutoBackupMenuItemActionPerformed - if (selectedRow != -1) { - Backup backup = backups.get(selectedRow); - boolean res = !backup.isAutoBackup(); - setAutoBackupPreference(backup, res); - AutoBackupMenuItem.setSelected(res); - if (res) { - AutomaticBackup(backup); - } - } - }//GEN-LAST:event_AutoBackupMenuItemActionPerformed - - private void OpenInitialFolderItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OpenInitialFolderItemActionPerformed - if (selectedRow != -1) { - OpenFolder(backups.get(selectedRow).getInitialPath()); - } - }//GEN-LAST:event_OpenInitialFolderItemActionPerformed - - private void OpenInitialDestinationItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OpenInitialDestinationItemActionPerformed - if (selectedRow != -1) { - OpenFolder(backups.get(selectedRow).getDestinationPath()); - } - }//GEN-LAST:event_OpenInitialDestinationItemActionPerformed - - private void renamePopupItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_renamePopupItemActionPerformed - if (selectedRow != -1) { - renameBackup(backups.get(selectedRow)); - } - }//GEN-LAST:event_renamePopupItemActionPerformed - - private void MenuDonateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuDonateActionPerformed - Logger.logMessage("Event --> donate", Logger.LogLevel.INFO); - openWebSite(ConfigKey.DONATE_PAGE_LINK.getValue()); - }//GEN-LAST:event_MenuDonateActionPerformed - - private void MenuBugReportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuBugReportActionPerformed - Logger.logMessage("Event --> bug report", Logger.LogLevel.INFO); - openWebSite(ConfigKey.ISSUE_PAGE_LINK.getValue()); - }//GEN-LAST:event_MenuBugReportActionPerformed - - private void MenuShareActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuShareActionPerformed - Logger.logMessage("Event --> share", Logger.LogLevel.INFO); - - // pop-up message - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.SHARE_LINK_COPIED_MESSAGE)); - - // copy link to the clipboard - StringSelection stringSelectionObj = new StringSelection(ConfigKey.SHARE_LINK.getValue()); - Clipboard clipboardObj = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboardObj.setContents(stringSelectionObj, null); - }//GEN-LAST:event_MenuShareActionPerformed - - private void toggleAutoBackupActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toggleAutoBackupActionPerformed - Logger.logMessage("Event --> Changing auto backup preference", Logger.LogLevel.INFO); - - // checks - if (!BackupOperations.CheckInputCorrect(currentBackup.getBackupName(),startPathField.getText(), destinationPathField.getText(), null)) { - toggleAutoBackup.setSelected(false); - return; - } - if (currentBackup.isAutoBackup()) { - int response = JOptionPane.showConfirmDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_MESSAGE_CANCEL_AUTO_BACKUP), TranslationCategory.DIALOGS.getTranslation(TranslationKey.CONFIRMATION_REQUIRED_TITLE), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); - if (response != JOptionPane.YES_OPTION) { - toggleAutoBackup.setSelected(false); - return; - } - } - - boolean enabled = toggleAutoBackup.isSelected(); - if (enabled && AutomaticBackup()) { - Logger.logMessage("Event --> Auto Backup setted to Enabled", Logger.LogLevel.INFO); - toggleAutoBackup.setSelected(true); - } - else { - Logger.logMessage("Event --> Auto Backup setted to Disabled", Logger.LogLevel.INFO); - disableAutoBackup(currentBackup); - toggleAutoBackup.setSelected(false); - return; - } - - toggleAutoBackup.setText(toggleAutoBackup.isSelected() ? backupOnText : backupOffText); - currentBackup.setAutoBackup(enabled); - BackupOperations.updateBackupList(backups); - }//GEN-LAST:event_toggleAutoBackupActionPerformed - - private void MenuWebsiteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuWebsiteActionPerformed - Logger.logMessage("Event --> shard website", Logger.LogLevel.INFO); - openWebSite(ConfigKey.SHARD_WEBSITE.getValue()); - }//GEN-LAST:event_MenuWebsiteActionPerformed - - private void MenuSupportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuSupportActionPerformed - Logger.logMessage("Event --> support", Logger.LogLevel.INFO); - - if (Desktop.isDesktopSupported()) { - Desktop desktop = Desktop.getDesktop(); - - if (desktop.isSupported(Desktop.Action.MAIL)) { - String subject = "Support - Backup Manager"; - String mailTo = "mailto:" + ConfigKey.EMAIL.getValue() + "?subject=" + encodeURI(subject); - - try { - URI uri = new URI(mailTo); - desktop.mail(uri); - } catch (IOException | URISyntaxException ex) { - Logger.logMessage("Failed to send email: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_UNABLE_TO_SEND_EMAIL), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - } else { - Logger.logMessage("Mail action is unsupported in your system's desktop environment.", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_NOT_SUPPORTED_EMAIL), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - } else { - Logger.logMessage("Desktop integration is unsupported on this system.", Logger.LogLevel.WARN); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_NOT_SUPPORTED_EMAIL_GENERIC), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_GENERIC_TITLE), JOptionPane.ERROR_MESSAGE); - } - }//GEN-LAST:event_MenuSupportActionPerformed - - private void MenuInfoPageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuInfoPageActionPerformed - Logger.logMessage("Event --> shard website", Logger.LogLevel.INFO); - openWebSite(ConfigKey.INFO_PAGE_LINK.getValue()); - }//GEN-LAST:event_MenuInfoPageActionPerformed - - private void btnPathSearch2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPathSearch2ActionPerformed - pathSearchWithFileChooser(destinationPathField, false); - }//GEN-LAST:event_btnPathSearch2ActionPerformed - - private void btnPathSearch1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPathSearch1ActionPerformed - pathSearchWithFileChooser(startPathField, true); - }//GEN-LAST:event_btnPathSearch1ActionPerformed - - private void btnTimePickerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnTimePickerActionPerformed - TimeInterval timeInterval = openTimePicker(currentBackup.getTimeIntervalBackup()); - if (timeInterval == null) return; - - btnTimePicker.setToolTipText(timeInterval.toString()); - LocalDateTime nextDateBackup = LocalDateTime.now().plusDays(timeInterval.getDays()) - .plusHours(timeInterval.getHours()) - .plusMinutes(timeInterval.getMinutes()); - - currentBackup.setTimeIntervalBackup(timeInterval); - currentBackup.setNextDateBackup(nextDateBackup); - currentBackup.setInitialPath(GetStartPathField()); - currentBackup.setDestinationPath(GetDestinationPathField()); - for (Backup b : backups) { - if (b.getBackupName().equals(currentBackup.getBackupName())) { - b.UpdateBackup(currentBackup); - break; - } - } - BackupOperations.updateBackupList(backups); - - openBackupActivationMessage(timeInterval); - - }//GEN-LAST:event_btnTimePickerActionPerformed - - private void MenuPreferencesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuPreferencesActionPerformed - openPreferences(); - }//GEN-LAST:event_MenuPreferencesActionPerformed - - private void MenuImportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuImportActionPerformed - Logger.logMessage("Event --> importing backup list", Logger.LogLevel.INFO); - - JFileChooser jfc = new JFileChooser(ConfigKey.RES_DIRECTORY_STRING.getValue()); - jfc.setFileSelectionMode(JFileChooser.FILES_ONLY); - - FileNameExtensionFilter jsonFilter = new FileNameExtensionFilter("JSON Files (*.json)", "json"); - jfc.setFileFilter(jsonFilter); - int returnValue = jfc.showSaveDialog(null); - - if (returnValue == JFileChooser.APPROVE_OPTION) { - File selectedFile = jfc.getSelectedFile(); - if (selectedFile.isFile() && selectedFile.getName().toLowerCase().endsWith(".json")) { - Logger.logMessage("File imported: " + selectedFile, Logger.LogLevel.INFO); - - Preferences.setBackupList(new BackupList(selectedFile.getParent()+File.separator, selectedFile.getName())); - Preferences.updatePreferencesToJSON(); - - try { - backups = JSON.ReadBackupListFromJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile()); - BackupOperations.updateTableWithNewBackupList(backups); - } catch (IOException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - } - - JOptionPane.showMessageDialog(this, TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_LIST_CORRECTLY_IMPORTED_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_LIST_CORRECTLY_IMPORTED_TITLE), JOptionPane.INFORMATION_MESSAGE); - } else { - JOptionPane.showMessageDialog(this, TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_WRONG_FILE_EXTENSION_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.ERROR_MESSAGE_FOR_WRONG_FILE_EXTENSION_TITLE), JOptionPane.ERROR_MESSAGE); - } - } - }//GEN-LAST:event_MenuImportActionPerformed - - private void MenuExportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MenuExportActionPerformed - Logger.logMessage("Event --> exporting backup list", Logger.LogLevel.INFO); - - Path desktopPath = Paths.get(System.getProperty("user.home"), "Desktop", Preferences.getBackupList().getFile()); - Path sourcePath = Paths.get(Preferences.getBackupList().getDirectory() + Preferences.getBackupList().getFile()); - - try { - Files.copy(sourcePath, desktopPath, StandardCopyOption.REPLACE_EXISTING); - JOptionPane.showMessageDialog(null, TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_LIST_CORRECTLY_EXPORTED_MESSAGE), TranslationCategory.DIALOGS.getTranslation(TranslationKey.BACKUP_LIST_CORRECTLY_EXPORTED_TITLE), JOptionPane.INFORMATION_MESSAGE); - } catch (java.nio.file.NoSuchFileException ex) { - Logger.logMessage("Source file not found: " + ex.getMessage(), Logger.LogLevel.ERROR); - JOptionPane.showMessageDialog(null, "Error: The source file was not found.\nPlease check the file path.", "Export Error", JOptionPane.ERROR_MESSAGE); - } catch (java.nio.file.AccessDeniedException ex) { - Logger.logMessage("Access denied to desktop: " + ex.getMessage(), Logger.LogLevel.ERROR); - JOptionPane.showMessageDialog(null, "Error: Access to the Desktop is denied.\nPlease check folder permissions and try again.","Export Error", JOptionPane.ERROR_MESSAGE); - } catch (IOException ex) { - Logger.logMessage("Unexpected error: " + ex.getMessage(), Logger.LogLevel.ERROR); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - }//GEN-LAST:event_MenuExportActionPerformed - - private void maxBackupCountSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_maxBackupCountSpinnerStateChanged - maxBackupCountSpinnerChange(); - }//GEN-LAST:event_maxBackupCountSpinnerStateChanged - - private void maxBackupCountSpinnerMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_maxBackupCountSpinnerMouseWheelMoved - mouseWeel(evt); - }//GEN-LAST:event_maxBackupCountSpinnerMouseWheelMoved - - private void setTranslations() { - try { - backups = JSON.ReadBackupListFromJSON(Preferences.getBackupList().getDirectory(), Preferences.getBackupList().getFile()); - displayBackupList(backups); - } catch (IOException ex) { - backups = null; - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - - backupOnText = TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.AUTO_BACKUP_BUTTON_ON); - backupOffText = TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.AUTO_BACKUP_BUTTON_OFF); - - // general - jLabel3.setText(TranslationCategory.GENERAL.getTranslation(TranslationKey.VERSION) + " " + current_version); - - // menu - jMenu1.setText(TranslationCategory.MENU.getTranslation(TranslationKey.FILE)); - jMenu2.setText(TranslationCategory.MENU.getTranslation(TranslationKey.OPTIONS)); - jMenu3.setText(TranslationCategory.MENU.getTranslation(TranslationKey.ABOUT)); - jMenu5.setText(TranslationCategory.MENU.getTranslation(TranslationKey.HELP)); - - // menu items - MenuBugReport.setText(TranslationCategory.MENU.getTranslation(TranslationKey.BUG_REPORT)); - MenuClear.setText(TranslationCategory.MENU.getTranslation(TranslationKey.CLEAR)); - MenuDonate.setText(TranslationCategory.MENU.getTranslation(TranslationKey.DONATE)); - MenuHistory.setText(TranslationCategory.MENU.getTranslation(TranslationKey.HISTORY)); - MenuInfoPage.setText(TranslationCategory.MENU.getTranslation(TranslationKey.INFO_PAGE)); - MenuNew.setText(TranslationCategory.MENU.getTranslation(TranslationKey.NEW)); - MenuQuit.setText(TranslationCategory.MENU.getTranslation(TranslationKey.QUIT)); - MenuSave.setText(TranslationCategory.MENU.getTranslation(TranslationKey.SAVE)); - MenuSaveWithName.setText(TranslationCategory.MENU.getTranslation(TranslationKey.SAVE_WITH_NAME)); - MenuPreferences.setText(TranslationCategory.MENU.getTranslation(TranslationKey.PREFERENCES)); - MenuImport.setText(TranslationCategory.MENU.getTranslation(TranslationKey.IMPORT)); - MenuExport.setText(TranslationCategory.MENU.getTranslation(TranslationKey.EXPORT)); - MenuShare.setText(TranslationCategory.MENU.getTranslation(TranslationKey.SHARE)); - MenuSupport.setText(TranslationCategory.MENU.getTranslation(TranslationKey.SUPPORT)); - MenuWebsite.setText(TranslationCategory.MENU.getTranslation(TranslationKey.WEBSITE)); - - // backup entry - TabbedPane.setTitleAt(0, TranslationCategory.TABBED_FRAMES.getTranslation(TranslationKey.BACKUP_ENTRY)); - TabbedPane.setTitleAt(1, TranslationCategory.TABBED_FRAMES.getTranslation(TranslationKey.BACKUP_LIST)); - btnPathSearch1.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.INITIAL_FILE_CHOOSER_TOOLTIP)); - btnPathSearch2.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.DESTINATION_FILE_CHOOSER_TOOLTIP)); - startPathField.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.INITIAL_PATH_TOOLTIP)); - destinationPathField.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.DESTINATION_PATH_TOOLTIP)); - backupNoteTextArea.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.NOTES_TOOLTIP)); - SingleBackup.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.SINGLE_BACKUP_BUTTON)); - SingleBackup.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.SINGLE_BACKUP_TOOLTIP)); - toggleAutoBackup.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.AUTO_BACKUP_BUTTON_OFF)); - toggleAutoBackup.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.AUTO_BACKUP_TOOLTIP)); - currentFileLabel.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.CURRENT_FILE) + ":"); - jLabel2.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.NOTES) + ":"); - lastBackupLabel.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.LAST_BACKUP) + ": "); - txtTitle.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.PAGE_TITLE)); - startPathField.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.INITIAL_PATH_PLACEHOLDER)); - destinationPathField.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.DESTINATION_PATH_PLACEHOLDER)); - btnTimePicker.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.TIME_PICKER_TOOLTIP)); - maxBackupCountSpinner.setToolTipText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.MAX_BACKUPS_TO_KEEP_TOOLTIP).toString() + "\n" + TranslationCategory.TIME_PICKER_DIALOG.getTranslation(TranslationKey.SPINNER_TOOLTIP).toString()); - jLabel4.setText(TranslationCategory.BACKUP_ENTRY.getTranslation(TranslationKey.MAX_BACKUPS_TO_KEEP)); - - // backup list - addBackupEntryButton.setToolTipText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.ADD_BACKUP_TOOLTIP)); - researchField.setToolTipText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.RESEARCH_BAR_TOOLTIP)); - researchField.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.RESEARCH_BAR_PLACEHOLDER)); - - // popup - CopyBackupNamePopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.COPY_BACKUP_NAME_POPUP)); - CopyDestinationPathPopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.COPY_DESTINATION_PATH_BACKUP)); - RunBackupPopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.SINGLE_BACKUP_POPUP)); - CopyInitialPathPopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.COPY_INITIAL_PATH_POPUP)); - DeletePopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.DELETE_POPUP)); - DuplicatePopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.DUPLICATE_POPUP)); - EditPoputItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.EDIT_POPUP)); - OpenInitialDestinationItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.OPEN_DESTINATION_FOLDER_POPUP)); - OpenInitialFolderItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.OPEN_INITIAL_FOLDER_POPUP)); - renamePopupItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.RENAME_BACKUP_POPUP)); - jMenu4.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.COPY_TEXT_POPUP)); - AutoBackupMenuItem.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.AUTO_BACKUP_POPUP)); - Backup.setText(TranslationCategory.BACKUP_LIST.getTranslation(TranslationKey.BACKUP_POPUP)); - } - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JCheckBoxMenuItem AutoBackupMenuItem; - private javax.swing.JMenu Backup; - private javax.swing.JMenuItem CopyBackupNamePopupItem; - private javax.swing.JMenuItem CopyDestinationPathPopupItem; - private javax.swing.JMenuItem CopyInitialPathPopupItem; - private javax.swing.JMenuItem DeletePopupItem; - private javax.swing.JMenuItem DuplicatePopupItem; - private javax.swing.JMenuItem EditPoputItem; - private javax.swing.JMenuItem MenuBugReport; - private javax.swing.JMenuItem MenuClear; - private javax.swing.JMenuItem MenuDonate; - private javax.swing.JMenuItem MenuExport; - private javax.swing.JMenuItem MenuHistory; - private javax.swing.JMenuItem MenuImport; - private javax.swing.JMenuItem MenuInfoPage; - private javax.swing.JMenuItem MenuNew; - private javax.swing.JMenuItem MenuPreferences; - private javax.swing.JMenuItem MenuQuit; - private javax.swing.JMenuItem MenuSave; - private javax.swing.JMenuItem MenuSaveWithName; - private javax.swing.JMenuItem MenuShare; - private javax.swing.JMenuItem MenuSupport; - private javax.swing.JMenuItem MenuWebsite; - private javax.swing.JMenuItem OpenInitialDestinationItem; - private javax.swing.JMenuItem OpenInitialFolderItem; - private javax.swing.JMenuItem RunBackupPopupItem; - private javax.swing.JButton SingleBackup; - private javax.swing.JTabbedPane TabbedPane; - private javax.swing.JPopupMenu TablePopup; - private javax.swing.JButton addBackupEntryButton; - private javax.swing.JTextArea backupNoteTextArea; - private javax.swing.JButton btnPathSearch1; - private javax.swing.JButton btnPathSearch2; - private javax.swing.JButton btnTimePicker; - private javax.swing.JLabel currentFileLabel; - private javax.swing.JTextField destinationPathField; - private javax.swing.JLabel detailsLabel; - private javax.swing.JPanel detailsPanel; - private javax.swing.Box.Filler filler1; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; - private javax.swing.JLabel jLabel3; - private javax.swing.JLabel jLabel4; - private javax.swing.JMenu jMenu1; - private javax.swing.JMenu jMenu2; - private javax.swing.JMenu jMenu3; - private javax.swing.JMenu jMenu4; - private javax.swing.JMenu jMenu5; - private javax.swing.JMenuBar jMenuBar1; - private javax.swing.JPanel jPanel1; - private javax.swing.JPanel jPanel2; - private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JScrollPane jScrollPane2; - private javax.swing.JPopupMenu.Separator jSeparator1; - private javax.swing.JPopupMenu.Separator jSeparator2; - private javax.swing.JPopupMenu.Separator jSeparator3; - private javax.swing.JPopupMenu.Separator jSeparator4; - private javax.swing.JPopupMenu.Separator jSeparator5; - private javax.swing.JLabel lastBackupLabel; - private javax.swing.JSpinner maxBackupCountSpinner; - private javax.swing.JMenuItem renamePopupItem; - private javax.swing.JTextField researchField; - private javax.swing.JTextField startPathField; - private javax.swing.JTable table; - private javax.swing.JPanel tablePanel; - private javax.swing.JToggleButton toggleAutoBackup; - private javax.swing.JLabel txtTitle; - // End of variables declaration//GEN-END:variables -} \ No newline at end of file diff --git a/src/main/java/com/mycompany/autobackupprogram/Interfaces/IJSONAutoBackup.java b/src/main/java/com/mycompany/autobackupprogram/Interfaces/IJSONAutoBackup.java deleted file mode 100644 index 95779d8..0000000 --- a/src/main/java/com/mycompany/autobackupprogram/Interfaces/IJSONAutoBackup.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.mycompany.autobackupprogram.Interfaces; - -import java.io.IOException; -import java.util.List; - -import com.mycompany.autobackupprogram.Entities.Backup; - -public interface IJSONAutoBackup { - public List<Backup> ReadBackupListFromJSON(String directoryPath, String filename) throws IOException; - public void UpdateBackupListJSON(String directoryPath, String filename, List<Backup> backups); - public void UpdateSingleBackupInJSON(String directoryPath, String filename, Backup updatedBackup); -} diff --git a/src/main/java/com/mycompany/autobackupprogram/JSONAutoBackup.java b/src/main/java/com/mycompany/autobackupprogram/JSONAutoBackup.java deleted file mode 100644 index ff78dbb..0000000 --- a/src/main/java/com/mycompany/autobackupprogram/JSONAutoBackup.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.mycompany.autobackupprogram; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - -import com.mycompany.autobackupprogram.Entities.Backup; -import com.mycompany.autobackupprogram.Entities.Preferences; -import com.mycompany.autobackupprogram.Entities.TimeInterval; -import static com.mycompany.autobackupprogram.GUI.BackupManagerGUI.OpenExceptionMessage; -import com.mycompany.autobackupprogram.Interfaces.IJSONAutoBackup; -import com.mycompany.autobackupprogram.Logger.LogLevel; - -public class JSONAutoBackup implements IJSONAutoBackup { - @Override - public List<Backup> ReadBackupListFromJSON(String directoryPath, String filename) throws IOException { - List<Backup> backupList = new ArrayList<>(); - - // check if the directory is correct, otherwise we have to reset to default - File directory = new File(directoryPath); - if (!directory.exists() || !directory.isDirectory()) { - Logger.logMessage("Directory of the backup list file doesn't exists (" + directoryPath + "), resetted to default value.", LogLevel.INFO); - Preferences.setBackupList(Preferences.getDefaultBackupList()); - Preferences.updatePreferencesToJSON(); - directoryPath = Preferences.getBackupList().getDirectory(); - } - - String filePath = directoryPath + filename; - File file = new File(filePath); - - // Check if the file exists and is not empty - if (!file.exists()) { - file.createNewFile(); - Logger.logMessage("New backup list created with name: " + filePath, LogLevel.INFO); - } - if (file.length() == 0) { - try (FileWriter writer = new FileWriter(file)) { - writer.write("[]"); - Logger.logMessage("File initialized with empty JSON array: []", LogLevel.INFO); - } catch (IOException e) { - Logger.logMessage("Error initializing file: " + e.getMessage(), LogLevel.ERROR, e); - throw e; - } - } - - JSONParser parser = new JSONParser(); - - try (FileReader reader = new FileReader(filePath)) { - JSONArray backupArray = (JSONArray) parser.parse(reader); - - for (Object obj : backupArray) { - JSONObject backupObj = (JSONObject) obj; - - String backupNameValue = (String) backupObj.get("backup_name"); - String startPathValue = (String) backupObj.get("start_path"); - String destinationPathValue = (String) backupObj.get("destination_path"); - String lastBackupStr = (String) backupObj.get("last_backup"); - String notesValue = (String) backupObj.get("notes"); - String creationDateStr = (String) backupObj.get("creation_date"); - String lastUpdateDateStr = (String) backupObj.get("last_update_date"); - int backupCountValue = Math.toIntExact((Long) backupObj.get("backup_count")); - int maxBackupsToKeepValue = Math.toIntExact((Long) backupObj.get("max_backups_to_keep")); - - Object value = backupObj.get("automatic_backup"); - Boolean automaticBackupValue = null; - if (value instanceof Boolean aBoolean) { - automaticBackupValue = aBoolean; - } else if (value instanceof String string) { - automaticBackupValue = Boolean.valueOf(string); - } else if (value instanceof Integer integer) { - automaticBackupValue = (integer == 1); - } - String nextDateBackupStr = (String) backupObj.get("next_date_backup"); - String daysIntervalBackupStr = (String) backupObj.get("time_interval_backup"); - - LocalDateTime lastBackupValue = lastBackupStr != null ? LocalDateTime.parse(lastBackupStr) : null; - LocalDateTime nextDateBackupValue = nextDateBackupStr != null ? LocalDateTime.parse(nextDateBackupStr) : null; - LocalDateTime creationDateValue = creationDateStr != null ? LocalDateTime.parse(creationDateStr) : null; - LocalDateTime lastUpdateDateValue = lastUpdateDateStr != null ? LocalDateTime.parse(lastUpdateDateStr) : null; - - backupList.add(new Backup( - backupNameValue, - startPathValue, - destinationPathValue, - lastBackupValue, - automaticBackupValue, - nextDateBackupValue, - TimeInterval.getTimeIntervalFromString(daysIntervalBackupStr), - notesValue, - creationDateValue, - lastUpdateDateValue, - backupCountValue, - maxBackupsToKeepValue - )); - } - - } catch (IOException | ParseException | NullPointerException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - return backupList; - } - - @Override - public void UpdateBackupListJSON(String directoryPath, String filename, List<Backup> backups) { - String filePath = directoryPath + filename; - - JSONArray updatedBackupArray = new JSONArray(); - for (Backup backup : backups) { - JSONObject backupObject = new JSONObject(); - backupObject.put("backup_name", backup.getBackupName()); - backupObject.put("start_path", backup.getInitialPath()); - backupObject.put("destination_path", backup.getDestinationPath()); - backupObject.put("last_backup", backup.getLastBackup() != null ? backup.getLastBackup().toString() : null); - backupObject.put("automatic_backup", backup.isAutoBackup()); - backupObject.put("next_date_backup", backup.getNextDateBackup() != null ? backup.getNextDateBackup().toString() : null); - backupObject.put("time_interval_backup", backup.getTimeIntervalBackup() != null ? backup.getTimeIntervalBackup().toString() : null); - backupObject.put("notes", backup.getNotes()); - backupObject.put("creation_date", backup.getCreationDate() != null ? backup.getCreationDate().toString() : null); - backupObject.put("last_update_date", backup.getLastUpdateDate() != null ? backup.getLastUpdateDate().toString() : null); - backupObject.put("backup_count", backup.getBackupCount()); - backupObject.put("max_backups_to_keep", backup.getMaxBackupsToKeep()); - - updatedBackupArray.add(backupObject); - } - - try (FileWriter file = new FileWriter(filePath)) { - file.write(updatedBackupArray.toJSONString()); - file.flush(); - } catch (IOException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - } - - @Override - public void UpdateSingleBackupInJSON(String directoryPath, String filename, Backup updatedBackup) { - String filePath = directoryPath + filename; - - try (FileReader reader = new FileReader(filePath)) { - JSONParser jsonParser = new JSONParser(); - JSONArray backupArray = (JSONArray) jsonParser.parse(reader); - - for (Object obj : backupArray) { - JSONObject backupObject = (JSONObject) obj; - - String backupName = (String) backupObject.get("backup_name"); - if (backupName.equals(updatedBackup.getBackupName())) { - backupObject.put("start_path", updatedBackup.getInitialPath()); - backupObject.put("destination_path", updatedBackup.getDestinationPath()); - backupObject.put("last_backup", updatedBackup.getLastBackup() != null ? updatedBackup.getLastBackup().toString() : null); - backupObject.put("automatic_backup", updatedBackup.isAutoBackup()); - backupObject.put("next_date_backup", updatedBackup.getNextDateBackup() != null ? updatedBackup.getNextDateBackup().toString() : null); - backupObject.put("time_interval_backup", updatedBackup.getTimeIntervalBackup() != null ? updatedBackup.getTimeIntervalBackup().toString() : null); - backupObject.put("notes", updatedBackup.getNotes()); - backupObject.put("creation_date", updatedBackup.getCreationDate() != null ? updatedBackup.getCreationDate().toString() : null); - backupObject.put("last_update_date", updatedBackup.getLastUpdateDate() != null ? updatedBackup.getLastUpdateDate().toString() : null); - backupObject.put("backup_count", updatedBackup.getBackupCount()); - backupObject.put("max_backups_to_keep", updatedBackup.getMaxBackupsToKeep()); - break; - } - } - - try (FileWriter file = new FileWriter(filePath)) { - file.write(backupArray.toJSONString()); - file.flush(); - } catch (IOException ex) { - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - - } catch (IOException | ParseException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/mycompany/autobackupprogram/JSONConfigReader.java b/src/main/java/com/mycompany/autobackupprogram/JSONConfigReader.java deleted file mode 100644 index f3b00cc..0000000 --- a/src/main/java/com/mycompany/autobackupprogram/JSONConfigReader.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.mycompany.autobackupprogram; - -import java.io.FileReader; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; -import java.io.IOException; - -public class JSONConfigReader { - - private final String filename; - private final String directoryPath; - private JSONObject config; - - public JSONConfigReader(String filename, String directoryPath) { - this.filename = filename; - this.directoryPath = directoryPath; - loadConfig(); // Load configuration at instantiation - } - - public boolean isLogLevelEnabled(String level) { - if (config == null) { - Logger.logMessage("Configuration not loaded. Cannot check log level", Logger.LogLevel.ERROR); - return false; - } - - JSONObject logService = (JSONObject) config.get("LogService"); - if (logService != null) { - Boolean isEnabled = (Boolean) logService.get(level); - return isEnabled != null && isEnabled; - } - return false; // Default to false if LogService or level is missing - } - - public boolean isMenuItemEnabled(String menuItem) { - if (config == null) { - Logger.logMessage("Configuration not loaded. Cannot check menu items", Logger.LogLevel.ERROR); - return false; - } - - JSONObject menuService = (JSONObject) config.get("MenuItems"); - if (menuService != null) { - Boolean isEnabled = (Boolean) menuService.get(menuItem); - return isEnabled != null && isEnabled; - } - return true; // Default to true - } - - public int getMaxLines() { - return getConfigValue("MaxLines", 1500); // Default to 1500 - } - - public int getLinesToKeepAfterFileClear() { - return getConfigValue("LinesToKeepAfterFileClear", 150); // Default to 150 - } - - public int getMaxCountForSameBackup() { - return getConfigValue("MaxCountForSameBackup", 3); // Default to 3 - } - - public int readCheckForBackupTimeInterval() throws IOException { - int timeInterval; - try { - JSONObject backupService = getBackupServiceConfig(); - Long interval = (Long) backupService.get("value"); - - // if the interval is null, set to default of 5 minutes - timeInterval = (interval != null) ? interval.intValue() : 5; - } catch (NullPointerException e) { - Logger.logMessage("Error retrieving backup time interval, defaulting to 5 minutes: " + e.getMessage(), Logger.LogLevel.ERROR); - timeInterval = 5; - } - - Logger.logMessage("Time interval set to " + timeInterval + " minutes", Logger.LogLevel.INFO); - return timeInterval; - } - - private int getConfigValue(String key, int defaultValue) { - try { - JSONObject logService = getLogServiceConfig(); - JSONObject configValue = (JSONObject) logService.get(key); - Long value = (Long) configValue.get("value"); - return (value != null) ? value.intValue() : defaultValue; - } catch (IOException | NullPointerException e) { - Logger.logMessage("Error retrieving config value for " + key + ": " + e.getMessage(), Logger.LogLevel.ERROR); - return defaultValue; - } - } - - private void loadConfig() { - String filePath = directoryPath + filename; - try (FileReader reader = new FileReader(filePath)) { - JSONParser parser = new JSONParser(); - config = (JSONObject) parser.parse(reader); - } catch (IOException | ParseException e) { - Logger.logMessage("Failed to load configuration: " + e.getMessage(), Logger.LogLevel.ERROR); - } - } - - private JSONObject getLogServiceConfig() throws IOException { - if (config == null) { - throw new IOException("Configuration not loaded."); - } - return (JSONObject) config.get("LogService"); - } - - private JSONObject getBackupServiceConfig() throws IOException { - if (config == null) { - throw new IOException("Configuration not loaded."); - } - return (JSONObject) config.get("BackupService"); - } -} diff --git a/src/main/java/com/mycompany/autobackupprogram/Logger.java b/src/main/java/com/mycompany/autobackupprogram/Logger.java deleted file mode 100644 index f1cb091..0000000 --- a/src/main/java/com/mycompany/autobackupprogram/Logger.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.mycompany.autobackupprogram; - -import java.io.*; -import java.nio.file.*; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.locks.ReentrantLock; - -import com.mycompany.autobackupprogram.Enums.ConfigKey; - -public class Logger { - - private static String LOG_PATH = ConfigKey.RES_DIRECTORY_STRING.getValue() + ConfigKey.LOG_FILE_STRING.getValue(); - private static final ReentrantLock lock = new ReentrantLock(); - private static boolean consoleLoggingEnabled = true; // Toggle for console logging - - // Cached configuration - public static JSONConfigReader configReader; - - public enum LogLevel { - INFO, DEBUG, WARN, ERROR - } - - public static void logMessage(String message) { - logMessage(message, LogLevel.INFO); - } - - public static void logMessage(String message, LogLevel level) { - logMessage(message, level, null); - } - - public static void logMessage(String message, LogLevel level, Throwable throwable) { - if (!isLogLevelEnabled(level)) { - return; // Skip logging if the level is not enabled in config - } - - File logFile = new File(LOG_PATH); - - lock.lock(); - try { - int maxLines = configReader.getMaxLines(); - int linesToKeep = configReader.getLinesToKeepAfterFileClear(); - - List<String> lines = new ArrayList<>(); - if (logFile.exists()) { - lines = Files.readAllLines(logFile.toPath()); - } - - // Keep only the most recent lines if exceeding max lines - if (lines.size() > maxLines) { - lines = lines.subList(lines.size() - linesToKeep, lines.size()); - } - - String formattedMessage = String.format("%s [%s] %s", LocalDateTime.now(), level, message); - lines.add(0, formattedMessage); - - if (throwable != null) { - lines.add("Exception: " + throwable.getClass().getName() + " - " + throwable.getMessage()); - for (StackTraceElement element : throwable.getStackTrace()) { - lines.add("\tat " + element.toString()); - } - } - - writeLinesToFile(logFile, lines); - - if (consoleLoggingEnabled) { - System.out.println(formattedMessage); - } - - } catch (IOException ex) { - System.err.println("Logging failed: " + ex.getMessage()); - } finally { - lock.unlock(); - } - } - - private static void writeLinesToFile(File logFile, List<String> lines) throws IOException { - try (BufferedWriter bw = new BufferedWriter(new FileWriter(logFile))) { - for (String line : lines) { - bw.write(line); - bw.newLine(); - } - } - } - - private static boolean isLogLevelEnabled(LogLevel level) { - return configReader.isLogLevelEnabled(level.name()); - } - - public static void setConsoleLoggingEnabled(boolean enabled) { - consoleLoggingEnabled = enabled; - } - - public static void setLogFilePath(String filepath) { - LOG_PATH = filepath; - } -} diff --git a/src/main/java/com/mycompany/autobackupprogram/MainApp.java b/src/main/java/com/mycompany/autobackupprogram/MainApp.java deleted file mode 100644 index ec7fa80..0000000 --- a/src/main/java/com/mycompany/autobackupprogram/MainApp.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.mycompany.autobackupprogram; - -import java.io.IOException; -import java.util.Arrays; - -import org.json.simple.parser.ParseException; - -import com.mycompany.autobackupprogram.Entities.Preferences; -import com.mycompany.autobackupprogram.Enums.ConfigKey; -import com.mycompany.autobackupprogram.Enums.TranslationLoaderEnum; -import com.mycompany.autobackupprogram.GUI.BackupManagerGUI; -import static com.mycompany.autobackupprogram.GUI.BackupManagerGUI.OpenExceptionMessage; -import com.mycompany.autobackupprogram.Logger.LogLevel; - -public class MainApp { - private static final String CONFIG = "src/main/resources/res/config/config.json"; - - public static void main(String[] args) { - // load config keys - ConfigKey.loadFromJson(CONFIG); - Logger.configReader = new JSONConfigReader(ConfigKey.CONFIG_FILE_STRING.getValue(), ConfigKey.CONFIG_DIRECTORY_STRING.getValue()); - - // load preferred language - try { - Preferences.loadPreferencesFromJSON(); - TranslationLoaderEnum.loadTranslations(ConfigKey.LANGUAGES_DIRECTORY_STRING.getValue() + Preferences.getLanguage().getFileName()); - } catch (IOException | ParseException ex) { - Logger.logMessage("An error occurred during loading preferences: ", LogLevel.DEBUG, ex); - } - - boolean isBackgroundMode = args.length > 0 && args[0].equalsIgnoreCase("--background"); - - // check argument correction - if (!isBackgroundMode && args.length > 0) { - Logger.logMessage("Argument \""+ args[0] +"\" not valid!", Logger.LogLevel.WARN); - throw new IllegalArgumentException("Argument passed is not valid!"); - } - - Logger.logMessage("Application started", Logger.LogLevel.INFO); - Logger.logMessage("Background mode: " + isBackgroundMode, Logger.LogLevel.DEBUG); - - if (isBackgroundMode) { - Logger.logMessage("Backup service starting in the background", Logger.LogLevel.INFO); - BackupService service = new BackupService(); - try { - service.startService(); - } catch (IOException ex) { - Logger.logMessage("An error occurred: " + ex.getMessage(), Logger.LogLevel.ERROR, ex); - OpenExceptionMessage(ex.getMessage(), Arrays.toString(ex.getStackTrace())); - } - } - else if (!isBackgroundMode) { - javax.swing.SwingUtilities.invokeLater(() -> { - BackupManagerGUI gui = new BackupManagerGUI(); - gui.showWindow(); - }); - } - } -} diff --git a/src/main/resources/config.properties b/src/main/resources/config.properties new file mode 100644 index 0000000..8e21d62 --- /dev/null +++ b/src/main/resources/config.properties @@ -0,0 +1,4 @@ +smtp.from=backupmanager@shardpc.it +smtp.password=vfw@\#KtvOeRq +smtp.smtp=mail.shardpc.it +smtp.user=backupmanager@shardpc.it \ No newline at end of file diff --git a/src/main/resources/docs/code_documentation.md b/src/main/resources/docs/code_documentation.md new file mode 100644 index 0000000..539de02 --- /dev/null +++ b/src/main/resources/docs/code_documentation.md @@ -0,0 +1,62 @@ +<center> <img src="../res/img/logo.png" height="150"> </center> + +# Backup Manager Documentation + +## Startup backgroud service Logic +```mermaid +graph TD + n1(((PC Startup))) --> n2(Start Background Service) + n2 --> n3(Start TrayIcon) + n2 --> n4(Periodic Auto Backup Check) + n3 -->|click| n5(Start GUI) + n3 -->|exit| n6(Shutdown Backup Service) +``` + +## Link +* [SVG](https://www.svgrepo.com/) + +## Dependecies +For this project i'm using some dependencies: +* **Flatlaf** for multi theme ([demo](https://www.formdev.com/flatlaf/#demo), [themes](https://www.formdev.com/flatlaf/themes/), [github](https://github.com/JFormDesigner/FlatLaf/tree/main/flatlaf-intellij-themes)) +* **Gson** for manage json data +* **itextpdf** for pdf export +* **flatlaf-extras** to use svg images ([website]( https://mvnrepository.com/artifact/com.formdev/flatlaf-extras)) +* **slf4j-api** and **logback-classic** for logging + +## Logging +The logging system currently used is **logback**. You can check the current configuration in [CONFIG](../logback.xml). +Our logging system writes logs in console and in file .log. + +### configuration +* We use "ROLLING_FILE" configuration +* Our configuration has the objective to change log file every day and keep the last 7 days of .log files: + * During the current day, the active file will always be `logs/application.log`. + * At midnight, the current file is renamed with the date (e.g., `application-2025-01-22.log`), and a new `application.log` file is created. +* You can check if the current configuration works using `<configuration debug="true">` + +### Enable and disable log levels +To control log types (such as enabling/disabling log levels or specific appenders) without modifying the code, you can manage them through the Logback configuration file: logback.xml. + +To dynamically change the log level, edit the level value in the `<root>` tag: + +```xml +<root level="debug"> + <appender-ref ref="CONSOLE" /> + <appender-ref ref="FILE" /> +</root> +``` + +debug: Logs all messages (DEBUG, INFO, WARN, ERROR). +info: Ignores DEBUG, logs only INFO, WARN, and ERROR. +warn: Ignores DEBUG and INFO, logs only WARN and ERROR. +error: Logs only ERROR. + +## Threads +### [BackgroundService](../../java/backupmanager/Services/BackupService.java) +This thread is executed only on PC startup. <br> +It is used for + +### [RunningBackupObserver](../../java/backupmanager/Services/RunningBackupObserver.java) +I need a thread that constantly checks if there are something running and i can't use a simple method calls instead because +if a backup starts caused by the BackugroundService and we open the GUI, thre are 2 different instance of this program, +so we need something like an observer that constantly checks if there are some backups in progress. \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..22f4b44 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,133 @@ +<configuration debug="false" scan="true" scanPeriod="30 seconds"> + + <!--<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />--> <!--Scan this configuration for errors--> + + <!-- Properties --> + <property resource="config.properties" /> + <property name="smtp.user" value="${smtp.user}" /> + <property name="smtp.from" value="${smtp.from}" /> + <property name="smtp.password" value="${smtp.password}" /> + <property name="smtp.host" value="${smtp.smtp}" /> + <property name="smtp.email_confirmation_to" value="${smtp.email_confirmation_to}" /> + <property name="EMAIL_TO" value="assistenza@shardpc.it" /> <!--test1@shardpc.it--> + <property name="EMAIL_ERROR_SUBJECT" value="⚠ BackupManager - Critical error in application ⚠" /> + <property name="EMAIL_INFO_SUBJECT" value="🆕 BackupManager - New user registered!! 🆕" /> + <property name="EMAIL_CONFIRMATION_SUBJECT" value="BackupManager - Welcome!" /> + <property name="LOG_DIR" value="./src/main/resources/res/logs" /> + <property name="MAX_HISTORY" value="7" /> + <property name="TOTAL_SIZE" value="100MB" /> + + <!-- Console appender --> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] [%-5level] %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <!-- Rolling file appender --> + <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${LOG_DIR}/application.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${LOG_DIR}/application-%d{dd-MM-yyyy}.log.gz</fileNamePattern> + <maxHistory>${MAX_HISTORY}</maxHistory> + </rollingPolicy> + <encoder> + <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] [%-5level] %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <!-- async appender --> + <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> + <appender-ref ref="ROLLING_FILE" /> + </appender> + + <!--Appernder only for the error logs--> + <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${LOG_DIR}/error.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>${LOG_DIR}/error-%d{dd-MM-yyyy}.log.gz</fileNamePattern> + <maxHistory>${MAX_HISTORY}</maxHistory> + </rollingPolicy> + <encoder> + <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] [%-5level] %logger{36} - %msg%n</pattern> + </encoder> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- Error email appender --> + <appender name="ERROR_EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"> + <smtpHost>${smtp.host}</smtpHost> + <to>${EMAIL_TO}</to> + <from>${smtp.from}</from> + <username>${smtp.user}</username> + <password>${smtp.password}</password> + <subject>${EMAIL_ERROR_SUBJECT}</subject> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern> + </layout> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- info email appender --> + <appender name="INFO_EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"> + <smtpHost>${smtp.host}</smtpHost> + <to>${EMAIL_TO}</to> + <from>${smtp.from}</from> + <username>${smtp.user}</username> + <password>${smtp.password}</password> + <subject>${EMAIL_INFO_SUBJECT}</subject> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%d{yyyy-MM-dd HH:mm:ss} %logger{36} - %msg%n</pattern> + </layout> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> <!--Should be info, but if you change it, it doesn't work--> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- confirmation email appender --> + <appender name="EMAIL_CONFIRMATION_LOGGER" class="ch.qos.logback.classic.net.SMTPAppender"> + <smtpHost>${smtp.host}</smtpHost> + <to>${EMAIL_TO}</to> + <from>${smtp.from}</from> + <username>${smtp.user}</username> + <password>${smtp.password}</password> + <subject>${EMAIL_CONFIRMATION_SUBJECT}</subject> + <layout class="ch.qos.logback.classic.PatternLayout"> + <pattern>%msg%n</pattern> + </layout> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> <!--Should be info, but if you change it, it doesn't work--> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <logger name="EMAIL_ERROR_LOGGER" level="ERROR" additivity="false"> + <appender-ref ref="ERROR_EMAIL" /> + </logger> + + <logger name="EMAIL_INFO_LOGGER" level="ERROR" additivity="false"> <!--Should be info, but if you change it, it doesn't work--> + <appender-ref ref="INFO_EMAIL" /> + </logger> + + <logger name="EMAIL_CONFIRMATION_LOGGER" level="ERROR" additivity="false"> <!--Should be info, but if you change it, it doesn't work--> + <appender-ref ref="EMAIL_CONFIRMATION_LOGGER" /> + </logger> + + <!-- Root logger --> + <root level="info"> + <appender-ref ref="CONSOLE" /> + <appender-ref ref="ASYNC" /> + <appender-ref ref="ERROR_FILE" /> + </root> +</configuration> \ No newline at end of file diff --git a/src/main/resources/res/backup_list2.0.4.json b/src/main/resources/res/backup_list2.0.4.json deleted file mode 100644 index 760bc8f..0000000 --- a/src/main/resources/res/backup_list2.0.4.json +++ /dev/null @@ -1 +0,0 @@ -[{"time_interval_backup":null,"destination_path":"C:\\Users\\Utente\\Desktop","automatic_backup":false,"backup_name":"testone","notes":"","backup_count":28,"next_date_backup":null,"max_backups_to_keep":3,"start_path":"C:\\Users\\Utente\\Desktop\\DJI_20240925130642_0030_D.JPG","creation_date":"2024-12-12T21:44:37.283133900","last_backup":"2024-12-15T18:24:01.604149400","last_update_date":"2024-12-15T19:18:30.219573400"},{"time_interval_backup":null,"destination_path":"C:\\Users\\Utente\\Desktop","automatic_backup":false,"backup_name":"test","notes":"","backup_count":9,"next_date_backup":null,"max_backups_to_keep":3,"start_path":"C:\\Users\\Utente\\Desktop\\gg","creation_date":"2024-12-12T22:16:07.418800400","last_backup":"2024-12-15T18:23:46.142024700","last_update_date":"2024-12-15T19:48:22.694237500"},{"time_interval_backup":null,"destination_path":"C:\\Users\\Utente\\Desktop","automatic_backup":false,"backup_name":"test2","notes":"","backup_count":9,"next_date_backup":null,"max_backups_to_keep":3,"start_path":"C:\\Users\\Utente\\Desktop\\test.txt","creation_date":"2024-12-12T22:52:41.381624500","last_backup":"2024-12-12T23:29:01.963425500","last_update_date":"2024-12-15T19:42:11.680337300"},{"time_interval_backup":null,"destination_path":"C:\\Users\\Utente\\Desktop","automatic_backup":false,"backup_name":"testoso","notes":"","backup_count":1,"next_date_backup":null,"max_backups_to_keep":3,"start_path":"C:\\Users\\Utente\\Desktop\\test testoso","creation_date":"2024-12-14T15:25:02.587785800","last_backup":"2024-12-14T15:55:17.694068","last_update_date":"2024-12-15T18:56:37.110488"}] \ No newline at end of file diff --git a/src/main/resources/res/backup_list2.0.5.json b/src/main/resources/res/backup_list2.0.5.json new file mode 100644 index 0000000..b63b451 --- /dev/null +++ b/src/main/resources/res/backup_list2.0.5.json @@ -0,0 +1,206 @@ +[ + { + "backup_name": "testone", + "start_path": "CIAO899999", + "destination_path": "C:\\Users\\Utente\\Desktop^\u0026^", + "last_backup": "2025-02-02T13:25:36.508664500", + "automatic_backup": false, + "notes": "ghjgdsahjgdashjd\nasdiuasdh uijlasgdyhjkgasyjhdgasjhkgdhjasgdhjgashjgdhjasgd", + "creation_date": "2024-12-12T21:44:37.283133900", + "last_update_date": "2025-02-03T14:04:08.053368500", + "backup_count": 30, + "max_backups_to_keep": 3 + }, + { + "backup_name": "test2", + "start_path": "C:\\Users\\Utente\\Desktop\\test.txt", + "destination_path": "C:\\Users\\Utente\\Desktop", + "last_backup": "2024-12-12T23:29:01.963425500", + "automatic_backup": false, + "notes": "", + "creation_date": "2024-12-12T22:52:41.381624500", + "last_update_date": "2025-02-04T13:53:54.596237300", + "backup_count": 9, + "max_backups_to_keep": 3 + }, + { + "backup_name": "testoso", + "start_path": "C:\\Users\\Utente\\Desktop\\test testoso", + "destination_path": "C:\\Users\\Utente\\Desktop", + "last_backup": "2024-12-14T15:55:17.694068", + "automatic_backup": false, + "notes": "", + "creation_date": "2024-12-14T15:25:02.587785800", + "last_update_date": "2025-01-05T18:32:05.192917100", + "backup_count": 1, + "max_backups_to_keep": 3 + }, + { + "backup_name": "Immagini", + "start_path": "C:\\Users\\d.turco\\Desktop\\1728444935042.gif", + "destination_path": "C:\\Users\\d.turco\\Desktop", + "last_backup": "2024-12-31T00:28:58.600541", + "automatic_backup": false, + "notes": "", + "creation_date": "2024-12-25T21:09:27.794512800", + "last_update_date": "2025-01-23T11:09:52.304727200", + "backup_count": 7, + "max_backups_to_keep": 3 + }, + { + "backup_name": "lezioni", + "start_path": "C:\\Users\\Utente\\Desktop\\lezioni", + "destination_path": "C:\\Users\\Utente\\Desktop", + "last_backup": "2025-02-04T21:58:11.828011500", + "automatic_backup": false, + "notes": "", + "creation_date": "2024-12-26T11:39:05.784050", + "last_update_date": "2025-02-06T16:26:00.548931400", + "backup_count": 67, + "max_backups_to_keep": 1 + }, + { + "backup_name": "Documents2", + "start_path": "C:\\Users\\Utente\\Documents", + "destination_path": "C:\\Users\\Utente\\Desktop", + "last_backup": "2025-02-04T21:44:42.333563800", + "automatic_backup": false, + "notes": "", + "creation_date": "2024-12-27T21:03:01.013826200", + "last_update_date": "2025-01-22T23:37:11.115778400", + "backup_count": 20, + "max_backups_to_keep": 3 + }, + { + "backup_name": "dsaj", + "start_path": "C:\\Users\\Utente\\Desktop\\Dennis", + "destination_path": "C:\\Users\\Utente\\Desktop", + "automatic_backup": false, + "notes": "", + "creation_date": "2024-12-28T00:00:00.017265400", + "last_update_date": "2025-02-06T23:17:19.446141600", + "backup_count": 0, + "max_backups_to_keep": 3 + }, + { + "backup_name": "Documents1", + "start_path": "D:\\Documents", + "destination_path": "C:\\Users\\Utente\\Desktop", + "last_backup": "2025-02-06T22:58:58.910553", + "automatic_backup": false, + "notes": "", + "creation_date": "2024-12-29T13:28:19.132467600", + "last_update_date": "2025-02-06T23:26:57.363907600", + "backup_count": 12, + "max_backups_to_keep": 1 + }, + { + "backup_name": "Documents1_copy", + "start_path": "D:\\Documents", + "destination_path": "C:\\Users\\Utente\\Desktop", + "automatic_backup": false, + "notes": "", + "creation_date": "2024-12-29T13:30:37.591067200", + "last_update_date": "2025-02-05T09:15:20.591975100", + "backup_count": 0, + "max_backups_to_keep": 3 + }, + { + "backup_name": "asd_copy", + "start_path": "asdasd", + "destination_path": "saddsa", + "automatic_backup": false, + "notes": "", + "creation_date": "2025-01-08T13:02:22.396939", + "last_update_date": "2025-02-03T10:36:32.513605800", + "backup_count": 0, + "max_backups_to_keep": 3 + }, + { + "backup_name": "testooooo", + "start_path": "C:\\Users\\Utente\\Desktop\\gg", + "destination_path": "C:\\Users\\Utente\\Desktop\\", + "last_backup": "2025-01-24T23:07:17.176864600", + "automatic_backup": false, + "notes": "", + "creation_date": "2025-01-19T23:35:07.002086800", + "last_update_date": "2025-01-24T23:07:29.442828300", + "backup_count": 87, + "max_backups_to_keep": 1 + }, + { + "backup_name": "kkk", + "start_path": "C:\\Users\\d.turco\\Desktop\\1728444935042.gif", + "destination_path": "C:\\Users\\d.turco\\Desktop", + "automatic_backup": false, + "notes": "", + "creation_date": "2025-01-20T16:29:27.226503700", + "last_update_date": "2025-01-21T12:50:45.485537200", + "backup_count": 0, + "max_backups_to_keep": 3 + }, + { + "backup_name": "hh", + "start_path": "C:\\Users\\d.turco\\Desktop\\connections.xml", + "destination_path": "C:\\Users\\d.turco\\Desktop", + "last_backup": "2025-01-21T15:55:00.611051100", + "automatic_backup": false, + "notes": "", + "creation_date": "2025-01-20T16:37:28.849117800", + "last_update_date": "2025-01-22T23:30:10.017996700", + "backup_count": 2, + "max_backups_to_keep": 3 + }, + { + "backup_name": "d.turco", + "start_path": "D:\\Projects\\ISTrust", + "destination_path": "C:\\Users\\d.turco\\Desktop", + "last_backup": "2025-01-21T13:09:48.377993400", + "automatic_backup": false, + "notes": "", + "creation_date": "2025-01-21T12:50:16.698428400", + "last_update_date": "2025-01-22T23:30:07.790084300", + "backup_count": 0, + "max_backups_to_keep": 3 + }, + { + "backup_name": "d.turco2", + "start_path": "C:\\Users\\d.turco\\Desktop\\powershell_scripts", + "destination_path": "C:\\Users\\d.turco\\Desktop", + "last_backup": "2025-02-05T14:42:53.518990400", + "automatic_backup": true, + "next_date_backup": "2025-02-05T14:48:53.517991900", + "time_interval_backup": "0.0:6", + "notes": "", + "creation_date": "2025-01-21T14:27:24.724948700", + "last_update_date": "2025-02-05T09:41:12.210460800", + "backup_count": 23, + "max_backups_to_keep": 1 + }, + { + "backup_name": "test", + "start_path": "C:\\Users\\Utente\\Desktop\\Dennis\\File vari", + "destination_path": "C:\\Users\\Utente\\Desktop", + "last_backup": "2025-01-24T20:10:42.271929900", + "automatic_backup": false, + "notes": "", + "creation_date": "2025-01-23T19:16:38.608844600", + "last_update_date": "2025-02-04T14:06:48.066937", + "backup_count": 6, + "max_backups_to_keep": 1 + }, + { + "backup_name": "d.turco2_copy", + "start_path": "C:\\Users\\d.turco\\Desktop\\DennisTurco", + "destination_path": "C:\\Users\\d.turco\\Desktop", + "last_backup": "2025-02-05T14:46:41.766740200", + "automatic_backup": true, + "next_date_backup": "2025-02-05T14:48:41.766740200", + "time_interval_backup": "0.0:2", + "notes": "", + "creation_date": "2025-02-04T10:11:06.269395600", + "last_update_date": "2025-02-05T14:30:23.715447100", + "backup_count": 9, + "max_backups_to_keep": 1 + } +] \ No newline at end of file diff --git a/src/main/resources/res/config/config.json b/src/main/resources/res/config/config.json index 9bf3caa..b266390 100644 --- a/src/main/resources/res/config/config.json +++ b/src/main/resources/res/config/config.json @@ -1,19 +1,25 @@ { - "LOG_FILE_STRING": "log_file", "BACKUP_FILE_STRING": "backup_list", "CONFIG_FILE_STRING": "config.json", + "LOG_FILE_STRING": "application.log", + "LOG_DIRECTORY_STRING": "src/main/resources/res/logs/", + "RUNNING_BACKUPS_FILE_STRING": "running_backups.json", "PREFERENCES_FILE_STRING": "preferences.json", + "USER_FILE_STRING": "user.json", "RES_DIRECTORY_STRING": "src/main/resources/res/", + "PROPERTIES_FILE_STRING": "config.properties", + "RESURCES_DIRECTORY_STRING": "src/main/resources/", "LANGUAGES_DIRECTORY_STRING": "src/main/resources/res/languages/", "CONFIG_DIRECTORY_STRING": "src/main/resources/res/config/", - "DONATE_PAGE_LINK": "https://buymeacoffee.com/denno", + "DONATE_BUYMEACOFFE_LINK": "https://buymeacoffee.com/denno", + "DONATE_PAYPAL_LINK": "https://www.paypal.com/donate/?hosted_button_id=M7CJXS929334U", "ISSUE_PAGE_LINK": "https://github.com/DennisTurco/BackupManager/issues", "INFO_PAGE_LINK": "https://github.com/DennisTurco/BackupManager", "SHARE_LINK": "https://github.com/DennisTurco/BackupManager/releases", "EMAIL": "assistenza@shardpc.it", "SHARD_WEBSITE": "https://www.shardpc.it/", "LOGO_IMG": "/res/img/logo.png", - "VERSION": "2.0.4", + "VERSION": "2.0.5", "GUI_WIDTH": "982", "GUI_HEIGHT": "715", @@ -22,6 +28,8 @@ "Preferences": true, "Clear": true, "Donate": false, + "PaypalDonate": true, + "BuymeacoffeeDonate": true, "History": false, "InfoPage": true, "New": true, @@ -34,31 +42,14 @@ "Support": true, "Website": true }, - "BackupService": { "value": 1, "type": "int", "description": "Interval in minutes to check for auto backup" }, - "LogService": { - "ERROR": true, - "INFO": true, - "WARN": true, - "DEBUG": true, - "MaxLines": { - "value": 10000, - "type": "int", - "description": "Maximum number of logs for the file" - }, - "LinesToKeepAfterFileClear": { - "value": 1000, - "type": "int", - "description": "Lines to keep after file clear" - }, - "MaxCountForSameBackup": { - "value": 3, - "type": "int", - "description": "Max count for the same backup in the same directory" - } + "MaxCountForSameBackup": { + "value": 1, + "type": "int", + "description": "Max count for the same backup in the same directory" } } \ No newline at end of file diff --git a/src/main/resources/res/config/preferences.json b/src/main/resources/res/config/preferences.json index ddb4942..a2523ea 100644 --- a/src/main/resources/res/config/preferences.json +++ b/src/main/resources/res/config/preferences.json @@ -1 +1 @@ -{"Language":"deu.json","Theme":"Carbon","BackupList":{"Directory":"src/main/resources/res/","File":"backup_list2.0.4.json"}} \ No newline at end of file +{"Language":"eng.json","Theme":"Light","BackupList":{"Directory":"src/main/resources/res/","File":"backup_list2.0.5.json"}} \ No newline at end of file diff --git a/src/main/resources/res/config/running_backups.json b/src/main/resources/res/config/running_backups.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/src/main/resources/res/config/running_backups.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/main/resources/res/log_file b/src/main/resources/res/config/user.json similarity index 100% rename from src/main/resources/res/log_file rename to src/main/resources/res/config/user.json diff --git a/src/main/resources/res/img/add-file.png b/src/main/resources/res/img/add-file.png deleted file mode 100644 index 51b1baa..0000000 Binary files a/src/main/resources/res/img/add-file.png and /dev/null differ diff --git a/src/main/resources/res/img/add.svg b/src/main/resources/res/img/add.svg new file mode 100644 index 0000000..2aec1be --- /dev/null +++ b/src/main/resources/res/img/add.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M11 8C11 7.44772 11.4477 7 12 7C12.5523 7 13 7.44772 13 8V11H16C16.5523 11 17 11.4477 17 12C17 12.5523 16.5523 13 16 13H13V16C13 16.5523 12.5523 17 12 17C11.4477 17 11 16.5523 11 16V13H8C7.44771 13 7 12.5523 7 12C7 11.4477 7.44772 11 8 11H11V8Z" fill="#0F0F0F"/> +<path fill-rule="evenodd" clip-rule="evenodd" d="M23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12ZM3.00683 12C3.00683 16.9668 7.03321 20.9932 12 20.9932C16.9668 20.9932 20.9932 16.9668 20.9932 12C20.9932 7.03321 16.9668 3.00683 12 3.00683C7.03321 3.00683 3.00683 7.03321 3.00683 12Z" fill="#0F0F0F"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/bin.png b/src/main/resources/res/img/bin.png deleted file mode 100644 index a107504..0000000 Binary files a/src/main/resources/res/img/bin.png and /dev/null differ diff --git a/src/main/resources/res/img/bug.png b/src/main/resources/res/img/bug.png deleted file mode 100644 index 27d548f..0000000 Binary files a/src/main/resources/res/img/bug.png and /dev/null differ diff --git a/src/main/resources/res/img/bug.svg b/src/main/resources/res/img/bug.svg new file mode 100644 index 0000000..4ad6bcb --- /dev/null +++ b/src/main/resources/res/img/bug.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M12 19C9.23858 19 7 16.7614 7 14M12 19C14.7614 19 17 16.7614 17 14M12 19V14M7 14V11.8571C7 11.0592 7 10.6602 7.11223 10.3394C7.31326 9.76495 7.76495 9.31326 8.33944 9.11223C8.66019 9 9.05917 9 9.85714 9H14.1429C14.9408 9 15.3398 9 15.6606 9.11223C16.2351 9.31326 16.6867 9.76495 16.8878 10.3394C17 10.6602 17 11.0592 17 11.8571V14M7 14H4M17 14H20M17 10L19.5 7.5M4.5 20.5L8 17M7 10L4.5 7.5M19.5 20.5L16 17M14 6V5C14 3.89543 13.1046 3 12 3C10.8954 3 10 3.89543 10 5V6H14Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/buymeacoffee.svg b/src/main/resources/res/img/buymeacoffee.svg new file mode 100644 index 0000000..805aff9 --- /dev/null +++ b/src/main/resources/res/img/buymeacoffee.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"> + <path d="M9.197 0l-1.619 3.735h-2.407v3.359h0.921l0.943 5.975h-1.473l1.948 10.973 1.249-0.015 1.256 7.973h11.891l0.083-0.531 1.172-7.443 1.188 0.015 1.943-10.973h-1.407l0.937-5.975h1.011v-3.359h-2.557l-1.625-3.735zM9.901 1.073h12.057l1.025 2.375h-14.115zM6.235 4.803h19.525v1.228h-19.525zM6.839 14.136h18.183l-1.568 8.823-7.536-0.079-7.511 0.079z"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/chronometer.png b/src/main/resources/res/img/chronometer.png deleted file mode 100644 index 78842c6..0000000 Binary files a/src/main/resources/res/img/chronometer.png and /dev/null differ diff --git a/src/main/resources/res/img/clean.png b/src/main/resources/res/img/clean.png deleted file mode 100644 index 399ab8b..0000000 Binary files a/src/main/resources/res/img/clean.png and /dev/null differ diff --git a/src/main/resources/res/img/clear.svg b/src/main/resources/res/img/clear.svg new file mode 100644 index 0000000..a9f643c --- /dev/null +++ b/src/main/resources/res/img/clear.svg @@ -0,0 +1,2 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg fill="#000000" width="800px" height="800px" viewBox="0 0 1024 1024" t="1569683368540" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9723" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M899.1 869.6l-53-305.6H864c14.4 0 26-11.6 26-26V346c0-14.4-11.6-26-26-26H618V138c0-14.4-11.6-26-26-26H432c-14.4 0-26 11.6-26 26v182H160c-14.4 0-26 11.6-26 26v192c0 14.4 11.6 26 26 26h17.9l-53 305.6c-0.3 1.5-0.4 3-0.4 4.4 0 14.4 11.6 26 26 26h723c1.5 0 3-0.1 4.4-0.4 14.2-2.4 23.7-15.9 21.2-30zM204 390h272V182h72v208h272v104H204V390z m468 440V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H416V674c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v156H202.8l45.1-260H776l45.1 260H672z" p-id="9724"></path></svg> \ No newline at end of file diff --git a/src/main/resources/res/img/clock.png b/src/main/resources/res/img/clock.png deleted file mode 100644 index 521e6d4..0000000 Binary files a/src/main/resources/res/img/clock.png and /dev/null differ diff --git a/src/main/resources/res/img/cogwheel.png b/src/main/resources/res/img/cogwheel.png deleted file mode 100644 index 4bd0d65..0000000 Binary files a/src/main/resources/res/img/cogwheel.png and /dev/null differ diff --git a/src/main/resources/res/img/csv.svg b/src/main/resources/res/img/csv.svg new file mode 100644 index 0000000..c21c3c1 --- /dev/null +++ b/src/main/resources/res/img/csv.svg @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg fill="#000000" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" + viewBox="0 0 48 48" xml:space="preserve"> +<g> + <g> + <path d="M47.987,21.938c-0.006-0.091-0.023-0.178-0.053-0.264c-0.011-0.032-0.019-0.063-0.033-0.094 + c-0.048-0.104-0.109-0.202-0.193-0.285c-0.001-0.001-0.001-0.001-0.001-0.001L42,15.586V10c0-0.022-0.011-0.041-0.013-0.063 + c-0.006-0.088-0.023-0.173-0.051-0.257c-0.011-0.032-0.019-0.063-0.034-0.094c-0.049-0.106-0.11-0.207-0.196-0.293l-9-9 + c-0.086-0.086-0.187-0.148-0.294-0.196c-0.03-0.014-0.06-0.022-0.091-0.032c-0.085-0.03-0.172-0.047-0.263-0.052 + C32.039,0.01,32.021,0,32,0H7C6.448,0,6,0.448,6,1v14.586l-5.707,5.707c0,0-0.001,0.001-0.002,0.002 + c-0.084,0.084-0.144,0.182-0.192,0.285c-0.014,0.031-0.022,0.062-0.033,0.094c-0.03,0.086-0.048,0.173-0.053,0.264 + C0.011,21.96,0,21.978,0,22v19c0,0.552,0.448,1,1,1h5v5c0,0.552,0.448,1,1,1h34c0.552,0,1-0.448,1-1v-5h5c0.552,0,1-0.448,1-1V22 + C48,21.978,47.989,21.96,47.987,21.938z M44.586,21H42v-2.586L44.586,21z M38.586,9H33V3.414L38.586,9z M8,2h23v8 + c0,0.552,0.448,1,1,1h8v5v5H8v-5V2z M6,18.414V21H3.414L6,18.414z M40,46H8v-4h32V46z M46,40H2V23h5h34h5V40z"/> + <path d="M23.422,27.885c0.147-0.136,0.312-0.235,0.493-0.298c0.181-0.062,0.368-0.093,0.561-0.093 + c0.669,0,1.224,0.266,1.666,0.799l1.122-1.462c-0.329-0.385-0.734-0.677-1.215-0.876c-0.482-0.198-1.028-0.297-1.64-0.297 + c-0.419,0-0.833,0.071-1.241,0.212c-0.408,0.142-0.774,0.36-1.097,0.655c-0.323,0.295-0.584,0.666-0.782,1.113 + c-0.198,0.448-0.298,0.984-0.298,1.607c0,0.499,0.065,0.926,0.195,1.283c0.13,0.358,0.306,0.669,0.527,0.935 + c0.221,0.267,0.476,0.496,0.765,0.689c0.289,0.193,0.598,0.368,0.927,0.527c0.521,0.261,0.952,0.544,1.292,0.85 + c0.34,0.306,0.51,0.72,0.51,1.241c0,0.533-0.142,0.946-0.425,1.241s-0.64,0.442-1.071,0.442c-0.385,0-0.762-0.091-1.131-0.272 + s-0.683-0.431-0.944-0.748l-1.105,1.496c0.34,0.397,0.793,0.725,1.36,0.986c0.567,0.261,1.184,0.391,1.853,0.391 + c0.465,0,0.907-0.079,1.326-0.238c0.419-0.159,0.785-0.394,1.097-0.706c0.312-0.311,0.561-0.694,0.748-1.147 + c0.187-0.453,0.281-0.975,0.281-1.564c0-0.51-0.079-0.952-0.238-1.326c-0.159-0.374-0.363-0.697-0.612-0.969 + c-0.249-0.272-0.527-0.504-0.833-0.697c-0.306-0.193-0.606-0.363-0.901-0.51c-0.499-0.249-0.901-0.513-1.207-0.791 + c-0.306-0.277-0.459-0.671-0.459-1.181c0-0.295,0.042-0.55,0.128-0.765C23.159,28.197,23.275,28.021,23.422,27.885z"/> + <path d="M15.177,28.854c0.204-0.397,0.459-0.711,0.765-0.944c0.306-0.232,0.663-0.348,1.071-0.348 + c0.737,0,1.337,0.334,1.802,1.003l1.173-1.428c-0.329-0.476-0.754-0.841-1.275-1.097c-0.521-0.255-1.128-0.382-1.819-0.382 + c-0.669,0-1.278,0.156-1.828,0.467c-0.55,0.312-1.017,0.748-1.403,1.309c-0.385,0.562-0.683,1.23-0.892,2.006 + c-0.21,0.777-0.314,1.624-0.314,2.542c0,0.918,0.105,1.762,0.314,2.533s0.504,1.436,0.884,1.997 + c0.38,0.562,0.844,1.001,1.394,1.318s1.165,0.476,1.845,0.476c0.748,0,1.368-0.147,1.861-0.442s0.898-0.68,1.215-1.156 + l-1.173-1.377c-0.193,0.295-0.434,0.544-0.722,0.748s-0.632,0.306-1.028,0.306c-0.419,0-0.785-0.116-1.097-0.349 + c-0.312-0.232-0.569-0.546-0.774-0.943s-0.357-0.864-0.459-1.403c-0.102-0.538-0.153-1.107-0.153-1.708 + c0-0.612,0.051-1.187,0.153-1.726C14.82,29.718,14.973,29.251,15.177,28.854z"/> + <polygon points="32.007,35.62 31.956,35.62 29.95,25.964 27.672,25.964 30.613,38 33.197,38 36.189,25.964 34.013,25.964 "/> + </g> +</g> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/diskette.png b/src/main/resources/res/img/diskette.png deleted file mode 100644 index 2d8eb7b..0000000 Binary files a/src/main/resources/res/img/diskette.png and /dev/null differ diff --git a/src/main/resources/res/img/donate.svg b/src/main/resources/res/img/donate.svg new file mode 100644 index 0000000..e29d5b7 --- /dev/null +++ b/src/main/resources/res/img/donate.svg @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg fill="#000000" width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M17.726 13.02 14 16H9v-1h4.065a.5.5 0 0 0 .416-.777l-.888-1.332A1.995 1.995 0 0 0 10.93 12H3a1 1 0 0 0-1 1v6a2 2 0 0 0 2 2h9.639a3 3 0 0 0 2.258-1.024L22 13l-1.452-.484a2.998 2.998 0 0 0-2.822.504zm1.532-5.63c.451-.465.73-1.108.73-1.818s-.279-1.353-.73-1.818A2.447 2.447 0 0 0 17.494 3S16.25 2.997 15 4.286C13.75 2.997 12.506 3 12.506 3a2.45 2.45 0 0 0-1.764.753c-.451.466-.73 1.108-.73 1.818s.279 1.354.73 1.818L15 12l4.258-4.61z"/></svg> \ No newline at end of file diff --git a/src/main/resources/res/img/donation.png b/src/main/resources/res/img/donation.png deleted file mode 100644 index ac5e4a0..0000000 Binary files a/src/main/resources/res/img/donation.png and /dev/null differ diff --git a/src/main/resources/res/img/door.png b/src/main/resources/res/img/door.png deleted file mode 100644 index cefc71f..0000000 Binary files a/src/main/resources/res/img/door.png and /dev/null differ diff --git a/src/main/resources/res/img/export.png b/src/main/resources/res/img/export.png deleted file mode 100644 index 115b125..0000000 Binary files a/src/main/resources/res/img/export.png and /dev/null differ diff --git a/src/main/resources/res/img/export.svg b/src/main/resources/res/img/export.svg new file mode 100644 index 0000000..3bf712f --- /dev/null +++ b/src/main/resources/res/img/export.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg fill="#000000" width="800px" height="800px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="m0 1016.081 409.186 409.073 79.85-79.736-272.867-272.979h1136.415V959.611H216.169l272.866-272.866-79.85-79.85L0 1016.082ZM1465.592 305.32l315.445 315.445h-315.445V305.32Zm402.184 242.372-329.224-329.11C1507.042 187.07 1463.334 169 1418.835 169h-743.83v677.647h112.94V281.941h564.706v451.765h451.765v903.53H787.946V1185.47H675.003v564.705h1242.353V667.522c0-44.498-18.07-88.207-49.581-119.83Z" fill-rule="evenodd"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/folder.png b/src/main/resources/res/img/folder.png deleted file mode 100644 index 4966929..0000000 Binary files a/src/main/resources/res/img/folder.png and /dev/null differ diff --git a/src/main/resources/res/img/folder.svg b/src/main/resources/res/img/folder.svg new file mode 100644 index 0000000..5016a93 --- /dev/null +++ b/src/main/resources/res/img/folder.svg @@ -0,0 +1,12 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve"> + +<defs> +</defs> +<g style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(1.4065934065934016 1.4065934065934016) scale(2.81 2.81)" > + <path d="M 69.896 78.816 H 11.957 c -1.105 0 -2 -0.896 -2 -2 s 0.896 -2 2 -2 h 57.938 c 1.042 0 1.99 -0.614 2.416 -1.564 l 13.598 -30.325 c 0.193 -0.43 0.037 -0.78 -0.073 -0.95 c -0.109 -0.169 -0.364 -0.455 -0.836 -0.455 H 21.203 c -0.72 0 -1.376 0.425 -1.671 1.082 c -0.452 1.008 -1.638 1.457 -2.643 1.006 c -1.008 -0.452 -1.459 -1.635 -1.006 -2.643 c 0.938 -2.093 3.027 -3.445 5.321 -3.445 H 85 c 1.701 0 3.269 0.853 4.193 2.28 c 0.926 1.428 1.063 3.208 0.366 4.761 L 75.962 74.888 C 74.892 77.274 72.511 78.816 69.896 78.816 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" /> + <path d="M 2 68.859 c -1.105 0 -2 -0.896 -2 -2 V 23.616 c 0 -2.634 2.143 -4.777 4.777 -4.777 h 2.098 c 1.007 0 1.827 -0.82 1.827 -1.827 c 0 -3.213 2.614 -5.828 5.828 -5.828 h 21.768 c 2.182 0 4.163 1.203 5.169 3.138 l 1.838 3.533 c 0.315 0.607 0.937 0.984 1.621 0.984 h 25.202 c 2.634 0 4.777 2.143 4.777 4.777 v 15.905 c 0 1.105 -0.896 2 -2 2 s -2 -0.896 -2 -2 V 23.616 c 0 -0.429 -0.349 -0.777 -0.777 -0.777 H 44.926 c -2.181 0 -4.162 -1.202 -5.169 -3.137 l -1.839 -3.534 c -0.315 -0.607 -0.937 -0.984 -1.621 -0.984 H 14.53 c -1.008 0 -1.828 0.82 -1.828 1.828 c 0 3.213 -2.614 5.827 -5.827 5.827 H 4.777 C 4.348 22.839 4 23.187 4 23.616 v 43.243 C 4 67.963 3.104 68.859 2 68.859 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" /> + <path d="M 2.598 77.48 c -0.274 0 -0.552 -0.057 -0.817 -0.176 c -1.008 -0.452 -1.459 -1.636 -1.006 -2.644 l 15.107 -33.694 c 0.453 -1.008 1.637 -1.458 2.644 -1.007 c 1.008 0.452 1.459 1.636 1.007 2.644 L 4.424 76.297 C 4.091 77.039 3.362 77.48 2.598 77.48 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" /> + <path d="M 11.957 78.816 H 5.195 C 2.33 78.816 0 76.485 0 73.62 v -6.762 c 0 -1.104 0.896 -2 2 -2 s 2 0.896 2 2 v 6.762 c 0 0.659 0.536 1.195 1.195 1.195 h 6.762 c 1.104 0 2 0.896 2 2 S 13.062 78.816 11.957 78.816 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" /> + <path d="M 12.09 58.773 h -4 V 32.753 c 0 -3.168 2.577 -5.744 5.744 -5.744 h 47.82 c 3.167 0 5.744 2.577 5.744 5.744 v 6.768 h -4 v -6.768 c 0 -0.962 -0.782 -1.744 -1.744 -1.744 h -47.82 c -0.962 0 -1.744 0.782 -1.744 1.744 V 58.773 z" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform=" matrix(1 0 0 1 0 0) " stroke-linecap="round" /> +</g> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/help-desk.png b/src/main/resources/res/img/help-desk.png deleted file mode 100644 index b7256a3..0000000 Binary files a/src/main/resources/res/img/help-desk.png and /dev/null differ diff --git a/src/main/resources/res/img/history.svg b/src/main/resources/res/img/history.svg new file mode 100644 index 0000000..47da01c --- /dev/null +++ b/src/main/resources/res/img/history.svg @@ -0,0 +1,28 @@ +<?xml version="1.0" ?> + <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"> + <defs> + <style>.cls-1{fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:20px;}</style> + </defs> + <g data-name="Layer 2" id="Layer_2"> + <g data-name="E425, History, log, manuscript" id="E425_History_log_manuscript"> + <path class="cls-1" d="M75.11,117h0A21.34,21.34,0,0,1,53.83,95.57V31.39A21.34,21.34,0,0,1,75.11,10h0A21.34,21.34,0,0,1,96.39,31.39V95.57A21.34,21.34,0,0,1,75.11,117Z"/> + <rect class="cls-1" height="64.17" width="319.22" x="96.39" y="31.39"/> + <rect class="cls-1" height="320.87" width="319.22" x="96.39" y="95.57"/> + <path class="cls-1" d="M34.34,39.08H53.83a0,0,0,0,1,0,0v48.8a0,0,0,0,1,0,0H34.34A24.34,24.34,0,0,1,10,63.54v-.13A24.34,24.34,0,0,1,34.34,39.08Z"/> + <path class="cls-1" d="M436.89,117h0a21.34,21.34,0,0,0,21.28-21.39V31.39A21.34,21.34,0,0,0,436.89,10h0a21.34,21.34,0,0,0-21.28,21.39V95.57A21.34,21.34,0,0,0,436.89,117Z"/> + <path class="cls-1" d="M482.51,39.08H502a0,0,0,0,1,0,0v48.8a0,0,0,0,1,0,0H482.51a24.34,24.34,0,0,1-24.34-24.34v-.13a24.34,24.34,0,0,1,24.34-24.34Z" transform="translate(960.17 126.96) rotate(-180)"/> + <path class="cls-1" d="M75.11,395h0a21.34,21.34,0,0,0-21.28,21.39v64.18A21.34,21.34,0,0,0,75.11,502h0a21.34,21.34,0,0,0,21.28-21.39V416.43A21.34,21.34,0,0,0,75.11,395Z"/> + <rect class="cls-1" height="64.17" width="319.22" x="96.39" y="416.43"/> + <path class="cls-1" d="M34.34,424.12H53.83a0,0,0,0,1,0,0v48.8a0,0,0,0,1,0,0H34.34A24.34,24.34,0,0,1,10,448.58v-.13A24.34,24.34,0,0,1,34.34,424.12Z"/> + <path class="cls-1" d="M436.89,395h0a21.34,21.34,0,0,1,21.28,21.39v64.18A21.34,21.34,0,0,1,436.89,502h0a21.34,21.34,0,0,1-21.28-21.39V416.43A21.34,21.34,0,0,1,436.89,395Z"/> + <path class="cls-1" d="M482.51,424.12H502a0,0,0,0,1,0,0v48.8a0,0,0,0,1,0,0H482.51a24.34,24.34,0,0,1-24.34-24.34v-.13a24.34,24.34,0,0,1,24.34-24.34Z" transform="translate(960.17 897.04) rotate(-180)"/> + <line class="cls-1" x1="143.41" x2="256" y1="140.11" y2="140.11"/> + <line class="cls-1" x1="143.41" x2="371.26" y1="186.47" y2="186.47"/> + <line class="cls-1" x1="143.41" x2="371.26" y1="232.82" y2="232.82"/> + <line class="cls-1" x1="143.41" x2="371.26" y1="279.18" y2="279.18"/> + <line class="cls-1" x1="143.41" x2="371.26" y1="325.53" y2="325.53"/> + <line class="cls-1" x1="256" x2="371.26" y1="371.89" y2="371.89"/> + </g> + </g> + </svg> \ No newline at end of file diff --git a/src/main/resources/res/img/import.png b/src/main/resources/res/img/import.png deleted file mode 100644 index 45624d4..0000000 Binary files a/src/main/resources/res/img/import.png and /dev/null differ diff --git a/src/main/resources/res/img/import.svg b/src/main/resources/res/img/import.svg new file mode 100644 index 0000000..a312f65 --- /dev/null +++ b/src/main/resources/res/img/import.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg fill="#000000" width="800px" height="800px" viewBox="0 0 1920 1920" xmlns="http://www.w3.org/2000/svg"> + <path d="m807.186 686.592 272.864 272.864H0v112.94h1080.05l-272.864 272.978 79.736 79.849 409.296-409.183-409.296-409.184-79.736 79.736ZM1870.419 434.69l-329.221-329.11C1509.688 74.07 1465.979 56 1421.48 56H451.773v730.612h112.94V168.941h790.584v451.762h451.762v1129.405H564.714v-508.233h-112.94v621.173H1920V554.52c0-45.176-17.619-87.754-49.58-119.83Zm-402.181-242.37 315.443 315.442h-315.443V192.319Z" fill-rule="evenodd"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/info.svg b/src/main/resources/res/img/info.svg new file mode 100644 index 0000000..bab5f33 --- /dev/null +++ b/src/main/resources/res/img/info.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill="none"> + <path fill="#000000" fill-rule="evenodd" d="M10 3a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0zm8-4a1 1 0 011-1h.01a1 1 0 110 2H10a1 1 0 01-1-1zm.01 8a1 1 0 102 0V9a1 1 0 10-2 0v5z"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/information.png b/src/main/resources/res/img/information.png deleted file mode 100644 index 28baaa9..0000000 Binary files a/src/main/resources/res/img/information.png and /dev/null differ diff --git a/src/main/resources/res/img/new_file.svg b/src/main/resources/res/img/new_file.svg new file mode 100644 index 0000000..624ce80 --- /dev/null +++ b/src/main/resources/res/img/new_file.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M13.5 3H12H8C6.34315 3 5 4.34315 5 6V18C5 19.6569 6.34315 21 8 21H11M13.5 3L19 8.625M13.5 3V7.625C13.5 8.17728 13.9477 8.625 14.5 8.625H19M19 8.625V11.8125" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> +<path d="M17 15V18M17 21V18M17 18H14M17 18H20" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/paypal.svg b/src/main/resources/res/img/paypal.svg new file mode 100644 index 0000000..77a333a --- /dev/null +++ b/src/main/resources/res/img/paypal.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.16 13.4101C9.04 14.0801 8.55 17.2401 8.41 18.1301C8.41 18.2001 8.41 18.2201 8.3 18.2201H5.68C5.61811 18.2207 5.55681 18.2079 5.50031 18.1826C5.4438 18.1574 5.39341 18.1202 5.35259 18.0737C5.31176 18.0272 5.28146 17.9724 5.26376 17.9131C5.24605 17.8538 5.24136 17.7913 5.25 17.7301L7.31 4.61006C7.33743 4.44459 7.421 4.29361 7.54666 4.18252C7.67233 4.07142 7.83241 4.00699 8 4.00006C13.35 4.00006 13.8 3.87006 15.17 4.41006C17.28 5.23006 17.48 7.21006 16.72 9.36006C15.96 11.5101 14.17 12.5101 11.79 12.5401C10.27 12.5401 9.35 12.3001 9.14 13.4001L9.16 13.4101ZM17.8 8.33006C17.74 8.28006 17.72 8.27006 17.7 8.33006C17.6274 8.73409 17.5237 9.13193 17.39 9.52006C15.99 13.5201 12.1 13.1901 10.2 13.1901C10.1524 13.1845 10.1042 13.1888 10.0584 13.2027C10.0125 13.2165 9.97003 13.2396 9.93347 13.2705C9.89692 13.3015 9.86709 13.3396 9.84586 13.3825C9.82462 13.4254 9.81241 13.4722 9.81 13.5201C9.02 18.5201 8.81 19.5201 8.81 19.5201C8.79809 19.5754 8.79868 19.6326 8.81172 19.6877C8.82476 19.7427 8.84992 19.7942 8.88538 19.8382C8.92083 19.8823 8.96568 19.9179 9.01665 19.9425C9.06762 19.967 9.12343 19.9798 9.18 19.9801H11.42C11.5677 19.9772 11.7097 19.9226 11.8212 19.8257C11.9327 19.7289 12.0066 19.5959 12.03 19.4501C12.03 19.2601 12.03 19.6701 12.54 16.2301C12.7 15.4601 13.04 15.5401 13.54 15.5401C16.03 15.5401 17.98 14.5401 18.54 11.5401C18.726 10.9716 18.7457 10.3619 18.5969 9.78256C18.4481 9.20326 18.1369 8.67852 17.7 8.27006L17.8 8.33006Z" fill="#000000"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/pdf.svg b/src/main/resources/res/img/pdf.svg new file mode 100644 index 0000000..5940097 --- /dev/null +++ b/src/main/resources/res/img/pdf.svg @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg fill="#000000" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" + viewBox="0 0 48 48" xml:space="preserve"> +<g> + <g> + <path d="M47.987,21.938c-0.006-0.091-0.023-0.178-0.053-0.264c-0.011-0.032-0.019-0.063-0.033-0.094 + c-0.048-0.104-0.109-0.202-0.193-0.285c-0.001-0.001-0.001-0.001-0.001-0.001L42,15.586V10c0-0.022-0.011-0.041-0.013-0.063 + c-0.006-0.088-0.023-0.173-0.051-0.257c-0.011-0.032-0.019-0.063-0.034-0.094c-0.049-0.106-0.11-0.207-0.196-0.293l-9-9 + c-0.086-0.086-0.187-0.148-0.294-0.197c-0.03-0.013-0.06-0.022-0.09-0.032c-0.086-0.03-0.174-0.047-0.264-0.053 + C32.038,0.01,32.02,0,32,0H7C6.448,0,6,0.448,6,1v14.586l-5.707,5.707c0,0-0.001,0.001-0.002,0.002 + c-0.084,0.084-0.144,0.182-0.192,0.285c-0.014,0.031-0.022,0.062-0.033,0.094c-0.03,0.086-0.048,0.173-0.053,0.264 + C0.011,21.96,0,21.978,0,22v19c0,0.552,0.448,1,1,1h5v5c0,0.552,0.448,1,1,1h34c0.552,0,1-0.448,1-1v-5h5c0.552,0,1-0.448,1-1V22 + C48,21.978,47.989,21.96,47.987,21.938z M44.586,21H42v-2.586L44.586,21z M38.586,9H33V3.414L38.586,9z M8,2h23v8 + c0,0.552,0.448,1,1,1h8v5v5H8v-5V2z M6,18.414V21H3.414L6,18.414z M40,46H8v-4h32V46z M46,40H2V23h5h34h5V40z"/> + <path d="M18.254,26.72c-0.323-0.277-0.688-0.473-1.097-0.586c-0.408-0.113-0.805-0.17-1.19-0.17h-3.332V38h2.006v-4.828h1.428 + c0.419,0,0.827-0.074,1.224-0.221c0.397-0.147,0.748-0.374,1.054-0.68c0.306-0.306,0.552-0.688,0.74-1.148 + c0.187-0.459,0.281-0.994,0.281-1.606c0-0.68-0.105-1.247-0.315-1.7C18.843,27.364,18.577,26.998,18.254,26.72z M16.971,31.005 + c-0.306,0.334-0.697,0.501-1.173,0.501h-1.156v-3.825h1.156c0.476,0,0.867,0.147,1.173,0.442c0.306,0.295,0.459,0.765,0.459,1.411 + C17.43,30.18,17.277,30.67,16.971,31.005z"/> + <polygon points="30.723,38 32.78,38 32.78,32.832 35.857,32.832 35.857,31.081 32.764,31.081 32.764,27.8 36.112,27.8 + 36.112,25.964 30.723,25.964 "/> + <path d="M24.076,25.964H21.05V38h3.009c1.553,0,2.729-0.524,3.528-1.572c0.799-1.049,1.198-2.525,1.198-4.429 + c0-1.904-0.399-3.386-1.198-4.446C26.788,26.494,25.618,25.964,24.076,25.964z M26.55,33.843c-0.13,0.528-0.315,0.967-0.552,1.318 + c-0.238,0.351-0.521,0.615-0.85,0.79c-0.329,0.176-0.686,0.264-1.071,0.264h-0.969v-8.466h0.969c0.385,0,0.742,0.088,1.071,0.264 + c0.329,0.175,0.612,0.439,0.85,0.79c0.238,0.351,0.422,0.793,0.552,1.326s0.196,1.156,0.196,1.87 + C26.746,32.702,26.68,33.316,26.55,33.843z"/> + </g> +</g> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/pen.png b/src/main/resources/res/img/pen.png deleted file mode 100644 index eb1d93f..0000000 Binary files a/src/main/resources/res/img/pen.png and /dev/null differ diff --git a/src/main/resources/res/img/plus.png b/src/main/resources/res/img/plus.png deleted file mode 100644 index bf074a8..0000000 Binary files a/src/main/resources/res/img/plus.png and /dev/null differ diff --git a/src/main/resources/res/img/quit.svg b/src/main/resources/res/img/quit.svg new file mode 100644 index 0000000..b9ad87d --- /dev/null +++ b/src/main/resources/res/img/quit.svg @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> + <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none"> + <g fill="#000000"> + <path d="M1 8a6 6 0 018.514-5.45.75.75 0 01-.629 1.363 4.5 4.5 0 100 8.175.75.75 0 11.63 1.361A6 6 0 011 8z"/> + <path d="M11.245 4.695a.75.75 0 00-.05 1.06l1.36 1.495H6.75a.75.75 0 000 1.5h5.805l-1.36 1.495a.75.75 0 001.11 1.01l2.5-2.75a.748.748 0 00-.002-1.012l-2.498-2.748a.75.75 0 00-1.06-.05z"/> + </g> + </svg> \ No newline at end of file diff --git a/src/main/resources/res/img/remove.png b/src/main/resources/res/img/remove.png deleted file mode 100644 index 2938801..0000000 Binary files a/src/main/resources/res/img/remove.png and /dev/null differ diff --git a/src/main/resources/res/img/save.png b/src/main/resources/res/img/save.png deleted file mode 100644 index 5d0fad3..0000000 Binary files a/src/main/resources/res/img/save.png and /dev/null differ diff --git a/src/main/resources/res/img/save.svg b/src/main/resources/res/img/save.svg new file mode 100644 index 0000000..0298ad6 --- /dev/null +++ b/src/main/resources/res/img/save.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path fill-rule="evenodd" clip-rule="evenodd" d="M18.1716 1C18.702 1 19.2107 1.21071 19.5858 1.58579L22.4142 4.41421C22.7893 4.78929 23 5.29799 23 5.82843V20C23 21.6569 21.6569 23 20 23H4C2.34315 23 1 21.6569 1 20V4C1 2.34315 2.34315 1 4 1H18.1716ZM4 3C3.44772 3 3 3.44772 3 4V20C3 20.5523 3.44772 21 4 21L5 21L5 15C5 13.3431 6.34315 12 8 12L16 12C17.6569 12 19 13.3431 19 15V21H20C20.5523 21 21 20.5523 21 20V6.82843C21 6.29799 20.7893 5.78929 20.4142 5.41421L18.5858 3.58579C18.2107 3.21071 17.702 3 17.1716 3H17V5C17 6.65685 15.6569 8 14 8H10C8.34315 8 7 6.65685 7 5V3H4ZM17 21V15C17 14.4477 16.5523 14 16 14L8 14C7.44772 14 7 14.4477 7 15L7 21L17 21ZM9 3H15V5C15 5.55228 14.5523 6 14 6H10C9.44772 6 9 5.55228 9 5V3Z" fill="#0F0F0F"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/save_as.svg b/src/main/resources/res/img/save_as.svg new file mode 100644 index 0000000..a27a58a --- /dev/null +++ b/src/main/resources/res/img/save_as.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"> + <path d="M26 0H6a6 6 0 0 0-6 6v20a6 6 0 0 0 6 6h20a6 6 0 0 0 6-6V6a6 6 0 0 0-6-6zm-6 2v3a1 1 0 1 0 2 0V2h1v7H9V2zm10 24a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4V6a4 4 0 0 1 4-4h1v8a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1V2h1a4 4 0 0 1 4 4zM24 14H8a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1V15a1 1 0 0 0-1-1zm-1 12H9V16h14zM12 20h8a1 1 0 0 0 0-2h-8a1 1 0 0 0 0 2zM12 24h8a1 1 0 0 0 0-2h-8a1 1 0 0 0 0 2z"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/search.png b/src/main/resources/res/img/search.png deleted file mode 100644 index dd414ca..0000000 Binary files a/src/main/resources/res/img/search.png and /dev/null differ diff --git a/src/main/resources/res/img/search.svg b/src/main/resources/res/img/search.svg new file mode 100644 index 0000000..36988cd --- /dev/null +++ b/src/main/resources/res/img/search.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M14.9536 14.9458L21 21M17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/settings.svg b/src/main/resources/res/img/settings.svg new file mode 100644 index 0000000..44f6d89 --- /dev/null +++ b/src/main/resources/res/img/settings.svg @@ -0,0 +1,50 @@ +<?xml version="1.0" ?> + <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 96 96" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <style type="text/css"> + .st0{display:none;} + .st1{fill:#FFFFFF;} + .st2{fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st3{fill:#FFF8FA;} + .st4{stroke:#000000;stroke-width:2;stroke-miterlimit:10;} + .st5{fill:none;stroke:#000000;stroke-miterlimit:10;} + .st6{fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:10;} + .st7{fill:#231F20;stroke:#000000;stroke-width:0;stroke-miterlimit:10;} + .st8{fill:#FF0D5C;} + .st9{display:inline;} + .st10{fill:none;stroke:#00D8E9;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st11{fill:none;stroke:#00D8E9;stroke-width:0.25;stroke-linejoin:round;stroke-miterlimit:10;} + .st12{fill:none;stroke:#00D8E9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} + .st13{fill:none;stroke:#00D8E9;stroke-linejoin:round;stroke-miterlimit:10;} +</style> + <g id="banana"/> + <g id="Layer_12"/> + <g id="grape"/> + <g id="assasin"/> + <g id="gold"/> + <g id="mage_ass"/> + <g id="fighter"/> + <g id="SUPPORT"/> + <g id="marksman"/> + <g id="JUNGLE"/> + <g id="TANK"/> + <g class="st0" id="creditcard"/> + <g class="st0" id="CAKE"/> + <g class="st0" id="TOPI"/> + <g class="st0" id="SPATU"/> + <g class="st0" id="SETTING"/> + <g class="st0" id="CART"/> + <g class="st0" id="k3"/> + <g class="st0" id="computer"/> + <g class="st0" id="phone"/> + <g class="st0" id="location"/> + <g id="koper"> + <g id="Layer_29"/> + <path d="M66.8,61.8c1.4-2.2,2.4-4.6,2.9-7.1c0,0,0,0,0,0c0-0.1,0.1-0.1,0.1-0.2c0,0,0-0.1,0.1-0.1c0-0.1,0.1-0.1,0.1-0.1 c0,0,0.1-0.1,0.1-0.1c0,0,0.1,0,0.1-0.1c0.1,0,0.1-0.1,0.2-0.1c0,0,0,0,0,0l8.9-1.3v-5.6l-8.9-1.3c0,0-0.1,0-0.1,0 c-0.1,0-0.1,0-0.2-0.1c0,0-0.1,0-0.1-0.1c-0.1,0-0.1-0.1-0.2-0.1c0,0-0.1-0.1-0.1-0.1c0-0.1-0.1-0.1-0.1-0.2c0,0,0-0.1,0-0.1 c0,0,0,0,0,0c-0.6-2.5-1.5-4.8-2.9-7c0,0,0,0,0,0c0-0.1-0.1-0.1-0.1-0.2c0-0.1,0-0.1-0.1-0.2c0-0.1,0-0.1,0-0.2c0-0.1,0-0.1,0-0.2 c0-0.1,0-0.1,0.1-0.1c0-0.1,0.1-0.1,0.1-0.2c0,0,0,0,0,0l5.4-7.3l-4-4L61,31.1c0,0,0,0,0,0c-0.1,0.1-0.2,0.1-0.3,0.2c0,0,0,0,0,0 c-0.1,0-0.2,0-0.2,0c0,0-0.1,0-0.1,0c0,0-0.1,0-0.1,0c-0.1,0-0.2,0-0.3-0.1c0,0,0,0-0.1,0c0,0,0,0,0,0c-2.1-1.4-4.5-2.3-6.9-2.9 h-0.7l-1.4-9.9h-5.6l-1.4,9.9H43c-2.5,0.6-4.8,1.5-6.9,2.9c0,0,0,0,0,0c0,0,0,0-0.1,0c-0.1,0-0.2,0.1-0.3,0.1c0,0-0.1,0-0.1,0 c0,0-0.1,0-0.1,0c-0.1,0-0.2,0-0.2,0c0,0,0,0,0,0c-0.1,0-0.2-0.1-0.3-0.2c0,0,0,0,0,0l-7.3-5.4l-4,4l5.4,7.3c0,0,0,0,0,0 c0,0.1,0.1,0.1,0.1,0.2c0,0,0.1,0.1,0.1,0.1c0,0.1,0,0.1,0,0.2c0,0.1,0,0.1,0,0.2c0,0.1,0,0.1-0.1,0.2c0,0.1,0,0.1-0.1,0.2 c0,0,0,0,0,0c-1.4,2.2-2.4,4.5-2.9,7c0,0,0,0,0,0c0,0,0,0.1,0,0.1c0,0.1-0.1,0.2-0.1,0.2c0,0-0.1,0.1-0.1,0.1 c-0.1,0.1-0.1,0.1-0.2,0.2c0,0-0.1,0-0.1,0.1c-0.1,0-0.1,0.1-0.2,0.1c0,0,0,0-0.1,0l-8.9,1.3v5.6l8.9,1.3c0,0,0,0,0,0 c0.1,0,0.2,0,0.2,0.1c0,0,0.1,0,0.1,0.1c0.1,0,0.1,0.1,0.1,0.1c0,0,0.1,0.1,0.1,0.1c0,0,0,0.1,0.1,0.1c0,0.1,0.1,0.1,0.1,0.2 c0,0,0,0,0,0c0.5,2.5,1.5,4.9,2.9,7.1l0.2,0.2v0.3v0.3l-5.6,7.5l4,4l7.2-5.4c0,0,0,0,0,0c0.1,0,0.1-0.1,0.2-0.1c0,0,0.1,0,0.1-0.1 c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.1,0.1c0.1,0,0.2,0,0.2,0.1c0,0,0,0,0,0c2.2,1.4,4.6,2.4,7.1,3c0,0,0,0,0,0 c0.1,0,0.1,0,0.2,0.1c0.1,0,0.1,0.1,0.2,0.1c0,0,0.1,0.1,0.1,0.1c0.1,0.1,0.1,0.1,0.2,0.2c0,0,0,0.1,0.1,0.1c0,0.1,0.1,0.2,0.1,0.2 c0,0,0,0,0,0l1.3,8.9h5.6l1.3-8.9c0,0,0,0,0,0c0-0.1,0.1-0.2,0.1-0.3c0,0,0-0.1,0-0.1c0.1-0.1,0.1-0.2,0.2-0.2c0,0,0,0,0-0.1 c0.1,0,0.1-0.1,0.2-0.1c0,0,0.1-0.1,0.1-0.1c0,0,0,0,0,0c2.5-0.6,4.9-1.6,7.1-3c0,0,0,0,0,0c0.1,0,0.1-0.1,0.2-0.1c0,0,0.1,0,0.1,0 c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0.1c0.1,0,0.1,0.1,0.2,0.1c0,0,0,0,0,0l7.2,5.4l4-4L66.9,63c0,0,0-0.1,0-0.1 c0-0.1-0.1-0.1-0.1-0.2c0-0.1,0-0.1,0-0.2c0,0,0-0.1,0-0.1v-0.3L66.8,61.8z M62,51.4c-0.8,6.3-5.9,11.4-12.2,12.2 C40.6,64.8,32.8,57,34,47.7c0.8-6.3,5.9-11.4,12.2-12.2C55.4,34.4,63.2,42.2,62,51.4z"/> + </g> + <g class="st0" id="guide"/> + <g id="MAGICAL"/> + <g id="phisical"/> + <g id="mango"/> + <g id="orange"/> + </svg> \ No newline at end of file diff --git a/src/main/resources/res/img/share.png b/src/main/resources/res/img/share.png deleted file mode 100644 index eada534..0000000 Binary files a/src/main/resources/res/img/share.png and /dev/null differ diff --git a/src/main/resources/res/img/share.svg b/src/main/resources/res/img/share.svg new file mode 100644 index 0000000..5af7b2d --- /dev/null +++ b/src/main/resources/res/img/share.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M11 6C12.6569 6 14 4.65685 14 3C14 1.34315 12.6569 0 11 0C9.34315 0 8 1.34315 8 3C8 3.22371 8.02449 3.44169 8.07092 3.65143L4.86861 5.65287C4.35599 5.24423 3.70652 5 3 5C1.34315 5 0 6.34315 0 8C0 9.65685 1.34315 11 3 11C3.70652 11 4.35599 10.7558 4.86861 10.3471L8.07092 12.3486C8.02449 12.5583 8 12.7763 8 13C8 14.6569 9.34315 16 11 16C12.6569 16 14 14.6569 14 13C14 11.3431 12.6569 10 11 10C10.2935 10 9.644 10.2442 9.13139 10.6529L5.92908 8.65143C5.97551 8.44169 6 8.22371 6 8C6 7.77629 5.97551 7.55831 5.92908 7.34857L9.13139 5.34713C9.644 5.75577 10.2935 6 11 6Z" fill="#000000"/> +</svg> \ No newline at end of file diff --git a/src/main/resources/res/img/support.svg b/src/main/resources/res/img/support.svg new file mode 100644 index 0000000..5149f58 --- /dev/null +++ b/src/main/resources/res/img/support.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> +<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> + <title>support + + + \ No newline at end of file diff --git a/src/main/resources/res/img/timer.svg b/src/main/resources/res/img/timer.svg new file mode 100644 index 0000000..6a8668c --- /dev/null +++ b/src/main/resources/res/img/timer.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/main/resources/res/img/website.png b/src/main/resources/res/img/website.png deleted file mode 100644 index 08cbb40..0000000 Binary files a/src/main/resources/res/img/website.png and /dev/null differ diff --git a/src/main/resources/res/img/website.svg b/src/main/resources/res/img/website.svg new file mode 100644 index 0000000..60f1673 --- /dev/null +++ b/src/main/resources/res/img/website.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/main/resources/res/languages/deu.json b/src/main/resources/res/languages/deu.json index 3598b59..176a9d1 100644 --- a/src/main/resources/res/languages/deu.json +++ b/src/main/resources/res/languages/deu.json @@ -8,7 +8,9 @@ "OkButton": "Ok", "CancelButton": "Abbrechen", "CloseButton": "Schließen", - "ApplyButton": "Anwenden" + "ApplyButton": "Anwenden", + "SaveButton": "Speichern", + "CreateButton": "Erstellen" }, "Menu": { "File": "Datei", @@ -46,6 +48,8 @@ "AutoBackupButtonOFF": "Auto-Backup (AUS)", "InitialPathPlaceholder": "Anfangspfad", "DestinationPathPlaceholder": "Zielpfad", + "BackupName": "Sicherungsname: ", + "BackupNameTooltip": "(Erforderlich) Sicherungsname", "InitialPathTooltip": "(Erforderlich) Anfangspfad", "DestinationPathTooltip": "(Erforderlich) Zielpfad", "InitialFileChooserTooltip": "Dateiexplorer öffnen", @@ -77,10 +81,14 @@ "NotesDetail": "Notizen", "MaxBackupsToKeepDetail": "MaximaleSicherungenBehalten", "AddBackupTooltip": "Neues Backup hinzufügen", + "ExportAs": "Exportieren als: ", + "ExportAsPdfTooltip": "Exportieren als PDF", + "ExportAsCsvTooltip": "Exportieren als CSV", "ResearchBarTooltip": "Suchleiste", "ResearchBarPlaceholder": "Suchen...", "EditPopup": "Bearbeiten", "DeletePopup": "Löschen", + "InterruptPopup": "Unterbrechen", "DuplicatePopup": "Duplizieren", "RenameBackupPopup": "Backup umbenennen", "OpenInitialFolderPopup": "Anfangspfad öffnen", @@ -106,6 +114,16 @@ "Language": "Sprache", "Theme": "Thema" }, + "UserDialog": { + "UserTitle": "Geben Sie Ihre Daten ein", + "Name": "Vorname", + "Surname": "Nachname", + "Email": "E-Mail", + "ErrorMessageForMissingData": "Bitte füllen Sie alle erforderlichen Felder aus.", + "ErrorMessageForWrongEmail": "Die angegebene E-Mail-Adresse ist ungültig. Bitte geben Sie eine korrekte Adresse an.", + "EmailConfirmationSubject": "Vielen Dank, dass Sie sich für Backup Manager entschieden haben!", + "EmailConfirmationBody": "Hallo [UserName],\n\nVielen Dank, dass Sie Backup Manager heruntergeladen und registriert haben - Ihr neues Tool für eine sichere und effiziente Verwaltung Ihrer Backups!\n\nDies ist eine automatisierte E-Mail, die zur Bestätigung Ihrer Registrierung gesendet wurde. Wir werden Sie nur per E-Mail kontaktieren, um Sie über neue Versionen oder wichtige Updates der Anwendung zu informieren.\n\nFalls Sie Fragen haben, Unterstützung benötigen oder Vorschläge machen möchten, stehen wir Ihnen jederzeit gerne zur Verfügung. Sie können uns unter [SupportEmail] erreichen.\n\nVielen Dank nochmals, dass Sie sich für Backup Manager entschieden haben, und viel Erfolg bei der Verwaltung Ihrer Backups!\n\nMit freundlichen Grüßen,\nDas Backup Manager-Team" + }, "ProgressBackupFrame": { "ProgressBackupTitle": "Backup läuft", "StatusCompleted": "Backup abgeschlossen!", @@ -120,6 +138,9 @@ }, "Dialogs": { "ErrorGenericTitle": "Fehler", + "WarningGenericTitle": "Warnung", + "WarningBackupAlreadyInProgressMessage": "Es läuft bereits eine Sicherung. Es ist nicht möglich, parallele Sicherungen durchzuführen.", + "WarningShortTimeIntervalMessage": "Das ausgewählte Zeitintervall ist sehr kurz. Für eine optimale Leistung empfehlen wir, es auf mindestens eine Stunde einzustellen. Möchten Sie dennoch fortfahren?", "ErrorMessageForFolderNotExisting": "Der Ordner existiert nicht oder ist ungültig", "ErrorMessageForSavingFileWithPathsEmpty": "Die Datei konnte nicht gespeichert werden. Sowohl der Anfangs- als auch der Zielpfad müssen angegeben werden und dürfen nicht leer sein", "BackupSavedCorrectlyTitle": "Backup gespeichert", @@ -159,7 +180,22 @@ "BackupListCorrectlyImportedTitle": "Menü Importieren", "BackupListCorrectlyImportedMessage": "Backup-Liste erfolgreich importiert!", "ErrorMessageForWrongFileExtensionTitle": "Ungültige Datei", - "ErrorMessageForWrongFileExtensionMessage": "Fehler: Bitte wählen Sie eine gültige JSON-Datei aus." + "ErrorMessageForWrongFileExtensionMessage": "Fehler: Bitte wählen Sie eine gültige JSON-Datei aus.", + "ErrorMessageCountingFiles": "Fehler beim Zählen der zu sichernden Dateien.", + "ErrorMessageZippingGeneric": "Fehler beim Komprimieren der Dateien.", + "ErrorMessageZippingIO": "Fehler beim Komprimieren der Dateien: E/A-Fehler.", + "ErrorMessageZippingSecurity": "Fehler beim Komprimieren der Dateien: Sicherheitsfehler.", + "SuccessGenericTitle": "Erfolg", + "SuccessfullyExportedToCsvMessage": "Backups erfolgreich als CSV exportiert!", + "SuccessfullyExportedToPdfMessage": "Backups erfolgreich als PDF exportiert!", + "ErrorMessageForExportingToCsv": "Fehler beim Exportieren der Backups in CSV: ", + "ErrorMessageForExportingToPdf": "Fehler beim Exportieren der Backups in PDF: ", + "CsvNameMessageInput": "Geben Sie den Namen der CSV-Datei ein.", + "PdfNameMessageInput": "Geben Sie den Namen der PDF-Datei ein.", + "DuplicatedFileNameMessage": "Datei existiert bereits. Überschreiben?", + "ErrorMessageInvalidFilename": "Ungültiger Dateiname. Verwenden Sie nur alphanumerische Zeichen, Bindestriche und Unterstriche.", + "ConfirmationDeletionTitle": "Löschen bestätigen", + "ConfirmationDeletionMessage": "Sind Sie sicher, dass Sie die ausgewählten Zeilen löschen möchten?" } } \ No newline at end of file diff --git a/src/main/resources/res/languages/eng.json b/src/main/resources/res/languages/eng.json index 7a9173e..f669122 100644 --- a/src/main/resources/res/languages/eng.json +++ b/src/main/resources/res/languages/eng.json @@ -8,7 +8,9 @@ "OkButton": "Ok", "CancelButton": "Cancel", "CloseButton":"Close", - "ApplyButton":"Apply" + "ApplyButton":"Apply", + "SaveButton": "Save", + "CreateButton": "Create" }, "Menu": { "File": "File", @@ -46,6 +48,8 @@ "AutoBackupButtonOFF": "Auto Backup (OFF)", "InitialPathPlaceholder": "Initial path", "DestinationPathPlaceholder": "Destination path", + "BackupName": "Backup name: ", + "BackupNameTooltip": "(Required) Backup name", "InitialPathTooltip": "(Required) Initial path", "DestinationPathTooltip": "(Required) Destination path", "InitialFileChooserTooltip": "Open file explorer", @@ -77,10 +81,14 @@ "NotesDetail": "Notes", "MaxBackupsToKeepDetail": "MaxBackupsToKeep", "AddBackupTooltip": "Add new backup", + "ExportAs": "Export as: ", + "ExportAsPdfTooltip": "Export as PDF", + "ExportAsCsvTooltip": "Export as CSV", "ResearchBarTooltip": "Research bar", "ResearchBarPlaceholder": "Search...", "EditPopup": "Edit", "DeletePopup": "Delete", + "InterruptPopup": "Interrupt", "DuplicatePopup": "Duplicate", "RenameBackupPopup": "Rename backup", "OpenInitialFolderPopup": "Open initial path", @@ -106,6 +114,16 @@ "Language": "Language", "Theme": "Theme" }, + "UserDialog": { + "UserTitle": "Insert your data", + "Name": "Name", + "Surname": "Surname", + "Email": "Email", + "ErrorMessageForMissingData": "Please fill in all the required fields.", + "ErrorMessageForWrongEmail": "The provided email address is invalid. Please provide a correct one.", + "EmailConfirmationSubject": "Thank you for choosing Backup Manager!", + "EmailConfirmationBody": "Hi [UserName],\n\nThank you for downloading and registering Backup Manager, your new tool for secure and efficient backup management!\n\nThis is an automated email sent to confirm your registration. We will contact you by email only to inform you about new releases or important updates of the application.\n\nIn the meantime, if you have any questions, need assistance, or have suggestions, we are always here for you. You can reach us at [SupportEmail].\n\nThank you again for choosing Backup Manager, and enjoy managing your backups!\n\nBest regards,\nThe Backup Manager Team" + }, "ProgressBackupFrame": { "ProgressBackupTitle":"Backup in progress", "StatusCompleted":"Backup completed!", @@ -120,6 +138,9 @@ }, "Dialogs": { "ErrorGenericTitle":"Error", + "WarningGenericTitle": "Warning", + "WarningBackupAlreadyInProgressMessage": "There is already a backup in progress. It is not possible to perform parallel backups", + "WarningShortTimeIntervalMessage": "The selected time interval is very short. For optimal performance, we recommend setting it to at least one hour. Do you still want to proceed?", "ErrorMessageForFolderNotExisting":"The folder does not exist or is invalid", "ErrorMessageForSavingFileWithPathsEmpty":"Unable to save the file. Both the initial and destination paths must be specified and cannot be empty", "BackupSavedCorrectlyTitle":"Backup saved", @@ -159,6 +180,21 @@ "BackupListCorrectlyImportedMessage": "Backup list successfully imported!", "ErrorMessageForSamePaths": "The initial path and destination path cannot be the same. Please choose different paths!", "ErrorMessageForWrongFileExtensionTitle": "Invalid File", - "ErrorMessageForWrongFileExtensionMessage": "Error: Please select a valid JSON file." + "ErrorMessageForWrongFileExtensionMessage": "Error: Please select a valid JSON file.", + "ErrorMessageCountingFiles": "Error occurred while calculating files to back up.", + "ErrorMessageZippingGeneric": "Error occurred while zipping files.", + "ErrorMessageZippingIO": "Error occurred while zipping files: I/O error.", + "ErrorMessageZippingSecurity": "Error occurred while zipping files: Security error.", + "SuccessGenericTitle":"Success", + "SuccessfullyExportedToCsvMessage":"Backups exported to CSV successfully!", + "SuccessfullyExportedToPdfMessage":"Backups exported to PDF successfully!", + "ErrorMessageForExportingToCsv":"Error exporting backups to CSV: ", + "ErrorMessageForExportingToPdf":"Error exporting backups to PDF: ", + "CsvNameMessageInput":"Enter the name of the CSV file.", + "PdfNameMessageInput":"Enter the name of the PDF file.", + "DuplicatedFileNameMessage":"File already exists. Overwrite?", + "ErrorMessageInvalidFilename":"Invalid file name. Use only alphanumeric characters, dashes, and underscores.", + "ConfirmationDeletionTitle":"Confirm Deletion", + "ConfirmationDeletionMessage":"Are you sure you want to delete the selected rows?" } } \ No newline at end of file diff --git a/src/main/resources/res/languages/esp.json b/src/main/resources/res/languages/esp.json index e08e114..0468082 100644 --- a/src/main/resources/res/languages/esp.json +++ b/src/main/resources/res/languages/esp.json @@ -8,7 +8,9 @@ "OkButton": "Aceptar", "CancelButton": "Cancelar", "CloseButton": "Cerrar", - "ApplyButton": "Aplicar" + "ApplyButton": "Aplicar", + "SaveButton": "Guardar", + "CreateButton": "Crear" }, "Menu": { "File": "Archivo", @@ -46,6 +48,8 @@ "AutoBackupButtonOFF": "Copia de Seguridad Automática (DESACTIVADA)", "InitialPathPlaceholder": "Ruta inicial", "DestinationPathPlaceholder": "Ruta de destino", + "BackupName": "Nombre de la copia de seguridad: ", + "BackupNameTooltip": "(Requerido) Nombre de la copia de seguridad", "InitialPathTooltip": "(Requerido) Ruta inicial", "DestinationPathTooltip": "(Requerido) Ruta de destino", "InitialFileChooserTooltip": "Abrir explorador de archivos", @@ -77,10 +81,14 @@ "NotesDetail": "Notas", "MaxBackupsToKeepDetail": "MaximoCopiasDeSeguridadMantener", "AddBackupTooltip": "Agregar nueva copia de seguridad", + "ExportAs": "Exportar como: ", + "ExportAsPdfTooltip": "Exportar como PDF", + "ExportAsCsvTooltip": "Exportar como CSV", "ResearchBarTooltip": "Barra de búsqueda", "ResearchBarPlaceholder": "Buscar...", "EditPopup": "Editar", "DeletePopup": "Eliminar", + "InterruptPopup": "Interrumpir", "DuplicatePopup": "Duplicar", "RenameBackupPopup": "Renombrar copia de seguridad", "OpenInitialFolderPopup": "Abrir ruta inicial", @@ -106,6 +114,16 @@ "Language": "Idioma", "Theme": "Tema" }, + "UserDialog": { + "UserTitle": "Inserta tus datos", + "Name": "Nombre", + "Surname": "Apellido", + "Email": "Correo electrónico", + "ErrorMessageForMissingData": "Por favor, completa todos los campos requeridos.", + "ErrorMessageForWrongEmail": "La dirección de correo electrónico proporcionada no es válida. Por favor, proporciona una correcta.", + "EmailConfirmationSubject": "¡Gracias por elegir Backup Manager!", + "EmailConfirmationBody": "Hola [UserName],\n\n¡Gracias por descargar y registrar Backup Manager, tu nueva herramienta para una gestión segura y eficiente de tus copias de seguridad!\n\nEste es un correo automático enviado para confirmar tu registro. Nos pondremos en contacto contigo por correo solo para informarte sobre nuevas versiones o actualizaciones importantes de la aplicación.\n\nMientras tanto, si tienes preguntas, necesitas ayuda o tienes sugerencias, estamos siempre a tu disposición. Puedes contactarnos en [SupportEmail].\n\n¡Gracias nuevamente por elegir Backup Manager y disfruta gestionando tus copias de seguridad!\n\nSaludos cordiales,\nEl equipo de Backup Manager" + }, "ProgressBackupFrame": { "ProgressBackupTitle": "Copia de Seguridad en Progreso", "StatusCompleted": "¡Copia completada!", @@ -120,6 +138,9 @@ }, "Dialogs": { "ErrorGenericTitle": "Error", + "WarningGenericTitle": "Advertencia", + "WarningBackupAlreadyInProgressMessage": "Ya hay una copia de seguridad en progreso. No es posible realizar copias de seguridad en paralelo.", + "WarningShortTimeIntervalMessage": "El intervalo de tiempo seleccionado es muy corto. Para un funcionamiento óptimo, recomendamos configurarlo en al menos una hora. ¿Quieres continuar de todos modos?", "ErrorMessageForFolderNotExisting": "La carpeta no existe o no es válida", "ErrorMessageForSavingFileWithPathsEmpty": "No se puede guardar el archivo. Tanto la ruta inicial como la de destino deben especificarse y no pueden estar vacías", "BackupSavedCorrectlyTitle": "Copia Guardada", @@ -159,7 +180,22 @@ "BackupListCorrectlyImportedTitle": "Menú Importar", "BackupListCorrectlyImportedMessage": "¡Lista de copias de seguridad importada correctamente!", "ErrorMessageForWrongFileExtensionTitle": "Archivo no válido", - "ErrorMessageForWrongFileExtensionMessage": "Error: por favor selecciona un archivo JSON válido." + "ErrorMessageForWrongFileExtensionMessage": "Error: Seleccione un archivo JSON válido.", + "ErrorMessageCountingFiles": "Error al calcular los archivos para la copia de seguridad.", + "ErrorMessageZippingGeneric": "Error al comprimir los archivos.", + "ErrorMessageZippingIO": "Error al comprimir los archivos: error de E/S.", + "ErrorMessageZippingSecurity": "Error al comprimir los archivos: Error de seguridad.", + "SuccessGenericTitle": "Éxito", + "SuccessfullyExportedToCsvMessage": "¡Copias de seguridad exportadas a CSV con éxito!", + "SuccessfullyExportedToPdfMessage": "¡Copias de seguridad exportadas a PDF con éxito!", + "ErrorMessageForExportingToCsv": "Error al exportar copias de seguridad a CSV: ", + "ErrorMessageForExportingToPdf": "Error al exportar copias de seguridad a PDF: ", + "CsvNameMessageInput": "Introduce el nombre del archivo CSV.", + "PdfNameMessageInput": "Introduce el nombre del archivo PDF.", + "DuplicatedFileNameMessage": "El archivo ya existe. ¿Sobrescribir?", + "ErrorMessageInvalidFilename": "Nombre de archivo no válido. Usa solo caracteres alfanuméricos, guiones y guiones bajos.", + "ConfirmationDeletionTitle": "Confirmar Eliminación", + "ConfirmationDeletionMessage": "¿Está seguro de que desea eliminar las filas seleccionadas?" } } \ No newline at end of file diff --git a/src/main/resources/res/languages/fra.json b/src/main/resources/res/languages/fra.json index f9e6dbe..abfa797 100644 --- a/src/main/resources/res/languages/fra.json +++ b/src/main/resources/res/languages/fra.json @@ -8,7 +8,9 @@ "OkButton": "OK", "CancelButton": "Annuler", "CloseButton": "Fermer", - "ApplyButton": "Appliquer" + "ApplyButton": "Appliquer", + "SaveButton": "Enregistrer", + "CreateButton": "Créer" }, "Menu": { "File": "Fichier", @@ -46,6 +48,8 @@ "AutoBackupButtonOFF": "Sauvegarde Automatique (DÉSACTIVÉE)", "InitialPathPlaceholder": "Chemin initial", "DestinationPathPlaceholder": "Chemin de destination", + "BackupName": "Nom de la sauvegarde : ", + "BackupNameTooltip": "(Requis) Nom de la sauvegarde", "InitialPathTooltip": "(Requis) Chemin initial", "DestinationPathTooltip": "(Requis) Chemin de destination", "InitialFileChooserTooltip": "Ouvrir l'explorateur de fichiers", @@ -77,10 +81,14 @@ "NotesDetail": "Notes", "MaxBackupsToKeepDetail": "NombreMaxSauvegardesConserver", "AddBackupTooltip": "Ajouter une nouvelle sauvegarde", + "ExportAs": "Exporter en tant que : ", + "ExportAsPdfTooltip": "Exporter en tant que PDF", + "ExportAsCsvTooltip": "Exporter en tant que CSV", "ResearchBarTooltip": "Barre de recherche", "ResearchBarPlaceholder": "Rechercher...", "EditPopup": "Modifier", "DeletePopup": "Supprimer", + "InterruptPopup": "Interrompre", "DuplicatePopup": "Dupliquer", "RenameBackupPopup": "Renommer la sauvegarde", "OpenInitialFolderPopup": "Ouvrir le chemin initial", @@ -106,6 +114,16 @@ "Language": "Langue", "Theme": "Thème" }, + "UserDialog": { + "UserTitle": "Entrez vos informations", + "Name": "Prénom", + "Surname": "Nom de famille", + "Email": "E-Mail", + "ErrorMessageForMissingData": "Veuillez remplir tous les champs requis.", + "ErrorMessageForWrongEmail": "L'adresse e-mail fournie n'est pas valide. Veuillez en fournir une correcte.", + "EmailConfirmationSubject": "Merci d'avoir choisi Backup Manager !", + "EmailConfirmationBody": "Bonjour [UserName],\n\nMerci d'avoir téléchargé et enregistré Backup Manager, votre nouvel outil pour une gestion sécurisée et efficace des sauvegardes !\n\nCeci est un email automatique envoyé pour confirmer votre inscription. Nous vous contacterons uniquement par email pour vous informer des nouvelles versions ou des mises à jour importantes de l'application.\n\nEn attendant, si vous avez des questions, besoin d'aide ou des suggestions, nous sommes toujours à votre disposition. Vous pouvez nous contacter à [SupportEmail].\n\nMerci encore d'avoir choisi Backup Manager et bonne gestion de vos sauvegardes !\n\nCordialement,\nL'équipe de Backup Manager" + }, "ProgressBackupFrame": { "ProgressBackupTitle": "Sauvegarde en cours", "StatusCompleted": "Sauvegarde terminée !", @@ -120,6 +138,9 @@ }, "Dialogs": { "ErrorGenericTitle": "Erreur", + "WarningGenericTitle": "Avertissement", + "WarningBackupAlreadyInProgressMessage": "Une sauvegarde est déjà en cours. Il n'est pas possible d'effectuer des sauvegardes en parallèle.", + "WarningShortTimeIntervalMessage": "L'intervalle de temps sélectionné est très court. Pour un fonctionnement optimal, nous recommandons de le régler à au moins une heure. Voulez-vous quand même continuer ?", "ErrorMessageForFolderNotExisting": "Le dossier n'existe pas ou est invalide", "ErrorMessageForSavingFileWithPathsEmpty": "Impossible d'enregistrer le fichier. Les chemins initial et de destination doivent être spécifiés et ne peuvent pas être vides", "BackupSavedCorrectlyTitle": "Sauvegarde Enregistrée", @@ -159,7 +180,22 @@ "BackupListCorrectlyImportedTitle": "Menu Importer", "BackupListCorrectlyImportedMessage": "Liste de sauvegarde importée avec succès !", "ErrorMessageForWrongFileExtensionTitle": "Fichier invalide", - "ErrorMessageForWrongFileExtensionMessage": "Erreur : Veuillez sélectionner un fichier JSON valide." + "ErrorMessageForWrongFileExtensionMessage": "Erreur : Veuillez sélectionner un fichier JSON valide.", + "ErrorMessageCountingFiles": "Erreur lors du calcul des fichiers à sauvegarder.", + "ErrorMessageZippingGeneric": "Erreur lors de la compression des fichiers.", + "ErrorMessageZippingIO": "Erreur lors de la compression des fichiers : erreur d'E/S.", + "ErrorMessageZippingSecurity": "Erreur lors de la compression des fichiers : Erreur de sécurité.", + "SuccessGenericTitle": "Succès", + "SuccessfullyExportedToCsvMessage": "Sauvegardes exportées en CSV avec succès !", + "SuccessfullyExportedToPdfMessage": "Sauvegardes exportées en PDF avec succès !", + "ErrorMessageForExportingToCsv": "Erreur lors de l'exportation des sauvegardes en CSV : ", + "ErrorMessageForExportingToPdf": "Erreur lors de l'exportation des sauvegardes en PDF : ", + "CsvNameMessageInput": "Entrez le nom du fichier CSV.", + "PdfNameMessageInput": "Entrez le nom du fichier PDF.", + "DuplicatedFileNameMessage": "Le fichier existe déjà. Écraser?", + "ErrorMessageInvalidFilename": "Nom de fichier invalide. Utilisez uniquement des caractères alphanumériques, des tirets et des underscores.", + "ConfirmationDeletionTitle": "Confirmer la suppression", + "ConfirmationDeletionMessage": "Êtes-vous sûr de vouloir supprimer les lignes sélectionnées ?" } } \ No newline at end of file diff --git a/src/main/resources/res/languages/ita.json b/src/main/resources/res/languages/ita.json index 1c4ad4f..07fd713 100644 --- a/src/main/resources/res/languages/ita.json +++ b/src/main/resources/res/languages/ita.json @@ -8,7 +8,9 @@ "CloseButton": "Chiudi", "OkButton": "Ok", "CancelButton": "Annulla", - "ApplyButton":"Applica" + "ApplyButton":"Applica", + "SaveButton": "Salva", + "CreateButton": "Crea" }, "Menu": { "File": "File", @@ -46,6 +48,8 @@ "AutoBackupButtonOFF": "Backup Automatico (OFF)", "InitialPathPlaceholder": "Percorso iniziale", "DestinationPathPlaceholder": "Percorso di destinazione", + "BackupName": "Nome del backup: ", + "BackupNameTooltip": "(Obbligatorio) Nome del backup", "InitialPathTooltip": "(Obbligatorio) Percorso iniziale", "DestinationPathTooltip": "(Obbligatorio) Percorso di destinazione", "InitialFileChooserTooltip": "Apri esplora file", @@ -54,7 +58,7 @@ "SingleBackupTooltip": "Esegui il backup", "AutoBackupTooltip": "Attiva/Disattiva backup automatico", "TimePickerTooltip": "Selettore orario", - "MaxBackupsToKeep": "Massimo di backup da mantenere", + "MaxBackupsToKeep": "Massimo numero di backup da mantenere", "MaxBackupsToKeepTooltip": "Numero massimo di backup da conservare prima di eliminare i più vecchi." }, "BackupList": { @@ -74,13 +78,17 @@ "CreationDateDetail": "DataCreazione", "LastUpdateDateDetail": "DataUltimoAggiornamento", "BackupCountDetail": "ConteggioBackup", - "MaxBackupsToKeepDetail": "MassimoBackupDaMantenere", + "MaxBackupsToKeepDetail": "MassimoNumeroBackupDaMantenere", "NotesDetail": "Note", "AddBackupTooltip": "Aggiungi nuovo backup", + "ExportAs": "Esporta come: ", + "ExportAsPdfTooltip": "Esporta come PDF", + "ExportAsCsvTooltip": "Esporta come CSV", "ResearchBarTooltip": "Barra di ricerca", - "ResearchBarPlaceholder": "cerca...", + "ResearchBarPlaceholder": "Cerca...", "EditPopup": "Modifica", "DeletePopup": "Elimina", + "InterruptPopup": "Interrompi", "DuplicatePopup": "Duplica", "RenameBackupPopup": "Rinomina backup", "OpenInitialFolderPopup": "Apri percorso iniziale", @@ -106,6 +114,16 @@ "Language": "Lingua", "Theme": "Tema" }, + "UserDialog": { + "UserTitle": "Inserisci i tuoi dati", + "Name": "Nome", + "Surname": "Cognome", + "Email": "Email", + "ErrorMessageForMissingData": "Per favore, compila tutti i campi richiesti.", + "ErrorMessageForWrongEmail": "L'indirizzo email fornito non è valido. Inseriscine uno corretto.", + "EmailConfirmationSubject": "Grazie per aver scelto Backup Manager!", + "EmailConfirmationBody": "Ciao [UserName],\n\nGrazie per aver scaricato e registrato Backup Manager, il tuo nuovo strumento per una gestione sicura ed efficiente dei backup!\n\nQuesta è un’email automatica, inviata per confermare la tua registrazione. Ti contatteremo via email esclusivamente per comunicarti il rilascio di nuove versioni o aggiornamenti importanti dell’applicazione.\n\nNel frattempo, se hai domande, necessiti assistenza o hai suggerimenti, siamo sempre a tua disposizione. Puoi contattarci scrivendo a [SupportEmail].\n\nGrazie ancora per aver scelto Backup Manager e buon lavoro con i tuoi backup!\n\nA presto,\nIl Team di Backup Manager" + }, "ProgressBackupFrame": { "ProgressBackupTitle": "Backup in corso", "StatusCompleted": "Backup completato!", @@ -120,6 +138,9 @@ }, "Dialogs": { "ErrorGenericTitle": "Errore", + "WarningGenericTitle": "Avviso", + "WarningBackupAlreadyInProgressMessage": "È già in corso un backup. Non è possibile eseguire backup in parallelo.", + "WarningShortTimeIntervalMessage": "L'intervallo di tempo selezionato è molto breve. Per un funzionamento ottimale, consigliamo di impostarlo ad almeno un'ora. Vuoi comunque procedere?", "ErrorMessageForFolderNotExisting": "La cartella non esiste o non è valida", "ErrorMessageForSavingFileWithPathsEmpty": "Impossibile salvare il file. Entrambi i percorsi iniziale e di destinazione devono essere specificati e non possono essere vuoti", "BackupSavedCorrectlyTitle": "Backup salvato", @@ -159,6 +180,21 @@ "BackupListCorrectlyImportedTitle": "Menu Importa", "BackupListCorrectlyImportedMessage": "Lista di backup importata correttamente!", "ErrorMessageForWrongFileExtensionTitle": "File non valido", - "ErrorMessageForWrongFileExtensionMessage": "Errore: seleziona un file JSON valido." + "ErrorMessageForWrongFileExtensionMessage": "Errore: Selezionare un file JSON valido.", + "ErrorMessageCountingFiles": "Errore durante il calcolo dei file da eseguire il backup.", + "ErrorMessageZippingGeneric": "Errore durante la compressione dei file.", + "ErrorMessageZippingIO": "Errore durante la compressione dei file: errore di I/O.", + "ErrorMessageZippingSecurity": "Errore durante la compressione dei file: Errore di sicurezza.", + "SuccessGenericTitle": "Successo", + "SuccessfullyExportedToCsvMessage": "Backup esportati in CSV con successo!", + "SuccessfullyExportedToPdfMessage": "Backup esportati in PDF con successo!", + "ErrorMessageForExportingToCsv": "Errore durante l'esportazione dei backup in CSV: ", + "ErrorMessageForExportingToPdf": "Errore durante l'esportazione dei backup in PDF: ", + "CsvNameMessageInput": "Inserisci il nome del file CSV.", + "PdfNameMessageInput": "Inserisci il nome del file PDF.", + "DuplicatedFileNameMessage": "Il file esiste già. Sovrascrivere?", + "ErrorMessageInvalidFilename": "Nome file non valido. Usa solo caratteri alfanumerici, trattini e underscore.", + "ConfirmationDeletionTitle": "Conferma Eliminazione", + "ConfirmationDeletionMessage": "Sei sicuro di voler eliminare le righe selezionate?" } } \ No newline at end of file diff --git a/src/test/java/test/TestBackupOperations.java b/src/test/java/test/TestBackupOperations.java index bc05b7d..136a731 100644 --- a/src/test/java/test/TestBackupOperations.java +++ b/src/test/java/test/TestBackupOperations.java @@ -1,70 +1,70 @@ -package test; +// package test; -import com.mycompany.autobackupprogram.BackupOperations; -import com.mycompany.autobackupprogram.JSONConfigReader; -import com.mycompany.autobackupprogram.Logger; -import org.junit.jupiter.api.*; -import org.mockito.Mock; +// import backupmanager.Json.JSONConfigReader; +// import backupmanager.BackupOperations; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +// import org.junit.jupiter.api.*; +// import org.mockito.Mock; -import java.io.File; -import java.io.IOException; +// import static org.junit.Assert.assertFalse; +// import static org.junit.Assert.assertTrue; +// import static org.mockito.Mockito.mock; +// import static org.mockito.Mockito.when; -public class TestBackupOperations { +// import java.io.File; +// import java.io.IOException; + +// public class TestBackupOperations { - private static File temp_file; +// private static File temp_file; - @Mock - private static JSONConfigReader mockConfigReader; +// @Mock +// private static JSONConfigReader mockConfigReader; - @BeforeAll - static void setUpBeforeClass() throws IOException { - // Create test configuration file - temp_file = File.createTempFile("src/test/resources/config_test", ".json"); +// @BeforeAll +// static void setUpBeforeClass() throws IOException { +// // Create test configuration file +// temp_file = File.createTempFile("src/test/resources/config_test", ".json"); - // Set up the mock config reader - mockConfigReader = mock(JSONConfigReader.class); - when(mockConfigReader.getMaxLines()).thenReturn(100); - when(mockConfigReader.getLinesToKeepAfterFileClear()).thenReturn(50); - when(mockConfigReader.isLogLevelEnabled("INFO")).thenReturn(true); - when(mockConfigReader.isLogLevelEnabled("DEBUG")).thenReturn(true); - when(mockConfigReader.isLogLevelEnabled("WARN")).thenReturn(true); - when(mockConfigReader.isLogLevelEnabled("ERROR")).thenReturn(true); +// // Set up the mock config reader +// mockConfigReader = mock(JSONConfigReader.class); +// when(mockConfigReader.getMaxLines()).thenReturn(100); +// when(mockConfigReader.getLinesToKeepAfterFileClear()).thenReturn(50); +// when(mockConfigReader.isLogLevelEnabled("INFO")).thenReturn(true); +// when(mockConfigReader.isLogLevelEnabled("DEBUG")).thenReturn(true); +// when(mockConfigReader.isLogLevelEnabled("WARN")).thenReturn(true); +// when(mockConfigReader.isLogLevelEnabled("ERROR")).thenReturn(true); - Logger.configReader = mockConfigReader; +// Logger.configReader = mockConfigReader; - Logger.setLogFilePath(temp_file.getPath()); - } +// Logger.setLogFilePath(temp_file.getPath()); +// } - @BeforeEach - void setup() throws IOException { - // Reset the console logging flag before each test - temp_file = File.createTempFile("src/test/resources/config_test", ".json"); - Logger.setConsoleLoggingEnabled(false); - } +// @BeforeEach +// void setup() throws IOException { +// // Reset the console logging flag before each test +// temp_file = File.createTempFile("src/test/resources/config_test", ".json"); +// Logger.setConsoleLoggingEnabled(false); +// } - @Test - void testCheckInputCorrectWrongFilePaths() { - String path1 = "/wrong/path/file.txt"; - String path2 = "/wrong/path/dir"; - assertFalse(BackupOperations.CheckInputCorrect("backup", path1, path2, null)); - } +// @Test +// void testCheckInputCorrectWrongFilePaths() { +// String path1 = "/wrong/path/file.txt"; +// String path2 = "/wrong/path/dir"; +// assertFalse(BackupOperations.CheckInputCorrect("backup", path1, path2, null)); +// } - @Test - void testCheckInputCorrectSameFilePaths() throws IOException { - File file1 = File.createTempFile("file1", ".csv"); - File file2 = file1; - assertFalse(BackupOperations.CheckInputCorrect("backup", file1.getPath(), file2.getPath(), null)); - } +// @Test +// void testCheckInputCorrectSameFilePaths() throws IOException { +// File file1 = File.createTempFile("file1", ".csv"); +// File file2 = file1; +// assertFalse(BackupOperations.CheckInputCorrect("backup", file1.getPath(), file2.getPath(), null)); +// } - @Test - void testCheckInputCorrectCorrectFilePaths() throws IOException { - File tempFile1 = File.createTempFile("file1", ".txt"); - File tempFile2 = File.createTempFile("file2", ".txt"); - assertTrue(BackupOperations.CheckInputCorrect("backup", tempFile1.getPath(), tempFile2.getPath(), null)); - } -} +// @Test +// void testCheckInputCorrectCorrectFilePaths() throws IOException { +// File tempFile1 = File.createTempFile("file1", ".txt"); +// File tempFile2 = File.createTempFile("file2", ".txt"); +// assertTrue(BackupOperations.CheckInputCorrect("backup", tempFile1.getPath(), tempFile2.getPath(), null)); +// } +// } diff --git a/src/test/java/test/TestConfigKey.java b/src/test/java/test/TestConfigKey.java index d89fd06..7eab0f5 100644 --- a/src/test/java/test/TestConfigKey.java +++ b/src/test/java/test/TestConfigKey.java @@ -1,14 +1,14 @@ package test; -import com.mycompany.autobackupprogram.Enums.ConfigKey; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; -import java.nio.file.Files; -import java.io.File; -import java.io.IOException; +import backupmanager.Enums.ConfigKey; public class TestConfigKey { private final String LOG_FILE_STRING = "log_file"; @@ -69,7 +69,6 @@ void testLoadFromJson() { assertEquals(BACKUP_FILE_STRING, ConfigKey.BACKUP_FILE_STRING.getValue()); assertEquals(CONFIG_FILE_STRING, ConfigKey.CONFIG_FILE_STRING.getValue()); assertEquals(RES_DIRECTORY_STRING, ConfigKey.RES_DIRECTORY_STRING.getValue()); - assertEquals(DONATE_PAGE_LINK, ConfigKey.DONATE_PAGE_LINK.getValue()); assertEquals(ISSUE_PAGE_LINK, ConfigKey.ISSUE_PAGE_LINK.getValue()); assertEquals(INFO_PAGE_LINK, ConfigKey.INFO_PAGE_LINK.getValue()); assertEquals(EMAIL, ConfigKey.EMAIL.getValue()); @@ -90,9 +89,7 @@ void testMissingKeys() { try { Files.write(temp_file.toPath(), jsonContent.getBytes()); - } catch (IOException e) { - e.printStackTrace(); - } + } catch (IOException e) { } // load the values ConfigKey.loadFromJson(temp_file.getPath()); @@ -100,7 +97,6 @@ void testMissingKeys() { // checks assertEquals(CONFIG_FILE_STRING, ConfigKey.CONFIG_FILE_STRING.getValue()); assertEquals(RES_DIRECTORY_STRING, ConfigKey.RES_DIRECTORY_STRING.getValue()); - assertEquals(DONATE_PAGE_LINK, ConfigKey.DONATE_PAGE_LINK.getValue()); } @Test @@ -108,36 +104,11 @@ void testEmptyJsonFile() { String emptyJsonContent = "{}"; try { Files.write(temp_file.toPath(), emptyJsonContent.getBytes()); - } catch (IOException e) { - e.printStackTrace(); - } + } catch (IOException e) { } ConfigKey.loadFromJson(temp_file.getPath()); assertEquals(LOG_FILE_STRING, ConfigKey.LOG_FILE_STRING.getValue()); assertEquals(BACKUP_FILE_STRING, ConfigKey.BACKUP_FILE_STRING.getValue()); } - -// @Test -// void testJsonParsingException() { -// // Test JSON error -// String malformedJson = String.format(""" -// { -// "LOG_FILE_STRING": "log_file", -// "BACKUP_FILE_STRING": "backup_list.json" -// """, -// LOG_FILE_STRING, -// BACKUP_FILE_STRING -// ); // JSON error ('}' is missing) -// -// try { -// Files.write(temp_file.toPath(), malformedJson.getBytes()); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// -// ConfigKey.loadFromJson(temp_file.getPath()); -// assertEquals(LOG_FILE_STRING, ConfigKey.LOG_FILE_STRING.getValue()); -// assertEquals(BACKUP_FILE_STRING, ConfigKey.BACKUP_FILE_STRING.getValue()); -// } } diff --git a/src/test/java/test/TestLogger.java b/src/test/java/test/TestLogger.java index b4fbedf..8e2256a 100644 --- a/src/test/java/test/TestLogger.java +++ b/src/test/java/test/TestLogger.java @@ -1,111 +1,112 @@ -package test; +// package test; -import com.mycompany.autobackupprogram.JSONConfigReader; -import com.mycompany.autobackupprogram.Logger; -import org.junit.jupiter.api.*; -import org.mockito.*; +// import backupmanager.Json.JSONConfigReader; +// import backupmanager.Logger; -import java.io.*; -import java.nio.file.*; -import java.util.List; +// import org.junit.jupiter.api.*; +// import org.mockito.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +// import java.io.*; +// import java.nio.file.*; +// import java.util.List; -public class TestLogger { +// import static org.junit.jupiter.api.Assertions.*; +// import static org.mockito.Mockito.*; - private static File temp_file; +// public class TestLogger { - @Mock - private static JSONConfigReader mockConfigReader; +// private static File temp_file; - @BeforeAll - static void setUpBeforeClass() throws IOException { - // Create test configuration file - temp_file = File.createTempFile("src/test/resources/log_test", ""); +// @Mock +// private static JSONConfigReader mockConfigReader; - // Set up the mock config reader - mockConfigReader = mock(JSONConfigReader.class); - when(mockConfigReader.getMaxLines()).thenReturn(100); - when(mockConfigReader.getLinesToKeepAfterFileClear()).thenReturn(50); - when(mockConfigReader.isLogLevelEnabled("INFO")).thenReturn(true); - when(mockConfigReader.isLogLevelEnabled("DEBUG")).thenReturn(true); - when(mockConfigReader.isLogLevelEnabled("WARN")).thenReturn(true); - when(mockConfigReader.isLogLevelEnabled("ERROR")).thenReturn(true); +// @BeforeAll +// static void setUpBeforeClass() throws IOException { +// // Create test configuration file +// temp_file = File.createTempFile("src/test/resources/log_test", ""); - Logger.configReader = mockConfigReader; +// // Set up the mock config reader +// mockConfigReader = mock(JSONConfigReader.class); +// when(mockConfigReader.getMaxLines()).thenReturn(100); +// when(mockConfigReader.getLinesToKeepAfterFileClear()).thenReturn(50); +// when(mockConfigReader.isLogLevelEnabled("INFO")).thenReturn(true); +// when(mockConfigReader.isLogLevelEnabled("DEBUG")).thenReturn(true); +// when(mockConfigReader.isLogLevelEnabled("WARN")).thenReturn(true); +// when(mockConfigReader.isLogLevelEnabled("ERROR")).thenReturn(true); - Logger.setLogFilePath(temp_file.getPath()); - } +// Logger.configReader = mockConfigReader; - @BeforeEach - void setup() throws IOException { - Logger.setConsoleLoggingEnabled(false); +// Logger.setLogFilePath(temp_file.getPath()); +// } - // clear the content of the log file for each test - Files.write(temp_file.toPath(), new byte[0], StandardOpenOption.TRUNCATE_EXISTING); - } +// @BeforeEach +// void setup() throws IOException { +// Logger.setConsoleLoggingEnabled(false); - @Test - void testLogMessageInfoLevel() throws IOException { - Logger.logMessage("Test info message", Logger.LogLevel.INFO); +// // clear the content of the log file for each test +// Files.write(temp_file.toPath(), new byte[0], StandardOpenOption.TRUNCATE_EXISTING); +// } - List lines = Files.readAllLines(temp_file.toPath()); - assertTrue(lines.stream().anyMatch(line -> line.contains("INFO"))); - } +// @Test +// void testLogMessageInfoLevel() throws IOException { +// Logger.logMessage("Test info message", Logger.LogLevel.INFO); - @Test - void testLogMessageDebugLevel() throws IOException { - Logger.logMessage("Test debug message", Logger.LogLevel.DEBUG); +// List lines = Files.readAllLines(temp_file.toPath()); +// assertTrue(lines.stream().anyMatch(line -> line.contains("INFO"))); +// } - List lines = Files.readAllLines(temp_file.toPath()); - assertTrue(lines.stream().anyMatch(line -> line.contains("DEBUG") && line.contains("Test debug message"))); - } +// @Test +// void testLogMessageDebugLevel() throws IOException { +// Logger.logMessage("Test debug message", Logger.LogLevel.DEBUG); - @Test - void testLogMessageErrorLevel() throws IOException { - Logger.logMessage("Test error message", Logger.LogLevel.ERROR); +// List lines = Files.readAllLines(temp_file.toPath()); +// assertTrue(lines.stream().anyMatch(line -> line.contains("DEBUG") && line.contains("Test debug message"))); +// } - List lines = Files.readAllLines(temp_file.toPath()); - assertTrue(lines.stream().anyMatch(line -> line.contains("ERROR") && line.contains("Test error message"))); - } +// @Test +// void testLogMessageErrorLevel() throws IOException { +// Logger.logMessage("Test error message", Logger.LogLevel.ERROR); - @Test - void testLogMessageWithException() throws IOException { - Exception testException = new Exception("Test exception"); - Logger.logMessage("Test message with exception: " + testException.getMessage(), Logger.LogLevel.ERROR, testException); +// List lines = Files.readAllLines(temp_file.toPath()); +// assertTrue(lines.stream().anyMatch(line -> line.contains("ERROR") && line.contains("Test error message"))); +// } - List lines = Files.readAllLines(temp_file.toPath()); - assertTrue(lines.stream().anyMatch(line -> line.contains("ERROR") && line.contains("Test message with exception"))); - assertTrue(lines.stream().anyMatch(line -> line.contains("Exception: java.lang.Exception - Test exception"))); - } +// @Test +// void testLogMessageWithException() throws IOException { +// Exception testException = new Exception("Test exception"); +// Logger.logMessage("Test message with exception: " + testException.getMessage(), Logger.LogLevel.ERROR, testException); - @Test - void testConsoleLoggingEnabled() { - Logger.setConsoleLoggingEnabled(true); +// List lines = Files.readAllLines(temp_file.toPath()); +// assertTrue(lines.stream().anyMatch(line -> line.contains("ERROR") && line.contains("Test message with exception"))); +// assertTrue(lines.stream().anyMatch(line -> line.contains("Exception: java.lang.Exception - Test exception"))); +// } - // Capture the console output - PrintStream originalOut = System.out; - ByteArrayOutputStream consoleOutput = new ByteArrayOutputStream(); - System.setOut(new PrintStream(consoleOutput)); +// @Test +// void testConsoleLoggingEnabled() { +// Logger.setConsoleLoggingEnabled(true); - Logger.logMessage("Test console logging", Logger.LogLevel.INFO); +// // Capture the console output +// PrintStream originalOut = System.out; +// ByteArrayOutputStream consoleOutput = new ByteArrayOutputStream(); +// System.setOut(new PrintStream(consoleOutput)); - assertTrue(consoleOutput.toString().contains("Test console logging")); +// Logger.logMessage("Test console logging", Logger.LogLevel.INFO); - // Reset the console output - System.setOut(originalOut); - } +// assertTrue(consoleOutput.toString().contains("Test console logging")); - // @Test - void testFileLoggingWithMaxLines() throws IOException { - // Create a large number of log entries to test maxLines - for (int i = 0; i < 200; i++) { - Logger.logMessage("Log entry " + i, Logger.LogLevel.INFO); - } +// // Reset the console output +// System.setOut(originalOut); +// } - List lines = Files.readAllLines(temp_file.toPath()); - assertEquals(100, lines.size()); // After trimming, only 100 lines should remain - } +// // @Test +// void testFileLoggingWithMaxLines() throws IOException { +// // Create a large number of log entries to test maxLines +// for (int i = 0; i < 200; i++) { +// Logger.logMessage("Log entry " + i, Logger.LogLevel.INFO); +// } -} +// List lines = Files.readAllLines(temp_file.toPath()); +// assertEquals(100, lines.size()); // After trimming, only 100 lines should remain +// } + +// } diff --git a/src/test/java/test/TestMainApp.java b/src/test/java/test/TestMainApp.java index 8ec8286..487d1ad 100644 --- a/src/test/java/test/TestMainApp.java +++ b/src/test/java/test/TestMainApp.java @@ -1,6 +1,6 @@ package test; -import com.mycompany.autobackupprogram.MainApp; +import backupmanager.MainApp; import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/test/TestPreferences.java b/src/test/java/test/TestPreferences.java index 72ad495..f09dee0 100644 --- a/src/test/java/test/TestPreferences.java +++ b/src/test/java/test/TestPreferences.java @@ -1,19 +1,17 @@ package test; -import com.mycompany.autobackupprogram.Entities.Preferences; -import com.mycompany.autobackupprogram.Enums.ConfigKey; -import com.mycompany.autobackupprogram.Enums.LanguagesEnum; -import com.mycompany.autobackupprogram.Enums.ThemesEnum; -import com.mycompany.autobackupprogram.Logger; - import java.io.File; import java.io.IOException; -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - import org.junit.jupiter.api.AfterEach; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import backupmanager.Entities.Preferences; +import backupmanager.Enums.ConfigKey; +import backupmanager.Enums.LanguagesEnum; +import backupmanager.Enums.ThemesEnum; public class TestPreferences { @@ -25,20 +23,19 @@ static void setUpBeforeClass() throws IOException { ConfigKey.loadFromJson(CONFIG); temp_log_file = File.createTempFile("src/test/resources/temp_log_file", ""); - Logger.setLogFilePath(temp_log_file.getPath()); } @Test void testUpdatePreferences() { - Preferences.setLanguage(LanguagesEnum.DEU); - Preferences.setTheme(ThemesEnum.CARBON); + Preferences.setLanguage(LanguagesEnum.ENG); + Preferences.setTheme(ThemesEnum.INTELLIJ); Preferences.updatePreferencesToJSON(); // update Preferences.loadPreferencesFromJSON(); // reload // check if update changed everything correctly - assertEquals(LanguagesEnum.DEU.getLanguageName(), Preferences.getLanguage().getLanguageName()); - assertEquals(ThemesEnum.CARBON.getThemeName(), Preferences.getTheme().getThemeName()); + assertEquals(LanguagesEnum.ENG.getLanguageName(), Preferences.getLanguage().getLanguageName()); + assertEquals(ThemesEnum.INTELLIJ.getThemeName(), Preferences.getTheme().getThemeName()); } @AfterEach