added undo/redu, clipboard

This commit is contained in:
rdavidek 2026-01-14 21:12:07 +01:00
parent aac1531fae
commit 6f626b7607

View File

@ -38,6 +38,7 @@ public class FileEditor extends JDialog {
private JButton prevPageBtn = null; private JButton prevPageBtn = null;
private JButton nextPageBtn = null; private JButton nextPageBtn = null;
private JLabel pageOffsetLabel = null; private JLabel pageOffsetLabel = null;
private javax.swing.undo.UndoManager undoManager;
public FileEditor(Window parent, File file, AppConfig config, boolean readOnly) { public FileEditor(Window parent, File file, AppConfig config, boolean readOnly) {
super(parent, (readOnly ? "Prohlížeč - " : "Editor - ") + file.getName(), ModalityType.MODELESS); super(parent, (readOnly ? "Prohlížeč - " : "Editor - ") + file.getName(), ModalityType.MODELESS);
@ -72,11 +73,11 @@ public class FileEditor extends JDialog {
textArea.setTabSize(4); textArea.setTabSize(4);
textArea.setEditable(!readOnly); textArea.setEditable(!readOnly);
// V read-only režimu zajistit viditelnost kurzoru a možnost označování // Undo/Redo support
if (readOnly) { undoManager = new javax.swing.undo.UndoManager();
textArea.getCaret().setVisible(true); textArea.getDocument().addUndoableEditListener(e -> {
textArea.setCaretColor(Color.BLACK); undoManager.addEdit(e.getEdit());
} });
// Sledování změn (pouze pro editovatelný režim) // Sledování změn (pouze pro editovatelný režim)
if (!readOnly) { if (!readOnly) {
@ -99,6 +100,12 @@ public class FileEditor extends JDialog {
statusPanel.add(statusSelLabel, BorderLayout.EAST); statusPanel.add(statusSelLabel, BorderLayout.EAST);
add(statusPanel, BorderLayout.SOUTH); add(statusPanel, BorderLayout.SOUTH);
// Apply appearance settings (colors, contrast caret etc)
applyAppearance();
// Kontextové menu pro clipboard
setupContextMenu();
// Klávesové zkratky // Klávesové zkratky
setupKeyBindings(); setupKeyBindings();
@ -112,6 +119,109 @@ public class FileEditor extends JDialog {
}); });
} }
private void setupContextMenu() {
JPopupMenu popup = new JPopupMenu();
JMenuItem undoItem = new JMenuItem("Zpět");
undoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK));
undoItem.addActionListener(e -> { if (undoManager.canUndo()) undoManager.undo(); });
JMenuItem redoItem = new JMenuItem("Znovu");
redoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK));
redoItem.addActionListener(e -> { if (undoManager.canRedo()) undoManager.redo(); });
popup.add(undoItem);
popup.add(redoItem);
popup.addSeparator();
JMenuItem cutItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CutAction());
cutItem.setText("Vyjmout");
cutItem.setMnemonic(KeyEvent.VK_X);
JMenuItem copyItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CopyAction());
copyItem.setText("Kopírovat");
copyItem.setMnemonic(KeyEvent.VK_C);
JMenuItem pasteItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.PasteAction());
pasteItem.setText("Vložit");
pasteItem.setMnemonic(KeyEvent.VK_V);
popup.add(cutItem);
popup.add(copyItem);
popup.add(pasteItem);
popup.addSeparator();
JMenuItem selectAllItem = new JMenuItem("Vybrat vše");
selectAllItem.setMnemonic(KeyEvent.VK_A);
selectAllItem.addActionListener(e -> textArea.selectAll());
popup.add(selectAllItem);
popup.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent e) {
boolean editable = textArea.isEditable();
undoItem.setEnabled(editable && undoManager.canUndo());
redoItem.setEnabled(editable && undoManager.canRedo());
cutItem.setEnabled(editable);
pasteItem.setEnabled(editable);
}
@Override public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent e) {}
@Override public void popupMenuCanceled(javax.swing.event.PopupMenuEvent e) {}
});
textArea.setComponentPopupMenu(popup);
}
private void applyAppearance() {
Color bg = config.getBackgroundColor();
if (bg != null) {
boolean dark = isDark(bg);
// Apply to JTextArea
textArea.setBackground(bg);
textArea.setForeground(dark ? Color.WHITE : Color.BLACK);
textArea.setCaretColor(dark ? Color.WHITE : Color.BLACK);
// Apply to the rest of the components recursively
applyRecursiveColors(getContentPane(), bg, dark);
} else {
// Default colors - make sure caret is at least visible
Color defaultBg = textArea.getBackground();
if (defaultBg != null) {
boolean dark = isDark(defaultBg);
textArea.setCaretColor(dark ? Color.WHITE : Color.BLACK);
} else {
textArea.setCaretColor(Color.BLACK);
}
}
// Force caret visibility in read-only mode
if (readOnly) {
textArea.getCaret().setVisible(true);
}
}
private void applyRecursiveColors(Container container, Color bg, boolean dark) {
if (container == null) return;
container.setBackground(bg);
for (Component c : container.getComponents()) {
if (c instanceof JPanel || c instanceof JScrollPane || c instanceof JViewport) {
c.setBackground(bg);
}
if (c instanceof JLabel) {
c.setForeground(dark ? Color.WHITE : Color.BLACK);
}
if (c instanceof Container) {
applyRecursiveColors((Container) c, bg, dark);
}
}
}
private boolean isDark(Color c) {
if (c == null) return false;
double darkness = 1 - (0.299 * c.getRed() + 0.587 * c.getGreen() + 0.114 * c.getBlue()) / 255;
return darkness >= 0.5;
}
private void createMenuBar() { private void createMenuBar() {
JMenuBar menuBar = new JMenuBar(); JMenuBar menuBar = new JMenuBar();
@ -136,6 +246,60 @@ public class FileEditor extends JDialog {
menuBar.add(fileMenu); menuBar.add(fileMenu);
// Menu Edit
JMenu editMenu = new JMenu("Edit");
editMenu.setMnemonic(java.awt.event.KeyEvent.VK_E);
JMenuItem undoItem = new JMenuItem("Zpět");
undoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK));
undoItem.addActionListener(e -> { if (undoManager.canUndo()) undoManager.undo(); });
editMenu.add(undoItem);
JMenuItem redoItem = new JMenuItem("Znovu");
redoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK));
redoItem.addActionListener(e -> { if (undoManager.canRedo()) undoManager.redo(); });
editMenu.add(redoItem);
editMenu.addSeparator();
JMenuItem cutItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CutAction());
cutItem.setText("Vyjmout");
cutItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK));
editMenu.add(cutItem);
JMenuItem copyItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.CopyAction());
copyItem.setText("Kopírovat");
copyItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK));
editMenu.add(copyItem);
JMenuItem pasteItem = new JMenuItem(new javax.swing.text.DefaultEditorKit.PasteAction());
pasteItem.setText("Vložit");
pasteItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK));
editMenu.add(pasteItem);
editMenu.addSeparator();
JMenuItem selectAllItem = new JMenuItem("Vybrat vše");
selectAllItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK));
selectAllItem.addActionListener(e -> textArea.selectAll());
editMenu.add(selectAllItem);
// Update menu items state when menu is selected
editMenu.addMenuListener(new javax.swing.event.MenuListener() {
@Override
public void menuSelected(javax.swing.event.MenuEvent e) {
boolean editable = textArea.isEditable();
undoItem.setEnabled(editable && undoManager.canUndo());
redoItem.setEnabled(editable && undoManager.canRedo());
cutItem.setEnabled(editable);
pasteItem.setEnabled(editable);
}
@Override public void menuDeselected(javax.swing.event.MenuEvent e) {}
@Override public void menuCanceled(javax.swing.event.MenuEvent e) {}
});
menuBar.add(editMenu);
// Menu Nastavení // Menu Nastavení
JMenu settingsMenu = new JMenu("Nastavení"); JMenu settingsMenu = new JMenu("Nastavení");
settingsMenu.setMnemonic(java.awt.event.KeyEvent.VK_N); settingsMenu.setMnemonic(java.awt.event.KeyEvent.VK_N);
@ -215,6 +379,21 @@ public class FileEditor extends JDialog {
}, },
KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW); JComponent.WHEN_IN_FOCUSED_WINDOW);
// Ctrl+Z - Undo
rootPane.registerKeyboardAction(e -> {
if (undoManager.canUndo()) undoManager.undo();
}, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
// Ctrl+Y - Redo
rootPane.registerKeyboardAction(e -> {
if (undoManager.canRedo()) undoManager.redo();
}, KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
// Ctrl+Shift+Z - Redo (alternative shortcut)
rootPane.registerKeyboardAction(e -> {
if (undoManager.canRedo()) undoManager.redo();
}, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
} }
private void setHexMode(boolean on) { private void setHexMode(boolean on) {
@ -256,6 +435,7 @@ public class FileEditor extends JDialog {
textArea.setEditable(!readOnly); textArea.setEditable(!readOnly);
textArea.setFont(config.getEditorFont()); textArea.setFont(config.getEditorFont());
} }
applyAppearance();
updateStatus(); updateStatus();
} }
@ -442,6 +622,7 @@ public class FileEditor extends JDialog {
textArea.setCaretPosition(0); textArea.setCaretPosition(0);
} }
} }
if (undoManager != null) undoManager.discardAllEdits();
modified = false; modified = false;
updateTitle(); updateTitle();
updateStatus(); updateStatus();