From amitchoudhary0523 at gmail.com Wed Oct 12 03:46:07 2022 From: amitchoudhary0523 at gmail.com (Amit) Date: Wed, 12 Oct 2022 09:16:07 +0530 Subject: Backup Files and Folders. Message-ID: Java code for backing up files and folders (in case someone needs it). Description: This software is for taking backups of files and directories. You can specify which files and directories you want to backup. You can also remove files and directories from the backup list. You have to specify a directory where the backup will be stored (local or on network). This directory will also have a log file containing what all the software did. If you want, you can also cancel the backup after it starts. ------------------------------------------------------------------------------------------- /* * License: This file has been released under APACHE LICENSE, VERSION 2.0. * The license details can be found here: https://www.apache.org/licenses/LICENSE-2.0 */ import java.io.*; import javax.swing.*; import javax.swing.event.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.beans.PropertyChangeListener; import java.io.File; import java.text.*; import javax.swing.tree.*; import java.nio.file.*; import java.time.*; import java.time.format.*; import javax.swing.border.*; public class Backup_Files_And_Folders implements ActionListener { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int screenWidth = screenSize.width; int screenHeight = screenSize.height; int midScreenWidth = screenWidth / 2; int componentHeight = 25; // vertical gap between components int vGap = 25; int currentYPos = 0; JFrame jf = null; JPanel jp = null; JDialog jdShowRemoveFiles = null; JPanel jpShowRemoveFiles = null; JLabel jlInfoLabel = null; JButton jbAddFilesFolders = null; JButton jbShowRemoveFilesFolders = null; JLabel jlShowNumFiles = null; JButton jbRemoveAllEntries = null; JLabel jlChooseSaveBackupLocation = null; JTextField jtfChooseSaveBackupLocation = null; JButton jbBrowse = null; JButton jbTakeBackup = null; JButton jbCancelBackup = null; JLabel jlBackupProgressBarLabel = null; JProgressBar jpbBackupProgressBar = null; JLabel jlCurrentStatus = null; JTextArea jtaExceptionsAndErrorsTextArea = null; JScrollPane jspScrollableExceptionTextArea = null; JButton jbCloseMainWindow = null; Color DeepSkyBlue = new Color(0x00bfff); String userHomeDir = System.getProperty("user.home"); String backupSoftwareConfigDir = userHomeDir + File.separator + "Backup_Files_And_Folders"; String backupSoftwareConfigFile = backupSoftwareConfigDir + File.separator + "Config.txt"; String fileContainingNamesOfFilesDirectoriesToBackup = backupSoftwareConfigDir + File.separator + "Files_Directories_To_Backup.txt"; String backupDir = null; String logFile = null; Path logFilePath = null; boolean cancelBackup = false; LinkedList listOfFilesAndFoldersToBackupLL = new LinkedList<>(); LinkedList listOfFilesAndFoldersToBackupLabelsLL = new LinkedList<>(); LinkedList listOfFilesAndFoldersToBackupButtonsLL = new LinkedList<>(); public enum SetupStatus { DONE, NOT_DONE, CORRUPTED, } // end of enum SetupStatus @Override public void actionPerformed(ActionEvent ae) { String text = ""; Object source = ae.getSource(); if (source == jbBrowse) { JFileChooser jfc = new JFileChooser(); jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); if ((jfc.showOpenDialog(jf)) == JFileChooser.APPROVE_OPTION) { File selectedFile = jfc.getSelectedFile(); backupDir = selectedFile.getAbsolutePath(); jtfChooseSaveBackupLocation.setText(backupDir); // Put this path in config file also. Open file for writing in truncated mode. try { Files.write(Paths.get(backupSoftwareConfigFile), selectedFile.getAbsolutePath().getBytes(), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC); } catch (Exception e) { text = "Exception happened: Could not write to file \"" + backupSoftwareConfigFile + "\". Please check whether file exists and permissions of file."; JOptionPane.showMessageDialog(jf, text, "Error", JOptionPane.ERROR_MESSAGE); } // end of try-catch block // Create log file if not already existing. logFile = backupDir + File.separator + "log.txt"; if (checkAndCreateFileIfItDoesNotExist(logFile) == true) { logFilePath = Paths.get(logFile); } } } else if (source == jbAddFilesFolders) { boolean error = false; int filesAdded = 0; String lineToWrite = ""; File selectedFiles[] = null; JFileChooser jfc = new JFileChooser(); jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); jfc.setMultiSelectionEnabled(true); if ((jfc.showOpenDialog(jf)) == JFileChooser.APPROVE_OPTION) { selectedFiles = jfc.getSelectedFiles(); // Append the file selected to file Files_Directories_To_Backup.txt. for (File f : selectedFiles) { lineToWrite = f.getAbsolutePath() + System.lineSeparator(); try { Files.write(Paths.get(fileContainingNamesOfFilesDirectoriesToBackup), lineToWrite.getBytes(), StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.SYNC); filesAdded = filesAdded + 1; } catch (Exception e) { error = true; text = "Exception happened: Could not write to file \"" + fileContainingNamesOfFilesDirectoriesToBackup + "\". Please check whether file exists and permissions of file."; JOptionPane.showMessageDialog(jf, text, "Error", JOptionPane.ERROR_MESSAGE); } // end of try-catch block } // end of for loop if ((filesAdded > 0) && (error == false)) { JOptionPane.showMessageDialog(jf, "File(s) / Folder(s) added successfully.", "Info", JOptionPane.INFORMATION_MESSAGE); } else if ((filesAdded > 0) && (error == true)) { JOptionPane.showMessageDialog(jf, "Some File(s) / Folder(s) added successfully.", "Info", JOptionPane.INFORMATION_MESSAGE); } } // end of jfc.showOpenDialog(jf)) == JFileChooser.APPROVE_OPTION } else if (source == jbShowRemoveFilesFolders) { processShowRemoveFilesFolders(); } else if (source == jbRemoveAllEntries) { // this event is from JDialog int result = JOptionPane.showConfirmDialog(jpShowRemoveFiles, "Are you sure you want to remove all entries?", "Question", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (result == JOptionPane.CANCEL_OPTION) { return; } try { Files.write(Paths.get(fileContainingNamesOfFilesDirectoriesToBackup), new byte[0], StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC); } catch (Exception e) { text = "Error: Exception happened while removing entries from file \"" + fileContainingNamesOfFilesDirectoriesToBackup + "\". Remove operation has been cancelled."; JOptionPane.showMessageDialog(jdShowRemoveFiles, text, "Error", JOptionPane.ERROR_MESSAGE); return; } listOfFilesAndFoldersToBackupLL.clear(); listOfFilesAndFoldersToBackupButtonsLL.clear(); listOfFilesAndFoldersToBackupLabelsLL.clear(); jpShowRemoveFiles.removeAll(); jpShowRemoveFiles.add(jlShowNumFiles); jlShowNumFiles.setText("Total File(s) / Folder(s): " + listOfFilesAndFoldersToBackupLL.size()); jpShowRemoveFiles.add(jbRemoveAllEntries); jpShowRemoveFiles.revalidate(); jpShowRemoveFiles.repaint(); } else if ((((JButton) (source)).getText()).equals("Remove") == true) { // this event is from JDialog //JOptionPane.showMessageDialog(jdShowRemoveFiles, "Remove event from JDialog", "Info", JOptionPane.INFORMATION_MESSAGE); int index = listOfFilesAndFoldersToBackupButtonsLL.indexOf(source); if (index == -1) { text = "Some bug in software because returned index is -1. This should not be the case."; JOptionPane.showMessageDialog(jdShowRemoveFiles, text, "Error", JOptionPane.ERROR_MESSAGE); return; } String tmpFile = backupSoftwareConfigDir + File.separator + ".tmpFile"; boolean status = removeLineFromFileAtIndex(index, fileContainingNamesOfFilesDirectoriesToBackup, tmpFile); if (status == true) { // now remove the entry from jdialog's jpanel and from all linked lists. jpShowRemoveFiles.remove(listOfFilesAndFoldersToBackupButtonsLL.get(index)); jpShowRemoveFiles.remove(listOfFilesAndFoldersToBackupLabelsLL.get(index)); listOfFilesAndFoldersToBackupLL.remove(index); listOfFilesAndFoldersToBackupButtonsLL.remove(index); listOfFilesAndFoldersToBackupLabelsLL.remove(index); jpShowRemoveFiles.revalidate(); jpShowRemoveFiles.repaint(); jlShowNumFiles.setText("Total File(s) / Folder(s): " + listOfFilesAndFoldersToBackupLL.size()); } return; } else if (source == jbTakeBackup) { // we need to start a new thread for this so that UI can be updated because UI update // events will come on this thread (event thread) itself but this thread is already processing // processTakeBackup(), so UI update events wait in the queue for processTakeBackup() to finish. // So, we don't see any UI updates while processTakeBackup() is running but we want to see UI // updates while processTakeBackup() is running and so we have to run processTakeBackup() in a new thread. Thread thread = new Thread() { @Override public void run() { processTakeBackup(); } }; // end of new thread thread.start(); } else if (source == jbCancelBackup) { cancelBackup = true; } else if (source == jbCloseMainWindow) { jf.dispatchEvent(new WindowEvent(jf, WindowEvent.WINDOW_CLOSING)); } } // end of actionPerformed void processShowRemoveFilesFolders() { int numEntries = 0; String line = null; String text = null; // clear all linkedlists (delete all elements from all linkedlists) listOfFilesAndFoldersToBackupLL.clear(); listOfFilesAndFoldersToBackupButtonsLL.clear(); listOfFilesAndFoldersToBackupLabelsLL.clear(); // we need to save entries from fileContainingNamesOfFilesDirectoriesToBackup in a linkedlist. try (BufferedReader br = new BufferedReader(new FileReader(fileContainingNamesOfFilesDirectoriesToBackup))) { while ((line = br.readLine()) != null) { //System.out.println(line); // no need to remove newline characters. readLine already removes them. //line = line.replaceFirst("\\r\\n$|\\r$|\\n$", ""); listOfFilesAndFoldersToBackupLL.add(line); } } catch (Exception e) { text = "Exception happened: Could not read file \"" + fileContainingNamesOfFilesDirectoriesToBackup + "\": " + e.getMessage(); JOptionPane.showMessageDialog(jf, text, "Error", JOptionPane.ERROR_MESSAGE); return; // we do not want to show anything now as exception has happened. } // end of try-catch block numEntries = listOfFilesAndFoldersToBackupLL.size(); int dialogWidth = (int) (screenWidth * (0.775)); int dialogHeight = (int) (screenHeight * (0.56)); int panelWidth = 10 + 100 + 10 + 1024 + 10; int panelHeight = 35 * numEntries + 35 + 10; ArrayList a = SwingLibrary.setupScrollableJDialogAndGetDialogAndPanel(jf, "List of Files for backing up", true, dialogWidth, dialogHeight, panelWidth, panelHeight); jdShowRemoveFiles = (JDialog) (a.get(0)); jpShowRemoveFiles = (JPanel) (a.get(1)); // show list of files for backing up JLabel jl = null; JButton jb = null; int xPos = 10; int yPos = 10; // show total file(s) / folder(s) text = "Total File(s) / Folder(s): " + numEntries; jlShowNumFiles = SwingLibrary.setupJLabelAndGet(text, true, Color.WHITE, SwingConstants.LEFT, SwingConstants.CENTER, true, xPos, yPos, 300, componentHeight); jpShowRemoveFiles.add(jlShowNumFiles); // implement remove all entries here jbRemoveAllEntries = SwingLibrary.setupJButtonAndGet("Remove All Entries", this, true, xPos + 350, yPos, 300, componentHeight); yPos = yPos + 25 + 10; jpShowRemoveFiles.add(jbRemoveAllEntries); for (String s : listOfFilesAndFoldersToBackupLL) { //System.out.println(s); xPos = 10; jb = SwingLibrary.setupJButtonAndGet("Remove", this, true, xPos, yPos, 100, componentHeight); xPos = xPos + 110; jl = SwingLibrary.setupJLabelAndGet(s, true, Color.WHITE, SwingConstants.LEFT, SwingConstants.CENTER, true, xPos, yPos, 1024, componentHeight); yPos = yPos + 25 + 10; listOfFilesAndFoldersToBackupButtonsLL.add(jb); listOfFilesAndFoldersToBackupLabelsLL.add(jl); jpShowRemoveFiles.add(jb); jpShowRemoveFiles.add(jl); } // end of for loop jdShowRemoveFiles.setVisible(true); } // end of processShowRemoveFilesFolders // If append is true then append text, else truncate the file. void writeToLogFile(String text, OpenOption op) { if (logFilePath == null) { return; } try { text = text + System.lineSeparator(); Files.write(logFilePath, text.getBytes(), StandardOpenOption.WRITE, op, StandardOpenOption.SYNC); } catch (Exception e) { } } // end of writeToLogFile void processCancelBackup() { // write trailer in log file writeToLogFile(System.lineSeparator() + "Backup Cancelled.", StandardOpenOption.APPEND); writeToLogFile(System.lineSeparator() + "=============== Backup Cancelled ===============", StandardOpenOption.APPEND); jlCurrentStatus.setForeground(Color.RED); jlCurrentStatus.setText("Backup Cancelled. You can look at log file at location: " + logFile); JOptionPane.showMessageDialog(jf, "Backup Cancelled.", "Info", JOptionPane.INFORMATION_MESSAGE); // the following method sets cancelBackup to false. enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); } // end of processCancelBackup void enableComponentsAndDisableCancelOnBackupEndOrBackupCancel() { cancelBackup = false; jbCancelBackup.setEnabled(false); jbAddFilesFolders.setEnabled(true); jbShowRemoveFilesFolders.setEnabled(true); jbBrowse.setEnabled(true); jbTakeBackup.setEnabled(true); } // end of enableComponentsAndDisableCancelOnBackupEndOrBackupCancel void disableComponentsAndEnableCancelOnBackupStart() { jbTakeBackup.setEnabled(false); jbBrowse.setEnabled(false); jbAddFilesFolders.setEnabled(false); jbShowRemoveFilesFolders.setEnabled(false); jbCancelBackup.setEnabled(true); } // end of disableComponentsAndEnableCancelOnBackupStart long copyDirectoryRecursively(String sourceDir, String destDir, long numFilesCopied, long totalFilesCount) { String entryAsString = null; String targetFileOrDir = null; String text = null; try { Files.createDirectory(Paths.get(destDir)); // write in log file and update current status label text = "Created directory: " + destDir; jlCurrentStatus.setText(text); writeToLogFile(text, StandardOpenOption.APPEND); } catch (FileAlreadyExistsException faee) { text = "** Exception happened while creating directory \"" + destDir + "\": Directory \"" + destDir + "\" already exists: " + faee.getMessage(); writeToLogFile(text, StandardOpenOption.APPEND); jtaExceptionsAndErrorsTextArea.append(text + "\n"); jlCurrentStatus.setText(text); return numFilesCopied; } catch (Exception e) { text = "** Exception happened while creating directory \"" + destDir + "\": " + e.getMessage(); writeToLogFile(text, StandardOpenOption.APPEND); jtaExceptionsAndErrorsTextArea.append(text + "\n"); jlCurrentStatus.setText(text); return numFilesCopied; } try (DirectoryStream ds = Files.newDirectoryStream(Paths.get(sourceDir))) { for (Path entry : ds) { if (cancelBackup == true) { try { ds.close(); } catch (Exception e) { } return numFilesCopied; } entryAsString = entry.toAbsolutePath().toString(); targetFileOrDir = destDir + File.separator + entryAsString.substring(entryAsString.lastIndexOf(File.separator) + 1); if (Files.isRegularFile(entry) == true) { try { Files.copy(entry, Paths.get(targetFileOrDir), StandardCopyOption.COPY_ATTRIBUTES); numFilesCopied = numFilesCopied + 1; // write in log file and update current status label text = "Copied file " + entryAsString + " to " + targetFileOrDir; jlCurrentStatus.setText(text); writeToLogFile(text, StandardOpenOption.APPEND); jlBackupProgressBarLabel.setText("Backup Progress (Files backed up: " + numFilesCopied + " / " + totalFilesCount + ")"); jpbBackupProgressBar.setValue((int) ((numFilesCopied * 100) / totalFilesCount)); } catch (Exception e) { text = "** Exception happened while copying \"" + entry.toAbsolutePath().toString() + "\" to \"" + targetFileOrDir + "\": " + e.getMessage(); writeToLogFile(text, StandardOpenOption.APPEND); jtaExceptionsAndErrorsTextArea.append(text + "\n"); jlCurrentStatus.setText(text); } } else if (Files.isDirectory(entry) == true) { numFilesCopied = copyDirectoryRecursively(entryAsString, targetFileOrDir, numFilesCopied, totalFilesCount); } } // end of for Path entry : ds } catch (Exception e) { text = "** Exception happened while processing directory \"" + sourceDir + "\": " + e.getMessage(); writeToLogFile(text, StandardOpenOption.APPEND); jtaExceptionsAndErrorsTextArea.append(text + "\n"); jlCurrentStatus.setText(text); } return numFilesCopied; } // end of copyDirectoryRecursively long getNumberOfFilesAndDirsInDir(Path p, long totalFilesCount) { try (DirectoryStream ds = Files.newDirectoryStream(p)) { for (Path entry : ds) { if (cancelBackup == true) { try { ds.close(); } catch (Exception e) { } return totalFilesCount; } if (Files.isRegularFile(entry) == true) { totalFilesCount = totalFilesCount + 1; jlCurrentStatus.setText("Counting number of files to be backed up: " + totalFilesCount); } else if (Files.isDirectory(entry) == true) { totalFilesCount = getNumberOfFilesAndDirsInDir(entry, totalFilesCount); jlCurrentStatus.setText("Counting number of files to be backed up: " + totalFilesCount); } } } catch (Exception e) { } // end of try-catch block return totalFilesCount; } // end of getNumberOfFilesAndDirsInDir void processBackupNotTaken(String text) { // write trailer to log file writeToLogFile(System.lineSeparator() + text, StandardOpenOption.APPEND); writeToLogFile(System.lineSeparator() + "=============== End ===============", StandardOpenOption.APPEND); jtaExceptionsAndErrorsTextArea.append(text + "\n"); jlCurrentStatus.setText(text); JOptionPane.showMessageDialog(jf, text, "Error", JOptionPane.ERROR_MESSAGE); } // end of processBackupNotTaken void processTakeBackup() { disableComponentsAndEnableCancelOnBackupStart(); String text = null; String targetBackupDir = null; Path p = null; boolean someFileOrFolderExists = false; LocalDateTime currentLocalDateTime = LocalDateTime.now(); DateTimeFormatter dateTimeFormatter = null; // reset few things writeToLogFile("", StandardOpenOption.TRUNCATE_EXISTING); jtaExceptionsAndErrorsTextArea.setText(null); jlCurrentStatus.setForeground(null); jlCurrentStatus.setText("Backup Process Started"); jlBackupProgressBarLabel.setText("Backup Progress: Backup Process Started."); jpbBackupProgressBar.setValue(0); // write header and date/time to log file. writeToLogFile("=============== Backup Process Started ===============" + System.lineSeparator(), StandardOpenOption.APPEND); try { dateTimeFormatter = DateTimeFormatter.ofPattern("dd LLL yyyy, hh:mm:ss a"); writeToLogFile("Date/Time: " + currentLocalDateTime.format(dateTimeFormatter) + System.lineSeparator(), StandardOpenOption.APPEND); } catch (Exception e) { } // end of try-catch block // check if backup directory is given or not if (backupDir.isBlank() == true) { processBackupNotTaken("Error: Directory where backups will be saved is not given. No backup will be taken."); enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); return; } // check if backup directory exists if (Files.exists(Paths.get(backupDir)) == false) { processBackupNotTaken("Error: Backup directory \"" + backupDir + "\" does not exist or may be permissions issue. No backup will be taken."); enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); return; } // we need to save entries from fileContainingNamesOfFilesDirectoriesToBackup in an array list. ArrayList filesFoldersArrayList = new ArrayList<>(); String line = null; try (BufferedReader br = new BufferedReader(new FileReader(fileContainingNamesOfFilesDirectoriesToBackup))) { while ((line = br.readLine()) != null) { filesFoldersArrayList.add(line); } } catch (Exception e) { processBackupNotTaken("Error: Exception happened: Could not read file \"" + fileContainingNamesOfFilesDirectoriesToBackup + "\": " + e.getMessage() + ". No backup will be taken."); enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); return; } // end of try-catch block // if there are no files/folders to backup then show a message and return if (filesFoldersArrayList.isEmpty() == true) { processBackupNotTaken("Error: No file(s) / folder(s) have been added for backup. Nothing to backup."); enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); return; } // check which file(s)/folder(s) present in fileContainingNamesOfFilesDirectoriesToBackup do not exist. for (String fileOrDir : filesFoldersArrayList) { if (cancelBackup == true) { processCancelBackup(); return; } p = Paths.get(fileOrDir); if (Files.exists(p) == false) { // file/directory does not exist text = "Error: File/Folder does not exist: " + p.toAbsolutePath().toString(); writeToLogFile(text, StandardOpenOption.APPEND); jtaExceptionsAndErrorsTextArea.append(text + "\n"); jlCurrentStatus.setText(text); } else { someFileOrFolderExists = true; } // processing cancelBackup here is necessary because it is possible that the // for loop has already consumed the last entry in filesFoldersArrayList, // so when now the control goes back to the for loop, it will not enter the loop // because there are no more entries to be read from filesFoldersArrayList and // hence it will come out of for loop and "cancelBackup == true" condition will // never hit. if (cancelBackup == true) { processCancelBackup(); return; } } // end of for (String fileOrDir : filesFoldersArrayList) if (someFileOrFolderExists == false) { processBackupNotTaken("Error: No File(s)/Folder(s) given for backup exist. No backup has been taken."); enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); return; } // count total number of files for progress bar long totalFilesCount = 0; for (String dirOrFile : filesFoldersArrayList) { if (cancelBackup == true) { processCancelBackup(); return; } p = Paths.get(dirOrFile); if (Files.isRegularFile(p) == true) { totalFilesCount = totalFilesCount + 1; jlCurrentStatus.setText("Counting number of files to be backed up: " + totalFilesCount); } else if (Files.isDirectory(p) == true) { totalFilesCount = getNumberOfFilesAndDirsInDir(p, totalFilesCount); jlCurrentStatus.setText("Counting number of files to be backed up: " + totalFilesCount); } // processing cancelBackup here is necessary because it is possible that the // for loop has already consumed the last entry in filesFoldersArrayList, // so when now the control goes back to the for loop, it will not enter the loop // because there are no more entries to be read from filesFoldersArrayList and // hence it will come out of for loop and "cancelBackup == true" condition will // never hit. if (cancelBackup == true) { processCancelBackup(); return; } } // end of for (String dirOrFile : filesFoldersArrayList) // create directory where backups will be saved. try { dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyLLLdd-HH-mm-ss"); targetBackupDir = backupDir + File.separator + "Backup-" + currentLocalDateTime.format(dateTimeFormatter); } catch (Exception e) { processBackupNotTaken("Error: Exception happened: Could not get current date and time in desired format: " + e.getMessage() + ". No backup will be taken."); enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); return; } // end of try-catch block // debug //JOptionPane.showMessageDialog(jf, "Target Backup Dir: " + targetBackupDir, "Target Backup Dir", JOptionPane.INFORMATION_MESSAGE); // create new directories if they don't exist if (checkAndCreateDirectoryIfItDoesNotExist(targetBackupDir) == false) { processBackupNotTaken("Error: Exception happened: Could not create directory \"" + targetBackupDir + "\". Please check permissions of directory \"" + backupDir + "\". No backup will be taken."); enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); return; } // start taking backup of files and folders long numFilesCopied = 0; String targetFileOrDir = null; String transformSourceFileOrDir = null; jlBackupProgressBarLabel.setText("Backup Progress (Files backed up: " + numFilesCopied + " / " + totalFilesCount + ")"); writeToLogFile(System.lineSeparator() + "Backup is being taken in directory: " + targetBackupDir + System.lineSeparator(), StandardOpenOption.APPEND); for (String sourceFileOrDir : filesFoldersArrayList) { if (cancelBackup == true) { processCancelBackup(); return; } p = Paths.get(sourceFileOrDir); // transform source directory to full path if (Files.isDirectory(p) == true) { transformSourceFileOrDir = sourceFileOrDir.replace(File.separator, "-"); transformSourceFileOrDir = transformSourceFileOrDir.replace(":", ""); // to fix C:\AAA\BBB, etc. targetFileOrDir = targetBackupDir + File.separator + transformSourceFileOrDir; } else { targetFileOrDir = targetBackupDir + File.separator + sourceFileOrDir.substring(sourceFileOrDir.lastIndexOf(File.separator) + 1); } if (Files.isRegularFile(p) == true) { try { Files.copy(p, Paths.get(targetFileOrDir), StandardCopyOption.COPY_ATTRIBUTES); numFilesCopied = numFilesCopied + 1; // write in log file and update current status label text = "Copied file " + sourceFileOrDir + " to " + targetFileOrDir; jlCurrentStatus.setText(text); writeToLogFile(text, StandardOpenOption.APPEND); jlBackupProgressBarLabel.setText("Backup Progress (Files backed up: " + numFilesCopied + " / " + totalFilesCount + ")"); jpbBackupProgressBar.setValue((int) ((numFilesCopied * 100) / totalFilesCount)); } catch (Exception e) { text = "** Exception happened while copying \"" + p.toAbsolutePath().toString() + "\" to \"" + targetFileOrDir + "\": " + e.getMessage(); writeToLogFile(text, StandardOpenOption.APPEND); jtaExceptionsAndErrorsTextArea.append(text + "\n"); jlCurrentStatus.setText(text); } } else if (Files.isDirectory(p) == true) { numFilesCopied = copyDirectoryRecursively(sourceFileOrDir, targetFileOrDir, numFilesCopied, totalFilesCount); } // print an empty line after each entry is processed writeToLogFile("", StandardOpenOption.APPEND); // processing cancelBackup here is necessary because it is possible that the // for loop has already consumed the last entry in filesFoldersArrayList, // so when now the control goes back to the for loop, it will not enter the loop // because there are no more entries to be read from filesFoldersArrayList and // hence it will come out of for loop and "cancelBackup == true" condition will // never hit. if (cancelBackup == true) { processCancelBackup(); return; } } // end of for (String sourceFileOrDir : filesFoldersArrayList) // write trailer in log file writeToLogFile(System.lineSeparator() + "=============== End of Backup ===============", StandardOpenOption.APPEND); text = "Backup taken in directory \"" + targetBackupDir + "\"."; text = text + " You can look at log file at location: " + logFile; jlCurrentStatus.setText(text); text = "Backup taken in directory \"" + targetBackupDir + "\"."; JOptionPane.showMessageDialog(jf, text, "Info", JOptionPane.INFORMATION_MESSAGE); // the following method sets cancelBackup to false. enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); } // end of processTakeBackup boolean removeLineFromFileAtIndex(int index, String file, String tmpFile) { String text = null; String line = null; boolean lineFound = false; int i = -1; if (index < 0) { text = "Index given is invalid: It is less than zero: " + index; JOptionPane.showMessageDialog(jdShowRemoveFiles, text, "Error", JOptionPane.ERROR_MESSAGE); return false; } try ( BufferedReader br = new BufferedReader(new FileReader(file)); FileWriter fw = new FileWriter(new File(tmpFile), false);) { while ((line = br.readLine()) != null) { //System.out.println(line); // increment i i = i + 1; if (index == i) { lineFound = true; continue; } fw.write(line + System.lineSeparator()); fw.flush(); } // end of while br.close(); fw.close(); Files.move(Paths.get(tmpFile), Paths.get(file), StandardCopyOption.REPLACE_EXISTING); } catch (Exception e) { try { // delete temp file Files.delete(Paths.get(tmpFile)); } catch (Exception ee) { } text = "Exception happened: " + e.getMessage(); JOptionPane.showMessageDialog(jdShowRemoveFiles, text, "Error", JOptionPane.ERROR_MESSAGE); return false; } // end of try-catch block if (lineFound == false) { text = "No line found at given Index. Index given: " + index; JOptionPane.showMessageDialog(jdShowRemoveFiles, text, "Error", JOptionPane.ERROR_MESSAGE); return false; } return true; } // end of removeLineFromFileAtIndex boolean checkAndCreateFileIfItDoesNotExist(String file) { try { Files.createFile(Paths.get(file)); } catch (FileAlreadyExistsException faee) { // don't do anything. file exists. } catch (Exception e) { return false; } return true; } // end of checkAndCreateFileIfItDoesNotExist boolean checkAndCreateDirectoryIfItDoesNotExist(String dir) { try { Files.createDirectory(Paths.get(dir)); } catch (FileAlreadyExistsException faee) { // don't do anything. directory exists. } catch (Exception e) { return false; } return true; } // end of checkAndCreateDirectoryIfItDoesNotExist // Create required files and directories if they don't exist. void doSetup(SetupStatus ss) { String text = ""; int result = -1; if (ss == SetupStatus.NOT_DONE) { text = "Setup is not done. Setup will create a directory in \"" + userHomeDir + "\" and then create " + "some files inside the new directory. Do you want to continue doing setup?"; } else { text = "Setup is corrupted. Do you want to fix setup?"; } result = JOptionPane.showConfirmDialog(jf, text, "Question", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (result == JOptionPane.CANCEL_OPTION) { JOptionPane.showMessageDialog(jf, "Exiting..", "Error", JOptionPane.ERROR_MESSAGE); System.exit(1); } // create files and directories if they don't exist if (checkAndCreateDirectoryIfItDoesNotExist(backupSoftwareConfigDir) == false) { text = "Exception happened: Could not create directory \"" + backupSoftwareConfigDir + "\". Please check permissions of directory \"" + userHomeDir + "\". Exiting.."; JOptionPane.showMessageDialog(jf, text, "Error", JOptionPane.ERROR_MESSAGE); System.exit(1); } if (checkAndCreateFileIfItDoesNotExist(backupSoftwareConfigFile) == false) { text = "Exception happened: Could not create file \"" + backupSoftwareConfigFile + "\". Please check permissions of directory \"" + backupSoftwareConfigDir + "\". Exiting.."; JOptionPane.showMessageDialog(jf, text, "Error", JOptionPane.ERROR_MESSAGE); System.exit(1); } if (checkAndCreateFileIfItDoesNotExist(fileContainingNamesOfFilesDirectoriesToBackup) == false) { text = "Exception happened: Could not create file \"" + fileContainingNamesOfFilesDirectoriesToBackup + "\". Please check permissions of directory \"" + backupSoftwareConfigDir + "\". Exiting.."; JOptionPane.showMessageDialog(jf, text, "Error", JOptionPane.ERROR_MESSAGE); System.exit(1); } if (ss == SetupStatus.NOT_DONE) { JOptionPane.showMessageDialog(jf, "Setup done successfully.", "Info", JOptionPane.INFORMATION_MESSAGE); } else { JOptionPane.showMessageDialog(jf, "Setup fixed successfully.", "Info", JOptionPane.INFORMATION_MESSAGE); } } // end of doSetup // Check that required files and directories exist. SetupStatus checkSetupDone() { if (Files.exists(Paths.get(backupSoftwareConfigDir)) == false) { return SetupStatus.NOT_DONE; } if (Files.exists(Paths.get(backupSoftwareConfigFile)) == false) { return SetupStatus.CORRUPTED; } if (Files.exists(Paths.get(fileContainingNamesOfFilesDirectoriesToBackup)) == false) { return SetupStatus.CORRUPTED; } return SetupStatus.DONE; } // end of checkSetupDone void doSetupAndCreateAndShowGUI() { String text = ""; JLabel jl = null; ArrayList a = SwingLibrary.setupScrollableJFrameAndGetFrameAndPanel("Backup Files And Folders", screenWidth - 10, screenHeight - 50); jf = (JFrame) (a.get(0)); jp = (JPanel) (a.get(1)); jf.setVisible(true); // check if setup is done or not. If not, then do the setup. SetupStatus ss = checkSetupDone(); if (ss != SetupStatus.DONE) { doSetup(ss); } currentYPos = 0; text = "

" + "Backups will be saved in a directory named as Backup_Date_Time in the directory you have chosen for saving backups.

" + "In Backup_Date_Time, Date is the date on which the backup has been taken and Time is the time at which the backup has been taken.

" + "A log file is created in the directory Backup_Date_Time and it will contain details of last backup only (including all exceptions if they happened).
" + "

"; jlInfoLabel = SwingLibrary.setupJLabelAndGet(text, true, DeepSkyBlue, SwingConstants.CENTER, SwingConstants.CENTER, true, 0, currentYPos, screenWidth, componentHeight * 4); jp.add(jlInfoLabel); currentYPos = currentYPos + vGap * 6; jbAddFilesFolders = SwingLibrary.setupJButtonAndGet("ADD file(s) / folder(s) for backing up", this, true, midScreenWidth - 500, currentYPos, 350, componentHeight); jp.add(jbAddFilesFolders); jbShowRemoveFilesFolders = SwingLibrary.setupJButtonAndGet("SHOW / REMOVE file(s) / folder(s) added for backing up", this, true, midScreenWidth + 150, currentYPos, 350, componentHeight); jp.add(jbShowRemoveFilesFolders); currentYPos = currentYPos + vGap * 3; jlChooseSaveBackupLocation = SwingLibrary.setupJLabelAndGet("Choose a directory where backups will be saved:", true, null, SwingConstants.LEFT, SwingConstants.CENTER, true, 25, currentYPos, 300, componentHeight); jp.add(jlChooseSaveBackupLocation); currentYPos = currentYPos + vGap; jtfChooseSaveBackupLocation = SwingLibrary.setupJTextFieldAndGet(25, currentYPos, screenWidth - 180, componentHeight); jtfChooseSaveBackupLocation.setEditable(false); jtfChooseSaveBackupLocation.setBackground(Color.WHITE); jtfChooseSaveBackupLocation.setBorder(new LineBorder(Color.BLUE, 2)); jp.add(jtfChooseSaveBackupLocation); jbBrowse = SwingLibrary.setupJButtonAndGet("Browse", this, true, screenWidth - 140, currentYPos, 100, componentHeight); jp.add(jbBrowse); currentYPos = currentYPos + vGap * 3; jbTakeBackup = SwingLibrary.setupJButtonAndGet("Take Backup", this, true, midScreenWidth - 400, currentYPos, 200, componentHeight); jp.add(jbTakeBackup); //currentYPos = currentYPos + vGap * 3; jbCancelBackup = SwingLibrary.setupJButtonAndGet("Cancel Backup", this, true, midScreenWidth + 200, currentYPos, 200, componentHeight); jbCancelBackup.setEnabled(false); jp.add(jbCancelBackup); currentYPos = currentYPos + vGap * 2; jlBackupProgressBarLabel = SwingLibrary.setupJLabelAndGet("Backup Progress: Not Started.", false, null, SwingConstants.LEFT, SwingConstants.CENTER, true, 25, currentYPos, 500, componentHeight); jp.add(jlBackupProgressBarLabel); currentYPos = currentYPos + vGap; jpbBackupProgressBar = SwingLibrary.setupJProgressBarAndGet(SwingConstants.HORIZONTAL, 0, 100, 0, true, true, true, 25, currentYPos, screenWidth - 80, componentHeight); jp.add(jpbBackupProgressBar); currentYPos = currentYPos + vGap * 2; jl = SwingLibrary.setupJLabelAndGet("Current Status:", false, null, SwingConstants.LEFT, SwingConstants.CENTER, true, 25, currentYPos, 100, componentHeight); jp.add(jl); currentYPos = currentYPos + vGap; jlCurrentStatus = SwingLibrary.setupJLabelAndGet("", false, null, SwingConstants.CENTER, SwingConstants.CENTER, true, 25, currentYPos, screenWidth - 80, componentHeight); jlCurrentStatus.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1)); jp.add(jlCurrentStatus); currentYPos = currentYPos + vGap * 2; jl = SwingLibrary.setupJLabelAndGet("Exceptions and Errors:", false, null, SwingConstants.LEFT, SwingConstants.CENTER, true, 25, currentYPos, 200, componentHeight); jp.add(jl); currentYPos = currentYPos + vGap; jtaExceptionsAndErrorsTextArea = SwingLibrary.setupJTextAreaAndGet("", 100, 225, false, true, true, false, 0, 0, 0, 0); jspScrollableExceptionTextArea = SwingLibrary.setupScrollableJTextAreaAndGet(jtaExceptionsAndErrorsTextArea, 25, currentYPos, screenWidth - 80, componentHeight * 7); jp.add(jspScrollableExceptionTextArea); currentYPos = currentYPos + vGap * 8; jbCloseMainWindow = SwingLibrary.setupJButtonAndGet("Close Main Window", this, true, midScreenWidth - 100, currentYPos, 200, componentHeight); jp.add(jbCloseMainWindow); jp.revalidate(); jp.repaint(); // Check if there is some path saved in backupSoftwareConfigFile. If yes, then set the text field jtfChooseSaveBackupLocation to that path. try { byte[] allBytes = Files.readAllBytes(Paths.get(backupSoftwareConfigFile)); // check that "\n" appended at the end of file name results in exception //byte[] allBytes = Files.readAllBytes(Paths.get(backupSoftwareConfigFile + "\n")); backupDir = new String(allBytes); jtfChooseSaveBackupLocation.setText(backupDir); // Create log file if not already existing. logFile = backupDir + File.separator + "log.txt"; if (checkAndCreateFileIfItDoesNotExist(logFile) == true) { logFilePath = Paths.get(logFile); } } catch (Exception e) { text = "Exception happened: Could not read file \"" + backupSoftwareConfigFile + "\": " + e.getMessage(); JOptionPane.showMessageDialog(jf, text, "Error", JOptionPane.ERROR_MESSAGE); } // end of try-catch block } // end of doSetupAndCreateAndShowGUI public static void main(String args[]) { Backup_Files_And_Folders bfaf = new Backup_Files_And_Folders(); bfaf.doSetupAndCreateAndShowGUI(); } // end of main } // end of Backup_Files_And_Folders class SwingLibrary { // if width is 0 then the frame is maximized horizontally // if height is 0 then the frame is maximized vertically public static JFrame setupJFrameAndGet(String title, int width, int height) { int state = 0; JFrame tmpJF = new JFrame(title); if (width == 0) { state = state | JFrame.MAXIMIZED_HORIZ; } if (height == 0) { state = state | JFrame.MAXIMIZED_VERT; } if ((width != 0) || (height != 0)) { tmpJF.setSize(width, height); } tmpJF.setExtendedState(tmpJF.getExtendedState() | state); tmpJF.setLocationRelativeTo(null); tmpJF.setLayout(null); tmpJF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); return tmpJF; } // end of setupJFrameAndGet // width and height are the preferred width and height of JPanel public static ArrayList setupScrollableJFrameAndGetFrameAndPanel(String title, int width, int height) { JFrame tmpJF = new JFrame(title); tmpJF.setExtendedState(tmpJF.getExtendedState() | JFrame.MAXIMIZED_BOTH); tmpJF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //tmpJF.setLayout(null); JPanel tmpJP = new JPanel(); //tmpJP.setBounds(xpos, ypos, width + 1000, height + 1000); tmpJP.setPreferredSize(new Dimension(width, height)); tmpJP.setLayout(null); JScrollPane tmpJSPFrame = new JScrollPane(tmpJP, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); tmpJSPFrame.getHorizontalScrollBar().setUnitIncrement(10); tmpJSPFrame.getVerticalScrollBar().setUnitIncrement(10); tmpJF.add(tmpJSPFrame); ArrayList tmpA = new ArrayList<>(); tmpA.add((Object) (tmpJF)); tmpA.add((Object) (tmpJP)); return tmpA; } // end of setupScrollableJFrameAndGetFrameAndPanel // actLisObj: object which implements action listener public static JButton setupJButtonAndGet(String text, Object actLisObj, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JButton tmpJB = new JButton(text); if (setBoundsFlag == true) { tmpJB.setBounds(xpos, ypos, width, height); } tmpJB.addActionListener((ActionListener) actLisObj); return tmpJB; } // end of setupJButtonAndGet // halign: horizontal alignment of text, valign: vertical alignment of text public static JLabel setupJLabelAndGet(String text, boolean opaque, Color bg, int halign, int valign, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JLabel tmpJL = new JLabel(text); if (setBoundsFlag == true) { tmpJL.setBounds(xpos, ypos, width, height); } tmpJL.setOpaque(opaque); if (bg != null) { tmpJL.setBackground(bg); } tmpJL.setHorizontalAlignment(halign); tmpJL.setVerticalAlignment(valign); return tmpJL; } // end of setupJlabelAndGet public static JTextField setupJTextFieldAndGet(int xpos, int ypos, int width, int height) { JTextField tmpJTF = new JTextField(); tmpJTF.setBounds(xpos, ypos, width, height); return tmpJTF; } // end of setupJTextFieldAndGet public static JFormattedTextField setupJFormattedTextFieldAndGet(Format fmt, Object initialVal, Object propertyChangeLis, String propertyToListenFor, int xpos, int ypos, int width, int height) { JFormattedTextField tmpJFTF = new JFormattedTextField(fmt); tmpJFTF.setValue(initialVal); tmpJFTF.addPropertyChangeListener(propertyToListenFor, (PropertyChangeListener) propertyChangeLis); tmpJFTF.setBounds(xpos, ypos, width, height); return tmpJFTF; } // end of setupJFormattedTextFieldAndGet // itemLisObj: object which implements item listener public static JCheckBox setupJCheckBoxAndGet(String text, boolean state, Object itemLisObj, int xpos, int ypos, int width, int height) { JCheckBox tmpJCB = new JCheckBox(text, state); tmpJCB.setBounds(xpos, ypos, width, height); tmpJCB.addItemListener((ItemListener) itemLisObj); return tmpJCB; } // end of setupJCheckBoxAndGet // actLisObj: object which implements action listener public static JRadioButton setupJRadioButtonAndGet(String text, boolean state, Object actLisObj, int xpos, int ypos, int width, int height) { JRadioButton tmpJRB = new JRadioButton(text, state); tmpJRB.setBounds(xpos, ypos, width, height); tmpJRB.addActionListener((ActionListener) actLisObj); return tmpJRB; } // end of setupJRadioButtonAndGet public static ButtonGroup setupButtonGroupAndGet() { ButtonGroup tmpBG = new ButtonGroup(); return tmpBG; } // end of setupButtonGroupAndGet public static JPasswordField setupJPasswordFieldAndGet(int xpos, int ypos, int width, int height) { JPasswordField tmpJPF = new JPasswordField(); tmpJPF.setBounds(xpos, ypos, width, height); return tmpJPF; } // end of setupJPasswordFieldAndGet public static JTextArea setupJTextAreaAndGet(String text, int rows, int columns, boolean setEditableFlag, boolean setLineWrapFlag, boolean setWrapStyleWordFlag, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JTextArea tmpJTA = new JTextArea(text, rows, columns); tmpJTA.setEditable(setEditableFlag); tmpJTA.setLineWrap(setLineWrapFlag); tmpJTA.setWrapStyleWord(setWrapStyleWordFlag); if (setBoundsFlag == true) { tmpJTA.setBounds(xpos, ypos, width, height); } return tmpJTA; } // end of setupJTextAreaAndGet public static JScrollPane setupScrollableJTextAreaAndGet(JTextArea jta, int xpos, int ypos, int width, int height) { JScrollPane tmpJSP = new JScrollPane(jta); tmpJSP.setBounds(xpos, ypos, width, height); return tmpJSP; } // end of setupScrollableJTextAreaAndGet public static JList setupJListAndGet(ListModel lm, int selectionMode, int visibleRowCount, int initialSelectedIndex, Object listSelLisObj, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JList tmpJList = new JList<>(lm); tmpJList.setSelectionMode(selectionMode); tmpJList.setVisibleRowCount(visibleRowCount); if (initialSelectedIndex >= 0) { tmpJList.setSelectedIndex(initialSelectedIndex); } tmpJList.addListSelectionListener((ListSelectionListener) listSelLisObj); if (setBoundsFlag == true) { tmpJList.setBounds(xpos, ypos, width, height); } return tmpJList; } // end of setupJListAndGet public static JScrollPane setupScrollableJListAndGet(JList jlist, int xpos, int ypos, int width, int height) { JScrollPane tmpJSP = new JScrollPane(jlist); tmpJSP.setBounds(xpos, ypos, width, height); return tmpJSP; } // end of setupScrollableJListAndGet public static JComboBox setupJComboBoxAndGet(ComboBoxModel cbm, int initialSelectedIndex, Object actLisObj, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JComboBox tmpJComboBox = new JComboBox<>(cbm); if (initialSelectedIndex >= 0) { tmpJComboBox.setSelectedIndex(initialSelectedIndex); } tmpJComboBox.addActionListener((ActionListener) actLisObj); if (setBoundsFlag == true) { tmpJComboBox.setBounds(xpos, ypos, width, height); } return tmpJComboBox; } // end of setupJComboBoxAndGet public static JProgressBar setupJProgressBarAndGet(int orientation, int min, int max, int initialVal, boolean borderPaintedFlag, boolean stringPaintedFlag, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JProgressBar tmpJPB = new JProgressBar(orientation, min, max); tmpJPB.setValue(initialVal); tmpJPB.setBorderPainted(borderPaintedFlag); tmpJPB.setStringPainted(stringPaintedFlag); if (setBoundsFlag == true) { tmpJPB.setBounds(xpos, ypos, width, height); } return tmpJPB; } // end of setupJProgressBarAndGet public static JSlider setupJSliderAndGet(int orientation, int min, int max, int initialVal, int minorTickSpacing, int majorTickSpacing, boolean paintTicksFlag, boolean paintLabelsFlag, Object changeLisObj, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JSlider tmpJS = new JSlider(orientation, min, max, initialVal); tmpJS.setMinorTickSpacing(minorTickSpacing); tmpJS.setMajorTickSpacing(majorTickSpacing); tmpJS.setPaintTicks(paintTicksFlag); tmpJS.setPaintLabels(paintLabelsFlag); tmpJS.addChangeListener((ChangeListener) changeLisObj); if (setBoundsFlag == true) { tmpJS.setBounds(xpos, ypos, width, height); } return tmpJS; } // end of setupJSliderAndGet public static JTree setupJTreeAndGet(DefaultMutableTreeNode rootNode, int selectionMode, Object treeSelLisObj, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JTree tmpJTree = new JTree(rootNode); tmpJTree.getSelectionModel().setSelectionMode(selectionMode); tmpJTree.addTreeSelectionListener((TreeSelectionListener) treeSelLisObj); if (setBoundsFlag == true) { tmpJTree.setBounds(xpos, ypos, width, height); } return tmpJTree; } // end of setupJTreeAndGet public static JScrollPane setupScrollableJTreeAndGet(JTree jtree, int xpos, int ypos, int width, int height) { JScrollPane tmpJSP = new JScrollPane(jtree); tmpJSP.setBounds(xpos, ypos, width, height); return tmpJSP; } // end of setupScrollableJTreeAndGet public static JSpinner setupJSpinnerAndGet(SpinnerModel sm, boolean editableFlag, Object spinnerChangeLisObj, int xpos, int ypos, int width, int height) { JSpinner tmpJSPN = new JSpinner(sm); tmpJSPN.addChangeListener((ChangeListener) spinnerChangeLisObj); if (editableFlag == false) { JComponent editor = tmpJSPN.getEditor(); if (editor instanceof JSpinner.DefaultEditor) { ((JSpinner.DefaultEditor) editor).getTextField().setEditable(editableFlag); } else { System.out.println("Error: Could not set editableFlag for JSpinner."); } } tmpJSPN.setBounds(xpos, ypos, width, height); return tmpJSPN; } // end of setupJSpinnerAndGet public static JColorChooser setupJColorChooserAndGet(Color initialColor, boolean borderTitleFlag, String borderTitle, Object colorChooserChangeLisObj, int xpos, int ypos, int width, int height) { JColorChooser tmpJCC = new JColorChooser(initialColor); tmpJCC.getSelectionModel().addChangeListener((ChangeListener) colorChooserChangeLisObj); if (borderTitleFlag == true) { tmpJCC.setBorder(BorderFactory.createTitledBorder(borderTitle)); } tmpJCC.setBounds(xpos, ypos, width, height); return tmpJCC; } // end of setupJColorChooserAndGet public static JDialog setupJDialogAndGet(Frame owner, String title, boolean modal, int width, int height) { JDialog tmpJD = new JDialog(owner, title, modal); tmpJD.setSize(width, height); tmpJD.setLocationRelativeTo(null); tmpJD.setLayout(null); tmpJD.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); return tmpJD; } // end of setupJDialogAndGet public static ArrayList setupScrollableJDialogAndGetDialogAndPanel(Frame owner, String title, boolean modal, int dialogWidth, int dialogHeight, int panelWidth, int panelHeight) { JDialog tmpJD = new JDialog(owner, title, modal); tmpJD.setSize(dialogWidth, dialogHeight); tmpJD.setLocationRelativeTo(null); tmpJD.setLayout(null); tmpJD.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); JPanel tmpJP = new JPanel(); tmpJP.setPreferredSize(new Dimension(panelWidth, panelHeight)); tmpJP.setLayout(null); ScrollPane sp = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); sp.add(tmpJP); tmpJD.getRootPane().setContentPane(sp); ArrayList tmpA = new ArrayList<>(); tmpA.add((Object) (tmpJD)); tmpA.add((Object) (tmpJP)); return tmpA; } // end of setupJDialogAndGet public static JToggleButton setupJToggleButtonAndGet(String text, Object itemLisObj, boolean opaque, Color bgcolor, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JToggleButton tmpJTB = new JToggleButton(text); if (setBoundsFlag == true) { tmpJTB.setBounds(xpos, ypos, width, height); } tmpJTB.addItemListener((ItemListener) itemLisObj); tmpJTB.setOpaque(opaque); tmpJTB.setBackground(bgcolor); return tmpJTB; } // end of setupJToggleButtonAndGet public static JSeparator setupJSeparatorAndGet(int orientation, Color bgcolor, boolean setBoundsFlag, int xpos, int ypos, int width, int height) { JSeparator tmpJS = new JSeparator(orientation); tmpJS.setBackground(bgcolor); if (setBoundsFlag == true) { tmpJS.setBounds(xpos, ypos, width, height); } return tmpJS; } // end of setupJSeparatorAndGet public static JMenuBar setupJMenuBarAndGet(Color fgcolor, Color bgcolor) { JMenuBar tmpJMB = new JMenuBar(); tmpJMB.setOpaque(true); tmpJMB.setForeground(fgcolor); tmpJMB.setBackground(bgcolor); return tmpJMB; } // end of setupJMenuBarAndGet public static JMenu setupJMenuAndGet(String text, Color fgcolor, Color bgcolor) { JMenu tmpJM = new JMenu(text); tmpJM.setOpaque(true); tmpJM.setForeground(fgcolor); tmpJM.setBackground(bgcolor); return tmpJM; } // end of setupJMenuAndGet public static JMenuItem setupJMenuItemAndGet(String text, Object actLisObj, KeyStroke k, Color fgcolor, Color bgcolor) { JMenuItem tmpJMI = new JMenuItem(text); tmpJMI.setOpaque(true); tmpJMI.setForeground(fgcolor); tmpJMI.setBackground(bgcolor); tmpJMI.setAccelerator(k); if (actLisObj != null) { tmpJMI.addActionListener((ActionListener) actLisObj); } return tmpJMI; } // end of setupJMenuItemAndGet } // end of SwingLibrary ------------------------------------------------------------------------------------------- From david.holmes at oracle.com Wed Oct 12 05:29:54 2022 From: david.holmes at oracle.com (David Holmes) Date: Wed, 12 Oct 2022 15:29:54 +1000 Subject: Backup Files and Folders. In-Reply-To: References: Message-ID: <21732892-49f2-a66a-ef12-5b81f5aed4c0@oracle.com> Hi Amit, On 12/10/2022 1:46 pm, Amit wrote: > Java code for backing up files and folders (in case someone needs it). This kind of email is not appropriate for these OpenJDK mailing lists. Regards, David Holmes > Description: This software is for taking backups of files and > directories. You can specify which files and directories you want to > backup. You can also remove files and directories from the backup > list. You have to specify a directory where the backup will be stored > (local or on network). This directory will also have a log file > containing what all the software did. If you want, you can also cancel > the backup after it starts. > > ------------------------------------------------------------------------------------------- > > /* > * License: This file has been released under APACHE LICENSE, VERSION 2.0. > * The license details can be found here: > https://www.apache.org/licenses/LICENSE-2.0 > */ > > import java.io.*; > import javax.swing.*; > import javax.swing.event.*; > import java.awt.*; > import java.awt.event.*; > import java.util.*; > import java.beans.PropertyChangeListener; > import java.io.File; > import java.text.*; > import javax.swing.tree.*; > import java.nio.file.*; > import java.time.*; > import java.time.format.*; > import javax.swing.border.*; > > public class Backup_Files_And_Folders implements ActionListener { > > Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); > int screenWidth = screenSize.width; > int screenHeight = screenSize.height; > int midScreenWidth = screenWidth / 2; > > int componentHeight = 25; > // vertical gap between components > int vGap = 25; > int currentYPos = 0; > > JFrame jf = null; > JPanel jp = null; > JDialog jdShowRemoveFiles = null; > JPanel jpShowRemoveFiles = null; > JLabel jlInfoLabel = null; > JButton jbAddFilesFolders = null; > JButton jbShowRemoveFilesFolders = null; > JLabel jlShowNumFiles = null; > JButton jbRemoveAllEntries = null; > JLabel jlChooseSaveBackupLocation = null; > JTextField jtfChooseSaveBackupLocation = null; > JButton jbBrowse = null; > JButton jbTakeBackup = null; > JButton jbCancelBackup = null; > JLabel jlBackupProgressBarLabel = null; > JProgressBar jpbBackupProgressBar = null; > JLabel jlCurrentStatus = null; > JTextArea jtaExceptionsAndErrorsTextArea = null; > JScrollPane jspScrollableExceptionTextArea = null; > JButton jbCloseMainWindow = null; > > Color DeepSkyBlue = new Color(0x00bfff); > > String userHomeDir = System.getProperty("user.home"); > String backupSoftwareConfigDir = userHomeDir + File.separator + > "Backup_Files_And_Folders"; > String backupSoftwareConfigFile = backupSoftwareConfigDir + > File.separator + "Config.txt"; > String fileContainingNamesOfFilesDirectoriesToBackup = > backupSoftwareConfigDir + File.separator + > "Files_Directories_To_Backup.txt"; > String backupDir = null; > String logFile = null; > Path logFilePath = null; > > boolean cancelBackup = false; > > LinkedList listOfFilesAndFoldersToBackupLL = new LinkedList<>(); > LinkedList listOfFilesAndFoldersToBackupLabelsLL = new > LinkedList<>(); > LinkedList listOfFilesAndFoldersToBackupButtonsLL = new > LinkedList<>(); > > public enum SetupStatus { > DONE, > NOT_DONE, > CORRUPTED, > } // end of enum SetupStatus > > @Override > public void actionPerformed(ActionEvent ae) { > > String text = ""; > > Object source = ae.getSource(); > > if (source == jbBrowse) { > > JFileChooser jfc = new JFileChooser(); > jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); > if ((jfc.showOpenDialog(jf)) == JFileChooser.APPROVE_OPTION) { > File selectedFile = jfc.getSelectedFile(); > backupDir = selectedFile.getAbsolutePath(); > jtfChooseSaveBackupLocation.setText(backupDir); > > // Put this path in config file also. Open file for > writing in truncated mode. > try { > Files.write(Paths.get(backupSoftwareConfigFile), > selectedFile.getAbsolutePath().getBytes(), StandardOpenOption.WRITE, > StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC); > } catch (Exception e) { > text = "Exception happened: Could not write to > file \"" + backupSoftwareConfigFile + "\". Please check whether file > exists and permissions of file."; > JOptionPane.showMessageDialog(jf, text, "Error", > JOptionPane.ERROR_MESSAGE); > } // end of try-catch block > > // Create log file if not already existing. > logFile = backupDir + File.separator + "log.txt"; > if (checkAndCreateFileIfItDoesNotExist(logFile) == true) { > logFilePath = Paths.get(logFile); > } > } > > } else if (source == jbAddFilesFolders) { > > boolean error = false; > int filesAdded = 0; > String lineToWrite = ""; > File selectedFiles[] = null; > JFileChooser jfc = new JFileChooser(); > jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); > jfc.setMultiSelectionEnabled(true); > if ((jfc.showOpenDialog(jf)) == JFileChooser.APPROVE_OPTION) { > selectedFiles = jfc.getSelectedFiles(); > // Append the file selected to file > Files_Directories_To_Backup.txt. > for (File f : selectedFiles) { > lineToWrite = f.getAbsolutePath() + System.lineSeparator(); > try { > > Files.write(Paths.get(fileContainingNamesOfFilesDirectoriesToBackup), > lineToWrite.getBytes(), StandardOpenOption.WRITE, > StandardOpenOption.APPEND, StandardOpenOption.SYNC); > filesAdded = filesAdded + 1; > } catch (Exception e) { > error = true; > text = "Exception happened: Could not write to > file \"" + fileContainingNamesOfFilesDirectoriesToBackup + "\". Please > check whether file exists and permissions of file."; > JOptionPane.showMessageDialog(jf, text, > "Error", JOptionPane.ERROR_MESSAGE); > } // end of try-catch block > } // end of for loop > if ((filesAdded > 0) && (error == false)) { > JOptionPane.showMessageDialog(jf, "File(s) / > Folder(s) added successfully.", "Info", > JOptionPane.INFORMATION_MESSAGE); > } else if ((filesAdded > 0) && (error == true)) { > JOptionPane.showMessageDialog(jf, "Some File(s) / > Folder(s) added successfully.", "Info", > JOptionPane.INFORMATION_MESSAGE); > } > } // end of jfc.showOpenDialog(jf)) == JFileChooser.APPROVE_OPTION > > } else if (source == jbShowRemoveFilesFolders) { > > processShowRemoveFilesFolders(); > > } else if (source == jbRemoveAllEntries) { // this event is from JDialog > > int result = > JOptionPane.showConfirmDialog(jpShowRemoveFiles, "Are you sure you > want to remove all entries?", "Question", > JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); > if (result == JOptionPane.CANCEL_OPTION) { > return; > } > try { > > Files.write(Paths.get(fileContainingNamesOfFilesDirectoriesToBackup), > new byte[0], StandardOpenOption.WRITE, > StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC); > } catch (Exception e) { > text = "Error: Exception happened while removing > entries from file \"" + fileContainingNamesOfFilesDirectoriesToBackup > + "\". Remove operation has been cancelled."; > JOptionPane.showMessageDialog(jdShowRemoveFiles, text, > "Error", JOptionPane.ERROR_MESSAGE); > return; > } > > listOfFilesAndFoldersToBackupLL.clear(); > listOfFilesAndFoldersToBackupButtonsLL.clear(); > listOfFilesAndFoldersToBackupLabelsLL.clear(); > > jpShowRemoveFiles.removeAll(); > > jpShowRemoveFiles.add(jlShowNumFiles); > jlShowNumFiles.setText("Total File(s) / Folder(s): " + > listOfFilesAndFoldersToBackupLL.size()); > jpShowRemoveFiles.add(jbRemoveAllEntries); > > jpShowRemoveFiles.revalidate(); > jpShowRemoveFiles.repaint(); > > } else if ((((JButton) (source)).getText()).equals("Remove") > == true) { // this event is from JDialog > > //JOptionPane.showMessageDialog(jdShowRemoveFiles, "Remove > event from JDialog", "Info", JOptionPane.INFORMATION_MESSAGE); > > int index = listOfFilesAndFoldersToBackupButtonsLL.indexOf(source); > > if (index == -1) { > text = "Some bug in software because returned index is > -1. This should not be the case."; > JOptionPane.showMessageDialog(jdShowRemoveFiles, text, > "Error", JOptionPane.ERROR_MESSAGE); > return; > } > > String tmpFile = backupSoftwareConfigDir + File.separator > + ".tmpFile"; > boolean status = removeLineFromFileAtIndex(index, > fileContainingNamesOfFilesDirectoriesToBackup, tmpFile); > > if (status == true) { > // now remove the entry from jdialog's jpanel and from > all linked lists. > > jpShowRemoveFiles.remove(listOfFilesAndFoldersToBackupButtonsLL.get(index)); > > jpShowRemoveFiles.remove(listOfFilesAndFoldersToBackupLabelsLL.get(index)); > listOfFilesAndFoldersToBackupLL.remove(index); > listOfFilesAndFoldersToBackupButtonsLL.remove(index); > listOfFilesAndFoldersToBackupLabelsLL.remove(index); > jpShowRemoveFiles.revalidate(); > jpShowRemoveFiles.repaint(); > jlShowNumFiles.setText("Total File(s) / Folder(s): " + > listOfFilesAndFoldersToBackupLL.size()); > } > > return; > > } else if (source == jbTakeBackup) { > > // we need to start a new thread for this so that UI can > be updated because UI update > // events will come on this thread (event thread) itself > but this thread is already processing > // processTakeBackup(), so UI update events wait in the > queue for processTakeBackup() to finish. > // So, we don't see any UI updates while > processTakeBackup() is running but we want to see UI > // updates while processTakeBackup() is running and so we > have to run processTakeBackup() in a new thread. > Thread thread = new Thread() { > @Override > public void run() { > processTakeBackup(); > } > }; // end of new thread > > thread.start(); > > } else if (source == jbCancelBackup) { > > cancelBackup = true; > > } else if (source == jbCloseMainWindow) { > > jf.dispatchEvent(new WindowEvent(jf, WindowEvent.WINDOW_CLOSING)); > > } > > } // end of actionPerformed > > void processShowRemoveFilesFolders() { > > int numEntries = 0; > String line = null; > String text = null; > > // clear all linkedlists (delete all elements from all linkedlists) > listOfFilesAndFoldersToBackupLL.clear(); > listOfFilesAndFoldersToBackupButtonsLL.clear(); > listOfFilesAndFoldersToBackupLabelsLL.clear(); > > // we need to save entries from > fileContainingNamesOfFilesDirectoriesToBackup in a linkedlist. > try (BufferedReader br = new BufferedReader(new > FileReader(fileContainingNamesOfFilesDirectoriesToBackup))) { > > while ((line = br.readLine()) != null) { > //System.out.println(line); > // no need to remove newline characters. readLine > already removes them. > //line = line.replaceFirst("\\r\\n$|\\r$|\\n$", ""); > > listOfFilesAndFoldersToBackupLL.add(line); > } > > } catch (Exception e) { > > text = "Exception happened: Could not read file \"" + > fileContainingNamesOfFilesDirectoriesToBackup + "\": " + > e.getMessage(); > JOptionPane.showMessageDialog(jf, text, "Error", > JOptionPane.ERROR_MESSAGE); > > return; // we do not want to show anything now as > exception has happened. > > } // end of try-catch block > > numEntries = listOfFilesAndFoldersToBackupLL.size(); > > int dialogWidth = (int) (screenWidth * (0.775)); > int dialogHeight = (int) (screenHeight * (0.56)); > int panelWidth = 10 + 100 + 10 + 1024 + 10; > int panelHeight = 35 * numEntries + 35 + 10; > > ArrayList a = > SwingLibrary.setupScrollableJDialogAndGetDialogAndPanel(jf, "List of > Files for backing up", true, dialogWidth, dialogHeight, panelWidth, > panelHeight); > jdShowRemoveFiles = (JDialog) (a.get(0)); > jpShowRemoveFiles = (JPanel) (a.get(1)); > > // show list of files for backing up > JLabel jl = null; > JButton jb = null; > int xPos = 10; > int yPos = 10; > > // show total file(s) / folder(s) > text = "Total File(s) / Folder(s): " + numEntries; > jlShowNumFiles = SwingLibrary.setupJLabelAndGet(text, true, > Color.WHITE, SwingConstants.LEFT, SwingConstants.CENTER, true, xPos, > yPos, 300, componentHeight); > jpShowRemoveFiles.add(jlShowNumFiles); > > // implement remove all entries here > jbRemoveAllEntries = SwingLibrary.setupJButtonAndGet("Remove > All Entries", this, true, xPos + 350, yPos, 300, componentHeight); > yPos = yPos + 25 + 10; > jpShowRemoveFiles.add(jbRemoveAllEntries); > > for (String s : listOfFilesAndFoldersToBackupLL) { > > //System.out.println(s); > xPos = 10; > jb = SwingLibrary.setupJButtonAndGet("Remove", this, true, > xPos, yPos, 100, componentHeight); > xPos = xPos + 110; > jl = SwingLibrary.setupJLabelAndGet(s, true, Color.WHITE, > SwingConstants.LEFT, SwingConstants.CENTER, true, xPos, yPos, 1024, > componentHeight); > yPos = yPos + 25 + 10; > listOfFilesAndFoldersToBackupButtonsLL.add(jb); > listOfFilesAndFoldersToBackupLabelsLL.add(jl); > jpShowRemoveFiles.add(jb); > jpShowRemoveFiles.add(jl); > > } // end of for loop > > jdShowRemoveFiles.setVisible(true); > > } // end of processShowRemoveFilesFolders > > // If append is true then append text, else truncate the file. > void writeToLogFile(String text, OpenOption op) { > > if (logFilePath == null) { > return; > } > > try { > text = text + System.lineSeparator(); > Files.write(logFilePath, text.getBytes(), > StandardOpenOption.WRITE, op, StandardOpenOption.SYNC); > } catch (Exception e) { > } > > } // end of writeToLogFile > > void processCancelBackup() { > > // write trailer in log file > writeToLogFile(System.lineSeparator() + "Backup Cancelled.", > StandardOpenOption.APPEND); > writeToLogFile(System.lineSeparator() + "=============== > Backup Cancelled ===============", StandardOpenOption.APPEND); > > jlCurrentStatus.setForeground(Color.RED); > jlCurrentStatus.setText("Backup Cancelled. > You can look at log file at location: " + logFile); > > JOptionPane.showMessageDialog(jf, "Backup Cancelled.", "Info", > JOptionPane.INFORMATION_MESSAGE); > > // the following method sets cancelBackup to false. > enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); > > } // end of processCancelBackup > > void enableComponentsAndDisableCancelOnBackupEndOrBackupCancel() { > > cancelBackup = false; > jbCancelBackup.setEnabled(false); > jbAddFilesFolders.setEnabled(true); > jbShowRemoveFilesFolders.setEnabled(true); > jbBrowse.setEnabled(true); > jbTakeBackup.setEnabled(true); > > } // end of enableComponentsAndDisableCancelOnBackupEndOrBackupCancel > > void disableComponentsAndEnableCancelOnBackupStart() { > > jbTakeBackup.setEnabled(false); > jbBrowse.setEnabled(false); > jbAddFilesFolders.setEnabled(false); > jbShowRemoveFilesFolders.setEnabled(false); > jbCancelBackup.setEnabled(true); > > } // end of disableComponentsAndEnableCancelOnBackupStart > > long copyDirectoryRecursively(String sourceDir, String destDir, > long numFilesCopied, long totalFilesCount) { > > String entryAsString = null; > String targetFileOrDir = null; > String text = null; > > try { > Files.createDirectory(Paths.get(destDir)); > > // write in log file and update current status label > text = "Created directory: " + destDir; > jlCurrentStatus.setText(text); > writeToLogFile(text, StandardOpenOption.APPEND); > } catch (FileAlreadyExistsException faee) { > text = "** Exception happened while creating directory \"" > + destDir + "\": Directory \"" + destDir + "\" already exists: " + > faee.getMessage(); > writeToLogFile(text, StandardOpenOption.APPEND); > jtaExceptionsAndErrorsTextArea.append(text + "\n"); > jlCurrentStatus.setText(text); > return numFilesCopied; > } catch (Exception e) { > text = "** Exception happened while creating directory \"" > + destDir + "\": " + e.getMessage(); > writeToLogFile(text, StandardOpenOption.APPEND); > jtaExceptionsAndErrorsTextArea.append(text + "\n"); > jlCurrentStatus.setText(text); > return numFilesCopied; > } > > try (DirectoryStream ds = > Files.newDirectoryStream(Paths.get(sourceDir))) { > > for (Path entry : ds) { > > if (cancelBackup == true) { > try { > ds.close(); > } catch (Exception e) { > } > return numFilesCopied; > } > > entryAsString = entry.toAbsolutePath().toString(); > targetFileOrDir = destDir + File.separator + > entryAsString.substring(entryAsString.lastIndexOf(File.separator) + > 1); > > if (Files.isRegularFile(entry) == true) { > try { > Files.copy(entry, Paths.get(targetFileOrDir), > StandardCopyOption.COPY_ATTRIBUTES); > numFilesCopied = numFilesCopied + 1; > > // write in log file and update current status label > text = "Copied file " + entryAsString + " to " > + targetFileOrDir; > jlCurrentStatus.setText(text); > writeToLogFile(text, StandardOpenOption.APPEND); > > jlBackupProgressBarLabel.setText("Backup > Progress (Files backed up: " + numFilesCopied + " / " + > totalFilesCount + ")"); > jpbBackupProgressBar.setValue((int) > ((numFilesCopied * 100) / totalFilesCount)); > } catch (Exception e) { > text = "** Exception happened while copying > \"" + entry.toAbsolutePath().toString() + "\" to \"" + targetFileOrDir > + "\": " + e.getMessage(); > writeToLogFile(text, StandardOpenOption.APPEND); > jtaExceptionsAndErrorsTextArea.append(text + "\n"); > jlCurrentStatus.setText(text); > } > } else if (Files.isDirectory(entry) == true) { > numFilesCopied = > copyDirectoryRecursively(entryAsString, targetFileOrDir, > numFilesCopied, totalFilesCount); > } > > } // end of for Path entry : ds > > } catch (Exception e) { > > text = "** Exception happened while processing directory > \"" + sourceDir + "\": " + e.getMessage(); > writeToLogFile(text, StandardOpenOption.APPEND); > jtaExceptionsAndErrorsTextArea.append(text + "\n"); > jlCurrentStatus.setText(text); > > } > > return numFilesCopied; > > } // end of copyDirectoryRecursively > > long getNumberOfFilesAndDirsInDir(Path p, long totalFilesCount) { > > try (DirectoryStream ds = Files.newDirectoryStream(p)) { > > for (Path entry : ds) { > if (cancelBackup == true) { > try { > ds.close(); > } catch (Exception e) { > } > return totalFilesCount; > } > if (Files.isRegularFile(entry) == true) { > totalFilesCount = totalFilesCount + 1; > jlCurrentStatus.setText("Counting number of files > to be backed up: " + totalFilesCount); > } else if (Files.isDirectory(entry) == true) { > totalFilesCount = > getNumberOfFilesAndDirsInDir(entry, totalFilesCount); > jlCurrentStatus.setText("Counting number of files > to be backed up: " + totalFilesCount); > } > } > > } catch (Exception e) { > } // end of try-catch block > > return totalFilesCount; > > } // end of getNumberOfFilesAndDirsInDir > > void processBackupNotTaken(String text) { > > // write trailer to log file > writeToLogFile(System.lineSeparator() + text, > StandardOpenOption.APPEND); > writeToLogFile(System.lineSeparator() + "=============== End > ===============", StandardOpenOption.APPEND); > jtaExceptionsAndErrorsTextArea.append(text + "\n"); > jlCurrentStatus.setText(text); > JOptionPane.showMessageDialog(jf, text, "Error", > JOptionPane.ERROR_MESSAGE); > > } // end of processBackupNotTaken > > void processTakeBackup() { > > disableComponentsAndEnableCancelOnBackupStart(); > > String text = null; > String targetBackupDir = null; > Path p = null; > boolean someFileOrFolderExists = false; > > LocalDateTime currentLocalDateTime = LocalDateTime.now(); > DateTimeFormatter dateTimeFormatter = null; > > // reset few things > writeToLogFile("", StandardOpenOption.TRUNCATE_EXISTING); > jtaExceptionsAndErrorsTextArea.setText(null); > jlCurrentStatus.setForeground(null); > jlCurrentStatus.setText("Backup Process Started"); > jlBackupProgressBarLabel.setText("Backup Progress: Backup > Process Started."); > jpbBackupProgressBar.setValue(0); > > // write header and date/time to log file. > writeToLogFile("=============== Backup Process Started > ===============" + System.lineSeparator(), StandardOpenOption.APPEND); > try { > dateTimeFormatter = DateTimeFormatter.ofPattern("dd LLL > yyyy, hh:mm:ss a"); > writeToLogFile("Date/Time: " + > currentLocalDateTime.format(dateTimeFormatter) + > System.lineSeparator(), StandardOpenOption.APPEND); > } catch (Exception e) { > } // end of try-catch block > > // check if backup directory is given or not > if (backupDir.isBlank() == true) { > processBackupNotTaken("Error: Directory where backups will > be saved is not given. No backup will be taken."); > enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); > return; > } > > // check if backup directory exists > if (Files.exists(Paths.get(backupDir)) == false) { > processBackupNotTaken("Error: Backup directory \"" + > backupDir + "\" does not exist or may be permissions issue. No backup > will be taken."); > enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); > return; > } > > // we need to save entries from > fileContainingNamesOfFilesDirectoriesToBackup in an array list. > ArrayList filesFoldersArrayList = new ArrayList<>(); > String line = null; > try (BufferedReader br = new BufferedReader(new > FileReader(fileContainingNamesOfFilesDirectoriesToBackup))) { > while ((line = br.readLine()) != null) { > filesFoldersArrayList.add(line); > } > } catch (Exception e) { > processBackupNotTaken("Error: Exception happened: Could > not read file \"" + fileContainingNamesOfFilesDirectoriesToBackup + > "\": " + e.getMessage() + ". No backup will be taken."); > enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); > return; > } // end of try-catch block > > // if there are no files/folders to backup then show a message > and return > if (filesFoldersArrayList.isEmpty() == true) { > processBackupNotTaken("Error: No file(s) / folder(s) have > been added for backup. Nothing to backup."); > enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); > return; > } > > // check which file(s)/folder(s) present in > fileContainingNamesOfFilesDirectoriesToBackup do not exist. > for (String fileOrDir : filesFoldersArrayList) { > > if (cancelBackup == true) { > processCancelBackup(); > return; > } > > p = Paths.get(fileOrDir); > > if (Files.exists(p) == false) { // file/directory does not exist > text = "Error: File/Folder does not exist: " + > p.toAbsolutePath().toString(); > writeToLogFile(text, StandardOpenOption.APPEND); > jtaExceptionsAndErrorsTextArea.append(text + "\n"); > jlCurrentStatus.setText(text); > } else { > someFileOrFolderExists = true; > } > > // processing cancelBackup here is necessary because it is > possible that the > // for loop has already consumed the last entry in > filesFoldersArrayList, > // so when now the control goes back to the for loop, it > will not enter the loop > // because there are no more entries to be read from > filesFoldersArrayList and > // hence it will come out of for loop and "cancelBackup == > true" condition will > // never hit. > if (cancelBackup == true) { > processCancelBackup(); > return; > } > > } // end of for (String fileOrDir : filesFoldersArrayList) > > if (someFileOrFolderExists == false) { > processBackupNotTaken("Error: No File(s)/Folder(s) given > for backup exist. No backup has been taken."); > enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); > return; > } > > // count total number of files for progress bar > long totalFilesCount = 0; > for (String dirOrFile : filesFoldersArrayList) { > > if (cancelBackup == true) { > processCancelBackup(); > return; > } > > p = Paths.get(dirOrFile); > > if (Files.isRegularFile(p) == true) { > totalFilesCount = totalFilesCount + 1; > jlCurrentStatus.setText("Counting number of files to > be backed up: " + totalFilesCount); > } else if (Files.isDirectory(p) == true) { > totalFilesCount = getNumberOfFilesAndDirsInDir(p, > totalFilesCount); > jlCurrentStatus.setText("Counting number of files to > be backed up: " + totalFilesCount); > } > > // processing cancelBackup here is necessary because it is > possible that the > // for loop has already consumed the last entry in > filesFoldersArrayList, > // so when now the control goes back to the for loop, it > will not enter the loop > // because there are no more entries to be read from > filesFoldersArrayList and > // hence it will come out of for loop and "cancelBackup == > true" condition will > // never hit. > if (cancelBackup == true) { > processCancelBackup(); > return; > } > > } // end of for (String dirOrFile : filesFoldersArrayList) > > // create directory where backups will be saved. > try { > dateTimeFormatter = > DateTimeFormatter.ofPattern("yyyyLLLdd-HH-mm-ss"); > targetBackupDir = backupDir + File.separator + "Backup-" + > currentLocalDateTime.format(dateTimeFormatter); > } catch (Exception e) { > processBackupNotTaken("Error: Exception happened: Could > not get current date and time in desired format: " + e.getMessage() + > ". No backup will be taken."); > enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); > return; > } // end of try-catch block > > // debug > //JOptionPane.showMessageDialog(jf, "Target Backup Dir: " + > targetBackupDir, "Target Backup Dir", > JOptionPane.INFORMATION_MESSAGE); > // create new directories if they don't exist > if (checkAndCreateDirectoryIfItDoesNotExist(targetBackupDir) == false) { > processBackupNotTaken("Error: Exception happened: Could > not create directory \"" + targetBackupDir + "\". Please check > permissions of directory \"" + backupDir + "\". No backup will be > taken."); > enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); > return; > } > > // start taking backup of files and folders > long numFilesCopied = 0; > String targetFileOrDir = null; > String transformSourceFileOrDir = null; > > jlBackupProgressBarLabel.setText("Backup Progress (Files > backed up: " + numFilesCopied + " / " + totalFilesCount + ")"); > writeToLogFile(System.lineSeparator() + "Backup is being taken > in directory: " + targetBackupDir + System.lineSeparator(), > StandardOpenOption.APPEND); > > for (String sourceFileOrDir : filesFoldersArrayList) { > > if (cancelBackup == true) { > processCancelBackup(); > return; > } > > p = Paths.get(sourceFileOrDir); > > // transform source directory to full path > if (Files.isDirectory(p) == true) { > transformSourceFileOrDir = > sourceFileOrDir.replace(File.separator, "-"); > transformSourceFileOrDir = > transformSourceFileOrDir.replace(":", ""); // to fix C:\AAA\BBB, etc. > targetFileOrDir = targetBackupDir + File.separator + > transformSourceFileOrDir; > } else { > targetFileOrDir = targetBackupDir + File.separator + > sourceFileOrDir.substring(sourceFileOrDir.lastIndexOf(File.separator) > + 1); > } > > if (Files.isRegularFile(p) == true) { > try { > Files.copy(p, Paths.get(targetFileOrDir), > StandardCopyOption.COPY_ATTRIBUTES); > numFilesCopied = numFilesCopied + 1; > > // write in log file and update current status label > text = "Copied file " + sourceFileOrDir + " to " + > targetFileOrDir; > jlCurrentStatus.setText(text); > writeToLogFile(text, StandardOpenOption.APPEND); > > jlBackupProgressBarLabel.setText("Backup Progress > (Files backed up: " + numFilesCopied + " / " + totalFilesCount + ")"); > jpbBackupProgressBar.setValue((int) > ((numFilesCopied * 100) / totalFilesCount)); > } catch (Exception e) { > text = "** Exception happened while copying \"" + > p.toAbsolutePath().toString() + "\" to \"" + targetFileOrDir + "\": " > + e.getMessage(); > writeToLogFile(text, StandardOpenOption.APPEND); > jtaExceptionsAndErrorsTextArea.append(text + "\n"); > jlCurrentStatus.setText(text); > } > } else if (Files.isDirectory(p) == true) { > numFilesCopied = > copyDirectoryRecursively(sourceFileOrDir, targetFileOrDir, > numFilesCopied, totalFilesCount); > } > > // print an empty line after each entry is processed > writeToLogFile("", StandardOpenOption.APPEND); > > // processing cancelBackup here is necessary because it is > possible that the > // for loop has already consumed the last entry in > filesFoldersArrayList, > // so when now the control goes back to the for loop, it > will not enter the loop > // because there are no more entries to be read from > filesFoldersArrayList and > // hence it will come out of for loop and "cancelBackup == > true" condition will > // never hit. > if (cancelBackup == true) { > processCancelBackup(); > return; > } > > } // end of for (String sourceFileOrDir : filesFoldersArrayList) > > // write trailer in log file > writeToLogFile(System.lineSeparator() + "=============== End > of Backup ===============", StandardOpenOption.APPEND); > > text = "Backup taken in directory \"" + targetBackupDir + "\"."; > text = text + " You can look at log file at > location: " + logFile; > jlCurrentStatus.setText(text); > > text = "Backup taken in directory \"" + targetBackupDir + "\"."; > JOptionPane.showMessageDialog(jf, text, "Info", > JOptionPane.INFORMATION_MESSAGE); > > // the following method sets cancelBackup to false. > enableComponentsAndDisableCancelOnBackupEndOrBackupCancel(); > > } // end of processTakeBackup > > boolean removeLineFromFileAtIndex(int index, String file, String tmpFile) { > > String text = null; > String line = null; > boolean lineFound = false; > int i = -1; > > if (index < 0) { > text = "Index given is invalid: It is less than zero: " + index; > JOptionPane.showMessageDialog(jdShowRemoveFiles, text, > "Error", JOptionPane.ERROR_MESSAGE); > return false; > } > > try ( > BufferedReader br = new BufferedReader(new FileReader(file)); > FileWriter fw = new FileWriter(new File(tmpFile), false);) { > > while ((line = br.readLine()) != null) { > //System.out.println(line); > // increment i > i = i + 1; > if (index == i) { > lineFound = true; > continue; > } > fw.write(line + System.lineSeparator()); > fw.flush(); > } // end of while > > br.close(); > fw.close(); > > Files.move(Paths.get(tmpFile), Paths.get(file), > StandardCopyOption.REPLACE_EXISTING); > > } catch (Exception e) { > > try { > // delete temp file > Files.delete(Paths.get(tmpFile)); > } catch (Exception ee) { > } > > text = "Exception happened: " + e.getMessage(); > JOptionPane.showMessageDialog(jdShowRemoveFiles, text, > "Error", JOptionPane.ERROR_MESSAGE); > > return false; > > } // end of try-catch block > > if (lineFound == false) { > text = "No line found at given Index. Index given: " + index; > JOptionPane.showMessageDialog(jdShowRemoveFiles, text, > "Error", JOptionPane.ERROR_MESSAGE); > return false; > } > > return true; > > } // end of removeLineFromFileAtIndex > > boolean checkAndCreateFileIfItDoesNotExist(String file) { > > try { > Files.createFile(Paths.get(file)); > } catch (FileAlreadyExistsException faee) { > // don't do anything. file exists. > } catch (Exception e) { > return false; > } > > return true; > > } // end of checkAndCreateFileIfItDoesNotExist > > boolean checkAndCreateDirectoryIfItDoesNotExist(String dir) { > > try { > Files.createDirectory(Paths.get(dir)); > } catch (FileAlreadyExistsException faee) { > // don't do anything. directory exists. > } catch (Exception e) { > return false; > } > > return true; > > } // end of checkAndCreateDirectoryIfItDoesNotExist > > // Create required files and directories if they don't exist. > void doSetup(SetupStatus ss) { > > String text = ""; > int result = -1; > > if (ss == SetupStatus.NOT_DONE) { > text = "Setup is not done. Setup will create a directory > in \"" + userHomeDir + "\" and then create " > + "some files inside the new directory. Do you > want to continue doing setup?"; > } else { > text = "Setup is corrupted. Do you want to fix setup?"; > } > > result = JOptionPane.showConfirmDialog(jf, text, "Question", > JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); > if (result == JOptionPane.CANCEL_OPTION) { > JOptionPane.showMessageDialog(jf, "Exiting..", "Error", > JOptionPane.ERROR_MESSAGE); > System.exit(1); > } > > // create files and directories if they don't exist > if (checkAndCreateDirectoryIfItDoesNotExist(backupSoftwareConfigDir) > == false) { > text = "Exception happened: Could not create directory \"" > + backupSoftwareConfigDir + "\". Please check permissions of directory > \"" + userHomeDir + "\". Exiting.."; > JOptionPane.showMessageDialog(jf, text, "Error", > JOptionPane.ERROR_MESSAGE); > System.exit(1); > } > > if (checkAndCreateFileIfItDoesNotExist(backupSoftwareConfigFile) > == false) { > text = "Exception happened: Could not create file \"" + > backupSoftwareConfigFile + "\". Please check permissions of directory > \"" + backupSoftwareConfigDir + "\". Exiting.."; > JOptionPane.showMessageDialog(jf, text, "Error", > JOptionPane.ERROR_MESSAGE); > System.exit(1); > } > > if (checkAndCreateFileIfItDoesNotExist(fileContainingNamesOfFilesDirectoriesToBackup) > == false) { > text = "Exception happened: Could not create file \"" + > fileContainingNamesOfFilesDirectoriesToBackup + "\". Please check > permissions of directory \"" + backupSoftwareConfigDir + "\". > Exiting.."; > JOptionPane.showMessageDialog(jf, text, "Error", > JOptionPane.ERROR_MESSAGE); > System.exit(1); > } > > if (ss == SetupStatus.NOT_DONE) { > JOptionPane.showMessageDialog(jf, "Setup done > successfully.", "Info", JOptionPane.INFORMATION_MESSAGE); > } else { > JOptionPane.showMessageDialog(jf, "Setup fixed > successfully.", "Info", JOptionPane.INFORMATION_MESSAGE); > } > > } // end of doSetup > > // Check that required files and directories exist. > SetupStatus checkSetupDone() { > > if (Files.exists(Paths.get(backupSoftwareConfigDir)) == false) { > return SetupStatus.NOT_DONE; > } > > if (Files.exists(Paths.get(backupSoftwareConfigFile)) == false) { > return SetupStatus.CORRUPTED; > } > > if (Files.exists(Paths.get(fileContainingNamesOfFilesDirectoriesToBackup)) > == false) { > return SetupStatus.CORRUPTED; > } > > return SetupStatus.DONE; > > } // end of checkSetupDone > > void doSetupAndCreateAndShowGUI() { > > String text = ""; > JLabel jl = null; > > ArrayList a = > SwingLibrary.setupScrollableJFrameAndGetFrameAndPanel("Backup Files > And Folders", screenWidth - 10, screenHeight - 50); > jf = (JFrame) (a.get(0)); > jp = (JPanel) (a.get(1)); > jf.setVisible(true); > > // check if setup is done or not. If not, then do the setup. > SetupStatus ss = checkSetupDone(); > if (ss != SetupStatus.DONE) { > doSetup(ss); > } > > currentYPos = 0; > text = "

