added dir synchronization feature, complete translation to english
This commit is contained in:
parent
61b6269a5e
commit
413487f25c
44
README.md
44
README.md
@ -1,47 +1,51 @@
|
|||||||
# KF File Manager
|
# KF File Manager
|
||||||
|
|
||||||
Dvoupanelový souborový manažer podobný Total Commander, vytvořený v Java 11.
|
A two-panel file manager similar to Total Commander, built with Java 11.
|
||||||
|
|
||||||
## Funkce
|
## Features
|
||||||
|
|
||||||
- **Two panels** for browsing files and directories
|
- **Two panels** for browsing files and directories
|
||||||
- **Copying** files and directories (F5)
|
- **Copying** files and directories (F5)
|
||||||
- **Moving** files and directories (F6)
|
- **Moving** files and directories (F6)
|
||||||
|
- **Rename** (Shift+F6)
|
||||||
- **Create directory** (F7)
|
- **Create directory** (F7)
|
||||||
- **Delete** files and directories (F8)
|
- **Delete** files and directories (F8)
|
||||||
- **Přejmenování** (Shift+F6)
|
- **Search** for files (Ctrl+F)
|
||||||
- **Vyhledávání** souborů (Ctrl+F)
|
- **Sync Directories** - side-by-side folder comparison and synchronization
|
||||||
- **Přepínání** mezi panely (TAB)
|
- **Toggle** between panels (TAB)
|
||||||
- **Navigation** - double-click or Enter to open a directory
|
- **Navigation** - double-click or Enter to open a directory
|
||||||
- **Zobrazení** velikosti souborů, data modifikace
|
- **View** file sizes, modification dates, and attributes
|
||||||
|
|
||||||
## Spuštění
|
## Running
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mvn clean compile
|
mvn clean compile
|
||||||
mvn exec:java -Dexec.mainClass="cz.kamma.kfmanager.MainApp"
|
mvn exec:java -Dexec.mainClass="cz.kamma.kfmanager.MainApp"
|
||||||
```
|
```
|
||||||
|
|
||||||
Nebo vytvoření JAR souboru:
|
Or build a JAR file:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mvn clean package
|
mvn clean package
|
||||||
java -jar target/kf-manager-1.0-SNAPSHOT.jar
|
java -jar target/kf-manager-1.0-SNAPSHOT.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
## Klávesové zkratky
|
## Keyboard Shortcuts
|
||||||
|
|
||||||
- **F5** - Kopírovat
|
- **F3** - View file (internal viewer)
|
||||||
- **F6** - Přesunout
|
- **F4** - Edit file
|
||||||
- **Shift+F6** - Přejmenovat
|
- **F5** - Copy
|
||||||
- **F7** - Nový adresář
|
- **F6** - Move
|
||||||
- **F8** - Smazat
|
- **Shift+F6** - Rename
|
||||||
- **TAB** - Přepnout mezi panely
|
- **F7** - New directory
|
||||||
- **Ctrl+F** - Vyhledat soubory
|
- **F8** - Delete
|
||||||
- **Enter** - Otevřít adresář
|
- **TAB** - Toggle between panels
|
||||||
- **Backspace** - Nadřazený adresář
|
- **Ctrl+F** - Search files
|
||||||
|
- **Ctrl+Y** - Sync directories
|
||||||
|
- **Enter** - Open directory
|
||||||
|
- **Backspace** - Parent directory
|
||||||
|
|
||||||
## Požadavky
|
## Requirements
|
||||||
|
|
||||||
- Java 11 nebo vyšší
|
- Java 11 or higher
|
||||||
- Maven 3.6+
|
- Maven 3.6+
|
||||||
|
|||||||
@ -7,5 +7,5 @@ Exec=java -jar /home/kamma/projects/kf-manager/target/kf-manager-1.0-SNAPSHOT-ja
|
|||||||
Name=KF File Manager
|
Name=KF File Manager
|
||||||
Icon=/home/kamma/projects/kf-manager/src/main/resources/icon.png
|
Icon=/home/kamma/projects/kf-manager/src/main/resources/icon.png
|
||||||
StartupWMClass=cz-kamma-kfmanager-MainApp
|
StartupWMClass=cz-kamma-kfmanager-MainApp
|
||||||
Comment=Dvoupanelový souborový manažer pro Linux
|
Comment=Two-panel file manager for Linux
|
||||||
Categories=Utility;System;
|
Categories=Utility;System;
|
||||||
|
|||||||
@ -24,7 +24,7 @@ public class DriveSelector extends JDialog {
|
|||||||
setLayout(new BorderLayout(10, 10));
|
setLayout(new BorderLayout(10, 10));
|
||||||
((JComponent) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
((JComponent) getContentPane()).setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||||
|
|
||||||
// Získat seznam dostupných disků
|
// Get list of available drives
|
||||||
File[] roots = File.listRoots();
|
File[] roots = File.listRoots();
|
||||||
List<DriveInfo> drives = new ArrayList<>();
|
List<DriveInfo> drives = new ArrayList<>();
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ public class DriveSelector extends JDialog {
|
|||||||
drives.add(new DriveInfo(root));
|
drives.add(new DriveInfo(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seznam disků
|
// List of drives
|
||||||
JList<DriveInfo> driveList = new JList<>(drives.toArray(new DriveInfo[0]));
|
JList<DriveInfo> driveList = new JList<>(drives.toArray(new DriveInfo[0]));
|
||||||
driveList.setFont(new Font("Monospaced", Font.PLAIN, 14));
|
driveList.setFont(new Font("Monospaced", Font.PLAIN, 14));
|
||||||
driveList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
driveList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
@ -53,7 +53,7 @@ public class DriveSelector extends JDialog {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Double-click pro výběr
|
// Double-click to select
|
||||||
driveList.addMouseListener(new java.awt.event.MouseAdapter() {
|
driveList.addMouseListener(new java.awt.event.MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked(java.awt.event.MouseEvent e) {
|
public void mouseClicked(java.awt.event.MouseEvent e) {
|
||||||
@ -67,7 +67,7 @@ public class DriveSelector extends JDialog {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enter pro výběr
|
// Enter to select
|
||||||
driveList.addKeyListener(new java.awt.event.KeyAdapter() {
|
driveList.addKeyListener(new java.awt.event.KeyAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void keyPressed(java.awt.event.KeyEvent e) {
|
public void keyPressed(java.awt.event.KeyEvent e) {
|
||||||
@ -84,7 +84,7 @@ public class DriveSelector extends JDialog {
|
|||||||
JScrollPane scrollPane = new JScrollPane(driveList);
|
JScrollPane scrollPane = new JScrollPane(driveList);
|
||||||
add(scrollPane, BorderLayout.CENTER);
|
add(scrollPane, BorderLayout.CENTER);
|
||||||
|
|
||||||
// Panel s tlačítky
|
// Panel with buttons
|
||||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||||
|
|
||||||
JButton okButton = new JButton("OK");
|
JButton okButton = new JButton("OK");
|
||||||
@ -109,7 +109,7 @@ public class DriveSelector extends JDialog {
|
|||||||
|
|
||||||
add(buttonPanel, BorderLayout.SOUTH);
|
add(buttonPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
// Automaticky vybrat první disk
|
// Automatically select the first drive
|
||||||
if (drives.size() > 0) {
|
if (drives.size() > 0) {
|
||||||
driveList.setSelectedIndex(0);
|
driveList.setSelectedIndex(0);
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ public class DriveSelector extends JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pomocná třída pro informace o disku
|
* Helper class for drive information
|
||||||
*/
|
*/
|
||||||
private static class DriveInfo {
|
private static class DriveInfo {
|
||||||
private final File root;
|
private final File root;
|
||||||
|
|||||||
@ -61,7 +61,7 @@ public class FileEditor extends JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public FileEditor(Window parent, File file, String virtualPath, AppConfig config, boolean readOnly) {
|
public FileEditor(Window parent, File file, String virtualPath, AppConfig config, boolean readOnly) {
|
||||||
super(parent, (readOnly ? "Prohlížeč - " : "Editor - ") + (virtualPath != null ? virtualPath.substring(virtualPath.lastIndexOf(File.separator) + 1) : file.getName()), ModalityType.MODELESS);
|
super(parent, (readOnly ? "Viewer - " : "Editor - ") + (virtualPath != null ? virtualPath.substring(virtualPath.lastIndexOf(File.separator) + 1) : file.getName()), ModalityType.MODELESS);
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.virtualPath = virtualPath;
|
this.virtualPath = virtualPath;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
@ -101,10 +101,10 @@ public class FileEditor extends JDialog {
|
|||||||
searchField = new JTextField(20);
|
searchField = new JTextField(20);
|
||||||
searchField.addActionListener(e -> findNext());
|
searchField.addActionListener(e -> findNext());
|
||||||
|
|
||||||
JButton nextBtn = new JButton("Dále");
|
JButton nextBtn = new JButton("Next");
|
||||||
nextBtn.addActionListener(e -> findNext());
|
nextBtn.addActionListener(e -> findNext());
|
||||||
|
|
||||||
JButton prevBtn = new JButton("Zpět");
|
JButton prevBtn = new JButton("Back");
|
||||||
prevBtn.addActionListener(e -> findPrevious());
|
prevBtn.addActionListener(e -> findPrevious());
|
||||||
|
|
||||||
JButton closeBtn = new JButton("X");
|
JButton closeBtn = new JButton("X");
|
||||||
@ -113,7 +113,7 @@ public class FileEditor extends JDialog {
|
|||||||
|
|
||||||
searchStatusLabel = new JLabel("");
|
searchStatusLabel = new JLabel("");
|
||||||
|
|
||||||
searchPanel.add(new JLabel("Hledat:"));
|
searchPanel.add(new JLabel("Search:"));
|
||||||
searchPanel.add(searchField);
|
searchPanel.add(searchField);
|
||||||
searchPanel.add(nextBtn);
|
searchPanel.add(nextBtn);
|
||||||
searchPanel.add(prevBtn);
|
searchPanel.add(prevBtn);
|
||||||
@ -199,7 +199,7 @@ public class FileEditor extends JDialog {
|
|||||||
} catch (Exception ignore) {}
|
} catch (Exception ignore) {}
|
||||||
searchStatusLabel.setText("");
|
searchStatusLabel.setText("");
|
||||||
} else {
|
} else {
|
||||||
searchStatusLabel.setText("Nenalezeno");
|
searchStatusLabel.setText("Not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ public class FileEditor extends JDialog {
|
|||||||
} catch (Exception ignore) {}
|
} catch (Exception ignore) {}
|
||||||
searchStatusLabel.setText("");
|
searchStatusLabel.setText("");
|
||||||
} else {
|
} else {
|
||||||
searchStatusLabel.setText("Nenalezeno");
|
searchStatusLabel.setText("Not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +259,7 @@ public class FileEditor extends JDialog {
|
|||||||
// Menu bar
|
// Menu bar
|
||||||
createMenuBar();
|
createMenuBar();
|
||||||
|
|
||||||
// Textová oblast (editable nebo read-only)
|
// Text area (editable or read-only)
|
||||||
textArea = new JTextArea();
|
textArea = new JTextArea();
|
||||||
textArea.setFont(config.getEditorFont());
|
textArea.setFont(config.getEditorFont());
|
||||||
textArea.setTabSize(4);
|
textArea.setTabSize(4);
|
||||||
@ -271,7 +271,7 @@ public class FileEditor extends JDialog {
|
|||||||
undoManager.addEdit(e.getEdit());
|
undoManager.addEdit(e.getEdit());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sledování změn (pouze pro editovatelný režim)
|
// Track changes (editable mode only)
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
textArea.getDocument().addDocumentListener(new javax.swing.event.DocumentListener() {
|
textArea.getDocument().addDocumentListener(new javax.swing.event.DocumentListener() {
|
||||||
public void insertUpdate(javax.swing.event.DocumentEvent e) { setModified(true); }
|
public void insertUpdate(javax.swing.event.DocumentEvent e) { setModified(true); }
|
||||||
@ -295,10 +295,10 @@ public class FileEditor extends JDialog {
|
|||||||
// Apply appearance settings (colors, contrast caret etc)
|
// Apply appearance settings (colors, contrast caret etc)
|
||||||
applyAppearance();
|
applyAppearance();
|
||||||
|
|
||||||
// Kontextové menu pro clipboard
|
// Context menu for clipboard
|
||||||
setupContextMenu();
|
setupContextMenu();
|
||||||
|
|
||||||
// Klávesové zkratky
|
// Keyboard shortcuts
|
||||||
setupKeyBindings();
|
setupKeyBindings();
|
||||||
|
|
||||||
// Caret listener to update position and selection info
|
// Caret listener to update position and selection info
|
||||||
@ -314,11 +314,11 @@ public class FileEditor extends JDialog {
|
|||||||
private void setupContextMenu() {
|
private void setupContextMenu() {
|
||||||
JPopupMenu popup = new JPopupMenu();
|
JPopupMenu popup = new JPopupMenu();
|
||||||
|
|
||||||
JMenuItem undoItem = new JMenuItem("Zpět");
|
JMenuItem undoItem = new JMenuItem("Undo");
|
||||||
undoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK));
|
undoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK));
|
||||||
undoItem.addActionListener(e -> { if (undoManager.canUndo()) undoManager.undo(); });
|
undoItem.addActionListener(e -> { if (undoManager.canUndo()) undoManager.undo(); });
|
||||||
|
|
||||||
JMenuItem redoItem = new JMenuItem("Znovu");
|
JMenuItem redoItem = new JMenuItem("Redo");
|
||||||
redoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK));
|
redoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK));
|
||||||
redoItem.addActionListener(e -> { if (undoManager.canRedo()) undoManager.redo(); });
|
redoItem.addActionListener(e -> { if (undoManager.canRedo()) undoManager.redo(); });
|
||||||
|
|
||||||
@ -327,15 +327,15 @@ public class FileEditor extends JDialog {
|
|||||||
popup.addSeparator();
|
popup.addSeparator();
|
||||||
|
|
||||||
JMenuItem cutItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CutAction());
|
JMenuItem cutItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CutAction());
|
||||||
cutItem.setText("Vyjmout");
|
cutItem.setText("Cut");
|
||||||
cutItem.setMnemonic(KeyEvent.VK_X);
|
cutItem.setMnemonic(KeyEvent.VK_X);
|
||||||
|
|
||||||
JMenuItem copyItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CopyAction());
|
JMenuItem copyItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CopyAction());
|
||||||
copyItem.setText("Kopírovat");
|
copyItem.setText("Copy");
|
||||||
copyItem.setMnemonic(KeyEvent.VK_C);
|
copyItem.setMnemonic(KeyEvent.VK_C);
|
||||||
|
|
||||||
JMenuItem pasteItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.PasteAction());
|
JMenuItem pasteItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.PasteAction());
|
||||||
pasteItem.setText("Vložit");
|
pasteItem.setText("Paste");
|
||||||
pasteItem.setMnemonic(KeyEvent.VK_V);
|
pasteItem.setMnemonic(KeyEvent.VK_V);
|
||||||
|
|
||||||
popup.add(cutItem);
|
popup.add(cutItem);
|
||||||
@ -343,7 +343,7 @@ public class FileEditor extends JDialog {
|
|||||||
popup.add(pasteItem);
|
popup.add(pasteItem);
|
||||||
popup.addSeparator();
|
popup.addSeparator();
|
||||||
|
|
||||||
JMenuItem selectAllItem = new JMenuItem("Vybrat vše");
|
JMenuItem selectAllItem = new JMenuItem("Select All");
|
||||||
selectAllItem.setMnemonic(KeyEvent.VK_A);
|
selectAllItem.setMnemonic(KeyEvent.VK_A);
|
||||||
selectAllItem.addActionListener(e -> textArea.selectAll());
|
selectAllItem.addActionListener(e -> textArea.selectAll());
|
||||||
popup.add(selectAllItem);
|
popup.add(selectAllItem);
|
||||||
@ -428,9 +428,9 @@ public class FileEditor extends JDialog {
|
|||||||
JMenu fileMenu = new JMenu("File");
|
JMenu fileMenu = new JMenu("File");
|
||||||
fileMenu.setMnemonic(java.awt.event.KeyEvent.VK_S);
|
fileMenu.setMnemonic(java.awt.event.KeyEvent.VK_S);
|
||||||
|
|
||||||
// Uložit - pouze v editovacím režimu
|
// Save - editable mode only
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
JMenuItem saveItem = new JMenuItem("Uložit");
|
JMenuItem saveItem = new JMenuItem("Save");
|
||||||
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
|
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
|
||||||
saveItem.addActionListener(e -> saveFile());
|
saveItem.addActionListener(e -> saveFile());
|
||||||
fileMenu.add(saveItem);
|
fileMenu.add(saveItem);
|
||||||
@ -438,23 +438,23 @@ public class FileEditor extends JDialog {
|
|||||||
fileMenu.addSeparator();
|
fileMenu.addSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
JMenuItem closeItem = new JMenuItem("Zavřít");
|
JMenuItem closeItem = new JMenuItem("Close");
|
||||||
closeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
|
closeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
|
||||||
closeItem.addActionListener(e -> closeEditor());
|
closeItem.addActionListener(e -> closeEditor());
|
||||||
fileMenu.add(closeItem);
|
fileMenu.add(closeItem);
|
||||||
|
|
||||||
menuBar.add(fileMenu);
|
menuBar.add(fileMenu);
|
||||||
|
|
||||||
// Menu Edit
|
// Edit Menu
|
||||||
JMenu editMenu = new JMenu("Edit");
|
JMenu editMenu = new JMenu("Edit");
|
||||||
editMenu.setMnemonic(java.awt.event.KeyEvent.VK_E);
|
editMenu.setMnemonic(java.awt.event.KeyEvent.VK_E);
|
||||||
|
|
||||||
JMenuItem undoItem = new JMenuItem("Zpět");
|
JMenuItem undoItem = new JMenuItem("Undo");
|
||||||
undoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK));
|
undoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK));
|
||||||
undoItem.addActionListener(e -> { if (undoManager.canUndo()) undoManager.undo(); });
|
undoItem.addActionListener(e -> { if (undoManager.canUndo()) undoManager.undo(); });
|
||||||
editMenu.add(undoItem);
|
editMenu.add(undoItem);
|
||||||
|
|
||||||
JMenuItem redoItem = new JMenuItem("Znovu");
|
JMenuItem redoItem = new JMenuItem("Redo");
|
||||||
redoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK));
|
redoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK));
|
||||||
redoItem.addActionListener(e -> { if (undoManager.canRedo()) undoManager.redo(); });
|
redoItem.addActionListener(e -> { if (undoManager.canRedo()) undoManager.redo(); });
|
||||||
editMenu.add(redoItem);
|
editMenu.add(redoItem);
|
||||||
@ -462,35 +462,35 @@ public class FileEditor extends JDialog {
|
|||||||
editMenu.addSeparator();
|
editMenu.addSeparator();
|
||||||
|
|
||||||
JMenuItem cutItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CutAction());
|
JMenuItem cutItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CutAction());
|
||||||
cutItem.setText("Vyjmout");
|
cutItem.setText("Cut");
|
||||||
cutItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK));
|
cutItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK));
|
||||||
editMenu.add(cutItem);
|
editMenu.add(cutItem);
|
||||||
|
|
||||||
JMenuItem copyItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CopyAction());
|
JMenuItem copyItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CopyAction());
|
||||||
copyItem.setText("Kopírovat");
|
copyItem.setText("Copy");
|
||||||
copyItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK));
|
copyItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK));
|
||||||
editMenu.add(copyItem);
|
editMenu.add(copyItem);
|
||||||
|
|
||||||
JMenuItem pasteItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.PasteAction());
|
JMenuItem pasteItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.PasteAction());
|
||||||
pasteItem.setText("Vložit");
|
pasteItem.setText("Paste");
|
||||||
pasteItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK));
|
pasteItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK));
|
||||||
editMenu.add(pasteItem);
|
editMenu.add(pasteItem);
|
||||||
|
|
||||||
editMenu.addSeparator();
|
editMenu.addSeparator();
|
||||||
|
|
||||||
JMenuItem selectAllItem = new JMenuItem("Vybrat vše");
|
JMenuItem selectAllItem = new JMenuItem("Select All");
|
||||||
selectAllItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK));
|
selectAllItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK));
|
||||||
selectAllItem.addActionListener(e -> textArea.selectAll());
|
selectAllItem.addActionListener(e -> textArea.selectAll());
|
||||||
editMenu.add(selectAllItem);
|
editMenu.add(selectAllItem);
|
||||||
|
|
||||||
editMenu.addSeparator();
|
editMenu.addSeparator();
|
||||||
|
|
||||||
JMenuItem findItem = new JMenuItem("Hledat...");
|
JMenuItem findItem = new JMenuItem("Search...");
|
||||||
findItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK));
|
findItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK));
|
||||||
findItem.addActionListener(e -> showSearchPanel(true));
|
findItem.addActionListener(e -> showSearchPanel(true));
|
||||||
editMenu.add(findItem);
|
editMenu.add(findItem);
|
||||||
|
|
||||||
JMenuItem findNextItem = new JMenuItem("Hledat další");
|
JMenuItem findNextItem = new JMenuItem("Find Next");
|
||||||
findNextItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0));
|
findNextItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0));
|
||||||
findNextItem.addActionListener(e -> findNext());
|
findNextItem.addActionListener(e -> findNext());
|
||||||
editMenu.add(findNextItem);
|
editMenu.add(findNextItem);
|
||||||
@ -511,8 +511,8 @@ public class FileEditor extends JDialog {
|
|||||||
|
|
||||||
menuBar.add(editMenu);
|
menuBar.add(editMenu);
|
||||||
|
|
||||||
// Menu Nastavení
|
// Settings Menu
|
||||||
JMenu settingsMenu = new JMenu("Nastavení");
|
JMenu settingsMenu = new JMenu("Settings");
|
||||||
settingsMenu.setMnemonic(java.awt.event.KeyEvent.VK_N);
|
settingsMenu.setMnemonic(java.awt.event.KeyEvent.VK_N);
|
||||||
|
|
||||||
JMenuItem fontItem = new JMenuItem("Font...");
|
JMenuItem fontItem = new JMenuItem("Font...");
|
||||||
@ -556,14 +556,14 @@ public class FileEditor extends JDialog {
|
|||||||
private void setupKeyBindings() {
|
private void setupKeyBindings() {
|
||||||
JRootPane rootPane = getRootPane();
|
JRootPane rootPane = getRootPane();
|
||||||
|
|
||||||
// F2 - Uložit (pouze v editovacím režimu)
|
// F2 - Save (editable mode only)
|
||||||
if (!readOnly) {
|
if (!readOnly) {
|
||||||
rootPane.registerKeyboardAction(e -> saveFile(),
|
rootPane.registerKeyboardAction(e -> saveFile(),
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0),
|
KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0),
|
||||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ESC - Zavřít view
|
// ESC - Close view
|
||||||
rootPane.registerKeyboardAction(e -> closeEditor(),
|
rootPane.registerKeyboardAction(e -> closeEditor(),
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
||||||
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
@ -626,7 +626,7 @@ public class FileEditor extends JDialog {
|
|||||||
if (undoManager.canRedo()) undoManager.redo();
|
if (undoManager.canRedo()) undoManager.redo();
|
||||||
}, KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
}, KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
|
|
||||||
// Doprava/Doleva a Mezerník pro listování obrázků
|
// Right/Left arrow and Space for image cycling
|
||||||
rootPane.registerKeyboardAction(e -> {
|
rootPane.registerKeyboardAction(e -> {
|
||||||
if (isImageFile(file)) nextImage();
|
if (isImageFile(file)) nextImage();
|
||||||
}, KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
}, KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
@ -644,7 +644,7 @@ public class FileEditor extends JDialog {
|
|||||||
if (undoManager.canRedo()) undoManager.redo();
|
if (undoManager.canRedo()) undoManager.redo();
|
||||||
}, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
}, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||||
|
|
||||||
// Hledání
|
// Search
|
||||||
rootPane.registerKeyboardAction(e -> {
|
rootPane.registerKeyboardAction(e -> {
|
||||||
if (!isImageFile(file)) showSearchPanel(true);
|
if (!isImageFile(file)) showSearchPanel(true);
|
||||||
},
|
},
|
||||||
@ -821,11 +821,11 @@ public class FileEditor extends JDialog {
|
|||||||
if (readOnly) return;
|
if (readOnly) return;
|
||||||
if (!modified) {
|
if (!modified) {
|
||||||
// No changes - inform the user briefly
|
// No changes - inform the user briefly
|
||||||
JOptionPane.showMessageDialog(this, "Žádné změny k uložení.", "Info", JOptionPane.INFORMATION_MESSAGE);
|
JOptionPane.showMessageDialog(this, "No changes to save.", "Info", JOptionPane.INFORMATION_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = showSaveConfirmDialog("Soubor byl změněn. Uložit změny?", "Uložit změny");
|
int result = showSaveConfirmDialog("File was modified. Save changes?", "Save changes");
|
||||||
|
|
||||||
if (result == JOptionPane.YES_OPTION) {
|
if (result == JOptionPane.YES_OPTION) {
|
||||||
saveFile();
|
saveFile();
|
||||||
@ -863,7 +863,7 @@ public class FileEditor extends JDialog {
|
|||||||
updateStatus();
|
updateStatus();
|
||||||
return;
|
return;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
JOptionPane.showMessageDialog(this, "Chyba při čtení z archivu: " + e.getMessage(), "Chyba", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(this, "Error reading from archive: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
dispose();
|
dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1078,7 +1078,7 @@ public class FileEditor extends JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateTitle() {
|
private void updateTitle() {
|
||||||
setTitle((readOnly ? "Prohlížeč - " : "Editor - ") + file.getName() + (modified ? " *" : ""));
|
setTitle((readOnly ? "Viewer - " : "Editor - ") + file.getName() + (modified ? " *" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveFile() {
|
private void saveFile() {
|
||||||
@ -1088,14 +1088,14 @@ public class FileEditor extends JDialog {
|
|||||||
modified = false;
|
modified = false;
|
||||||
updateTitle();
|
updateTitle();
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
"Soubor uložen",
|
"File saved",
|
||||||
"Úspěch",
|
"Success",
|
||||||
JOptionPane.INFORMATION_MESSAGE);
|
JOptionPane.INFORMATION_MESSAGE);
|
||||||
updateStatus();
|
updateStatus();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
"Chyba při ukládání:\n" + e.getMessage(),
|
"Error during saving:\n" + e.getMessage(),
|
||||||
"Chyba",
|
"Error",
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1113,7 +1113,7 @@ public class FileEditor extends JDialog {
|
|||||||
private void closeEditor() {
|
private void closeEditor() {
|
||||||
saveWindowState();
|
saveWindowState();
|
||||||
if (!readOnly && modified) {
|
if (!readOnly && modified) {
|
||||||
int result = showSaveConfirmDialog("Soubor byl změněn. Uložit změny?", "Neuložené změny");
|
int result = showSaveConfirmDialog("File was modified. Save changes?", "Unsaved changes");
|
||||||
|
|
||||||
if (result == JOptionPane.YES_OPTION) {
|
if (result == JOptionPane.YES_OPTION) {
|
||||||
saveFile();
|
saveFile();
|
||||||
@ -1121,7 +1121,7 @@ public class FileEditor extends JDialog {
|
|||||||
} else if (result == JOptionPane.NO_OPTION) {
|
} else if (result == JOptionPane.NO_OPTION) {
|
||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
// CANCEL_OPTION - nedělat nic
|
// CANCEL_OPTION - do nothing
|
||||||
} else {
|
} else {
|
||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
@ -1154,9 +1154,9 @@ public class FileEditor extends JDialog {
|
|||||||
dlg.add(new JLabel(message), BorderLayout.CENTER);
|
dlg.add(new JLabel(message), BorderLayout.CENTER);
|
||||||
|
|
||||||
JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||||
JButton yesBtn = new JButton("Ano");
|
JButton yesBtn = new JButton("Yes");
|
||||||
JButton noBtn = new JButton("Ne");
|
JButton noBtn = new JButton("No");
|
||||||
JButton cancelBtn = new JButton("Zrušit");
|
JButton cancelBtn = new JButton("Cancel");
|
||||||
|
|
||||||
final int[] result = {JOptionPane.CANCEL_OPTION};
|
final int[] result = {JOptionPane.CANCEL_OPTION};
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import javax.swing.*;
|
|||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog pro výběr fontu
|
* Font selection dialog
|
||||||
*/
|
*/
|
||||||
public class FontChooserDialog extends JDialog {
|
public class FontChooserDialog extends JDialog {
|
||||||
private Font selectedFont;
|
private Font selectedFont;
|
||||||
@ -17,7 +17,7 @@ public class FontChooserDialog extends JDialog {
|
|||||||
private JTextArea previewArea;
|
private JTextArea previewArea;
|
||||||
|
|
||||||
public FontChooserDialog(Window parent, Font initialFont) {
|
public FontChooserDialog(Window parent, Font initialFont) {
|
||||||
super(parent, "Výběr fontu", ModalityType.APPLICATION_MODAL);
|
super(parent, "Select Font", ModalityType.APPLICATION_MODAL);
|
||||||
this.selectedFont = initialFont;
|
this.selectedFont = initialFont;
|
||||||
|
|
||||||
initComponents();
|
initComponents();
|
||||||
@ -31,10 +31,10 @@ public class FontChooserDialog extends JDialog {
|
|||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
setLayout(new BorderLayout(10, 10));
|
setLayout(new BorderLayout(10, 10));
|
||||||
|
|
||||||
// Panel pro výběr (font, velikost, styl)
|
// Selection panel (font, size, style)
|
||||||
JPanel selectionPanel = new JPanel(new GridLayout(1, 3, 10, 0));
|
JPanel selectionPanel = new JPanel(new GridLayout(1, 3, 10, 0));
|
||||||
|
|
||||||
// Seznam fontů
|
// Font list
|
||||||
JPanel fontPanel = new JPanel(new BorderLayout());
|
JPanel fontPanel = new JPanel(new BorderLayout());
|
||||||
fontPanel.add(new JLabel("Font:"), BorderLayout.NORTH);
|
fontPanel.add(new JLabel("Font:"), BorderLayout.NORTH);
|
||||||
|
|
||||||
@ -51,9 +51,9 @@ public class FontChooserDialog extends JDialog {
|
|||||||
JScrollPane fontScroll = new JScrollPane(fontList);
|
JScrollPane fontScroll = new JScrollPane(fontList);
|
||||||
fontPanel.add(fontScroll, BorderLayout.CENTER);
|
fontPanel.add(fontScroll, BorderLayout.CENTER);
|
||||||
|
|
||||||
// Seznam velikostí
|
// Size list
|
||||||
JPanel sizePanel = new JPanel(new BorderLayout());
|
JPanel sizePanel = new JPanel(new BorderLayout());
|
||||||
sizePanel.add(new JLabel("Velikost:"), BorderLayout.NORTH);
|
sizePanel.add(new JLabel("Size:"), BorderLayout.NORTH);
|
||||||
|
|
||||||
Integer[] sizes = {8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28, 32, 36, 40, 48, 56, 64, 72};
|
Integer[] sizes = {8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28, 32, 36, 40, 48, 56, 64, 72};
|
||||||
sizeList = new JList<>(sizes);
|
sizeList = new JList<>(sizes);
|
||||||
@ -67,9 +67,9 @@ public class FontChooserDialog extends JDialog {
|
|||||||
JScrollPane sizeScroll = new JScrollPane(sizeList);
|
JScrollPane sizeScroll = new JScrollPane(sizeList);
|
||||||
sizePanel.add(sizeScroll, BorderLayout.CENTER);
|
sizePanel.add(sizeScroll, BorderLayout.CENTER);
|
||||||
|
|
||||||
// Seznam stylů (Plain, Bold, Italic, Bold Italic)
|
// Style list (Plain, Bold, Italic, Bold Italic)
|
||||||
JPanel stylePanel = new JPanel(new BorderLayout());
|
JPanel stylePanel = new JPanel(new BorderLayout());
|
||||||
stylePanel.add(new JLabel("Styl:"), BorderLayout.NORTH);
|
stylePanel.add(new JLabel("Style:"), BorderLayout.NORTH);
|
||||||
|
|
||||||
String[] styles = {"Plain", "Bold", "Italic", "Bold Italic"};
|
String[] styles = {"Plain", "Bold", "Italic", "Bold Italic"};
|
||||||
styleList = new JList<>(styles);
|
styleList = new JList<>(styles);
|
||||||
@ -100,7 +100,7 @@ public class FontChooserDialog extends JDialog {
|
|||||||
previewScroll.setPreferredSize(new Dimension(0, 120));
|
previewScroll.setPreferredSize(new Dimension(0, 120));
|
||||||
previewPanel.add(previewScroll, BorderLayout.CENTER);
|
previewPanel.add(previewScroll, BorderLayout.CENTER);
|
||||||
|
|
||||||
// Tlačítka
|
// Buttons
|
||||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||||
|
|
||||||
JButton okButton = new JButton("OK");
|
JButton okButton = new JButton("OK");
|
||||||
@ -109,7 +109,7 @@ public class FontChooserDialog extends JDialog {
|
|||||||
dispose();
|
dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
JButton cancelButton = new JButton("Zrušit");
|
JButton cancelButton = new JButton("Cancel");
|
||||||
cancelButton.addActionListener(e -> {
|
cancelButton.addActionListener(e -> {
|
||||||
approved = false;
|
approved = false;
|
||||||
dispose();
|
dispose();
|
||||||
@ -129,13 +129,13 @@ public class FontChooserDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void selectFont(Font font) {
|
private void selectFont(Font font) {
|
||||||
// Najít a vybrat font
|
// Find and select font
|
||||||
fontList.setSelectedValue(font.getName(), true);
|
fontList.setSelectedValue(font.getName(), true);
|
||||||
|
|
||||||
// Najít a vybrat velikost
|
// Find and select size
|
||||||
sizeList.setSelectedValue(font.getSize(), true);
|
sizeList.setSelectedValue(font.getSize(), true);
|
||||||
|
|
||||||
// Najít a vybrat styl
|
// Find and select style
|
||||||
int style = font.getStyle();
|
int style = font.getStyle();
|
||||||
switch (style) {
|
switch (style) {
|
||||||
case Font.BOLD:
|
case Font.BOLD:
|
||||||
|
|||||||
@ -452,11 +452,18 @@ public class MainWindow extends JFrame {
|
|||||||
|
|
||||||
// Search button
|
// Search button
|
||||||
JButton btnSearch = new JButton("🔍");
|
JButton btnSearch = new JButton("🔍");
|
||||||
btnSearch.setToolTipText("Hledat soubory (Alt+F7)");
|
btnSearch.setToolTipText("Search files (Alt+F7)");
|
||||||
btnSearch.setFocusable(false);
|
btnSearch.setFocusable(false);
|
||||||
btnSearch.addActionListener(e -> showSearchDialog());
|
btnSearch.addActionListener(e -> showSearchDialog());
|
||||||
toolBar.add(btnSearch);
|
toolBar.add(btnSearch);
|
||||||
|
|
||||||
|
// Sync button
|
||||||
|
JButton btnSync = new JButton("⚖");
|
||||||
|
btnSync.setToolTipText("Compare directories");
|
||||||
|
btnSync.setFocusable(false);
|
||||||
|
btnSync.addActionListener(e -> showSyncDialog());
|
||||||
|
toolBar.add(btnSync);
|
||||||
|
|
||||||
toolBar.addSeparator();
|
toolBar.addSeparator();
|
||||||
|
|
||||||
// Load custom shortcuts from config
|
// Load custom shortcuts from config
|
||||||
@ -1725,6 +1732,16 @@ public class MainWindow extends JFrame {
|
|||||||
dialog.setVisible(true);
|
dialog.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show Sync Directories dialog
|
||||||
|
*/
|
||||||
|
private void showSyncDialog() {
|
||||||
|
File leftDir = leftPanel.getCurrentDirectory();
|
||||||
|
File rightDir = rightPanel.getCurrentDirectory();
|
||||||
|
SyncDirectoriesDialog dialog = new SyncDirectoriesDialog(this, leftDir, rightDir, config);
|
||||||
|
dialog.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show wildcard select dialog
|
* Show wildcard select dialog
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -124,7 +124,7 @@ public class SearchDialog extends JDialog {
|
|||||||
|
|
||||||
gbc.gridx = 0;
|
gbc.gridx = 0;
|
||||||
gbc.gridy = 0;
|
gbc.gridy = 0;
|
||||||
searchPanel.add(new JLabel("Hledat:"), gbc);
|
searchPanel.add(new JLabel("Search for:"), gbc);
|
||||||
|
|
||||||
gbc.gridx = 1;
|
gbc.gridx = 1;
|
||||||
gbc.weightx = 1.0;
|
gbc.weightx = 1.0;
|
||||||
@ -231,7 +231,7 @@ public class SearchDialog extends JDialog {
|
|||||||
});
|
});
|
||||||
|
|
||||||
JScrollPane scrollPane = new JScrollPane(resultsTable);
|
JScrollPane scrollPane = new JScrollPane(resultsTable);
|
||||||
scrollPane.setBorder(BorderFactory.createTitledBorder("Výsledky"));
|
scrollPane.setBorder(BorderFactory.createTitledBorder("Results"));
|
||||||
add(scrollPane, BorderLayout.CENTER);
|
add(scrollPane, BorderLayout.CENTER);
|
||||||
|
|
||||||
// Status bar with progress and message
|
// Status bar with progress and message
|
||||||
@ -244,24 +244,24 @@ public class SearchDialog extends JDialog {
|
|||||||
statusPanel.add(statusLabel, BorderLayout.CENTER);
|
statusPanel.add(statusLabel, BorderLayout.CENTER);
|
||||||
statusPanel.add(statusProgressBar, BorderLayout.EAST);
|
statusPanel.add(statusProgressBar, BorderLayout.EAST);
|
||||||
|
|
||||||
// Panel s tlačítky
|
// Panel with buttons
|
||||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||||
|
|
||||||
searchButton = new JButton("Hledat");
|
searchButton = new JButton("Search");
|
||||||
searchButton.addActionListener(e -> performSearch());
|
searchButton.addActionListener(e -> performSearch());
|
||||||
|
|
||||||
viewButton = new JButton("Zobrazit");
|
viewButton = new JButton("View");
|
||||||
viewButton.setEnabled(false);
|
viewButton.setEnabled(false);
|
||||||
viewButton.addActionListener(e -> viewSelectedFile());
|
viewButton.addActionListener(e -> viewSelectedFile());
|
||||||
|
|
||||||
editButton = new JButton("Upravit");
|
editButton = new JButton("Edit");
|
||||||
editButton.setEnabled(false);
|
editButton.setEnabled(false);
|
||||||
editButton.addActionListener(e -> editSelectedFile());
|
editButton.addActionListener(e -> editSelectedFile());
|
||||||
|
|
||||||
cancelButton = new JButton("Zavřít");
|
cancelButton = new JButton("Close");
|
||||||
cancelButton.addActionListener(e -> dispose());
|
cancelButton.addActionListener(e -> dispose());
|
||||||
|
|
||||||
JButton openButton = new JButton("Otevřít umístění");
|
JButton openButton = new JButton("Open location");
|
||||||
openButton.addActionListener(e -> openSelectedFile());
|
openButton.addActionListener(e -> openSelectedFile());
|
||||||
|
|
||||||
buttonPanel.add(searchButton);
|
buttonPanel.add(searchButton);
|
||||||
@ -571,15 +571,15 @@ public class SearchDialog extends JDialog {
|
|||||||
statusLabel.setText("Done — found " + foundCount + " files");
|
statusLabel.setText("Done — found " + foundCount + " files");
|
||||||
if (tableModel.getRowCount() == 0) {
|
if (tableModel.getRowCount() == 0) {
|
||||||
JOptionPane.showMessageDialog(SearchDialog.this,
|
JOptionPane.showMessageDialog(SearchDialog.this,
|
||||||
"Nebyly nalezeny žádné soubory",
|
"No files found",
|
||||||
"Výsledek",
|
"Result",
|
||||||
JOptionPane.INFORMATION_MESSAGE);
|
JOptionPane.INFORMATION_MESSAGE);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
statusLabel.setText("Error");
|
statusLabel.setText("Error");
|
||||||
JOptionPane.showMessageDialog(SearchDialog.this,
|
JOptionPane.showMessageDialog(SearchDialog.this,
|
||||||
"Chyba při hledání: " + e.getMessage(),
|
"Error during search: " + e.getMessage(),
|
||||||
"Chyba",
|
"Error",
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +589,7 @@ public class SearchDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Otevře umístění vybraného souboru v exploreru
|
* Open selected file location
|
||||||
*/
|
*/
|
||||||
private void openSelectedFile() {
|
private void openSelectedFile() {
|
||||||
int selectedRow = resultsTable.getSelectedRow();
|
int selectedRow = resultsTable.getSelectedRow();
|
||||||
@ -622,8 +622,8 @@ public class SearchDialog extends JDialog {
|
|||||||
Desktop.getDesktop().open(item.getFile().getParentFile());
|
Desktop.getDesktop().open(item.getFile().getParentFile());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
"Nepodařilo se otevřít umístění: " + e.getMessage(),
|
"Could not open location: " + e.getMessage(),
|
||||||
"Chyba",
|
"Error",
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -666,7 +666,7 @@ public class SearchDialog extends JDialog {
|
|||||||
});
|
});
|
||||||
viewer.setVisible(true);
|
viewer.setVisible(true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
JOptionPane.showMessageDialog(this, "Chyba při otevírání souboru: " + e.getMessage(), "Chyba", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(this, "Error opening file: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -682,7 +682,7 @@ public class SearchDialog extends JDialog {
|
|||||||
if (item != null && !item.isDirectory() && !"..".equals(item.getName())) {
|
if (item != null && !item.isDirectory() && !"..".equals(item.getName())) {
|
||||||
boolean inArchive = item.getPath() != null && !item.getPath().equals(item.getFile().getAbsolutePath());
|
boolean inArchive = item.getPath() != null && !item.getPath().equals(item.getFile().getAbsolutePath());
|
||||||
if (inArchive) {
|
if (inArchive) {
|
||||||
JOptionPane.showMessageDialog(this, "Editace souborů přímo v archivu není podporována. Použijte 'Otevřít umístění' pro přístup k archivu.", "Informace", JOptionPane.INFORMATION_MESSAGE);
|
JOptionPane.showMessageDialog(this, "Editing web files directly in an archive is not supported. Use 'Go to File' to access the archive.", "Information", JOptionPane.INFORMATION_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -710,18 +710,18 @@ public class SearchDialog extends JDialog {
|
|||||||
});
|
});
|
||||||
editor.setVisible(true);
|
editor.setVisible(true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
JOptionPane.showMessageDialog(this, "Chyba při otevírání souboru: " + e.getMessage(), "Chyba", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(this, "Error opening file: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model tabulky pro výsledky hledání
|
* Table model for search results
|
||||||
*/
|
*/
|
||||||
private class ResultsTableModel extends AbstractTableModel {
|
private class ResultsTableModel extends AbstractTableModel {
|
||||||
|
|
||||||
private final String[] columnNames = {"Cesta", "Velikost", "Datum změny"};
|
private final String[] columnNames = {"Path", "Size", "Modified Date"};
|
||||||
private List<FileItem> results = new ArrayList<>();
|
private List<FileItem> results = new ArrayList<>();
|
||||||
|
|
||||||
public void addResult(FileItem item) {
|
public void addResult(FileItem item) {
|
||||||
|
|||||||
414
src/main/java/cz/kamma/kfmanager/ui/SyncDirectoriesDialog.java
Normal file
414
src/main/java/cz/kamma/kfmanager/ui/SyncDirectoriesDialog.java
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
package cz.kamma.kfmanager.ui;
|
||||||
|
|
||||||
|
import cz.kamma.kfmanager.config.AppConfig;
|
||||||
|
import cz.kamma.kfmanager.model.FileItem;
|
||||||
|
import cz.kamma.kfmanager.service.FileOperations;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
import javax.swing.table.DefaultTableCellRenderer;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class SyncDirectoriesDialog extends JDialog {
|
||||||
|
private JTextField leftPathField;
|
||||||
|
private JTextField rightPathField;
|
||||||
|
private JCheckBox subdirsCheckbox;
|
||||||
|
private JCheckBox byContentCheckbox;
|
||||||
|
private JCheckBox ignoreDateCheckbox;
|
||||||
|
private JToggleButton showLeftOnlyBtn;
|
||||||
|
private JToggleButton showEqualBtn;
|
||||||
|
private JToggleButton showDiffBtn;
|
||||||
|
private JToggleButton showRightOnlyBtn;
|
||||||
|
private List<SyncEntry> allEntries = new ArrayList<>();
|
||||||
|
private JTable resultsTable;
|
||||||
|
private SyncTableModel tableModel;
|
||||||
|
private AppConfig config;
|
||||||
|
private JLabel statusLabel;
|
||||||
|
|
||||||
|
public SyncDirectoriesDialog(Frame owner, File leftDir, File rightDir, AppConfig config) {
|
||||||
|
super(owner, "Synchronize Directories", true);
|
||||||
|
this.config = config;
|
||||||
|
|
||||||
|
initComponents(leftDir, rightDir);
|
||||||
|
setSize(1000, 600);
|
||||||
|
setLocationRelativeTo(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initComponents(File leftDir, File rightDir) {
|
||||||
|
setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
JPanel topPanel = new JPanel();
|
||||||
|
topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.Y_AXIS));
|
||||||
|
topPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||||
|
|
||||||
|
// Paths row
|
||||||
|
JPanel pathsPanel = new JPanel(new GridLayout(1, 2, 10, 0));
|
||||||
|
|
||||||
|
JPanel leftP = new JPanel(new BorderLayout(5, 0));
|
||||||
|
leftPathField = new JTextField(leftDir != null ? leftDir.getAbsolutePath() : "");
|
||||||
|
JButton browseLeft = new JButton("...");
|
||||||
|
browseLeft.addActionListener(e -> browsePath(leftPathField));
|
||||||
|
leftP.add(leftPathField, BorderLayout.CENTER);
|
||||||
|
leftP.add(browseLeft, BorderLayout.EAST);
|
||||||
|
|
||||||
|
JPanel rightP = new JPanel(new BorderLayout(5, 0));
|
||||||
|
rightPathField = new JTextField(rightDir != null ? rightDir.getAbsolutePath() : "");
|
||||||
|
JButton browseRight = new JButton("...");
|
||||||
|
browseRight.addActionListener(e -> browsePath(rightPathField));
|
||||||
|
rightP.add(rightPathField, BorderLayout.CENTER);
|
||||||
|
rightP.add(browseRight, BorderLayout.EAST);
|
||||||
|
|
||||||
|
pathsPanel.add(leftP);
|
||||||
|
pathsPanel.add(rightP);
|
||||||
|
topPanel.add(pathsPanel);
|
||||||
|
topPanel.add(Box.createVerticalStrut(10));
|
||||||
|
|
||||||
|
// Options toolbar
|
||||||
|
JPanel optionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||||
|
JButton compareBtn = new JButton("Compare");
|
||||||
|
compareBtn.addActionListener(e -> performComparison());
|
||||||
|
optionsPanel.add(compareBtn);
|
||||||
|
|
||||||
|
subdirsCheckbox = new JCheckBox("Include subdirectories");
|
||||||
|
byContentCheckbox = new JCheckBox("By content");
|
||||||
|
ignoreDateCheckbox = new JCheckBox("Ignore date");
|
||||||
|
|
||||||
|
optionsPanel.add(subdirsCheckbox);
|
||||||
|
optionsPanel.add(byContentCheckbox);
|
||||||
|
optionsPanel.add(ignoreDateCheckbox);
|
||||||
|
|
||||||
|
optionsPanel.add(Box.createHorizontalStrut(20));
|
||||||
|
optionsPanel.add(new JLabel("Show:"));
|
||||||
|
|
||||||
|
showLeftOnlyBtn = new JToggleButton("➡");
|
||||||
|
showEqualBtn = new JToggleButton("=");
|
||||||
|
showDiffBtn = new JToggleButton("≠");
|
||||||
|
showRightOnlyBtn = new JToggleButton("⬅");
|
||||||
|
|
||||||
|
showLeftOnlyBtn.setSelected(true);
|
||||||
|
showEqualBtn.setSelected(true);
|
||||||
|
showDiffBtn.setSelected(true);
|
||||||
|
showRightOnlyBtn.setSelected(true);
|
||||||
|
|
||||||
|
java.awt.event.ActionListener filterAl = e -> applyFilters();
|
||||||
|
showLeftOnlyBtn.addActionListener(filterAl);
|
||||||
|
showEqualBtn.addActionListener(filterAl);
|
||||||
|
showDiffBtn.addActionListener(filterAl);
|
||||||
|
showRightOnlyBtn.addActionListener(filterAl);
|
||||||
|
|
||||||
|
optionsPanel.add(showLeftOnlyBtn);
|
||||||
|
optionsPanel.add(showEqualBtn);
|
||||||
|
optionsPanel.add(showDiffBtn);
|
||||||
|
optionsPanel.add(showRightOnlyBtn);
|
||||||
|
|
||||||
|
optionsPanel.add(Box.createHorizontalStrut(10));
|
||||||
|
JButton duplicatesBtn = new JButton("duplicates");
|
||||||
|
duplicatesBtn.addActionListener(e -> {
|
||||||
|
showEqualBtn.setSelected(true);
|
||||||
|
showDiffBtn.setSelected(true);
|
||||||
|
showLeftOnlyBtn.setSelected(false);
|
||||||
|
showRightOnlyBtn.setSelected(false);
|
||||||
|
applyFilters();
|
||||||
|
});
|
||||||
|
JButton singlesBtn = new JButton("singles");
|
||||||
|
singlesBtn.addActionListener(e -> {
|
||||||
|
showEqualBtn.setSelected(false);
|
||||||
|
showDiffBtn.setSelected(false);
|
||||||
|
showLeftOnlyBtn.setSelected(true);
|
||||||
|
showRightOnlyBtn.setSelected(true);
|
||||||
|
applyFilters();
|
||||||
|
});
|
||||||
|
optionsPanel.add(duplicatesBtn);
|
||||||
|
optionsPanel.add(singlesBtn);
|
||||||
|
|
||||||
|
topPanel.add(optionsPanel);
|
||||||
|
add(topPanel, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
// Table
|
||||||
|
tableModel = new SyncTableModel();
|
||||||
|
resultsTable = new JTable(tableModel);
|
||||||
|
resultsTable.setShowGrid(false);
|
||||||
|
resultsTable.setIntercellSpacing(new Dimension(0, 0));
|
||||||
|
resultsTable.setDefaultRenderer(Object.class, new SyncTableCellRenderer());
|
||||||
|
|
||||||
|
// Adjust column widths
|
||||||
|
resultsTable.getColumnModel().getColumn(3).setMaxWidth(40); // Icon column
|
||||||
|
|
||||||
|
add(new JScrollPane(resultsTable), BorderLayout.CENTER);
|
||||||
|
|
||||||
|
// Bottom panel
|
||||||
|
JPanel bottomPanel = new JPanel(new BorderLayout());
|
||||||
|
statusLabel = new JLabel("Waiting for comparison...");
|
||||||
|
statusLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||||
|
bottomPanel.add(statusLabel, BorderLayout.WEST);
|
||||||
|
|
||||||
|
JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||||
|
JButton syncBtn = new JButton("Synchronize...");
|
||||||
|
syncBtn.addActionListener(e -> performSync());
|
||||||
|
JButton closeBtn = new JButton("Close");
|
||||||
|
closeBtn.addActionListener(e -> dispose());
|
||||||
|
btnPanel.add(syncBtn);
|
||||||
|
btnPanel.add(closeBtn);
|
||||||
|
bottomPanel.add(btnPanel, BorderLayout.EAST);
|
||||||
|
|
||||||
|
add(bottomPanel, BorderLayout.SOUTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void browsePath(JTextField field) {
|
||||||
|
JFileChooser chooser = new JFileChooser(field.getText());
|
||||||
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||||
|
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
||||||
|
field.setText(chooser.getSelectedFile().getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performComparison() {
|
||||||
|
File leftDir = new File(leftPathField.getText());
|
||||||
|
File rightDir = new File(rightPathField.getText());
|
||||||
|
|
||||||
|
if (!leftDir.isDirectory() || !rightDir.isDirectory()) {
|
||||||
|
JOptionPane.showMessageDialog(this, "Both paths must be directories.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
statusLabel.setText("Comparing...");
|
||||||
|
|
||||||
|
new SwingWorker<List<SyncEntry>, Void>() {
|
||||||
|
@Override
|
||||||
|
protected List<SyncEntry> doInBackground() throws Exception {
|
||||||
|
return compareDirectories(leftDir, rightDir, "", subdirsCheckbox.isSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
try {
|
||||||
|
allEntries = get();
|
||||||
|
applyFilters();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
JOptionPane.showMessageDialog(SyncDirectoriesDialog.this, "Error during comparison: " + e.getMessage());
|
||||||
|
statusLabel.setText("Error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SyncEntry> compareDirectories(File leftRoot, File rightRoot, String relativePath, boolean recursive) {
|
||||||
|
Map<String, SyncEntry> map = new TreeMap<>();
|
||||||
|
|
||||||
|
File leftDir = relativePath.isEmpty() ? leftRoot : new File(leftRoot, relativePath);
|
||||||
|
File rightDir = relativePath.isEmpty() ? rightRoot : new File(rightRoot, relativePath);
|
||||||
|
|
||||||
|
File[] leftFiles = leftDir.listFiles();
|
||||||
|
File[] rightFiles = rightDir.listFiles();
|
||||||
|
|
||||||
|
if (leftFiles != null) {
|
||||||
|
for (File f : leftFiles) {
|
||||||
|
String name = relativePath.isEmpty() ? f.getName() : relativePath + File.separator + f.getName();
|
||||||
|
SyncEntry entry = new SyncEntry(name);
|
||||||
|
entry.leftFile = f;
|
||||||
|
entry.leftSize = f.isDirectory() ? -1 : f.length();
|
||||||
|
entry.leftModified = f.lastModified();
|
||||||
|
entry.isDirectory = f.isDirectory();
|
||||||
|
map.put(name, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rightFiles != null) {
|
||||||
|
for (File f : rightFiles) {
|
||||||
|
String name = relativePath.isEmpty() ? f.getName() : relativePath + File.separator + f.getName();
|
||||||
|
SyncEntry entry = map.get(name);
|
||||||
|
if (entry == null) {
|
||||||
|
entry = new SyncEntry(name);
|
||||||
|
map.put(name, entry);
|
||||||
|
}
|
||||||
|
entry.rightFile = f;
|
||||||
|
entry.rightSize = f.isDirectory() ? -1 : f.length();
|
||||||
|
entry.rightModified = f.lastModified();
|
||||||
|
entry.isDirectory = entry.isDirectory || f.isDirectory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SyncEntry> resultList = new ArrayList<>();
|
||||||
|
List<String> subdirsToProcess = new ArrayList<>();
|
||||||
|
|
||||||
|
for (SyncEntry entry : map.values()) {
|
||||||
|
if (entry.isDirectory) {
|
||||||
|
if (recursive) {
|
||||||
|
subdirsToProcess.add(entry.relativePath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updateRelation(entry);
|
||||||
|
resultList.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recursive) {
|
||||||
|
for (String sub : subdirsToProcess) {
|
||||||
|
resultList.addAll(compareDirectories(leftRoot, rightRoot, sub, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyFilters() {
|
||||||
|
List<SyncEntry> filtered = new ArrayList<>();
|
||||||
|
for (SyncEntry e : allEntries) {
|
||||||
|
if ("=".equals(e.relation) && showEqualBtn.isSelected()) filtered.add(e);
|
||||||
|
else if ("!=".equals(e.relation) && showDiffBtn.isSelected()) filtered.add(e);
|
||||||
|
else if ("->".equals(e.relation) && showLeftOnlyBtn.isSelected()) filtered.add(e);
|
||||||
|
else if ("<-".equals(e.relation) && showRightOnlyBtn.isSelected()) filtered.add(e);
|
||||||
|
}
|
||||||
|
tableModel.setResults(filtered);
|
||||||
|
statusLabel.setText(String.format("Showing %d of %d items.", filtered.size(), allEntries.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRelation(SyncEntry entry) {
|
||||||
|
if (entry.leftFile != null && entry.rightFile == null) {
|
||||||
|
entry.relation = "->";
|
||||||
|
} else if (entry.leftFile == null && entry.rightFile != null) {
|
||||||
|
entry.relation = "<-";
|
||||||
|
} else {
|
||||||
|
boolean sizeMatch = entry.leftSize == entry.rightSize;
|
||||||
|
boolean dateMatch = ignoreDateCheckbox.isSelected() || (entry.leftModified / 1000 == entry.rightModified / 1000);
|
||||||
|
|
||||||
|
if (sizeMatch && dateMatch) {
|
||||||
|
if (byContentCheckbox.isSelected()) {
|
||||||
|
if (compareByContent(entry.leftFile, entry.rightFile)) {
|
||||||
|
entry.relation = "=";
|
||||||
|
} else {
|
||||||
|
entry.relation = "!=";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entry.relation = "=";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (entry.leftModified > entry.rightModified) {
|
||||||
|
entry.relation = "->";
|
||||||
|
} else if (entry.leftModified < entry.rightModified) {
|
||||||
|
entry.relation = "<-";
|
||||||
|
} else {
|
||||||
|
entry.relation = "!=";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean compareByContent(File f1, File f2) {
|
||||||
|
if (f1.length() != f2.length()) return false;
|
||||||
|
try (java.io.InputStream i1 = new java.io.FileInputStream(f1);
|
||||||
|
java.io.InputStream i2 = new java.io.FileInputStream(f2)) {
|
||||||
|
byte[] b1 = new byte[8192];
|
||||||
|
byte[] b2 = new byte[8192];
|
||||||
|
int n;
|
||||||
|
while ((n = i1.read(b1)) != -1) {
|
||||||
|
if (i2.read(b2) != n) return false;
|
||||||
|
if (!java.util.Arrays.equals(b1, 0, n, b2, 0, n)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performSync() {
|
||||||
|
// Basic implementation of sync (copy missing/newer files)
|
||||||
|
// For now just show info, actual copy logic would use FileOperationQueue
|
||||||
|
JOptionPane.showMessageDialog(this, "Synchronization feature will be implemented soon. For now, only comparison is available.", "Information", JOptionPane.INFORMATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SyncEntry {
|
||||||
|
String relativePath;
|
||||||
|
File leftFile;
|
||||||
|
File rightFile;
|
||||||
|
long leftSize;
|
||||||
|
long rightSize;
|
||||||
|
long leftModified;
|
||||||
|
long rightModified;
|
||||||
|
String relation = ""; // "=", "!=", "->", "<-"
|
||||||
|
boolean isDirectory;
|
||||||
|
|
||||||
|
SyncEntry(String rel) { this.relativePath = rel; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SyncTableModel extends AbstractTableModel {
|
||||||
|
private String[] columns = {"Name (L)", "Size", "Date", "", "Date", "Size", "Name (R)"};
|
||||||
|
private List<SyncEntry> entries = new ArrayList<>();
|
||||||
|
|
||||||
|
public void setResults(List<SyncEntry> results) {
|
||||||
|
this.entries = results;
|
||||||
|
fireTableDataChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public int getRowCount() { return entries.size(); }
|
||||||
|
@Override public int getColumnCount() { return columns.length; }
|
||||||
|
@Override public String getColumnName(int col) { return columns[col]; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValueAt(int row, int col) {
|
||||||
|
SyncEntry e = entries.get(row);
|
||||||
|
switch(col) {
|
||||||
|
case 0: return e.leftFile != null ? e.relativePath : "";
|
||||||
|
case 1: return e.leftFile != null ? formatSize(e.leftSize) : "";
|
||||||
|
case 2: return e.leftFile != null ? formatDate(e.leftModified) : "";
|
||||||
|
case 3: return e.relation;
|
||||||
|
case 4: return e.rightFile != null ? formatDate(e.rightModified) : "";
|
||||||
|
case 5: return e.rightFile != null ? formatSize(e.rightSize) : "";
|
||||||
|
case 6: return e.rightFile != null ? e.relativePath : "";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatSize(long size) {
|
||||||
|
if (size < 0) return "<DIR>";
|
||||||
|
return String.format("%,d", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatDate(long time) {
|
||||||
|
return new java.text.SimpleDateFormat("dd.MM.yy HH:mm:ss").format(new Date(time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SyncTableCellRenderer extends DefaultTableCellRenderer {
|
||||||
|
@Override
|
||||||
|
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSel, boolean hasFocus, int row, int col) {
|
||||||
|
Component c = super.getTableCellRendererComponent(table, value, isSel, hasFocus, row, col);
|
||||||
|
SyncTableModel model = (SyncTableModel) table.getModel();
|
||||||
|
SyncEntry entry = model.entries.get(row);
|
||||||
|
|
||||||
|
if (!isSel) {
|
||||||
|
if ("=".equals(entry.relation)) {
|
||||||
|
c.setForeground(Color.BLACK);
|
||||||
|
} else if ("!=".equals(entry.relation)) {
|
||||||
|
c.setForeground(Color.RED);
|
||||||
|
} else if ("->".equals(entry.relation)) {
|
||||||
|
c.setForeground(new Color(0, 100, 0)); // Dark green
|
||||||
|
} else if ("<-".equals(entry.relation)) {
|
||||||
|
c.setForeground(Color.BLUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (col == 3) {
|
||||||
|
setHorizontalAlignment(CENTER);
|
||||||
|
setFont(getFont().deriveFont(Font.BOLD));
|
||||||
|
} else if (col == 1 || col == 5) {
|
||||||
|
setHorizontalAlignment(RIGHT);
|
||||||
|
} else {
|
||||||
|
setHorizontalAlignment(LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,7 +14,7 @@ public class WildcardSelectDialog extends JDialog {
|
|||||||
private boolean confirmed = false;
|
private boolean confirmed = false;
|
||||||
|
|
||||||
public WildcardSelectDialog(Frame parent) {
|
public WildcardSelectDialog(Frame parent) {
|
||||||
super(parent, "Vybrat podle masky", true);
|
super(parent, "Select by pattern", true);
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
MainApp.applyReflectiveCaretColor(getContentPane());
|
MainApp.applyReflectiveCaretColor(getContentPane());
|
||||||
@ -31,7 +31,7 @@ public class WildcardSelectDialog extends JDialog {
|
|||||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||||
|
|
||||||
// Label
|
// Label
|
||||||
JLabel label = new JLabel("Zadejte masku (např. *.txt, test*.*, file?.dat):");
|
JLabel label = new JLabel("Enter pattern (e.g. *.txt, test*.*, file?.dat):");
|
||||||
mainPanel.add(label, BorderLayout.NORTH);
|
mainPanel.add(label, BorderLayout.NORTH);
|
||||||
|
|
||||||
// Text field for pattern
|
// Text field for pattern
|
||||||
@ -50,7 +50,7 @@ public class WildcardSelectDialog extends JDialog {
|
|||||||
dispose();
|
dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
JButton cancelButton = new JButton("Zrušit");
|
JButton cancelButton = new JButton("Cancel");
|
||||||
cancelButton.addActionListener(e -> {
|
cancelButton.addActionListener(e -> {
|
||||||
confirmed = false;
|
confirmed = false;
|
||||||
dispose();
|
dispose();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user