From 2ab1edc47e899a811faae8bf6d4be9fb9de6e5c5 Mon Sep 17 00:00:00 2001 From: Maximiliano Diaz Date: Sat, 23 Jun 2018 10:31:09 -0300 Subject: [PATCH 1/2] the undo item was added in the edit menu --- .../com/jvms/i18neditor/editor/Editor.java | 442 +++++++++--------- .../jvms/i18neditor/editor/EditorMenuBar.java | 300 ++++++------ .../menu/UndoTranslationKeyMenuItem.java | 26 ++ .../resources/bundles/messages.properties | 1 + .../resources/bundles/messages_nl.properties | 1 + 5 files changed, 396 insertions(+), 374 deletions(-) create mode 100644 src/main/java/com/jvms/i18neditor/editor/menu/UndoTranslationKeyMenuItem.java diff --git a/src/main/java/com/jvms/i18neditor/editor/Editor.java b/src/main/java/com/jvms/i18neditor/editor/Editor.java index c426969..960da0a 100644 --- a/src/main/java/com/jvms/i18neditor/editor/Editor.java +++ b/src/main/java/com/jvms/i18neditor/editor/Editor.java @@ -82,7 +82,7 @@ public class Editor extends JFrame { private final static long serialVersionUID = 1113029729495390082L; private final static Logger log = LoggerFactory.getLogger(Editor.class); - + public final static String TITLE = "i18n-editor"; public final static String VERSION = "1.0.0"; public final static String GITHUB_REPO = "jcbvm/i18n-editor"; @@ -90,12 +90,12 @@ public class Editor extends JFrame { public final static String PROJECT_FILE = ".i18n-editor-metadata"; public final static String SETTINGS_FILE = ".i18n-editor"; public final static String SETTINGS_DIR = System.getProperty("user.home"); - + private EditorProject project; private EditorSettings settings = new EditorSettings(); private ExecutorService executor = Executors.newFixedThreadPool(2); private boolean dirty; - + private EditorMenuBar editorMenu; private JSplitPane contentPane; private JLabel introText; @@ -105,39 +105,38 @@ public class Editor extends JFrame { private TranslationField translationField; private JPanel resourcesPanel; private List resourceFields = Lists.newArrayList(); - + public Editor() { super(); setupUI(); setupFileDrop(); setupGlobalKeyEventDispatcher(); } - + public void createProject(Path dir, ResourceType type) { try { Preconditions.checkArgument(Files.isDirectory(dir)); - + if (!closeCurrentProject()) { return; } - + List resourceList = Resources.get(dir, settings.getResourceName(), Optional.empty()); if (!resourceList.isEmpty()) { - boolean importProject = Dialogs.showConfirmDialog(this, + boolean importProject = Dialogs.showConfirmDialog(this, MessageBundle.get("dialogs.project.new.conflict.title"), - MessageBundle.get("dialogs.project.new.conflict.text"), - JOptionPane.YES_NO_OPTION); + MessageBundle.get("dialogs.project.new.conflict.text"), JOptionPane.YES_NO_OPTION); if (importProject) { importProject(dir, false); return; } } - + clearUI(); project = new EditorProject(dir); restoreProjectState(project); project.setResourceType(type); - + if (type == ResourceType.Properties) { Resource resource = Resources.create(dir, type, Optional.empty(), project.getResourceName()); setupResource(resource); @@ -146,7 +145,7 @@ public void createProject(Path dir, ResourceType type) { SwingUtilities.invokeLater(() -> showAddLocaleDialog()); } translationTree.setModel(new TranslationTreeModel()); - + updateHistory(); updateUI(); requestFocusInFirstResourceField(); @@ -155,23 +154,23 @@ public void createProject(Path dir, ResourceType type) { showError(MessageBundle.get("resources.create.error")); } } - + public void importProject(Path dir, boolean showEmptyProjectError) { try { Preconditions.checkArgument(Files.isDirectory(dir)); - + if (!closeCurrentProject()) { return; } - + clearUI(); project = new EditorProject(dir); restoreProjectState(project); - + Optional type = Optional.ofNullable(project.getResourceType()); List resourceList = Resources.get(dir, project.getResourceName(), type); - Map keys = Maps.newTreeMap(); - + Map keys = Maps.newTreeMap(); + if (resourceList.isEmpty()) { project = null; if (showEmptyProjectError) { @@ -196,7 +195,7 @@ public void importProject(Path dir, boolean showEmptyProjectError) { project.getResources().forEach(r -> keys.putAll(r.getTranslations())); } translationTree.setModel(new TranslationTreeModel(Lists.newArrayList(keys.keySet()))); - + updateTreeNodeStatuses(); updateHistory(); updateUI(); @@ -206,7 +205,7 @@ public void importProject(Path dir, boolean showEmptyProjectError) { showError(MessageBundle.get("resources.import.error.multiple")); } } - + public boolean saveProject() { boolean error = false; if (project != null) { @@ -221,17 +220,17 @@ public boolean saveProject() { } } if (dirty) { - setDirty(error); + setDirty(error); } return !error; } - + public void reloadProject() { if (project != null) { - importProject(project.getPath(), true); + importProject(project.getPath(), true); } } - + public void removeSelectedTranslation() { TranslationTreeNode node = translationTree.getSelectionNode(); if (node != null && !node.isRoot()) { @@ -240,14 +239,14 @@ public void removeSelectedTranslation() { translationTree.setSelectionNode(parent); } } - + public void renameSelectedTranslation() { TranslationTreeNode node = translationTree.getSelectionNode(); if (node != null && !node.isRoot()) { showRenameTranslationDialog(node.getKey()); } } - + public void copySelectedTranslationKey() { TranslationTreeNode node = translationTree.getSelectionNode(); if (node != null && !node.isRoot()) { @@ -257,27 +256,27 @@ public void copySelectedTranslationKey() { clipboard.setContents(selection, selection); } } - + public void duplicateSelectedTranslation() { TranslationTreeNode node = translationTree.getSelectionNode(); if (node != null && !node.isRoot()) { showDuplicateTranslationDialog(node.getKey()); } } - + public void addTranslationKey(String key) { TranslationTreeNode node = translationTree.getNodeByKey(key); if (node != null) { translationTree.setSelectionNode(node); } else { if (project != null) { - project.getResources().forEach(resource -> resource.storeTranslation(key, "")); + project.getResources().forEach(resource -> resource.storeTranslation(key, "")); } - translationTree.addNodeByKey(key); + translationTree.addNodeByKey(key); } requestFocusInFirstResourceField(); } - + public void removeTranslationKey(String key) { if (project != null) { project.getResources().forEach(resource -> resource.removeTranslation(key)); @@ -285,7 +284,7 @@ public void removeTranslationKey(String key) { translationTree.removeNodeByKey(key); requestFocusInFirstResourceField(); } - + public void renameTranslationKey(String key, String newKey) { if (project != null) { project.getResources().forEach(resource -> resource.renameTranslation(key, newKey)); @@ -293,7 +292,7 @@ public void renameTranslationKey(String key, String newKey) { translationTree.renameNodeByKey(key, newKey); requestFocusInFirstResourceField(); } - + public void duplicateTranslationKey(String key, String newKey) { if (project != null) { project.getResources().forEach(resource -> resource.duplicateTranslation(key, newKey)); @@ -301,7 +300,7 @@ public void duplicateTranslationKey(String key, String newKey) { translationTree.duplicateNodeByKey(key, newKey); requestFocusInFirstResourceField(); } - + public void addResource(Resource resource) { setupResource(resource); updateUI(); @@ -310,30 +309,30 @@ public void addResource(Resource resource) { updateTreeNodeStatuses(); } } - + public EditorProject getProject() { return project; } - + public EditorSettings getSettings() { return settings; } - + public boolean isDirty() { return dirty; } - + public void setDirty(boolean dirty) { this.dirty = dirty; updateTitle(); editorMenu.setSaveable(dirty); } - + public void clearHistory() { settings.setHistory(Lists.newArrayList()); editorMenu.setRecentItems(Lists.newArrayList()); } - + public void showCreateProjectDialog(ResourceType type) { JFileChooser fc = new JFileChooser(); fc.setDialogTitle(MessageBundle.get("dialogs.project.new.title")); @@ -346,7 +345,7 @@ public void showCreateProjectDialog(ResourceType type) { updateUI(); } } - + public void showImportProjectDialog() { String path = null; if (project != null) { @@ -360,16 +359,14 @@ public void showImportProjectDialog() { importProject(Paths.get(fc.getSelectedFile().getPath()), true); } } - + public void showAddLocaleDialog() { String localeString = ""; Path path = project.getPath(); ResourceType type = project.getResourceType(); while (localeString != null && localeString.isEmpty()) { - localeString = Dialogs.showInputDialog(this, - MessageBundle.get("dialogs.locale.add.title", type), - MessageBundle.get("dialogs.locale.add.text"), - JOptionPane.QUESTION_MESSAGE); + localeString = Dialogs.showInputDialog(this, MessageBundle.get("dialogs.locale.add.title", type), + MessageBundle.get("dialogs.locale.add.text"), JOptionPane.QUESTION_MESSAGE); if (localeString != null) { localeString = localeString.trim(); if (localeString.isEmpty()) { @@ -377,7 +374,8 @@ public void showAddLocaleDialog() { } else { try { Locale locale = LocaleUtils.toLocale(localeString); - Resource resource = Resources.create(path, type, Optional.of(locale), project.getResourceName()); + Resource resource = Resources.create(path, type, Optional.of(locale), + project.getResourceName()); addResource(resource); } catch (IOException e) { log.error("Error creating new locale", e); @@ -387,14 +385,12 @@ public void showAddLocaleDialog() { } } } - + public void showRenameTranslationDialog(String key) { String newKey = ""; while (newKey != null && newKey.isEmpty()) { - newKey = Dialogs.showInputDialog(this, - MessageBundle.get("dialogs.translation.rename.title"), - MessageBundle.get("dialogs.translation.rename.text"), - JOptionPane.QUESTION_MESSAGE, key, true); + newKey = Dialogs.showInputDialog(this, MessageBundle.get("dialogs.translation.rename.title"), + MessageBundle.get("dialogs.translation.rename.text"), JOptionPane.QUESTION_MESSAGE, key, true); if (newKey != null) { if (!ResourceKeys.isValid(newKey)) { showError(MessageBundle.get("dialogs.translation.rename.error")); @@ -403,9 +399,10 @@ public void showRenameTranslationDialog(String key) { TranslationTreeNode oldNode = translationTree.getNodeByKey(key); if (newNode != null) { boolean isReplace = newNode.isLeaf() || oldNode.isLeaf(); - boolean confirm = Dialogs.showConfirmDialog(this, - MessageBundle.get("dialogs.translation.conflict.title"), - MessageBundle.get("dialogs.translation.conflict.text." + (isReplace?"replace":"merge")), + boolean confirm = Dialogs.showConfirmDialog(this, + MessageBundle.get("dialogs.translation.conflict.title"), + MessageBundle + .get("dialogs.translation.conflict.text." + (isReplace ? "replace" : "merge")), JOptionPane.WARNING_MESSAGE); if (confirm) { renameTranslationKey(key, newKey); @@ -417,14 +414,12 @@ public void showRenameTranslationDialog(String key) { } } } - + public void showDuplicateTranslationDialog(String key) { String newKey = ""; while (newKey != null && newKey.isEmpty()) { - newKey = Dialogs.showInputDialog(this, - MessageBundle.get("dialogs.translation.duplicate.title"), - MessageBundle.get("dialogs.translation.duplicate.text"), - JOptionPane.QUESTION_MESSAGE, key, true); + newKey = Dialogs.showInputDialog(this, MessageBundle.get("dialogs.translation.duplicate.title"), + MessageBundle.get("dialogs.translation.duplicate.text"), JOptionPane.QUESTION_MESSAGE, key, true); if (newKey != null) { newKey = newKey.trim(); if (!ResourceKeys.isValid(newKey)) { @@ -434,9 +429,10 @@ public void showDuplicateTranslationDialog(String key) { TranslationTreeNode oldNode = translationTree.getNodeByKey(key); if (newNode != null) { boolean isReplace = newNode.isLeaf() || oldNode.isLeaf(); - boolean confirm = Dialogs.showConfirmDialog(this, - MessageBundle.get("dialogs.translation.conflict.title"), - MessageBundle.get("dialogs.translation.conflict.text." + (isReplace?"replace":"merge")), + boolean confirm = Dialogs.showConfirmDialog(this, + MessageBundle.get("dialogs.translation.conflict.title"), + MessageBundle + .get("dialogs.translation.conflict.text." + (isReplace ? "replace" : "merge")), JOptionPane.WARNING_MESSAGE); if (confirm) { duplicateTranslationKey(key, newKey); @@ -448,7 +444,7 @@ public void showDuplicateTranslationDialog(String key) { } } } - + public void showAddTranslationDialog(TranslationTreeNode node) { String key = ""; String newKey = ""; @@ -456,10 +452,8 @@ public void showAddTranslationDialog(TranslationTreeNode node) { key = node.getKey() + "."; } while (newKey != null && newKey.isEmpty()) { - newKey = Dialogs.showInputDialog(this, - MessageBundle.get("dialogs.translation.add.title"), - MessageBundle.get("dialogs.translation.add.text"), - JOptionPane.QUESTION_MESSAGE, key, false); + newKey = Dialogs.showInputDialog(this, MessageBundle.get("dialogs.translation.add.title"), + MessageBundle.get("dialogs.translation.add.text"), JOptionPane.QUESTION_MESSAGE, key, false); if (newKey != null) { newKey = newKey.trim(); if (!ResourceKeys.isValid(newKey)) { @@ -470,34 +464,28 @@ public void showAddTranslationDialog(TranslationTreeNode node) { } } } - + public void showFindTranslationDialog() { - String key = Dialogs.showInputDialog(this, - MessageBundle.get("dialogs.translation.find.title"), - MessageBundle.get("dialogs.translation.find.text"), - JOptionPane.QUESTION_MESSAGE); + String key = Dialogs.showInputDialog(this, MessageBundle.get("dialogs.translation.find.title"), + MessageBundle.get("dialogs.translation.find.text"), JOptionPane.QUESTION_MESSAGE); if (key != null) { TranslationTreeNode node = translationTree.getNodeByKey(key.trim()); if (node == null) { - Dialogs.showWarningDialog(this, - MessageBundle.get("dialogs.translation.find.title"), + Dialogs.showWarningDialog(this, MessageBundle.get("dialogs.translation.find.title"), MessageBundle.get("dialogs.translation.find.error")); } else { translationTree.setSelectionNode(node); } } } - + public void showAboutDialog() { - Dialogs.showHtmlDialog(this, MessageBundle.get("dialogs.about.title", TITLE), - "
" + - "" + TITLE + "
" + - VERSION + "

" + - "Copyright (c) 2015 - 2017
" + - "Jacob van Mourik
" + - "MIT Licensed"); - } - + Dialogs.showHtmlDialog(this, MessageBundle.get("dialogs.about.title", TITLE), + "
" + + "" + TITLE + "
" + VERSION + + "

" + "Copyright (c) 2015 - 2017
" + "Jacob van Mourik
" + "MIT Licensed"); + } + public void showVersionDialog(boolean newVersionOnly) { executor.execute(() -> { GithubRepoReleaseData data; @@ -508,25 +496,23 @@ public void showVersionDialog(boolean newVersionOnly) { data = null; } if (data != null && VERSION.compareToIgnoreCase(data.getTagName()) < 0) { - content = MessageBundle.get("dialogs.version.new") + " " + - "" + data.getTagName() + "
" + - "" + MessageBundle.get("dialogs.version.link") + ""; + content = MessageBundle.get("dialogs.version.new") + " " + "" + data.getTagName() + + "
" + "" + + MessageBundle.get("dialogs.version.link") + ""; } else if (!newVersionOnly) { content = MessageBundle.get("dialogs.version.uptodate"); } else { return; } - Dialogs.showHtmlDialog(this, MessageBundle.get("dialogs.version.title"), content); + Dialogs.showHtmlDialog(this, MessageBundle.get("dialogs.version.title"), content); }); } - + public boolean closeCurrentProject() { boolean result = true; if (dirty) { - int confirm = JOptionPane.showConfirmDialog(this, - MessageBundle.get("dialogs.save.text"), - MessageBundle.get("dialogs.save.title"), - JOptionPane.YES_NO_CANCEL_OPTION); + int confirm = JOptionPane.showConfirmDialog(this, MessageBundle.get("dialogs.save.text"), + MessageBundle.get("dialogs.save.title"), JOptionPane.YES_NO_CANCEL_OPTION); if (confirm == JOptionPane.YES_OPTION) { result = saveProject(); } else { @@ -541,45 +527,44 @@ public boolean closeCurrentProject() { } return result; } - + public void openProjectDirectory() { - if (project == null) return; + if (project == null) + return; try { Desktop.getDesktop().open(project.getPath().toFile()); } catch (IOException ex) { log.error("Unable to open project directory " + project.getPath(), ex); } } - + public void launch() { restoreEditorState(); - + setPreferredSize(new Dimension(settings.getWindowWidth(), settings.getWindowHeight())); setLocation(settings.getWindowPositionX(), settings.getWindowPositionY()); contentPane.setDividerLocation(settings.getWindowDeviderPosition()); - - pack(); - setVisible(true); - + + pack(); + setVisible(true); + List dirs = settings.getHistory(); - if (!dirs.isEmpty()) { - String lastDir = dirs.get(dirs.size()-1); - Path path = Paths.get(lastDir); - if (Files.exists(path)) { - importProject(path, false); - } - } - - if (project == null) { - updateHistory(); - } + if (!dirs.isEmpty()) { + String lastDir = dirs.get(dirs.size() - 1); + Path path = Paths.get(lastDir); + if (Files.exists(path)) { + importProject(path, false); + } + } + + if (project == null) { + updateHistory(); + } if (project != null && project.hasResources()) { // Restore last expanded nodes List expandedKeys = settings.getLastExpandedNodes(); - List expandedNodes = expandedKeys.stream() - .map(translationTree::getNodeByKey) - .filter(n -> n != null) - .collect(Collectors.toList()); + List expandedNodes = expandedKeys.stream().map(translationTree::getNodeByKey) + .filter(n -> n != null).collect(Collectors.toList()); translationTree.expand(expandedNodes); // Restore last selected node String selectedKey = settings.getLastSelectedNode(); @@ -588,15 +573,15 @@ public void launch() { translationTree.setSelectionNode(selectedNode); } } - + if (settings.isCheckVersionOnStartup()) { - showVersionDialog(true); + showVersionDialog(true); } } - + public void updateUI() { TranslationTreeNode selectedNode = translationTree.getSelectionNode(); - + resourcesPanel.removeAll(); resourceFields = resourceFields.stream().sorted().collect(Collectors.toList()); resourceFields.forEach(field -> { @@ -610,7 +595,7 @@ public void updateUI() { resourcesPanel.add(field); resourcesPanel.add(Box.createVerticalStrut(10)); }); - + Container container = getContentPane(); if (project != null) { container.add(contentPane); @@ -626,85 +611,89 @@ public void updateUI() { editorMenu.setEditable(false); translationField.setEditable(false); } - + translationField.setVisible(settings.isKeyFieldEnabled()); translationTree.setToggleClickCount(settings.isDoubleClickTreeToggling() ? 2 : 1); - + updateTitle(); validate(); repaint(); } - + + public void UndoTranslationKey() { + + } + private void requestFocusInFirstResourceField() { resourceFields.stream().findFirst().ifPresent(f -> { f.requestFocusInWindow(); }); } - + private void clearUI() { translationField.clear(); translationTree.clear(); resourceFields.clear(); updateUI(); } - + private void setupUI() { Color borderColor = Colors.scale(UIManager.getColor("Panel.background"), .8f); - + setTitle(TITLE); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); addWindowListener(new EditorWindowListener()); - - setIconImages(Lists.newArrayList("512","256","128","64","48","32","24","20","16").stream() + + setIconImages(Lists.newArrayList("512", "256", "128", "64", "48", "32", "24", "20", "16").stream() .map(size -> Images.loadFromClasspath("images/icon-" + size + ".png").getImage()) .collect(Collectors.toList())); - - translationTree = new TranslationTree(); - translationTree.setBorder(BorderFactory.createEmptyBorder(0,5,0,5)); - translationTree.addTreeSelectionListener(new TranslationTreeNodeSelectionListener()); - translationTree.addMouseListener(new TranslationTreeMouseListener()); - + + translationTree = new TranslationTree(); + translationTree.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); + translationTree.addTreeSelectionListener(new TranslationTreeNodeSelectionListener()); + translationTree.addMouseListener(new TranslationTreeMouseListener()); + translationField = new TranslationField(); translationField.addKeyListener(new TranslationFieldKeyListener()); - translationField.setBorder(BorderFactory.createCompoundBorder( - BorderFactory.createMatteBorder(1,0,0,1,borderColor), - ((CompoundBorder)translationField.getBorder()).getInsideBorder())); - + translationField + .setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(1, 0, 0, 1, borderColor), + ((CompoundBorder) translationField.getBorder()).getInsideBorder())); + JScrollPane translationsScrollPane = new JScrollPane(translationTree); translationsScrollPane.getViewport().setOpaque(false); translationsScrollPane.setOpaque(false); - translationsScrollPane.setBorder(BorderFactory.createMatteBorder(0,0,0,1,borderColor)); - + translationsScrollPane.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, borderColor)); + translationsPanel = new JPanel(new BorderLayout()); translationsPanel.add(translationsScrollPane); translationsPanel.add(translationField, BorderLayout.SOUTH); - - resourcesPanel = new JScrollablePanel(true, false); - resourcesPanel.setLayout(new BoxLayout(resourcesPanel, BoxLayout.Y_AXIS)); - resourcesPanel.setBorder(BorderFactory.createEmptyBorder(10,20,10,20)); - resourcesPanel.setOpaque(false); - resourcesPanel.addMouseListener(new ResourcesPaneMouseListener()); - - resourcesScrollPane = new JScrollPane(resourcesPanel); - resourcesScrollPane.getViewport().setOpaque(false); - resourcesScrollPane.setOpaque(false); - resourcesScrollPane.setBorder(null); - resourcesScrollPane.addMouseListener(new ResourcesPaneMouseListener()); - + + resourcesPanel = new JScrollablePanel(true, false); + resourcesPanel.setLayout(new BoxLayout(resourcesPanel, BoxLayout.Y_AXIS)); + resourcesPanel.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20)); + resourcesPanel.setOpaque(false); + resourcesPanel.addMouseListener(new ResourcesPaneMouseListener()); + + resourcesScrollPane = new JScrollPane(resourcesPanel); + resourcesScrollPane.getViewport().setOpaque(false); + resourcesScrollPane.setOpaque(false); + resourcesScrollPane.setBorder(null); + resourcesScrollPane.addMouseListener(new ResourcesPaneMouseListener()); + contentPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, translationsPanel, resourcesScrollPane); contentPane.setBorder(null); contentPane.setDividerSize(10); - + // Style the split pane divider if possible SplitPaneUI splitPaneUI = contentPane.getUI(); - if (splitPaneUI instanceof BasicSplitPaneUI) { - BasicSplitPaneDivider divider = ((BasicSplitPaneUI)splitPaneUI).getDivider(); - divider.setBorder(null); - resourcesPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,20)); - } - - introText = new JLabel("" + - MessageBundle.get("core.intro.text") + ""); + if (splitPaneUI instanceof BasicSplitPaneUI) { + BasicSplitPaneDivider divider = ((BasicSplitPaneUI) splitPaneUI).getDivider(); + divider.setBorder(null); + resourcesPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 20)); + } + + introText = new JLabel("" + + MessageBundle.get("core.intro.text") + ""); introText.setOpaque(true); introText.setFont(introText.getFont().deriveFont(28f)); introText.setHorizontalTextPosition(JLabel.CENTER); @@ -713,14 +702,14 @@ private void setupUI() { introText.setVerticalAlignment(JLabel.CENTER); introText.setForeground(getBackground().darker()); introText.setIcon(Images.loadFromClasspath("images/icon-intro.png")); - + Container container = getContentPane(); container.add(introText); - + editorMenu = new EditorMenuBar(this, translationTree); setJMenuBar(editorMenu); } - + private void setupFileDrop() { new JFileDrop(getContentPane(), null, new JFileDrop.Listener() { @Override @@ -728,19 +717,18 @@ public void filesDropped(java.io.File[] files) { try { Path path = Paths.get(files[0].getCanonicalPath()); importProject(path, true); - } catch (IOException e) { - log.error("Error importing resources via file drop", e); - showError(MessageBundle.get("resources.open.error.multiple")); - } - } - }); - } - + } catch (IOException e) { + log.error("Error importing resources via file drop", e); + showError(MessageBundle.get("resources.open.error.multiple")); + } + } + }); + } + private void setupGlobalKeyEventDispatcher() { KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(e -> { - if (e.getID() != KeyEvent.KEY_PRESSED || !e.isAltDown() || - (SystemUtils.IS_OS_MAC && !e.isMetaDown()) || - (!SystemUtils.IS_OS_MAC && !e.isShiftDown())) { + if (e.getID() != KeyEvent.KEY_PRESSED || !e.isAltDown() || (SystemUtils.IS_OS_MAC && !e.isMetaDown()) + || (!SystemUtils.IS_OS_MAC && !e.isShiftDown())) { return false; } TreePath selected = translationTree.getSelectionPath(); @@ -752,7 +740,7 @@ private void setupGlobalKeyEventDispatcher() { switch (e.getKeyCode()) { case KeyEvent.VK_RIGHT: if (!translationTree.isExpanded(row)) { - translationTree.expandRow(row); + translationTree.expandRow(row); } result = true; break; @@ -760,19 +748,19 @@ private void setupGlobalKeyEventDispatcher() { if (translationTree.isCollapsed(row)) { translationTree.setSelectionPath(selected.getParentPath()); } else { - translationTree.collapseRow(row); + translationTree.collapseRow(row); } result = true; break; case KeyEvent.VK_UP: - TreePath prev = translationTree.getPathForRow(Math.max(0, row-1)); + TreePath prev = translationTree.getPathForRow(Math.max(0, row - 1)); if (prev != null) { translationTree.setSelectionPath(prev); } result = true; break; case KeyEvent.VK_DOWN: - TreePath next = translationTree.getPathForRow(row+1); + TreePath next = translationTree.getPathForRow(row + 1); if (next != null) { translationTree.setSelectionPath(next); } @@ -793,14 +781,14 @@ private void setupGlobalKeyEventDispatcher() { return result; }); } - + private void setupResource(Resource resource) { resource.addListener(e -> setDirty(true)); ResourceField field = new ResourceField(resource); field.addKeyListener(new ResourceFieldKeyListener()); resourceFields.add(field); } - + private void updateHistory() { List recentDirs = settings.getHistory(); if (project != null) { @@ -810,11 +798,11 @@ private void updateHistory() { if (recentDirs.size() > 10) { recentDirs.remove(0); } - settings.setHistory(recentDirs); + settings.setHistory(recentDirs); } editorMenu.setRecentItems(Lists.reverse(recentDirs)); } - + private void updateTitle() { String dirtyPart = dirty ? "*" : ""; String projectPart = ""; @@ -823,24 +811,23 @@ private void updateTitle() { } setTitle(dirtyPart + projectPart + TITLE); } - + private void showError(String message) { Dialogs.showErrorDialog(this, MessageBundle.get("dialogs.error.title"), message); } - + private void updateTreeNodeStatuses() { - Set keys = project.getResources().stream() - .flatMap(r -> r.getTranslations().keySet().stream()) + Set keys = project.getResources().stream().flatMap(r -> r.getTranslations().keySet().stream()) .filter(key -> project.getResources().stream().anyMatch(r -> !r.hasTranslation(key))) .collect(Collectors.toSet()); translationTree.updateNodes(keys); } - + private void updateTreeNodeStatus(String key) { boolean hasError = project.getResources().stream().anyMatch(r -> !r.hasTranslation(key)); translationTree.updateNode(key, hasError); } - + private void storeProjectState() { ExtendedProperties props = new ExtendedProperties(); props.setProperty("minify_resources", project.isMinifyResources()); @@ -849,7 +836,7 @@ private void storeProjectState() { props.setProperty("resource_type", project.getResourceType().toString()); props.store(Paths.get(project.getPath().toString(), PROJECT_FILE)); } - + private void restoreProjectState(EditorProject project) { ExtendedProperties props = new ExtendedProperties(); Path path = Paths.get(project.getPath().toString(), PROJECT_FILE); @@ -864,7 +851,7 @@ private void restoreProjectState(EditorProject project) { project.setMinifyResources(settings.isMinifyResources()); } } - + private void storeEditorState() { ExtendedProperties props = new ExtendedProperties(); props.setProperty("window_width", getWidth()); @@ -884,8 +871,7 @@ private void storeEditorState() { } if (project != null) { // Store keys of expanded nodes - List expandedNodeKeys = translationTree.getExpandedNodes().stream() - .map(TranslationTreeNode::getKey) + List expandedNodeKeys = translationTree.getExpandedNodes().stream().map(TranslationTreeNode::getKey) .collect(Collectors.toList()); props.setProperty("last_expanded", expandedNodeKeys); // Store key of selected node @@ -894,7 +880,7 @@ private void storeEditorState() { } props.store(Paths.get(SETTINGS_DIR, SETTINGS_FILE)); } - + private void restoreEditorState() { ExtendedProperties props = new ExtendedProperties(); props.load(Paths.get(SETTINGS_DIR, SETTINGS_FILE)); @@ -914,44 +900,44 @@ private void restoreEditorState() { settings.setKeyFieldEnabled(props.getBooleanProperty("key_field_enabled", true)); settings.setDoubleClickTreeToggling(props.getBooleanProperty("double_click_tree_toggling", false)); } - + private class TranslationTreeMouseListener extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { showPopupMenu(e); } - + @Override public void mouseReleased(MouseEvent e) { showPopupMenu(e); - } - + } + private void showPopupMenu(MouseEvent e) { if (!e.isPopupTrigger() || project == null || !project.hasResources()) { return; } TreePath path = translationTree.getPathForLocation(e.getX(), e.getY()); - if (path == null) { - TranslationTreeMenu menu = new TranslationTreeMenu(Editor.this, translationTree); - menu.show(e.getComponent(), e.getX(), e.getY()); - } else { - translationTree.setSelectionPath(path); - TranslationTreeNode node = translationTree.getSelectionNode(); - TranslationTreeNodeMenu menu = new TranslationTreeNodeMenu(Editor.this, node); - menu.show(e.getComponent(), e.getX(), e.getY()); - } - } - } - + if (path == null) { + TranslationTreeMenu menu = new TranslationTreeMenu(Editor.this, translationTree); + menu.show(e.getComponent(), e.getX(), e.getY()); + } else { + translationTree.setSelectionPath(path); + TranslationTreeNode node = translationTree.getSelectionNode(); + TranslationTreeNodeMenu menu = new TranslationTreeNodeMenu(Editor.this, node); + menu.show(e.getComponent(), e.getX(), e.getY()); + } + } + } + private class TranslationTreeNodeSelectionListener implements TreeSelectionListener { @Override public void valueChanged(TreeSelectionEvent e) { TranslationTreeNode node = translationTree.getSelectionNode(); - + if (node != null) { // Store scroll position int scrollValue = resourcesScrollPane.getVerticalScrollBar().getValue(); - + // Update UI values String key = node.getKey(); translationField.setValue(key); @@ -959,13 +945,13 @@ public void valueChanged(TreeSelectionEvent e) { f.setValue(key); f.setEnabled(node.isEditable()); }); - + // Restore scroll position and foc SwingUtilities.invokeLater(() -> resourcesScrollPane.getVerticalScrollBar().setValue(scrollValue)); } } } - + private class TranslationFieldKeyListener extends KeyAdapter { @Override public void keyReleased(KeyEvent e) { @@ -973,32 +959,32 @@ public void keyReleased(KeyEvent e) { TranslationField field = (TranslationField) e.getSource(); String key = field.getValue(); if (ResourceKeys.isValid(key)) { - addTranslationKey(key); + addTranslationKey(key); } } } } - + private class ResourcesPaneMouseListener extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { showPopupMenu(e); } - + @Override public void mouseReleased(MouseEvent e) { showPopupMenu(e); - } - + } + private void showPopupMenu(MouseEvent e) { if (!e.isPopupTrigger() || project == null) { return; } ResourcesPaneMenu menu = new ResourcesPaneMenu(Editor.this); - menu.show(e.getComponent(), e.getX(), e.getY()); - } + menu.show(e.getComponent(), e.getX(), e.getY()); + } } - + private class ResourceFieldKeyListener extends KeyAdapter { @Override public void keyReleased(KeyEvent e) { @@ -1010,7 +996,7 @@ public void keyReleased(KeyEvent e) { updateTreeNodeStatus(key); } } - + private class EditorWindowListener extends WindowAdapter { @Override public void windowClosing(WindowEvent e) { @@ -1018,6 +1004,6 @@ public void windowClosing(WindowEvent e) { storeEditorState(); System.exit(0); } - } + } } } \ No newline at end of file diff --git a/src/main/java/com/jvms/i18neditor/editor/EditorMenuBar.java b/src/main/java/com/jvms/i18neditor/editor/EditorMenuBar.java index 4d3e3ec..ca0d9ee 100644 --- a/src/main/java/com/jvms/i18neditor/editor/EditorMenuBar.java +++ b/src/main/java/com/jvms/i18neditor/editor/EditorMenuBar.java @@ -24,6 +24,7 @@ import com.jvms.i18neditor.editor.menu.FindTranslationMenuItem; import com.jvms.i18neditor.editor.menu.RemoveTranslationMenuItem; import com.jvms.i18neditor.editor.menu.RenameTranslationMenuItem; +import com.jvms.i18neditor.editor.menu.UndoTranslationKeyMenuItem; import com.jvms.i18neditor.swing.util.Dialogs; import com.jvms.i18neditor.util.MessageBundle; @@ -34,7 +35,7 @@ */ public class EditorMenuBar extends JMenuBar { private final static long serialVersionUID = -101788804096708514L; - + private final Editor editor; private final TranslationTree tree; private JMenuItem saveMenuItem; @@ -43,6 +44,7 @@ public class EditorMenuBar extends JMenuBar { private JMenuItem findTranslationMenuItem; private JMenuItem renameTranslationMenuItem; private JMenuItem copyTranslationKeyMenuItem; + private JMenuItem undoTranslationKeyMenuItem; private JMenuItem duplicateTranslationMenuItem; private JMenuItem removeTranslationMenuItem; private JMenuItem openContainingFolderMenuItem; @@ -52,7 +54,7 @@ public class EditorMenuBar extends JMenuBar { private JMenu editMenu; private JMenu viewMenu; private JMenu settingsMenu; - + public EditorMenuBar(Editor editor, TranslationTree tree) { super(); this.editor = editor; @@ -62,7 +64,7 @@ public EditorMenuBar(Editor editor, TranslationTree tree) { setSaveable(false); setEditable(false); } - + @Override public void setEnabled(boolean enabled) { reloadMenuItem.setEnabled(enabled); @@ -79,166 +81,172 @@ public void setEnabled(boolean enabled) { } SwingUtilities.updateComponentTreeUI(this); } - + public void setSaveable(boolean saveable) { saveMenuItem.setEnabled(saveable); } - + public void setEditable(boolean editable) { addTranslationMenuItem.setEnabled(editable); findTranslationMenuItem.setEnabled(editable); } - + public void setRecentItems(List items) { openRecentMenuItem.removeAll(); - if (items.isEmpty()) { - openRecentMenuItem.setEnabled(false); - } else { - openRecentMenuItem.setEnabled(true); - for (int i = 0; i < items.size(); i++) { - Integer n = i + 1; - JMenuItem menuItem = new JMenuItem(n + ": " + items.get(i), Character.forDigit(i, 10)); - Path path = Paths.get(menuItem.getText().replaceFirst("[0-9]+: ","")); - menuItem.addActionListener(e -> editor.importProject(path, true)); - openRecentMenuItem.add(menuItem); - } - JMenuItem clearMenuItem = new JMenuItem(MessageBundle.get("menu.file.recent.clear.title")); - clearMenuItem.addActionListener(e -> editor.clearHistory()); - openRecentMenuItem.addSeparator(); - openRecentMenuItem.add(clearMenuItem); - } + if (items.isEmpty()) { + openRecentMenuItem.setEnabled(false); + } else { + openRecentMenuItem.setEnabled(true); + for (int i = 0; i < items.size(); i++) { + Integer n = i + 1; + JMenuItem menuItem = new JMenuItem(n + ": " + items.get(i), Character.forDigit(i, 10)); + Path path = Paths.get(menuItem.getText().replaceFirst("[0-9]+: ", "")); + menuItem.addActionListener(e -> editor.importProject(path, true)); + openRecentMenuItem.add(menuItem); + } + JMenuItem clearMenuItem = new JMenuItem(MessageBundle.get("menu.file.recent.clear.title")); + clearMenuItem.addActionListener(e -> editor.clearHistory()); + openRecentMenuItem.addSeparator(); + openRecentMenuItem.add(clearMenuItem); + } } - + private void setupUI() { int keyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); - + // File menu - JMenu fileMenu = new JMenu(MessageBundle.get("menu.file.title")); - fileMenu.setMnemonic(MessageBundle.getMnemonic("menu.file.vk")); - - JMenuItem createJsonMenuItem = new JMenuItem(MessageBundle.get("menu.file.project.new.json.title")); - createJsonMenuItem.addActionListener(e -> editor.showCreateProjectDialog(ResourceType.JSON)); - createJsonMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_J, keyMask+KeyEvent.SHIFT_DOWN_MASK)); - - JMenuItem createEs6MenuItem = new JMenuItem(MessageBundle.get("menu.file.project.new.es6.title")); - createEs6MenuItem.addActionListener(e -> editor.showCreateProjectDialog(ResourceType.ES6)); - createEs6MenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, keyMask+KeyEvent.SHIFT_DOWN_MASK)); - - JMenuItem createPropertiesMenuItem = new JMenuItem(MessageBundle.get("menu.file.project.new.properties.title")); - createPropertiesMenuItem.addActionListener(e -> editor.showCreateProjectDialog(ResourceType.Properties)); - createPropertiesMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, keyMask+KeyEvent.SHIFT_DOWN_MASK)); - - JMenu createMenuItem = new JMenu(MessageBundle.get("menu.file.project.new.title")); - createMenuItem.setMnemonic(MessageBundle.getMnemonic("menu.file.project.new.vk")); - createMenuItem.add(createJsonMenuItem); - createMenuItem.add(createEs6MenuItem); - createMenuItem.add(createPropertiesMenuItem); - - JMenuItem importMenuItem = new JMenuItem(MessageBundle.get("menu.file.project.import.title")); - importMenuItem.setMnemonic(MessageBundle.getMnemonic("menu.file.project.import.vk")); - importMenuItem.addActionListener(e -> editor.showImportProjectDialog()); - - openContainingFolderMenuItem = new JMenuItem(MessageBundle.get("menu.file.folder.title")); - openContainingFolderMenuItem.addActionListener(e -> editor.openProjectDirectory()); - - openRecentMenuItem = new JMenu(MessageBundle.get("menu.file.recent.title")); - openRecentMenuItem.setMnemonic(MessageBundle.getMnemonic("menu.file.recent.vk")); - - saveMenuItem = new JMenuItem(MessageBundle.get("menu.file.save.title"), MessageBundle.getMnemonic("menu.file.save.vk")); - saveMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, keyMask)); - saveMenuItem.addActionListener(e -> editor.saveProject()); - - reloadMenuItem = new JMenuItem(MessageBundle.get("menu.file.reload.title"), MessageBundle.getMnemonic("menu.file.reload.vk")); - reloadMenuItem.addActionListener(e -> editor.reloadProject()); - - JMenuItem exitMenuItem = new JMenuItem(MessageBundle.get("menu.file.exit.title"), MessageBundle.getMnemonic("menu.file.exit.vk")); - exitMenuItem.addActionListener(e -> editor.dispatchEvent(new WindowEvent(editor, WindowEvent.WINDOW_CLOSING))); - - fileMenu.add(createMenuItem); - fileMenu.add(importMenuItem); - if (Desktop.isDesktopSupported()) { - fileMenu.add(openContainingFolderMenuItem); + JMenu fileMenu = new JMenu(MessageBundle.get("menu.file.title")); + fileMenu.setMnemonic(MessageBundle.getMnemonic("menu.file.vk")); + + JMenuItem createJsonMenuItem = new JMenuItem(MessageBundle.get("menu.file.project.new.json.title")); + createJsonMenuItem.addActionListener(e -> editor.showCreateProjectDialog(ResourceType.JSON)); + createJsonMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_J, keyMask + KeyEvent.SHIFT_DOWN_MASK)); + + JMenuItem createEs6MenuItem = new JMenuItem(MessageBundle.get("menu.file.project.new.es6.title")); + createEs6MenuItem.addActionListener(e -> editor.showCreateProjectDialog(ResourceType.ES6)); + createEs6MenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, keyMask + KeyEvent.SHIFT_DOWN_MASK)); + + JMenuItem createPropertiesMenuItem = new JMenuItem(MessageBundle.get("menu.file.project.new.properties.title")); + createPropertiesMenuItem.addActionListener(e -> editor.showCreateProjectDialog(ResourceType.Properties)); + createPropertiesMenuItem + .setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, keyMask + KeyEvent.SHIFT_DOWN_MASK)); + + JMenu createMenuItem = new JMenu(MessageBundle.get("menu.file.project.new.title")); + createMenuItem.setMnemonic(MessageBundle.getMnemonic("menu.file.project.new.vk")); + createMenuItem.add(createJsonMenuItem); + createMenuItem.add(createEs6MenuItem); + createMenuItem.add(createPropertiesMenuItem); + + JMenuItem importMenuItem = new JMenuItem(MessageBundle.get("menu.file.project.import.title")); + importMenuItem.setMnemonic(MessageBundle.getMnemonic("menu.file.project.import.vk")); + importMenuItem.addActionListener(e -> editor.showImportProjectDialog()); + + openContainingFolderMenuItem = new JMenuItem(MessageBundle.get("menu.file.folder.title")); + openContainingFolderMenuItem.addActionListener(e -> editor.openProjectDirectory()); + + openRecentMenuItem = new JMenu(MessageBundle.get("menu.file.recent.title")); + openRecentMenuItem.setMnemonic(MessageBundle.getMnemonic("menu.file.recent.vk")); + + saveMenuItem = new JMenuItem(MessageBundle.get("menu.file.save.title"), + MessageBundle.getMnemonic("menu.file.save.vk")); + saveMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, keyMask)); + saveMenuItem.addActionListener(e -> editor.saveProject()); + + reloadMenuItem = new JMenuItem(MessageBundle.get("menu.file.reload.title"), + MessageBundle.getMnemonic("menu.file.reload.vk")); + reloadMenuItem.addActionListener(e -> editor.reloadProject()); + + JMenuItem exitMenuItem = new JMenuItem(MessageBundle.get("menu.file.exit.title"), + MessageBundle.getMnemonic("menu.file.exit.vk")); + exitMenuItem.addActionListener(e -> editor.dispatchEvent(new WindowEvent(editor, WindowEvent.WINDOW_CLOSING))); + + fileMenu.add(createMenuItem); + fileMenu.add(importMenuItem); + if (Desktop.isDesktopSupported()) { + fileMenu.add(openContainingFolderMenuItem); } - fileMenu.add(openRecentMenuItem); - fileMenu.addSeparator(); - fileMenu.add(saveMenuItem); - fileMenu.add(reloadMenuItem); - fileMenu.addSeparator(); - fileMenu.add(exitMenuItem); - - // Edit menu - editMenu = new JMenu(MessageBundle.get("menu.edit.title")); - editMenu.setMnemonic(MessageBundle.getMnemonic("menu.edit.vk")); - - addTranslationMenuItem = new AddTranslationMenuItem(editor, tree, false); - findTranslationMenuItem = new FindTranslationMenuItem(editor, false); - removeTranslationMenuItem = new RemoveTranslationMenuItem(editor, false); - duplicateTranslationMenuItem = new DuplicateTranslationMenuItem(editor, true); - renameTranslationMenuItem = new RenameTranslationMenuItem(editor, false); - copyTranslationKeyMenuItem = new CopyTranslationKeyToClipboardMenuItem(editor, false); - - editMenu.add(new AddLocaleMenuItem(editor, true)); - editMenu.addSeparator(); - editMenu.add(addTranslationMenuItem); - editMenu.add(findTranslationMenuItem); - editMenu.addSeparator(); - editMenu.add(renameTranslationMenuItem); - editMenu.add(copyTranslationKeyMenuItem); - editMenu.add(duplicateTranslationMenuItem); - editMenu.add(removeTranslationMenuItem); - - // View menu - viewMenu = new JMenu(MessageBundle.get("menu.view.title")); - viewMenu.setMnemonic(MessageBundle.getMnemonic("menu.view.vk")); - viewMenu.add(new ExpandTranslationsMenuItem(tree)); - viewMenu.add(new CollapseTranslationsMenuItem(tree)); - - // Settings menu - settingsMenu = new JMenu(MessageBundle.get("menu.settings.title")); - settingsMenu.setMnemonic(MessageBundle.getMnemonic("menu.settings.vk")); - - editorSettingsMenuItem = new JMenuItem(MessageBundle.get("menu.settings.preferences.editor.title")); - editorSettingsMenuItem.addActionListener(e -> { - Dialogs.showComponentDialog(editor, - MessageBundle.get("dialogs.preferences.editor.title"), - new EditorSettingsPane(editor)); - }); - - projectSettingsMenuItem = new JMenuItem(MessageBundle.get("menu.settings.preferences.project.title")); - projectSettingsMenuItem.addActionListener(e -> { - Dialogs.showComponentDialog(editor, - MessageBundle.get("dialogs.preferences.project.title"), - new EditorProjectSettingsPane(editor)); - }); - - settingsMenu.add(editorSettingsMenuItem); - - // Help menu - JMenu helpMenu = new JMenu(MessageBundle.get("menu.help.title")); - helpMenu.setMnemonic(MessageBundle.getMnemonic("menu.help.vk")); - - JMenuItem versionMenuItem = new JMenuItem(MessageBundle.get("menu.help.version.title")); - versionMenuItem.addActionListener(e -> editor.showVersionDialog(false)); - - JMenuItem aboutMenuItem = new JMenuItem(MessageBundle.get("menu.help.about.title", Editor.TITLE)); - aboutMenuItem.addActionListener(e -> editor.showAboutDialog()); - - helpMenu.add(versionMenuItem); - helpMenu.add(aboutMenuItem); - - add(fileMenu); - add(editMenu); - add(viewMenu); - add(settingsMenu); - add(helpMenu); - - tree.addTreeSelectionListener(e -> { - TranslationTreeNode node = tree.getSelectionNode(); - boolean enabled = node != null && !node.isRoot(); + fileMenu.add(openRecentMenuItem); + fileMenu.addSeparator(); + fileMenu.add(saveMenuItem); + fileMenu.add(reloadMenuItem); + fileMenu.addSeparator(); + fileMenu.add(exitMenuItem); + + // Edit menu + editMenu = new JMenu(MessageBundle.get("menu.edit.title")); + editMenu.setMnemonic(MessageBundle.getMnemonic("menu.edit.vk")); + + addTranslationMenuItem = new AddTranslationMenuItem(editor, tree, false); + findTranslationMenuItem = new FindTranslationMenuItem(editor, false); + removeTranslationMenuItem = new RemoveTranslationMenuItem(editor, false); + duplicateTranslationMenuItem = new DuplicateTranslationMenuItem(editor, true); + renameTranslationMenuItem = new RenameTranslationMenuItem(editor, false); + copyTranslationKeyMenuItem = new CopyTranslationKeyToClipboardMenuItem(editor, false); + undoTranslationKeyMenuItem = new UndoTranslationKeyMenuItem(editor, false); + + editMenu.add(new AddLocaleMenuItem(editor, true)); + editMenu.addSeparator(); + editMenu.add(undoTranslationKeyMenuItem); + editMenu.addSeparator(); + editMenu.add(addTranslationMenuItem); + editMenu.add(findTranslationMenuItem); + editMenu.addSeparator(); + editMenu.add(renameTranslationMenuItem); + editMenu.add(copyTranslationKeyMenuItem); + editMenu.add(duplicateTranslationMenuItem); + editMenu.add(removeTranslationMenuItem); + + // View menu + viewMenu = new JMenu(MessageBundle.get("menu.view.title")); + viewMenu.setMnemonic(MessageBundle.getMnemonic("menu.view.vk")); + viewMenu.add(new ExpandTranslationsMenuItem(tree)); + viewMenu.add(new CollapseTranslationsMenuItem(tree)); + + // Settings menu + settingsMenu = new JMenu(MessageBundle.get("menu.settings.title")); + settingsMenu.setMnemonic(MessageBundle.getMnemonic("menu.settings.vk")); + + editorSettingsMenuItem = new JMenuItem(MessageBundle.get("menu.settings.preferences.editor.title")); + editorSettingsMenuItem.addActionListener(e -> { + Dialogs.showComponentDialog(editor, MessageBundle.get("dialogs.preferences.editor.title"), + new EditorSettingsPane(editor)); + }); + + projectSettingsMenuItem = new JMenuItem(MessageBundle.get("menu.settings.preferences.project.title")); + projectSettingsMenuItem.addActionListener(e -> { + Dialogs.showComponentDialog(editor, MessageBundle.get("dialogs.preferences.project.title"), + new EditorProjectSettingsPane(editor)); + }); + + settingsMenu.add(editorSettingsMenuItem); + + // Help menu + JMenu helpMenu = new JMenu(MessageBundle.get("menu.help.title")); + helpMenu.setMnemonic(MessageBundle.getMnemonic("menu.help.vk")); + + JMenuItem versionMenuItem = new JMenuItem(MessageBundle.get("menu.help.version.title")); + versionMenuItem.addActionListener(e -> editor.showVersionDialog(false)); + + JMenuItem aboutMenuItem = new JMenuItem(MessageBundle.get("menu.help.about.title", Editor.TITLE)); + aboutMenuItem.addActionListener(e -> editor.showAboutDialog()); + + helpMenu.add(versionMenuItem); + helpMenu.add(aboutMenuItem); + + add(fileMenu); + add(editMenu); + add(viewMenu); + add(settingsMenu); + add(helpMenu); + + tree.addTreeSelectionListener(e -> { + TranslationTreeNode node = tree.getSelectionNode(); + boolean enabled = node != null && !node.isRoot(); renameTranslationMenuItem.setEnabled(enabled); copyTranslationKeyMenuItem.setEnabled(enabled); + undoTranslationKeyMenuItem.setEnabled(enabled); duplicateTranslationMenuItem.setEnabled(enabled); removeTranslationMenuItem.setEnabled(enabled); - }); + }); } } diff --git a/src/main/java/com/jvms/i18neditor/editor/menu/UndoTranslationKeyMenuItem.java b/src/main/java/com/jvms/i18neditor/editor/menu/UndoTranslationKeyMenuItem.java new file mode 100644 index 0000000..bf7d419 --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/menu/UndoTranslationKeyMenuItem.java @@ -0,0 +1,26 @@ +package com.jvms.i18neditor.editor.menu; + +import javax.swing.JMenuItem; + +import com.jvms.i18neditor.editor.Editor; +import com.jvms.i18neditor.util.MessageBundle; + +/** + * This class represents a menu item for copying a translations key to the + * system clipboard. + * + * @author Fabian Terstegen + * + */ +public class UndoTranslationKeyMenuItem extends JMenuItem { + private static final long serialVersionUID = 6032182493888769724L; + + public UndoTranslationKeyMenuItem(Editor editor, boolean enabled) { + super(MessageBundle.get("menu.edit.undo.title")); + // setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, + // Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + addActionListener(e -> editor.UndoTranslationKey()); + setEnabled(enabled); + } + +} diff --git a/src/main/resources/bundles/messages.properties b/src/main/resources/bundles/messages.properties index 6d26699..fb02b67 100644 --- a/src/main/resources/bundles/messages.properties +++ b/src/main/resources/bundles/messages.properties @@ -43,6 +43,7 @@ menu.edit.find.translation.title = Find Translation... menu.edit.rename.title = Rename Translation... menu.edit.copy.key.title = Copy Translation Key... menu.edit.title = Edit +menu.edit.undo.title = Undo... menu.edit.vk = E menu.file.exit.title = Exit menu.file.exit.vk = E diff --git a/src/main/resources/bundles/messages_nl.properties b/src/main/resources/bundles/messages_nl.properties index fabea37..41e060b 100644 --- a/src/main/resources/bundles/messages_nl.properties +++ b/src/main/resources/bundles/messages_nl.properties @@ -43,6 +43,7 @@ menu.edit.find.translation.title = Vertaling Zoeken... menu.edit.rename.title = Vertaling Hernoemen... menu.edit.copy.key.title = Copy Translation Key... menu.edit.title = Bewerken +menu.edit.undo.title = Ongedaan maken... menu.edit.vk = W menu.file.exit.title = Sluiten menu.file.exit.vk = S From aadc209ee5b9706544c7ada28705dc7f2575642b Mon Sep 17 00:00:00 2001 From: Maximiliano Diaz Date: Sat, 7 Jul 2018 11:22:49 -0300 Subject: [PATCH 2/2] add undo redo functionality --- .../java/com/jvms/i18neditor/Resource.java | 159 +++++++++++------- .../i18neditor/editor/ActionTranslation.java | 19 +++ .../editor/ActionTranslationInterface.java | 17 ++ .../editor/AddActionTranslation.java | 30 ++++ .../com/jvms/i18neditor/editor/Editor.java | 31 ++++ .../jvms/i18neditor/editor/EditorMenuBar.java | 9 +- .../jvms/i18neditor/editor/EditorProject.java | 6 +- .../editor/RemoveActionTranslation.java | 36 ++++ .../editor/RenameActionTranslation.java | 32 ++++ .../editor/StatusUndoRedoTransaction.java | 5 + .../editor/UndoRedoManagerTranslation.java | 88 ++++++++++ .../menu/RedoTranslationKeyMenuItem.java | 25 +++ .../menu/UndoTranslationKeyMenuItem.java | 14 +- .../editor/menu/updateStatusInterface.java | 14 ++ .../resources/bundles/messages.properties | 1 + 15 files changed, 409 insertions(+), 77 deletions(-) create mode 100644 src/main/java/com/jvms/i18neditor/editor/ActionTranslation.java create mode 100644 src/main/java/com/jvms/i18neditor/editor/ActionTranslationInterface.java create mode 100644 src/main/java/com/jvms/i18neditor/editor/AddActionTranslation.java create mode 100644 src/main/java/com/jvms/i18neditor/editor/RemoveActionTranslation.java create mode 100644 src/main/java/com/jvms/i18neditor/editor/RenameActionTranslation.java create mode 100644 src/main/java/com/jvms/i18neditor/editor/StatusUndoRedoTransaction.java create mode 100644 src/main/java/com/jvms/i18neditor/editor/UndoRedoManagerTranslation.java create mode 100644 src/main/java/com/jvms/i18neditor/editor/menu/RedoTranslationKeyMenuItem.java create mode 100644 src/main/java/com/jvms/i18neditor/editor/menu/updateStatusInterface.java diff --git a/src/main/java/com/jvms/i18neditor/Resource.java b/src/main/java/com/jvms/i18neditor/Resource.java index 68c0e61..4d2eafd 100644 --- a/src/main/java/com/jvms/i18neditor/Resource.java +++ b/src/main/java/com/jvms/i18neditor/Resource.java @@ -14,17 +14,22 @@ import com.jvms.i18neditor.util.ResourceKeys; /** - * A resource is a container for storing i18n data and is defined by the following properties: + * A resource is a container for storing i18n data and is defined by the + * following properties: * *
    - *
  • {@code type} the type of the resource, either {@code JSON} or {@code ES6}.
  • - *
  • {@code path} the path to the resource file on disk.
  • + *
  • {@code type} the type of the resource, either {@code JSON} or + * {@code ES6}.
  • + *
  • {@code path} the path to the resource file on disk.
  • *
  • {@code locale} the locale of the resource.
  • - *
  • {@code translations} a sorted map containing the translations of the resource by key value pair.
  • + *
  • {@code translations} a sorted map containing the translations of the + * resource by key value pair.
  • *
* - *

Objects can listen to a resource by adding a {@link ResourceListener} which - * will be called when any change is made to the {@code translations}.

+ *

+ * Objects can listen to a resource by adding a {@link ResourceListener} which + * will be called when any change is made to the {@code translations}. + *

* * @author Jacob van Mourik */ @@ -33,104 +38,119 @@ public class Resource { private final Locale locale; private final ResourceType type; private final List listeners = Lists.newLinkedList(); - private SortedMap translations = Maps.newTreeMap(); - + private SortedMap translations = Maps.newTreeMap(); + /** * See {@link #Resource(ResourceType, Path, Locale)}. */ public Resource(ResourceType type, Path path) { this(type, path, null); } - + /** * Creates a new instance of a resource. * - * @param type the type of the resource. - * @param path the path to the file on disk. - * @param locale the locale of the translations. + * @param type + * the type of the resource. + * @param path + * the path to the file on disk. + * @param locale + * the locale of the translations. */ public Resource(ResourceType type, Path path, Locale locale) { this.path = path; this.locale = locale; this.type = type; } - + /** * Gets the type of the resource. * - * @return the type. + * @return the type. */ public ResourceType getType() { return type; } - + /** * Gets the path to the resource file on disk. * - * @return the path. + * @return the path. */ public Path getPath() { return path; } - + /** * Gets the locale of the translations of the resource. * - * @return the locale of the resource, may be {@code null}. + * @return the locale of the resource, may be {@code null}. */ public Locale getLocale() { return locale; } - + /** * Gets a map of the translations of the resource. * - *

The returned map is an immutable sorted map. Modifications to the translations should be done via - * {@link #storeTranslation(String, String)}, {@link #removeTranslation(String)} or - * {@link #renameTranslation(String, String)}.

+ *

+ * The returned map is an immutable sorted map. Modifications to the + * translations should be done via + * {@link #storeTranslation(String, String)}, + * {@link #removeTranslation(String)} or + * {@link #renameTranslation(String, String)}. + *

* - * @return the translations of the resource. + * @return the translations of the resource. */ - public SortedMap getTranslations() { + public SortedMap getTranslations() { return ImmutableSortedMap.copyOf(translations); } - - public void setTranslations(SortedMap translations) { + + public void setTranslations(SortedMap translations) { this.translations = translations; } - + public boolean hasTranslation(String key) { return !Strings.isNullOrEmpty(translations.get(key)); } - + /** * Gets a translation from the resource's translations. * - * @param key the key of the translation to get. - * @return value of the translation or {@code null} if there is no translation for the given key. + * @param key + * the key of the translation to get. + * @return value of the translation or {@code null} if there is no + * translation for the given key. */ public String getTranslation(String key) { return translations.get(key); } - + /** * Stores a translation to the resource's translations. * *
    - *
  • If the given key does not exists yet and is not empty, a new translation will be added to the map.
  • - *
  • If the given key already exists, the existing value will be overwritten with the given value.
  • - *
  • If the given key is a parent key of any existing keys, the existing child keys will be removed.
  • - *
  • If the given key is a child key of any existing keys, the existing parent keys will be removed.
  • + *
  • If the given key does not exists yet and is not empty, a new + * translation will be added to the map.
  • + *
  • If the given key already exists, the existing value will be + * overwritten with the given value.
  • + *
  • If the given key is a parent key of any existing keys, the existing + * child keys will be removed.
  • + *
  • If the given key is a child key of any existing keys, the existing + * parent keys will be removed.
  • *
* - * @param key the key of the translation to add. - * @param value the value of the translation to add corresponding the given key. + * @param key + * the key of the translation to add. + * @param value + * the value of the translation to add corresponding the given + * key. */ public void storeTranslation(String key, String value) { checkKey(key); String existing = translations.get(key); - if (existing == null && value.isEmpty() || - existing != null && existing.equals(value)) { + if (existing == null && value.isEmpty() || existing != null && existing.equals(value)) { return; } removeParents(key); @@ -142,65 +162,74 @@ public void storeTranslation(String key, String value) { } notifyListeners(); } - + /** - * Removes a translation from the resource's translations. - * Any child keys of the given key will also be removed. + * Removes a translation from the resource's translations. Any child keys of + * the given key will also be removed. * - * @param key the key of the translation to remove. + * @param key + * the key of the translation to remove. */ public void removeTranslation(String key) { removeChildren(key); translations.remove(key); notifyListeners(); } - + /** - * Renames a translation key in the resource's translations. - * Any existing child keys of the translation key will also be renamed. + * Renames a translation key in the resource's translations. Any existing + * child keys of the translation key will also be renamed. * - * @param key the old key of the translation to rename. - * @param newKey the new key. + * @param key + * the old key of the translation to rename. + * @param newKey + * the new key. */ public void renameTranslation(String key, String newKey) { checkKey(newKey); duplicateTranslation(key, newKey, false); notifyListeners(); } - + /** - * Duplicates a translation key, and any child keys, in the resource's translations. + * Duplicates a translation key, and any child keys, in the resource's + * translations. * - * @param key the key of the translation to duplicate. - * @param newKey the new key. + * @param key + * the key of the translation to duplicate. + * @param newKey + * the new key. */ public void duplicateTranslation(String key, String newKey) { checkKey(newKey); duplicateTranslation(key, newKey, true); notifyListeners(); } - + /** - * Adds a listener to the resource. The listener will be called whenever there is made - * a change to the translations of the resource. + * Adds a listener to the resource. The listener will be called whenever + * there is made a change to the translations of the resource. * - * @param listener the listener to add. + * @param listener + * the listener to add. */ public void addListener(ResourceListener listener) { listeners.add(listener); } - + /** - * Removes a listener from the resource previously added by {@link #addListener(ResourceListener)}. + * Removes a listener from the resource previously added by + * {@link #addListener(ResourceListener)}. * - * @param listener the listener to remove. + * @param listener + * the listener to remove. */ public void removeListener(ResourceListener listener) { listeners.remove(listener); } - + private void duplicateTranslation(String key, String newKey, boolean keepOld) { - Map newTranslations = Maps.newTreeMap(); + Map newTranslations = Maps.newTreeMap(); translations.keySet().forEach(k -> { if (ResourceKeys.isChildKeyOf(k, key)) { String nk = ResourceKeys.create(newKey, ResourceKeys.childKey(k, key)); @@ -216,7 +245,7 @@ private void duplicateTranslation(String key, String newKey, boolean keepOld) { } newTranslations.forEach(this::storeTranslation); } - + private void removeChildren(String key) { Lists.newLinkedList(translations.keySet()).forEach(k -> { if (ResourceKeys.isChildKeyOf(k, key)) { @@ -224,7 +253,7 @@ private void removeChildren(String key) { } }); } - + private void removeParents(String key) { Lists.newLinkedList(translations.keySet()).forEach(k -> { if (ResourceKeys.isChildKeyOf(key, k)) { @@ -232,11 +261,11 @@ private void removeParents(String key) { } }); } - + private void notifyListeners() { listeners.forEach(l -> l.resourceChanged(new ResourceEvent(this))); } - + private void checkKey(String key) { Preconditions.checkArgument(ResourceKeys.isValid(key), "Key is not valid."); } diff --git a/src/main/java/com/jvms/i18neditor/editor/ActionTranslation.java b/src/main/java/com/jvms/i18neditor/editor/ActionTranslation.java new file mode 100644 index 0000000..0e82be3 --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/ActionTranslation.java @@ -0,0 +1,19 @@ +package com.jvms.i18neditor.editor; + +/** + * This class represents the action save in Undo/Redo + * + * @author Maximiliano Diaz + */ +public abstract class ActionTranslation implements ActionTranslationInterface { + protected String key; + + public ActionTranslation(String key) { + this.key = key; + } + + public String getkey() { + return key; + } + +} diff --git a/src/main/java/com/jvms/i18neditor/editor/ActionTranslationInterface.java b/src/main/java/com/jvms/i18neditor/editor/ActionTranslationInterface.java new file mode 100644 index 0000000..2373061 --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/ActionTranslationInterface.java @@ -0,0 +1,17 @@ +package com.jvms.i18neditor.editor; + +import java.util.Map; + +import com.jvms.i18neditor.Resource; + +/** + * This interface represents the methods importants that execute the actions + * + * @author Maximiliano Diaz + */ +public interface ActionTranslationInterface { + + public void execute(Editor editor); + + public void setTranslationMap(Map map); +} diff --git a/src/main/java/com/jvms/i18neditor/editor/AddActionTranslation.java b/src/main/java/com/jvms/i18neditor/editor/AddActionTranslation.java new file mode 100644 index 0000000..0505486 --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/AddActionTranslation.java @@ -0,0 +1,30 @@ +package com.jvms.i18neditor.editor; + +import java.util.Map; + +import com.jvms.i18neditor.Resource; + +/** + * This class represents the action save in Undo/Redo when RemoveTranslationKey + * + * @author Maximiliano Diaz + */ +public class AddActionTranslation extends ActionTranslation { + + public AddActionTranslation(String key) { + super(key); + } + + @Override + public void execute(Editor editor) { + editor.removeTranslationKey(key); + editor.setNodeInFocus(""); + + } + + @Override + public void setTranslationMap(Map map) { + // TODO Auto-generated method stub + + } +} diff --git a/src/main/java/com/jvms/i18neditor/editor/Editor.java b/src/main/java/com/jvms/i18neditor/editor/Editor.java index 960da0a..34b04d1 100644 --- a/src/main/java/com/jvms/i18neditor/editor/Editor.java +++ b/src/main/java/com/jvms/i18neditor/editor/Editor.java @@ -104,6 +104,7 @@ public class Editor extends JFrame { private TranslationTree translationTree; private TranslationField translationField; private JPanel resourcesPanel; + private UndoRedoManagerTranslation undoManagerTranslations = new UndoRedoManagerTranslation(this, translationTree); private List resourceFields = Lists.newArrayList(); public Editor() { @@ -272,12 +273,15 @@ public void addTranslationKey(String key) { if (project != null) { project.getResources().forEach(resource -> resource.storeTranslation(key, "")); } + undoManagerTranslations.rememberAction(new AddActionTranslation(key)); translationTree.addNodeByKey(key); } requestFocusInFirstResourceField(); } public void removeTranslationKey(String key) { + undoManagerTranslations.rememberAction(new RemoveActionTranslation(key)); + if (project != null) { project.getResources().forEach(resource -> resource.removeTranslation(key)); } @@ -290,6 +294,7 @@ public void renameTranslationKey(String key, String newKey) { project.getResources().forEach(resource -> resource.renameTranslation(key, newKey)); } translationTree.renameNodeByKey(key, newKey); + undoManagerTranslations.rememberAction(new RenameActionTranslation(key, newKey)); requestFocusInFirstResourceField(); } @@ -297,6 +302,7 @@ public void duplicateTranslationKey(String key, String newKey) { if (project != null) { project.getResources().forEach(resource -> resource.duplicateTranslation(key, newKey)); } + undoManagerTranslations.rememberAction(new AddActionTranslation(newKey)); translationTree.duplicateNodeByKey(key, newKey); requestFocusInFirstResourceField(); } @@ -621,7 +627,22 @@ public void updateUI() { } public void UndoTranslationKey() { + undoManagerTranslations.undo(); + } + + public void RedoTranslationKey() { + undoManagerTranslations.redo(); + } + public UndoRedoManagerTranslation getUndoRedoManagerTranslation() { + return undoManagerTranslations; + } + + public void setNodeInFocus(String name) { + TranslationTreeNode selectedNode = translationTree.getNodeByKey(name); + if (selectedNode != null) { + translationTree.setSelectionNode(selectedNode); + } } private void requestFocusInFirstResourceField() { @@ -1006,4 +1027,14 @@ public void windowClosing(WindowEvent e) { } } } + + public boolean canUndoTranslation() { + // TODO Auto-generated method stub + return undoManagerTranslations.canUndo(); + } + + public boolean canRedoTranslation() { + // TODO Auto-generated method stub + return undoManagerTranslations.canRedo(); + } } \ No newline at end of file diff --git a/src/main/java/com/jvms/i18neditor/editor/EditorMenuBar.java b/src/main/java/com/jvms/i18neditor/editor/EditorMenuBar.java index ca0d9ee..3d9ccf6 100644 --- a/src/main/java/com/jvms/i18neditor/editor/EditorMenuBar.java +++ b/src/main/java/com/jvms/i18neditor/editor/EditorMenuBar.java @@ -22,6 +22,7 @@ import com.jvms.i18neditor.editor.menu.DuplicateTranslationMenuItem; import com.jvms.i18neditor.editor.menu.ExpandTranslationsMenuItem; import com.jvms.i18neditor.editor.menu.FindTranslationMenuItem; +import com.jvms.i18neditor.editor.menu.RedoTranslationKeyMenuItem; import com.jvms.i18neditor.editor.menu.RemoveTranslationMenuItem; import com.jvms.i18neditor.editor.menu.RenameTranslationMenuItem; import com.jvms.i18neditor.editor.menu.UndoTranslationKeyMenuItem; @@ -45,6 +46,7 @@ public class EditorMenuBar extends JMenuBar { private JMenuItem renameTranslationMenuItem; private JMenuItem copyTranslationKeyMenuItem; private JMenuItem undoTranslationKeyMenuItem; + private JMenuItem redoTranslationKeyMenuItem; private JMenuItem duplicateTranslationMenuItem; private JMenuItem removeTranslationMenuItem; private JMenuItem openContainingFolderMenuItem; @@ -183,10 +185,13 @@ private void setupUI() { renameTranslationMenuItem = new RenameTranslationMenuItem(editor, false); copyTranslationKeyMenuItem = new CopyTranslationKeyToClipboardMenuItem(editor, false); undoTranslationKeyMenuItem = new UndoTranslationKeyMenuItem(editor, false); - + redoTranslationKeyMenuItem = new RedoTranslationKeyMenuItem(editor, false); + editor.getUndoRedoManagerTranslation().addListener(undoTranslationKeyMenuItem); + editor.getUndoRedoManagerTranslation().addListener(redoTranslationKeyMenuItem); editMenu.add(new AddLocaleMenuItem(editor, true)); editMenu.addSeparator(); editMenu.add(undoTranslationKeyMenuItem); + editMenu.add(redoTranslationKeyMenuItem); editMenu.addSeparator(); editMenu.add(addTranslationMenuItem); editMenu.add(findTranslationMenuItem); @@ -242,9 +247,9 @@ private void setupUI() { tree.addTreeSelectionListener(e -> { TranslationTreeNode node = tree.getSelectionNode(); boolean enabled = node != null && !node.isRoot(); + renameTranslationMenuItem.setEnabled(enabled); copyTranslationKeyMenuItem.setEnabled(enabled); - undoTranslationKeyMenuItem.setEnabled(enabled); duplicateTranslationMenuItem.setEnabled(enabled); removeTranslationMenuItem.setEnabled(enabled); }); diff --git a/src/main/java/com/jvms/i18neditor/editor/EditorProject.java b/src/main/java/com/jvms/i18neditor/editor/EditorProject.java index 0f6a9e0..ca83cd1 100644 --- a/src/main/java/com/jvms/i18neditor/editor/EditorProject.java +++ b/src/main/java/com/jvms/i18neditor/editor/EditorProject.java @@ -20,7 +20,7 @@ public class EditorProject { private List resources = Lists.newLinkedList(); private boolean minifyResources; private boolean plainJSON; - + public EditorProject(Path path) { this.path = path; } @@ -48,11 +48,11 @@ public List getResources() { public void setResources(List resources) { this.resources = resources; } - + public void addResource(Resource resource) { resources.add(resource); } - + public boolean hasResources() { return !resources.isEmpty(); } diff --git a/src/main/java/com/jvms/i18neditor/editor/RemoveActionTranslation.java b/src/main/java/com/jvms/i18neditor/editor/RemoveActionTranslation.java new file mode 100644 index 0000000..cee7249 --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/RemoveActionTranslation.java @@ -0,0 +1,36 @@ +package com.jvms.i18neditor.editor; + +import java.util.Map; + +import com.jvms.i18neditor.Resource; + +/** + * This class represents the action save in Undo/Redo when execute a + * AddTranslationKey + * + * @author Maximiliano Diaz + */ +public class RemoveActionTranslation extends ActionTranslation { + private Map map; + + public RemoveActionTranslation(String key) { + super(key); + } + + @Override + public void execute(Editor editor) { + editor.addTranslationKey(this.key); + for (Map.Entry entry : map.entrySet()) { + entry.getKey().storeTranslation(key, entry.getValue()); + } + editor.setNodeInFocus(""); + editor.setNodeInFocus(this.key); + + } + + @Override + public void setTranslationMap(Map map) { + this.map = map; + } + +} diff --git a/src/main/java/com/jvms/i18neditor/editor/RenameActionTranslation.java b/src/main/java/com/jvms/i18neditor/editor/RenameActionTranslation.java new file mode 100644 index 0000000..db93c17 --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/RenameActionTranslation.java @@ -0,0 +1,32 @@ +package com.jvms.i18neditor.editor; + +import java.util.Map; + +import com.jvms.i18neditor.Resource; + +/** + * This class represents the action save in Undo/Redo when execute a + * RenameTranslationKey + * + * @author Maximiliano Diaz + */ +public class RenameActionTranslation extends ActionTranslation { + private String newKey; + + public RenameActionTranslation(String key, String newKey) { + super(key); + this.newKey = newKey; + } + + @Override + public void execute(Editor editor) { + editor.renameTranslationKey(this.newKey, this.key); + } + + @Override + public void setTranslationMap(Map map) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/com/jvms/i18neditor/editor/StatusUndoRedoTransaction.java b/src/main/java/com/jvms/i18neditor/editor/StatusUndoRedoTransaction.java new file mode 100644 index 0000000..c6ca4de --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/StatusUndoRedoTransaction.java @@ -0,0 +1,5 @@ +package com.jvms.i18neditor.editor; + +public enum StatusUndoRedoTransaction { + UNDO, REDO, OTHER +} diff --git a/src/main/java/com/jvms/i18neditor/editor/UndoRedoManagerTranslation.java b/src/main/java/com/jvms/i18neditor/editor/UndoRedoManagerTranslation.java new file mode 100644 index 0000000..ca31813 --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/UndoRedoManagerTranslation.java @@ -0,0 +1,88 @@ +package com.jvms.i18neditor.editor; + +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import javax.swing.JMenuItem; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.jvms.i18neditor.Resource; +import com.jvms.i18neditor.editor.menu.updateStatusInterface; + +/** + * This class represents the Manager of Undo/Redo Action + * + * @author Maximiliano Diaz + */ +public class UndoRedoManagerTranslation { + + private Stack actionsUndo = new Stack(); + private Stack actionsRedo = new Stack(); + private List optionMenus = Lists.newArrayList(); + private Editor editor; + private StatusUndoRedoTransaction status = StatusUndoRedoTransaction.OTHER; + + public UndoRedoManagerTranslation(Editor editor, TranslationTree translationTree) { + this.editor = editor; + } + + public void rememberAction(ActionTranslation actionTranslation) { + switch (status) { + case UNDO: + actionsRedo.push(actionTranslation); + break; + case OTHER: + actionsUndo.push(actionTranslation); + break; + default: + break; + } + Map map = Maps.newHashMap(); + List resources = editor.getProject().getResources(); + for (Resource resource : resources) { + if (resource.getTranslation(actionTranslation.getkey()) != null) { + map.put(resource, resource.getTranslation(actionTranslation.getkey())); + } + } + actionTranslation.setTranslationMap(map); + update(); + } + + public Boolean canUndo() { + return !actionsUndo.isEmpty(); + } + + public void undo() { + status = StatusUndoRedoTransaction.UNDO; + if (canUndo()) { + (actionsUndo.pop()).execute(editor); + } + status = StatusUndoRedoTransaction.OTHER; + update(); + } + + public Boolean canRedo() { + return !actionsRedo.isEmpty(); + } + + public void redo() { + status = StatusUndoRedoTransaction.REDO; + if (canRedo()) { + (actionsRedo.pop()).execute(editor); + } + status = StatusUndoRedoTransaction.OTHER; + update(); + } + + public void update() { + for (updateStatusInterface optionMenu : optionMenus) { + optionMenu.updateStatus(this.editor); + } + } + + public void addListener(JMenuItem translationKeyMenuItem) { + optionMenus.add((updateStatusInterface) translationKeyMenuItem); + } +} diff --git a/src/main/java/com/jvms/i18neditor/editor/menu/RedoTranslationKeyMenuItem.java b/src/main/java/com/jvms/i18neditor/editor/menu/RedoTranslationKeyMenuItem.java new file mode 100644 index 0000000..f1b0400 --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/menu/RedoTranslationKeyMenuItem.java @@ -0,0 +1,25 @@ +package com.jvms.i18neditor.editor.menu; + +import javax.swing.JMenuItem; + +import com.jvms.i18neditor.editor.Editor; +import com.jvms.i18neditor.util.MessageBundle; + +/** + * This class represents the Redo in Menu + * + * @author Maximiliano Diaz + */ +public class RedoTranslationKeyMenuItem extends JMenuItem implements updateStatusInterface { + private static final long serialVersionUID = 6032182493888769724L; + + public RedoTranslationKeyMenuItem(Editor editor, boolean enabled) { + super(MessageBundle.get("menu.edit.redo.title")); + addActionListener(e -> editor.RedoTranslationKey()); + setEnabled(enabled); + } + + public void updateStatus(Editor editor) { + setEnabled(editor.canRedoTranslation()); + } +} diff --git a/src/main/java/com/jvms/i18neditor/editor/menu/UndoTranslationKeyMenuItem.java b/src/main/java/com/jvms/i18neditor/editor/menu/UndoTranslationKeyMenuItem.java index bf7d419..09e0e5e 100644 --- a/src/main/java/com/jvms/i18neditor/editor/menu/UndoTranslationKeyMenuItem.java +++ b/src/main/java/com/jvms/i18neditor/editor/menu/UndoTranslationKeyMenuItem.java @@ -6,21 +6,21 @@ import com.jvms.i18neditor.util.MessageBundle; /** - * This class represents a menu item for copying a translations key to the - * system clipboard. + * This class represents the Undo in Menu * - * @author Fabian Terstegen - * + * @author Maximiliano Diaz */ -public class UndoTranslationKeyMenuItem extends JMenuItem { +public class UndoTranslationKeyMenuItem extends JMenuItem implements updateStatusInterface { private static final long serialVersionUID = 6032182493888769724L; public UndoTranslationKeyMenuItem(Editor editor, boolean enabled) { super(MessageBundle.get("menu.edit.undo.title")); - // setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, - // Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); addActionListener(e -> editor.UndoTranslationKey()); setEnabled(enabled); } + public void updateStatus(Editor editor) { + setEnabled(editor.canUndoTranslation()); + } + } diff --git a/src/main/java/com/jvms/i18neditor/editor/menu/updateStatusInterface.java b/src/main/java/com/jvms/i18neditor/editor/menu/updateStatusInterface.java new file mode 100644 index 0000000..ff57af8 --- /dev/null +++ b/src/main/java/com/jvms/i18neditor/editor/menu/updateStatusInterface.java @@ -0,0 +1,14 @@ +package com.jvms.i18neditor.editor.menu; + +import com.jvms.i18neditor.editor.Editor; + +/** + * This interface represents the class that has to update the view. + * + * @author Rosali Zaracho + */ +public interface updateStatusInterface { + + public void updateStatus(Editor editor); + +} diff --git a/src/main/resources/bundles/messages.properties b/src/main/resources/bundles/messages.properties index fb02b67..895f3aa 100644 --- a/src/main/resources/bundles/messages.properties +++ b/src/main/resources/bundles/messages.properties @@ -44,6 +44,7 @@ menu.edit.rename.title = Rename Translation... menu.edit.copy.key.title = Copy Translation Key... menu.edit.title = Edit menu.edit.undo.title = Undo... +menu.edit.redo.title = Redo... menu.edit.vk = E menu.file.exit.title = Exit menu.file.exit.vk = E