" > + "Backups will be saved in a directory named as > Backup_Date_Time in the directory you have chosen for saving > backups.

" > + "In Backup_Date_Time, Date is the date on which the > backup has been taken and Time is the time at which the backup has > been taken.

" > + "A log file is created in the directory > Backup_Date_Time and it will contain details of last backup only > (including all exceptions if they happened).
" > + "

"; > jlInfoLabel = SwingLibrary.setupJLabelAndGet(text, true, > DeepSkyBlue, SwingConstants.CENTER, SwingConstants.CENTER, true, 0, > currentYPos, screenWidth, componentHeight * 4); > jp.add(jlInfoLabel); > > currentYPos = currentYPos + vGap * 6; > jbAddFilesFolders = SwingLibrary.setupJButtonAndGet("ADD > file(s) / folder(s) for backing up", this, true, midScreenWidth - 500, > currentYPos, 350, componentHeight); > jp.add(jbAddFilesFolders); > > jbShowRemoveFilesFolders = > SwingLibrary.setupJButtonAndGet("SHOW / REMOVE file(s) / folder(s) > added for backing up", this, true, midScreenWidth + 150, currentYPos, > 350, componentHeight); > jp.add(jbShowRemoveFilesFolders); > > currentYPos = currentYPos + vGap * 3; > jlChooseSaveBackupLocation = > SwingLibrary.setupJLabelAndGet("Choose a directory where backups will > be saved:", true, null, SwingConstants.LEFT, SwingConstants.CENTER, > true, 25, currentYPos, 300, componentHeight); > jp.add(jlChooseSaveBackupLocation); > currentYPos = currentYPos + vGap; > jtfChooseSaveBackupLocation = > SwingLibrary.setupJTextFieldAndGet(25, currentYPos, screenWidth - 180, > componentHeight); > jtfChooseSaveBackupLocation.setEditable(false); > jtfChooseSaveBackupLocation.setBackground(Color.WHITE); > jtfChooseSaveBackupLocation.setBorder(new LineBorder(Color.BLUE, 2)); > jp.add(jtfChooseSaveBackupLocation); > jbBrowse = SwingLibrary.setupJButtonAndGet("Browse", this, > true, screenWidth - 140, currentYPos, 100, componentHeight); > jp.add(jbBrowse); > > currentYPos = currentYPos + vGap * 3; > jbTakeBackup = SwingLibrary.setupJButtonAndGet("Take Backup", > this, true, midScreenWidth - 400, currentYPos, 200, componentHeight); > jp.add(jbTakeBackup); > > //currentYPos = currentYPos + vGap * 3; > jbCancelBackup = SwingLibrary.setupJButtonAndGet("Cancel > Backup", this, true, midScreenWidth + 200, currentYPos, 200, > componentHeight); > jbCancelBackup.setEnabled(false); > jp.add(jbCancelBackup); > > currentYPos = currentYPos + vGap * 2; > jlBackupProgressBarLabel = > SwingLibrary.setupJLabelAndGet("Backup Progress: Not Started.", false, > null, SwingConstants.LEFT, SwingConstants.CENTER, true, 25, > currentYPos, 500, componentHeight); > jp.add(jlBackupProgressBarLabel); > currentYPos = currentYPos + vGap; > jpbBackupProgressBar = > SwingLibrary.setupJProgressBarAndGet(SwingConstants.HORIZONTAL, 0, > 100, 0, true, true, true, 25, currentYPos, screenWidth - 80, > componentHeight); > jp.add(jpbBackupProgressBar); > > currentYPos = currentYPos + vGap * 2; > jl = SwingLibrary.setupJLabelAndGet("Current Status:", false, > null, SwingConstants.LEFT, SwingConstants.CENTER, true, 25, > currentYPos, 100, componentHeight); > jp.add(jl); > currentYPos = currentYPos + vGap; > jlCurrentStatus = SwingLibrary.setupJLabelAndGet("", false, > null, SwingConstants.CENTER, SwingConstants.CENTER, true, 25, > currentYPos, screenWidth - 80, componentHeight); > jlCurrentStatus.setBorder(BorderFactory.createLineBorder(Color.BLACK, > 1)); > jp.add(jlCurrentStatus); > > currentYPos = currentYPos + vGap * 2; > jl = SwingLibrary.setupJLabelAndGet("Exceptions and Errors:", > false, null, SwingConstants.LEFT, SwingConstants.CENTER, true, 25, > currentYPos, 200, componentHeight); > jp.add(jl); > currentYPos = currentYPos + vGap; > jtaExceptionsAndErrorsTextArea = > SwingLibrary.setupJTextAreaAndGet("", 100, 225, false, true, true, > false, 0, 0, 0, 0); > jspScrollableExceptionTextArea = > SwingLibrary.setupScrollableJTextAreaAndGet(jtaExceptionsAndErrorsTextArea, > 25, currentYPos, screenWidth - 80, componentHeight * 7); > jp.add(jspScrollableExceptionTextArea); > > currentYPos = currentYPos + vGap * 8; > jbCloseMainWindow = SwingLibrary.setupJButtonAndGet("Close > Main Window", this, true, midScreenWidth - 100, currentYPos, 200, > componentHeight); > jp.add(jbCloseMainWindow); > > jp.revalidate(); > jp.repaint(); > > // Check if there is some path saved in > backupSoftwareConfigFile. If yes, then set the text field > jtfChooseSaveBackupLocation to that path. > try { > > byte[] allBytes = > Files.readAllBytes(Paths.get(backupSoftwareConfigFile)); > > // check that "\n" appended at the end of file name > results in exception > //byte[] allBytes = > Files.readAllBytes(Paths.get(backupSoftwareConfigFile + "\n")); > > backupDir = new String(allBytes); > jtfChooseSaveBackupLocation.setText(backupDir); > > // Create log file if not already existing. > logFile = backupDir + File.separator + "log.txt"; > if (checkAndCreateFileIfItDoesNotExist(logFile) == true) { > logFilePath = Paths.get(logFile); > } > > } catch (Exception e) { > > text = "Exception happened: Could not read file \"" + > backupSoftwareConfigFile + "\": " + e.getMessage(); > JOptionPane.showMessageDialog(jf, text, "Error", > JOptionPane.ERROR_MESSAGE); > > } // end of try-catch block > > } // end of doSetupAndCreateAndShowGUI > > public static void main(String args[]) { > > Backup_Files_And_Folders bfaf = new Backup_Files_And_Folders(); > bfaf.doSetupAndCreateAndShowGUI(); > > } // end of main > > } // end of Backup_Files_And_Folders > > class SwingLibrary { > > // if width is 0 then the frame is maximized horizontally > // if height is 0 then the frame is maximized vertically > public static JFrame setupJFrameAndGet(String title, int width, > int height) { > int state = 0; > JFrame tmpJF = new JFrame(title); > if (width == 0) { > state = state | JFrame.MAXIMIZED_HORIZ; > } > if (height == 0) { > state = state | JFrame.MAXIMIZED_VERT; > } > if ((width != 0) || (height != 0)) { > tmpJF.setSize(width, height); > } > tmpJF.setExtendedState(tmpJF.getExtendedState() | state); > tmpJF.setLocationRelativeTo(null); > tmpJF.setLayout(null); > tmpJF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); > return tmpJF; > } // end of setupJFrameAndGet > > // width and height are the preferred width and height of JPanel > public static ArrayList > setupScrollableJFrameAndGetFrameAndPanel(String title, int width, int > height) { > JFrame tmpJF = new JFrame(title); > tmpJF.setExtendedState(tmpJF.getExtendedState() | > JFrame.MAXIMIZED_BOTH); > tmpJF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); > //tmpJF.setLayout(null); > > JPanel tmpJP = new JPanel(); > //tmpJP.setBounds(xpos, ypos, width + 1000, height + 1000); > tmpJP.setPreferredSize(new Dimension(width, height)); > tmpJP.setLayout(null); > > JScrollPane tmpJSPFrame = new JScrollPane(tmpJP, > JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, > JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); > tmpJSPFrame.getHorizontalScrollBar().setUnitIncrement(10); > tmpJSPFrame.getVerticalScrollBar().setUnitIncrement(10); > tmpJF.add(tmpJSPFrame); > > ArrayList tmpA = new ArrayList<>(); > tmpA.add((Object) (tmpJF)); > tmpA.add((Object) (tmpJP)); > > return tmpA; > } // end of setupScrollableJFrameAndGetFrameAndPanel > > // actLisObj: object which implements action listener > public static JButton setupJButtonAndGet(String text, Object > actLisObj, boolean setBoundsFlag, int xpos, int ypos, int width, int > height) { > JButton tmpJB = new JButton(text); > if (setBoundsFlag == true) { > tmpJB.setBounds(xpos, ypos, width, height); > } > tmpJB.addActionListener((ActionListener) actLisObj); > return tmpJB; > } // end of setupJButtonAndGet > > // halign: horizontal alignment of text, valign: vertical alignment of text > public static JLabel setupJLabelAndGet(String text, boolean > opaque, Color bg, int halign, int valign, boolean setBoundsFlag, int > xpos, int ypos, int width, int height) { > JLabel tmpJL = new JLabel(text); > if (setBoundsFlag == true) { > tmpJL.setBounds(xpos, ypos, width, height); > } > tmpJL.setOpaque(opaque); > if (bg != null) { > tmpJL.setBackground(bg); > } > tmpJL.setHorizontalAlignment(halign); > tmpJL.setVerticalAlignment(valign); > return tmpJL; > } // end of setupJlabelAndGet > > public static JTextField setupJTextFieldAndGet(int xpos, int ypos, > int width, int height) { > JTextField tmpJTF = new JTextField(); > tmpJTF.setBounds(xpos, ypos, width, height); > return tmpJTF; > } // end of setupJTextFieldAndGet > > public static JFormattedTextField > setupJFormattedTextFieldAndGet(Format fmt, Object initialVal, Object > propertyChangeLis, String propertyToListenFor, int xpos, int ypos, int > width, int height) { > JFormattedTextField tmpJFTF = new JFormattedTextField(fmt); > tmpJFTF.setValue(initialVal); > tmpJFTF.addPropertyChangeListener(propertyToListenFor, > (PropertyChangeListener) propertyChangeLis); > tmpJFTF.setBounds(xpos, ypos, width, height); > return tmpJFTF; > } // end of setupJFormattedTextFieldAndGet > > // itemLisObj: object which implements item listener > public static JCheckBox setupJCheckBoxAndGet(String text, boolean > state, Object itemLisObj, int xpos, int ypos, int width, int height) { > JCheckBox tmpJCB = new JCheckBox(text, state); > tmpJCB.setBounds(xpos, ypos, width, height); > tmpJCB.addItemListener((ItemListener) itemLisObj); > return tmpJCB; > } // end of setupJCheckBoxAndGet > > // actLisObj: object which implements action listener > public static JRadioButton setupJRadioButtonAndGet(String text, > boolean state, Object actLisObj, int xpos, int ypos, int width, int > height) { > JRadioButton tmpJRB = new JRadioButton(text, state); > tmpJRB.setBounds(xpos, ypos, width, height); > tmpJRB.addActionListener((ActionListener) actLisObj); > return tmpJRB; > } // end of setupJRadioButtonAndGet > > public static ButtonGroup setupButtonGroupAndGet() { > ButtonGroup tmpBG = new ButtonGroup(); > return tmpBG; > } // end of setupButtonGroupAndGet > > public static JPasswordField setupJPasswordFieldAndGet(int xpos, > int ypos, int width, int height) { > JPasswordField tmpJPF = new JPasswordField(); > tmpJPF.setBounds(xpos, ypos, width, height); > return tmpJPF; > } // end of setupJPasswordFieldAndGet > > public static JTextArea setupJTextAreaAndGet(String text, int > rows, int columns, boolean setEditableFlag, boolean setLineWrapFlag, > boolean setWrapStyleWordFlag, boolean setBoundsFlag, int xpos, int > ypos, int width, int height) { > JTextArea tmpJTA = new JTextArea(text, rows, columns); > tmpJTA.setEditable(setEditableFlag); > tmpJTA.setLineWrap(setLineWrapFlag); > tmpJTA.setWrapStyleWord(setWrapStyleWordFlag); > if (setBoundsFlag == true) { > tmpJTA.setBounds(xpos, ypos, width, height); > } > return tmpJTA; > } // end of setupJTextAreaAndGet > > public static JScrollPane setupScrollableJTextAreaAndGet(JTextArea > jta, int xpos, int ypos, int width, int height) { > JScrollPane tmpJSP = new JScrollPane(jta); > tmpJSP.setBounds(xpos, ypos, width, height); > return tmpJSP; > } // end of setupScrollableJTextAreaAndGet > > public static JList setupJListAndGet(ListModel lm, > int selectionMode, int visibleRowCount, int initialSelectedIndex, > Object listSelLisObj, boolean setBoundsFlag, int xpos, int ypos, int > width, int height) { > JList tmpJList = new JList<>(lm); > tmpJList.setSelectionMode(selectionMode); > tmpJList.setVisibleRowCount(visibleRowCount); > if (initialSelectedIndex >= 0) { > tmpJList.setSelectedIndex(initialSelectedIndex); > } > tmpJList.addListSelectionListener((ListSelectionListener) > listSelLisObj); > if (setBoundsFlag == true) { > tmpJList.setBounds(xpos, ypos, width, height); > } > return tmpJList; > } // end of setupJListAndGet > > public static JScrollPane setupScrollableJListAndGet(JList jlist, > int xpos, int ypos, int width, int height) { > JScrollPane tmpJSP = new JScrollPane(jlist); > tmpJSP.setBounds(xpos, ypos, width, height); > return tmpJSP; > } // end of setupScrollableJListAndGet > > public static JComboBox > setupJComboBoxAndGet(ComboBoxModel cbm, int > initialSelectedIndex, Object actLisObj, boolean setBoundsFlag, int > xpos, int ypos, int width, int height) { > JComboBox tmpJComboBox = new JComboBox<>(cbm); > if (initialSelectedIndex >= 0) { > tmpJComboBox.setSelectedIndex(initialSelectedIndex); > } > tmpJComboBox.addActionListener((ActionListener) actLisObj); > if (setBoundsFlag == true) { > tmpJComboBox.setBounds(xpos, ypos, width, height); > } > return tmpJComboBox; > } // end of setupJComboBoxAndGet > > public static JProgressBar setupJProgressBarAndGet(int > orientation, int min, int max, int initialVal, boolean > borderPaintedFlag, boolean stringPaintedFlag, boolean setBoundsFlag, > int xpos, int ypos, int width, int height) { > JProgressBar tmpJPB = new JProgressBar(orientation, min, max); > tmpJPB.setValue(initialVal); > tmpJPB.setBorderPainted(borderPaintedFlag); > tmpJPB.setStringPainted(stringPaintedFlag); > if (setBoundsFlag == true) { > tmpJPB.setBounds(xpos, ypos, width, height); > } > return tmpJPB; > } // end of setupJProgressBarAndGet > > public static JSlider setupJSliderAndGet(int orientation, int min, > int max, int initialVal, int minorTickSpacing, int majorTickSpacing, > boolean paintTicksFlag, boolean paintLabelsFlag, Object changeLisObj, > boolean setBoundsFlag, int xpos, int ypos, int width, int height) { > JSlider tmpJS = new JSlider(orientation, min, max, initialVal); > tmpJS.setMinorTickSpacing(minorTickSpacing); > tmpJS.setMajorTickSpacing(majorTickSpacing); > tmpJS.setPaintTicks(paintTicksFlag); > tmpJS.setPaintLabels(paintLabelsFlag); > tmpJS.addChangeListener((ChangeListener) changeLisObj); > if (setBoundsFlag == true) { > tmpJS.setBounds(xpos, ypos, width, height); > } > return tmpJS; > } // end of setupJSliderAndGet > > public static JTree setupJTreeAndGet(DefaultMutableTreeNode > rootNode, int selectionMode, Object treeSelLisObj, boolean > setBoundsFlag, int xpos, int ypos, int width, int height) { > JTree tmpJTree = new JTree(rootNode); > tmpJTree.getSelectionModel().setSelectionMode(selectionMode); > tmpJTree.addTreeSelectionListener((TreeSelectionListener) > treeSelLisObj); > if (setBoundsFlag == true) { > tmpJTree.setBounds(xpos, ypos, width, height); > } > return tmpJTree; > } // end of setupJTreeAndGet > > public static JScrollPane setupScrollableJTreeAndGet(JTree jtree, > int xpos, int ypos, int width, int height) { > JScrollPane tmpJSP = new JScrollPane(jtree); > tmpJSP.setBounds(xpos, ypos, width, height); > return tmpJSP; > } // end of setupScrollableJTreeAndGet > > public static JSpinner setupJSpinnerAndGet(SpinnerModel sm, > boolean editableFlag, Object spinnerChangeLisObj, int xpos, int ypos, > int width, int height) { > JSpinner tmpJSPN = new JSpinner(sm); > tmpJSPN.addChangeListener((ChangeListener) spinnerChangeLisObj); > if (editableFlag == false) { > JComponent editor = tmpJSPN.getEditor(); > if (editor instanceof JSpinner.DefaultEditor) { > ((JSpinner.DefaultEditor) > editor).getTextField().setEditable(editableFlag); > } else { > System.out.println("Error: Could not set editableFlag > for JSpinner."); > } > } > tmpJSPN.setBounds(xpos, ypos, width, height); > return tmpJSPN; > } // end of setupJSpinnerAndGet > > public static JColorChooser setupJColorChooserAndGet(Color > initialColor, boolean borderTitleFlag, String borderTitle, Object > colorChooserChangeLisObj, int xpos, int ypos, int width, int height) { > JColorChooser tmpJCC = new JColorChooser(initialColor); > tmpJCC.getSelectionModel().addChangeListener((ChangeListener) > colorChooserChangeLisObj); > if (borderTitleFlag == true) { > tmpJCC.setBorder(BorderFactory.createTitledBorder(borderTitle)); > } > tmpJCC.setBounds(xpos, ypos, width, height); > return tmpJCC; > } // end of setupJColorChooserAndGet > > public static JDialog setupJDialogAndGet(Frame owner, String > title, boolean modal, int width, int height) { > JDialog tmpJD = new JDialog(owner, title, modal); > tmpJD.setSize(width, height); > tmpJD.setLocationRelativeTo(null); > tmpJD.setLayout(null); > tmpJD.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); > return tmpJD; > } // end of setupJDialogAndGet > > public static ArrayList > setupScrollableJDialogAndGetDialogAndPanel(Frame owner, String title, > boolean modal, int dialogWidth, int dialogHeight, int panelWidth, int > panelHeight) { > JDialog tmpJD = new JDialog(owner, title, modal); > tmpJD.setSize(dialogWidth, dialogHeight); > tmpJD.setLocationRelativeTo(null); > tmpJD.setLayout(null); > tmpJD.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); > > JPanel tmpJP = new JPanel(); > tmpJP.setPreferredSize(new Dimension(panelWidth, panelHeight)); > tmpJP.setLayout(null); > > ScrollPane sp = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); > sp.add(tmpJP); > tmpJD.getRootPane().setContentPane(sp); > > ArrayList tmpA = new ArrayList<>(); > tmpA.add((Object) (tmpJD)); > tmpA.add((Object) (tmpJP)); > > return tmpA; > } // end of setupJDialogAndGet > > public static JToggleButton setupJToggleButtonAndGet(String text, > Object itemLisObj, boolean opaque, Color bgcolor, boolean > setBoundsFlag, int xpos, int ypos, int width, int height) { > JToggleButton tmpJTB = new JToggleButton(text); > if (setBoundsFlag == true) { > tmpJTB.setBounds(xpos, ypos, width, height); > } > tmpJTB.addItemListener((ItemListener) itemLisObj); > tmpJTB.setOpaque(opaque); > tmpJTB.setBackground(bgcolor); > return tmpJTB; > } // end of setupJToggleButtonAndGet > > public static JSeparator setupJSeparatorAndGet(int orientation, > Color bgcolor, boolean setBoundsFlag, int xpos, int ypos, int width, > int height) { > JSeparator tmpJS = new JSeparator(orientation); > tmpJS.setBackground(bgcolor); > if (setBoundsFlag == true) { > tmpJS.setBounds(xpos, ypos, width, height); > } > return tmpJS; > } // end of setupJSeparatorAndGet > > public static JMenuBar setupJMenuBarAndGet(Color fgcolor, Color bgcolor) { > JMenuBar tmpJMB = new JMenuBar(); > tmpJMB.setOpaque(true); > tmpJMB.setForeground(fgcolor); > tmpJMB.setBackground(bgcolor); > return tmpJMB; > } // end of setupJMenuBarAndGet > > public static JMenu setupJMenuAndGet(String text, Color fgcolor, > Color bgcolor) { > JMenu tmpJM = new JMenu(text); > tmpJM.setOpaque(true); > tmpJM.setForeground(fgcolor); > tmpJM.setBackground(bgcolor); > return tmpJM; > } // end of setupJMenuAndGet > > public static JMenuItem setupJMenuItemAndGet(String text, Object > actLisObj, KeyStroke k, Color fgcolor, Color bgcolor) { > JMenuItem tmpJMI = new JMenuItem(text); > tmpJMI.setOpaque(true); > tmpJMI.setForeground(fgcolor); > tmpJMI.setBackground(bgcolor); > tmpJMI.setAccelerator(k); > if (actLisObj != null) { > tmpJMI.addActionListener((ActionListener) actLisObj); > } > return tmpJMI; > } // end of setupJMenuItemAndGet > > } // end of SwingLibrary > > ------------------------------------------------------------------------------------------- From amnojeeuw at gmail.com Thu Oct 13 15:22:33 2022 From: amnojeeuw at gmail.com (Amn) Date: Thu, 13 Oct 2022 11:22:33 -0400 Subject: System.getProperty("file.encoding.pkg") == null ??? Message-ID: <0cc4a85e-720e-8e7c-5b08-4dcbdb372b28@gmail.com> The following code: *System.getProperty("file.encoding.pkg");* in my Debian 11 box using Java 17 reports "null", I was expecting something like UTF-x. I did a search on the net in the hope to find some explanation regarding the behaviour of the above code, but to no avail. Can anyone help me understand the behaviour of the above method call? Thanks in advance. -------------- next part -------------- An HTML attachment was scrubbed... URL: From Alan.Bateman at oracle.com Fri Oct 14 10:32:09 2022 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Fri, 14 Oct 2022 11:32:09 +0100 Subject: System.getProperty("file.encoding.pkg") == null ??? In-Reply-To: <0cc4a85e-720e-8e7c-5b08-4dcbdb372b28@gmail.com> References: <0cc4a85e-720e-8e7c-5b08-4dcbdb372b28@gmail.com> Message-ID: <4aa82167-725f-5943-328c-708cef1b0b92@oracle.com> On 13/10/2022 17:22, Amn wrote: > > The following code: > *System.getProperty("file.encoding.pkg");* > in my Debian 11 box using Java 17 reports "null", I was expecting > something like UTF-x. > I did a search on the net in the hope to find some explanation > regarding the behaviour of the above code, but to no avail. Can anyone > help me understand the behaviour of the above method call? > I suspect you are looking for file.encoding rather than file.encoding.pkg.? I think the undocumented system property file.encoding.pkg dates from the sun.io converters where its value was "sun.io" rather then a charset name. All of this has been obsolete since JDK 1.4 (2004) so I suspect it's just a typo in the name of the system property. If there are issues in this area then it's best to follow-up on core-libs-dev, not here. -Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From larry.cable at oracle.com Tue Oct 18 00:04:28 2022 From: larry.cable at oracle.com (Laurence Cable) Date: Mon, 17 Oct 2022 17:04:28 -0700 Subject: Any interest in WatchService based on MacOS FSEvents? In-Reply-To: References: Message-ID: what came of this? On 8/29/22 11:50 PM, Maxim Kartashev wrote: > WatchService on MacOS is still implemented by the generic > PollingWatchService, which continuously re-scans the directory > consuming CPU, introduces large latencies to the generated > WatchEvent's, and misses changes that occur faster than the re-scan > interval. At the same time, there are two technologies available on > the platform to receive the necessary information from the OS similar > to what is available on Windows and Linux: Kernel Queues and File > System Events, the latter being more suitable for implementing the > WatchServie functionality. > > There are several stand-alone implementations out there that utilize > one or the other (or even both), which suggests that demand exists for > WatchService on MacOS to be more responsive and less resource-hungry. > > If the community is interested in getting this functionality in > OpenJDK proper, I'd be happy to contribute code that was developed, > tested, and used at JetBrains for around half a year. It is based on > FSEvents, supports the FILE_TREE modifier (recursive directory watch), > and does not do any excessive I/O except the necessary minimum. > > References > * WatchService interface > ? - > https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/nio/file/WatchService.html > * PollingWatchService source code > ? - > https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java > * File System Events > ? - > https://developer.apple.com/documentation/coreservices/file_system_events?language=objc > * Kernel Queues > ? - > https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/FSEvents_ProgGuide/KernelQueues/KernelQueues.html From Alan.Bateman at oracle.com Tue Oct 18 06:26:11 2022 From: Alan.Bateman at oracle.com (Alan Bateman) Date: Tue, 18 Oct 2022 07:26:11 +0100 Subject: Any interest in WatchService based on MacOS FSEvents? In-Reply-To: References: Message-ID: <4c59a571-91c4-3a51-da86-5a28d90d3d31@oracle.com> On 18/10/2022 02:04, Laurence Cable wrote: > what came of this? In progress/review via PR10140. -Alan.