diff --git a/CHANGELOG.md b/CHANGELOG.md index 65ffacd..2146da2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,15 @@ # easy-i18n Changelog ## [Unreleased] +### Added +- Scroll to created / edited translation inside Tree-/Table-View + ### Changed - Updated dependencies +### Fixed +- Always synchronize ui with loaded state by reloadFromDisk function + ## [1.2.0] ### Added - Sorting for properties files diff --git a/src/main/java/de/marhali/easyi18n/model/DataSynchronizer.java b/src/main/java/de/marhali/easyi18n/model/DataSynchronizer.java index fc25fe4..7cc3e71 100644 --- a/src/main/java/de/marhali/easyi18n/model/DataSynchronizer.java +++ b/src/main/java/de/marhali/easyi18n/model/DataSynchronizer.java @@ -12,7 +12,8 @@ public interface DataSynchronizer { /** * Propagates data changes to implementation classes. * @param translations Updated translations model - * @param searchQuery Can be used to filter visible data. Like a search function for the full key path. + * @param searchQuery Can be used to filter visible data. Like a search function for the full key path + * @param scrollToKey Focus specific translation. Can be null to disable this function */ - void synchronize(@NotNull Translations translations, @Nullable String searchQuery); + void synchronize(@NotNull Translations translations, @Nullable String searchQuery, @Nullable String scrollToKey); } \ No newline at end of file diff --git a/src/main/java/de/marhali/easyi18n/model/tree/TreeModelTranslator.java b/src/main/java/de/marhali/easyi18n/model/tree/TreeModelTranslator.java index dc87a52..a479deb 100644 --- a/src/main/java/de/marhali/easyi18n/model/tree/TreeModelTranslator.java +++ b/src/main/java/de/marhali/easyi18n/model/tree/TreeModelTranslator.java @@ -91,4 +91,42 @@ public class TreeModelTranslator extends DefaultTreeModel { } } } + + public TreePath findTreePath(@NotNull String fullPath) { + List sections = TranslationsUtil.getSections(fullPath); + Object[] nodes = new Object[sections.size() + 1]; + + int pos = 0; + TreeNode currentNode = (TreeNode) this.getRoot(); + nodes[pos] = currentNode; + + for(String section : sections) { + pos++; + currentNode = findNode(currentNode, section); + nodes[pos] = currentNode; + } + + return new TreePath(nodes); + } + + public @Nullable DefaultMutableTreeNode findNode(@NotNull TreeNode parent, @NotNull String key) { + for(int i = 0; i < parent.getChildCount(); i++) { + TreeNode child = parent.getChildAt(i); + + if(child instanceof DefaultMutableTreeNode) { + DefaultMutableTreeNode mutableChild = (DefaultMutableTreeNode) child; + String childKey = mutableChild.getUserObject().toString(); + + if(mutableChild.getUserObject() instanceof PresentationData) { + childKey = ((PresentationData) mutableChild.getUserObject()).getPresentableText(); + } + + if(childKey != null && childKey.equals(key)) { + return mutableChild; + } + } + } + + throw new NullPointerException("Cannot find node by key: " + key); + } } diff --git a/src/main/java/de/marhali/easyi18n/service/DataStore.java b/src/main/java/de/marhali/easyi18n/service/DataStore.java index 63e3f46..0f8b602 100644 --- a/src/main/java/de/marhali/easyi18n/service/DataStore.java +++ b/src/main/java/de/marhali/easyi18n/service/DataStore.java @@ -61,7 +61,7 @@ public class DataStore { new LocalizedNode(LocalizedNode.ROOT_KEY, new ArrayList<>())); // Propagate changes - synchronizer.forEach(synchronizer -> synchronizer.synchronize(translations, searchQuery)); + synchronizer.forEach(synchronizer -> synchronizer.synchronize(translations, searchQuery, null)); } else { TranslatorIO io = IOUtil.determineFormat(localesPath); @@ -71,7 +71,8 @@ public class DataStore { this.translations = translations; // Propagate changes - synchronizer.forEach(synchronizer -> synchronizer.synchronize(this.translations, searchQuery)); + synchronizer.forEach(synchronizer -> + synchronizer.synchronize(this.translations, searchQuery, null)); } else { // If state cannot be loaded from disk, show empty instance @@ -79,7 +80,8 @@ public class DataStore { new LocalizedNode(LocalizedNode.ROOT_KEY, new ArrayList<>())); // Propagate changes - synchronizer.forEach(synchronizer -> synchronizer.synchronize(this.translations, searchQuery)); + synchronizer.forEach(synchronizer -> + synchronizer.synchronize(this.translations, searchQuery, null)); } }); } @@ -106,7 +108,8 @@ public class DataStore { */ public void searchBeyKey(@Nullable String fullPath) { // Use synchronizer to propagate search instance to all views - synchronizer.forEach(synchronizer -> synchronizer.synchronize(translations, this.searchQuery = fullPath)); + synchronizer.forEach(synchronizer -> + synchronizer.synchronize(translations, this.searchQuery = fullPath, null)); } /** @@ -139,6 +142,8 @@ public class DataStore { } } + String scrollTo = update.isDeletion() ? null : update.getChange().getKey(); + if(!update.isDeletion()) { // Recreate with changed val / create LocalizedNode node = translations.getOrCreateNode(update.getChange().getKey()); node.setValue(update.getChange().getTranslations()); @@ -147,7 +152,7 @@ public class DataStore { // Persist changes and propagate them on success saveToDisk(success -> { if(success) { - synchronizer.forEach(synchronizer -> synchronizer.synchronize(translations, searchQuery)); + synchronizer.forEach(synchronizer -> synchronizer.synchronize(translations, searchQuery, scrollTo)); } }); } diff --git a/src/main/java/de/marhali/easyi18n/ui/tabs/TableView.java b/src/main/java/de/marhali/easyi18n/ui/tabs/TableView.java index ef8b00b..5e81cc1 100644 --- a/src/main/java/de/marhali/easyi18n/ui/tabs/TableView.java +++ b/src/main/java/de/marhali/easyi18n/ui/tabs/TableView.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.*; import java.awt.event.MouseEvent; import java.util.ResourceBundle; @@ -73,9 +74,26 @@ public class TableView implements DataSynchronizer { } @Override - public void synchronize(@NotNull Translations translations, @Nullable String searchQuery) { + public void synchronize(@NotNull Translations translations, + @Nullable String searchQuery, @Nullable String scrollTo) { + table.setModel(new TableModelTranslator(translations, searchQuery, update -> DataStore.getInstance(project).processUpdate(update))); + + if(scrollTo != null) { + int row = -1; + + for (int i = 0; i < table.getRowCount(); i++) { + if (String.valueOf(table.getValueAt(i, 0)).equals(scrollTo)) { + row = i; + } + } + + if (row > -1) { // Matched @scrollTo + table.scrollRectToVisible( + new Rectangle(0, (row * table.getRowHeight()) + table.getHeight(), 0, 0)); + } + } } public JPanel getRootPanel() { diff --git a/src/main/java/de/marhali/easyi18n/ui/tabs/TreeView.java b/src/main/java/de/marhali/easyi18n/ui/tabs/TreeView.java index 8014ca5..a4b77cd 100644 --- a/src/main/java/de/marhali/easyi18n/ui/tabs/TreeView.java +++ b/src/main/java/de/marhali/easyi18n/ui/tabs/TreeView.java @@ -20,6 +20,7 @@ import de.marhali.easyi18n.ui.dialog.EditDialog; import de.marhali.easyi18n.ui.listener.DeleteKeyListener; import de.marhali.easyi18n.ui.listener.PopupClickListener; import de.marhali.easyi18n.ui.renderer.TreeRenderer; +import de.marhali.easyi18n.util.TranslationsUtil; import de.marhali.easyi18n.util.TreeUtil; import org.jetbrains.annotations.NotNull; @@ -75,12 +76,19 @@ public class TreeView implements DataSynchronizer { } @Override - public void synchronize(@NotNull Translations translations, @Nullable String searchQuery) { - tree.setModel(new TreeModelTranslator(project, translations, searchQuery)); + public void synchronize(@NotNull Translations translations, + @Nullable String searchQuery, @Nullable String scrollTo) { + + TreeModelTranslator model = new TreeModelTranslator(project, translations, searchQuery); + tree.setModel(model); if(searchQuery != null && !searchQuery.isEmpty()) { expandAll().run(); } + + if(scrollTo != null) { + tree.scrollPathToVisible(model.findTreePath(scrollTo)); + } } private void handlePopup(MouseEvent e) {