backup config

This commit is contained in:
Radek Davidek 2026-01-20 19:51:50 +01:00
parent 4624e9f8d4
commit e72f9d602f
4 changed files with 245 additions and 3 deletions

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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());
}
});

View File

@ -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();