From e72f9d602fa85efcbfc72f15582edf93d4c8cd86 Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Tue, 20 Jan 2026 19:51:50 +0100 Subject: [PATCH] backup config --- .../cz/kamma/kfmanager/config/AppConfig.java | 60 ++++++++++ .../kamma/kfmanager/ui/FileChooserUtils.java | 73 ++++++++++++ .../cz/kamma/kfmanager/ui/MainWindow.java | 4 +- .../cz/kamma/kfmanager/ui/SettingsDialog.java | 111 +++++++++++++++++- 4 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 src/main/java/cz/kamma/kfmanager/ui/FileChooserUtils.java diff --git a/src/main/java/cz/kamma/kfmanager/config/AppConfig.java b/src/main/java/cz/kamma/kfmanager/config/AppConfig.java index 80d4511..3bd2a26 100644 --- a/src/main/java/cz/kamma/kfmanager/config/AppConfig.java +++ b/src/main/java/cz/kamma/kfmanager/config/AppConfig.java @@ -51,6 +51,25 @@ public class AppConfig { System.err.println("Could not save configuration: " + e.getMessage()); } } + + /** + * Export current configuration to a specified file + */ + public void exportConfig(File targetFile) throws IOException { + try (FileOutputStream fos = new FileOutputStream(targetFile)) { + properties.store(fos, "KF File Manager Exported Configuration"); + } + } + + /** + * Import configuration from a specified file + */ + public void importConfig(File sourceFile) throws IOException { + try (FileInputStream fis = new FileInputStream(sourceFile)) { + properties.load(fis); + } + saveConfig(); // Persist imported settings + } // Getters and setters for individual configuration values @@ -126,6 +145,39 @@ public class AppConfig { properties.setProperty("fileeditor.height", String.valueOf(height)); } + public String getLastFileChooserDirectory() { + return properties.getProperty("filechooser.last.dir", System.getProperty("user.home")); + } + + public void setLastFileChooserDirectory(String path) { + if (path != null) { + properties.setProperty("filechooser.last.dir", path); + } + } + + public int getFileChooserX() { + return Integer.parseInt(properties.getProperty("filechooser.x", "-1")); + } + + public int getFileChooserY() { + return Integer.parseInt(properties.getProperty("filechooser.y", "-1")); + } + + public int getFileChooserWidth() { + return Integer.parseInt(properties.getProperty("filechooser.width", "600")); + } + + public int getFileChooserHeight() { + return Integer.parseInt(properties.getProperty("filechooser.height", "450")); + } + + public void setFileChooserBounds(int x, int y, int width, int height) { + properties.setProperty("filechooser.x", String.valueOf(x)); + properties.setProperty("filechooser.y", String.valueOf(y)); + properties.setProperty("filechooser.width", String.valueOf(width)); + properties.setProperty("filechooser.height", String.valueOf(height)); + } + public String getActivePanel() { return properties.getProperty("active.panel", "left"); } @@ -744,4 +796,12 @@ public class AppConfig { properties.setProperty("toolbar.shortcut." + i + ".workingDir", s.workingDir != null ? s.workingDir : ""); } } + + public String getMigrationPath() { + return properties.getProperty("migration.path", ""); + } + + public void setMigrationPath(String path) { + properties.setProperty("migration.path", path); + } } diff --git a/src/main/java/cz/kamma/kfmanager/ui/FileChooserUtils.java b/src/main/java/cz/kamma/kfmanager/ui/FileChooserUtils.java new file mode 100644 index 0000000..c8c9d04 --- /dev/null +++ b/src/main/java/cz/kamma/kfmanager/ui/FileChooserUtils.java @@ -0,0 +1,73 @@ +package cz.kamma.kfmanager.ui; + +import cz.kamma.kfmanager.config.AppConfig; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.io.File; + +public class FileChooserUtils { + + public static int showOpenDialog(Component parent, JFileChooser chooser, AppConfig config) { + return showDialog(parent, chooser, config, true); + } + + public static int showSaveDialog(Component parent, JFileChooser chooser, AppConfig config) { + return showDialog(parent, chooser, config, false); + } + + private static int showDialog(Component parent, JFileChooser chooser, AppConfig config, boolean open) { + // Set initial directory only if not already set or points to home + File current = chooser.getCurrentDirectory(); + if (current == null || current.getAbsolutePath().equals(System.getProperty("user.home"))) { + String lastDir = config.getLastFileChooserDirectory(); + if (lastDir != null && !lastDir.isEmpty()) { + File dir = new File(lastDir); + if (dir.exists() && dir.isDirectory()) { + chooser.setCurrentDirectory(dir); + } + } + } + + final JDialog[] dialogRef = {null}; + HierarchyListener hierarchyListener = new HierarchyListener() { + @Override + public void hierarchyChanged(HierarchyEvent e) { + if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && chooser.isShowing()) { + Window window = SwingUtilities.getWindowAncestor(chooser); + if (window instanceof JDialog) { + dialogRef[0] = (JDialog) window; + // Restore size and position + int w = config.getFileChooserWidth(); + int h = config.getFileChooserHeight(); + if (w > 0 && h > 0) dialogRef[0].setSize(w, h); + + int x = config.getFileChooserX(); + int y = config.getFileChooserY(); + if (x >= 0 && y >= 0) { + dialogRef[0].setLocation(x, y); + } else { + dialogRef[0].setLocationRelativeTo(parent); + } + } + } + } + }; + + chooser.addHierarchyListener(hierarchyListener); + int result = open ? chooser.showOpenDialog(parent) : chooser.showSaveDialog(parent); + chooser.removeHierarchyListener(hierarchyListener); + + if (dialogRef[0] != null) { + config.setFileChooserBounds(dialogRef[0].getX(), dialogRef[0].getY(), dialogRef[0].getWidth(), dialogRef[0].getHeight()); + } + + File currentDir = chooser.getCurrentDirectory(); + if (currentDir != null) { + config.setLastFileChooserDirectory(currentDir.getAbsolutePath()); + } + config.saveConfig(); + + return result; + } +} diff --git a/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java b/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java index 6dc5809..b71e75c 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java +++ b/src/main/java/cz/kamma/kfmanager/ui/MainWindow.java @@ -608,7 +608,7 @@ public class MainWindow extends JFrame { browseWorkDir.addActionListener(e -> { JFileChooser chooser = new JFileChooser(workingDirField.getText()); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + if (FileChooserUtils.showOpenDialog(this, chooser, config) == JFileChooser.APPROVE_OPTION) { workingDirField.setText(chooser.getSelectedFile().getAbsolutePath()); } }); @@ -630,7 +630,7 @@ public class MainWindow extends JFrame { } JFileChooser chooser = new JFileChooser(startPath); - if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + if (FileChooserUtils.showOpenDialog(this, chooser, config) == JFileChooser.APPROVE_OPTION) { iconField.setText(chooser.getSelectedFile().getAbsolutePath()); } }); diff --git a/src/main/java/cz/kamma/kfmanager/ui/SettingsDialog.java b/src/main/java/cz/kamma/kfmanager/ui/SettingsDialog.java index d19dec2..68df6b0 100644 --- a/src/main/java/cz/kamma/kfmanager/ui/SettingsDialog.java +++ b/src/main/java/cz/kamma/kfmanager/ui/SettingsDialog.java @@ -74,6 +74,7 @@ public class SettingsDialog extends JDialog { model.addElement("Sorting"); model.addElement("Toolbar"); model.addElement("Associations"); + model.addElement("Import/Export"); categoryList = new JList<>(model); categoryList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); categoryList.setSelectedIndex(0); @@ -88,6 +89,7 @@ public class SettingsDialog extends JDialog { cards.add(buildSortingPanel(), "Sorting"); cards.add(buildToolbarPanel(), "Toolbar"); cards.add(buildAssociationsPanel(), "Associations"); + cards.add(buildImportExportPanel(), "Import/Export"); categoryList.addListSelectionListener(e -> { if (!e.getValueIsAdjusting()) { @@ -393,7 +395,7 @@ public class SettingsDialog extends JDialog { File f = new File(externalEditorField.getText()); if (f.exists()) fc.setSelectedFile(f); } - int r = fc.showOpenDialog(this); + int r = FileChooserUtils.showOpenDialog(this, fc, config); if (r == JFileChooser.APPROVE_OPTION) { File sel = fc.getSelectedFile(); externalEditorField.setText(sel.getAbsolutePath()); @@ -617,6 +619,113 @@ public class SettingsDialog extends JDialog { return p; } + private JPanel buildImportExportPanel() { + JPanel p = new JPanel(new GridBagLayout()); + p.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = 3; + gbc.weightx = 1.0; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(0, 0, 5, 0); + + p.add(new JLabel("Migration File Path:"), gbc); + + gbc.gridy++; + gbc.gridwidth = 1; + gbc.insets = new Insets(0, 0, 15, 5); + JTextField pathField = new JTextField(config.getMigrationPath()); + p.add(pathField, gbc); + + gbc.gridx = 1; + gbc.weightx = 0; + JButton browseBtn = new JButton("Browse..."); + browseBtn.addActionListener(e -> { + JFileChooser chooser = new JFileChooser(); + String currentPath = pathField.getText(); + if (!currentPath.isEmpty()) { + File f = new File(currentPath); + if (f.exists()) { + chooser.setSelectedFile(f); + } else { + chooser.setSelectedFile(new File(f.getParentFile(), "kfmanager.backup")); + } + } else { + chooser.setSelectedFile(new File("kfmanager.backup")); + } + if (FileChooserUtils.showOpenDialog(this, chooser, config) == JFileChooser.APPROVE_OPTION) { + String path = chooser.getSelectedFile().getAbsolutePath(); + pathField.setText(path); + config.setMigrationPath(path); + config.saveConfig(); + } + }); + p.add(browseBtn, gbc); + + gbc.gridx = 0; + gbc.gridy++; + gbc.gridwidth = 1; + gbc.weightx = 0.5; + JButton exportBtn = new JButton("Export"); + exportBtn.addActionListener(e -> { + String path = pathField.getText(); + if (path.isEmpty()) { + JOptionPane.showMessageDialog(this, "Please specify a file path first.", "Warning", JOptionPane.WARNING_MESSAGE); + return; + } + try { + config.exportConfig(new File(path)); + JOptionPane.showMessageDialog(this, "Configuration exported successfully.", "Success", JOptionPane.INFORMATION_MESSAGE); + config.setMigrationPath(path); + config.saveConfig(); + } catch (Exception ex) { + JOptionPane.showMessageDialog(this, "Error exporting configuration: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + }); + p.add(exportBtn, gbc); + + gbc.gridx = 1; + JButton importBtn = new JButton("Import"); + importBtn.addActionListener(e -> { + String path = pathField.getText(); + if (path.isEmpty()) { + JOptionPane.showMessageDialog(this, "Please specify a file path first.", "Warning", JOptionPane.WARNING_MESSAGE); + return; + } + File source = new File(path); + if (!source.exists()) { + JOptionPane.showMessageDialog(this, "Specified file does not exist.", "Error", JOptionPane.ERROR_MESSAGE); + return; + } + int res = JOptionPane.showConfirmDialog(this, + "Importing configuration will overwrite current settings and close the dialog. Continue?", + "Import", + JOptionPane.YES_NO_OPTION); + if (res == JOptionPane.YES_OPTION) { + try { + config.importConfig(source); + config.setMigrationPath(path); + config.saveConfig(); + if (onChange != null) onChange.run(); + dispose(); + } catch (Exception ex) { + JOptionPane.showMessageDialog(this, "Error importing configuration: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); + } + } + }); + p.add(importBtn, gbc); + + // Add spacer + gbc.gridx = 0; + gbc.gridy++; + gbc.gridwidth = 3; + gbc.weighty = 1.0; + p.add(new JPanel(), gbc); + + return p; + } + private static String capitalize(String s) { if (s == null || s.isEmpty()) return s; return s.substring(0,1).toUpperCase() + s.substring(1).toLowerCase();