introduce full-text-search inside i18n tool window

This commit is contained in:
Marcel Haßlinger 2021-11-09 19:35:37 +01:00
parent 1b1705a661
commit a34ae7e02f
4 changed files with 84 additions and 18 deletions

View File

@ -97,9 +97,9 @@ public class TableView implements BusListener {
@Override @Override
public void onSearchQuery(@Nullable String query) { public void onSearchQuery(@Nullable String query) {
// TODO: handle search functionality
if(this.currentMapper != null) { if(this.currentMapper != null) {
this.currentMapper.onSearchQuery(query); this.currentMapper.onSearchQuery(query);
this.table.updateUI();
} }
} }

View File

@ -41,14 +41,14 @@ public class TreeView implements BusListener {
private final Project project; private final Project project;
private TreeModelMapper currentMapper;
private JPanel rootPanel; private JPanel rootPanel;
private JPanel toolBarPanel; private JPanel toolBarPanel;
private JPanel containerPanel; private JPanel containerPanel;
private Tree tree; private Tree tree;
private TreeModelMapper mapper;
public TreeView(Project project) { public TreeView(Project project) {
this.project = project; this.project = project;
@ -81,19 +81,23 @@ public class TreeView implements BusListener {
@Override @Override
public void onUpdateData(@NotNull TranslationData data) { public void onUpdateData(@NotNull TranslationData data) {
tree.setModel(this.mapper = new TreeModelMapper(data, SettingsService.getInstance(project).getState(), null)); tree.setModel(this.currentMapper = new TreeModelMapper(data, SettingsService.getInstance(project).getState()));
} }
@Override @Override
public void onFocusKey(@Nullable String key) { public void onFocusKey(@Nullable String key) {
if(key != null && mapper != null) { if(key != null && currentMapper != null) {
this.tree.scrollPathToVisible(mapper.findTreePath(key)); this.tree.scrollPathToVisible(currentMapper.findTreePath(key));
} }
} }
@Override @Override
public void onSearchQuery(@Nullable String query) { public void onSearchQuery(@Nullable String query) {
// TODO: handle search functionality if(this.currentMapper != null) {
this.currentMapper.onSearchQuery(query);
this.expandAll().run();
this.tree.updateUI();
}
} }
private void handlePopup(MouseEvent e) { private void handlePopup(MouseEvent e) {

View File

@ -1,10 +1,8 @@
package de.marhali.easyi18n.tabs.mapper; package de.marhali.easyi18n.tabs.mapper;
import de.marhali.easyi18n.model.*; import de.marhali.easyi18n.model.*;
import de.marhali.easyi18n.model.bus.BusListener;
import de.marhali.easyi18n.model.bus.SearchQueryListener; import de.marhali.easyi18n.model.bus.SearchQueryListener;
import de.marhali.easyi18n.model.bus.UpdateDataListener;
import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -12,7 +10,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.event.TableModelListener; import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -24,7 +21,7 @@ public class TableModelMapper implements TableModel, SearchQueryListener {
private final @NotNull TranslationData data; private final @NotNull TranslationData data;
private final @NotNull List<String> locales; private final @NotNull List<String> locales;
private final @NotNull List<String> fullKeys; private @NotNull List<String> fullKeys;
private final @NotNull Consumer<TranslationUpdate> updater; private final @NotNull Consumer<TranslationUpdate> updater;
@ -38,7 +35,27 @@ public class TableModelMapper implements TableModel, SearchQueryListener {
@Override @Override
public void onSearchQuery(@Nullable String query) { public void onSearchQuery(@Nullable String query) {
this.fullKeys = new ArrayList<>(); if(query == null) { // Reset
this.fullKeys = new ArrayList<>(this.data.getFullKeys());
return;
}
query = query.toLowerCase();
List<String> matches = new ArrayList<>();
for(String key : this.data.getFullKeys()) {
if(key.toLowerCase().contains(query)) {
matches.add(key);
} else {
for(String content : this.data.getTranslation(key).values()) {
if(content.toLowerCase().contains(query)) {
matches.add(key);
}
}
}
}
this.fullKeys = matches;
} }
@Override @Override

View File

@ -6,6 +6,7 @@ import com.intellij.ui.JBColor;
import de.marhali.easyi18n.model.SettingsState; import de.marhali.easyi18n.model.SettingsState;
import de.marhali.easyi18n.model.TranslationData; import de.marhali.easyi18n.model.TranslationData;
import de.marhali.easyi18n.model.TranslationNode; import de.marhali.easyi18n.model.TranslationNode;
import de.marhali.easyi18n.model.bus.SearchQueryListener;
import de.marhali.easyi18n.util.PathUtil; import de.marhali.easyi18n.util.PathUtil;
import de.marhali.easyi18n.util.UiUtil; import de.marhali.easyi18n.util.UiUtil;
@ -20,31 +21,46 @@ import java.util.Map;
* Mapping {@link TranslationData} to {@link TreeModel}. * Mapping {@link TranslationData} to {@link TreeModel}.
* @author marhali * @author marhali
*/ */
public class TreeModelMapper extends DefaultTreeModel { public class TreeModelMapper extends DefaultTreeModel implements SearchQueryListener {
private final TranslationData data; private final TranslationData data;
private final SettingsState state; private final SettingsState state;
public TreeModelMapper(TranslationData data, SettingsState state, String searchQuery) { public TreeModelMapper(TranslationData data, SettingsState state) {
super(null); super(null);
this.data = data; this.data = data;
this.state = state; this.state = state;
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(); DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
this.generateNodes(rootNode, this.data.getRootNode()); this.generateNodes(rootNode, this.data.getRootNode(), null);
super.setRoot(rootNode); super.setRoot(rootNode);
} }
private void generateNodes(DefaultMutableTreeNode parent, TranslationNode translationNode) { @Override
public void onSearchQuery(@Nullable String query) {
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
this.generateNodes(rootNode, this.data.getRootNode(), query);
super.setRoot(rootNode);
}
private void generateNodes(@NotNull DefaultMutableTreeNode parent,
@NotNull TranslationNode translationNode, @Nullable String searchQuery) {
for(Map.Entry<String, TranslationNode> entry : translationNode.getChildren().entrySet()) { for(Map.Entry<String, TranslationNode> entry : translationNode.getChildren().entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
TranslationNode childTranslationNode = entry.getValue(); TranslationNode childTranslationNode = entry.getValue();
if(searchQuery != null) {
searchQuery = searchQuery.toLowerCase();
if(!this.isApplicable(key, childTranslationNode, searchQuery)) {
continue;
}
}
if(!childTranslationNode.isLeaf()) { if(!childTranslationNode.isLeaf()) {
// Nested node - run recursively // Nested node - run recursively
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(key); DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(key);
this.generateNodes(childNode, childTranslationNode); this.generateNodes(childNode, childTranslationNode, searchQuery);
parent.add(childNode); parent.add(childNode);
} else { } else {
String previewLocale = this.state.getPreviewLocale(); String previewLocale = this.state.getPreviewLocale();
@ -63,6 +79,35 @@ public class TreeModelMapper extends DefaultTreeModel {
} }
} }
/**
* Checks if the provided tree (@node) is applicable for the search string.
* A full-text-search is applied and section keys and every value will be evaluated.
* @param key Section key
* @param node Node which has @key as key
* @param searchQuery Search query to search for
* @return True if this node or ANY child is relevant for the search context
*/
private boolean isApplicable(@NotNull String key, @NotNull TranslationNode node, @NotNull String searchQuery) {
if(key.toLowerCase().contains(searchQuery)) {
return true;
}
if(!node.isLeaf()) {
for(Map.Entry<String, TranslationNode> entry : node.getChildren().entrySet()) {
if(this.isApplicable(entry.getKey(), entry.getValue(), searchQuery)) {
return true;
}
}
} else {
for(String content : node.getValue().values()) {
if(content.toLowerCase().contains(searchQuery)) {
return true;
}
}
}
return false;
}
public @NotNull TreePath findTreePath(@NotNull String fullPath) { public @NotNull TreePath findTreePath(@NotNull String fullPath) {
List<String> sections = new PathUtil(this.state.isNestedKeys()).split(fullPath); List<String> sections = new PathUtil(this.state.isNestedKeys()).split(fullPath);