Ticket #20573: 20573-0.2.diff
File 20573-0.2.diff, 83.0 KB (added by , 4 years ago) |
---|
-
src/org/openstreetmap/josm/data/preferences/sources/ExtendedSourceEntry.java
49 49 } 50 50 51 51 private static void appendRow(StringBuilder s, String th, String td) { 52 s.append("<tr><th>").append(th).append("</th><td>").append(Utils.escapeReservedCharactersHTML(td)).append("</td </tr>");52 s.append("<tr><th>").append(th).append("</th><td>").append(Utils.escapeReservedCharactersHTML(td)).append("</td></tr>"); 53 53 } 54 54 55 55 /** -
src/org/openstreetmap/josm/gui/preferences/DefaultTabPreferenceSetting.java
48 48 this.tabpane = tabpane; 49 49 this.subSettingMap = tabpane != null ? new HashMap<>() : null; 50 50 if (tabpane != null) { 51 tabpane.addMouseWheelListener(new PreferenceTabbedPane. WheelListener(tabpane));51 tabpane.addMouseWheelListener(new PreferenceTabbedPane.MouseAndWheelListener(tabpane)); 52 52 } 53 53 } 54 54 -
src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java
10 10 import java.awt.FontMetrics; 11 11 import java.awt.GridBagConstraints; 12 12 import java.awt.GridBagLayout; 13 import java.awt.event.MouseEvent; 14 import java.awt.event.MouseListener; 13 15 import java.awt.event.MouseWheelEvent; 14 16 import java.awt.event.MouseWheelListener; 15 17 import java.util.ArrayList; … … 60 62 import org.openstreetmap.josm.gui.preferences.plugin.PluginPreference; 61 63 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference; 62 64 import org.openstreetmap.josm.gui.preferences.remotecontrol.RemoteControlPreference; 65 import org.openstreetmap.josm.gui.preferences.search.SearchPanel; 66 import org.openstreetmap.josm.gui.preferences.search.SearchTextField; 63 67 import org.openstreetmap.josm.gui.preferences.server.ProxyPreference; 64 68 import org.openstreetmap.josm.gui.preferences.server.ServerAccessPreference; 65 69 import org.openstreetmap.josm.gui.preferences.shortcut.ShortcutPreference; … … 204 208 boolean validatePreferences(); 205 209 } 206 210 207 p rivateinterface PreferenceTab {211 public interface PreferenceTab { 208 212 TabPreferenceSetting getTabPreferenceSetting(); 209 213 210 214 Component getComponent(); … … 273 277 } 274 278 } 275 279 280 private final SearchPanel searchPanel = new SearchPanel(this); 281 private final SearchTextField searchTextField = new SearchTextField(searchPanel); 282 276 283 // all created tabs 277 284 private final transient List<PreferenceTab> tabs = new ArrayList<>(); 278 285 private static final Collection<PreferenceSettingFactory> SETTINGS_FACTORIES = new LinkedList<>(); … … 463 470 */ 464 471 public PreferenceTabbedPane() { 465 472 super(SwingConstants.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT); 466 super.addMouseWheelListener(new WheelListener(this)); 473 MouseAndWheelListener l = new MouseAndWheelListener(this); 474 super.addMouseWheelListener(l); 475 super.addMouseListener(l); 467 476 ExpertToggleAction.addExpertModeChangeListener(this); 468 477 } 469 478 … … 526 535 if (clear) { 527 536 removeAll(); 528 537 } 538 539 addTab(null, searchPanel); 540 setTabComponentAt(0, searchTextField); 529 541 // Compute max tab length in pixels 530 542 int maxWidth = computeMaxTabWidth(); 531 543 // Inspect each tab setting … … 557 569 Logging.debug("{0}: hiding empty {1}", getClass().getSimpleName(), tps); 558 570 }); 559 571 } 572 searchTextField.adjustWidth(); 560 573 setSelectedIndex(-1); 561 574 } 562 575 … … 626 639 * This mouse wheel listener reacts when a scroll is carried out over the 627 640 * tab strip and scrolls one tab/down or up, selecting it immediately. 628 641 */ 629 static final class WheelListener implements MouseWheelListener {642 static final class MouseAndWheelListener implements MouseWheelListener, MouseListener { 630 643 631 644 final JTabbedPane tabbedPane; 632 645 633 WheelListener(JTabbedPane tabbedPane) {646 MouseAndWheelListener(JTabbedPane tabbedPane) { 634 647 this.tabbedPane = tabbedPane; 635 648 } 636 649 … … 646 659 647 660 tabbedPane.setSelectedIndex(newTab); 648 661 } 662 663 @Override 664 public void mouseClicked(MouseEvent e) { 665 tabbedPane.requestFocus(); 666 } 667 668 @Override 669 public void mouseEntered(MouseEvent e) { 670 } 671 672 @Override 673 public void mouseExited(MouseEvent e) { 674 } 675 676 @Override 677 public void mousePressed(MouseEvent e) { 678 } 679 680 @Override 681 public void mouseReleased(MouseEvent e) { 682 } 649 683 } 650 684 651 685 @Override … … 653 687 int index = getSelectedIndex(); 654 688 Component sel = getSelectedComponent(); 655 689 if (index > -1 && sel instanceof PreferenceTab) { 656 PreferenceTab tab = (PreferenceTab) sel; 657 TabPreferenceSetting preferenceSettings = tab.getTabPreferenceSetting(); 658 if (!settingsInitialized.contains(preferenceSettings)) { 659 try { 660 getModel().removeChangeListener(this); 661 preferenceSettings.addGui(this); 662 // Add GUI for sub preferences 663 for (PreferenceSetting setting : settings) { 664 if (setting instanceof SubPreferenceSetting) { 665 addSubPreferenceSetting(preferenceSettings, (SubPreferenceSetting) setting); 666 } 690 initializeTab(index, (PreferenceTab) sel, false); 691 } 692 } 693 694 public void initializeTab(int index, PreferenceTab tab, boolean silent) { 695 TabPreferenceSetting preferenceSettings = tab.getTabPreferenceSetting(); 696 if (!settingsInitialized.contains(preferenceSettings)) { 697 try { 698 getModel().removeChangeListener(this); 699 preferenceSettings.addGui(this); 700 // Add GUI for sub preferences 701 for (PreferenceSetting setting : settings) { 702 if (setting instanceof SubPreferenceSetting) { 703 addSubPreferenceSetting(preferenceSettings, (SubPreferenceSetting) setting); 667 704 } 668 Icon icon = getIconAt(index);669 remove(index);670 if (index <= insertGUITabsForSetting(icon, preferenceSettings, index, computeMaxTabWidth())) {671 setSelectedIndex(index);672 }673 } catch (SecurityException ex) {674 Logging.error(ex);675 } catch (RuntimeException ex) { // NOPMD676 // allow to change most settings even if e.g. a plugin fails677 BugReportExceptionHandler.handleException(ex);678 } finally {679 settingsInitialized.add(preferenceSettings);680 getModel().addChangeListener(this);681 705 } 706 Icon icon = getIconAt(index); 707 remove(index); 708 if (index <= insertGUITabsForSetting(icon, preferenceSettings, index, computeMaxTabWidth()) && !silent) { 709 setSelectedIndex(index); 710 } 711 } catch (SecurityException ex) { 712 Logging.error(ex); 713 } catch (RuntimeException ex) { // NOPMD 714 // allow to change most settings even if e.g. a plugin fails 715 BugReportExceptionHandler.handleException(ex); 716 } finally { 717 settingsInitialized.add(preferenceSettings); 718 getModel().addChangeListener(this); 682 719 } 683 Container ancestor = getTopLevelAncestor();684 if (ancestor instanceof PreferenceDialog) {685 ((PreferenceDialog) ancestor).setHelpContext(preferenceSettings.getHelpContext());686 }687 720 } 721 Container ancestor = getTopLevelAncestor(); 722 if (ancestor instanceof PreferenceDialog) { 723 ((PreferenceDialog) ancestor).setHelpContext(preferenceSettings.getHelpContext()); 724 } 688 725 } 689 726 690 727 private void addSubPreferenceSetting(TabPreferenceSetting preferenceSettings, SubPreferenceSetting sps) { -
src/org/openstreetmap/josm/gui/preferences/advanced/AdvancedPreference.java
52 52 import org.openstreetmap.josm.gui.preferences.PreferenceSetting; 53 53 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory; 54 54 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 55 import org.openstreetmap.josm.gui.preferences.search.NotSearchablePanel; 55 56 import org.openstreetmap.josm.gui.util.GuiHelper; 56 57 import org.openstreetmap.josm.gui.widgets.AbstractFileChooser; 57 58 import org.openstreetmap.josm.gui.widgets.JosmTextField; … … 164 165 165 166 @Override 166 167 public void addGui(final PreferenceTabbedPane gui) { 167 JPanel p = gui.createPreferenceTab(this);168 JPanel panel = gui.createPreferenceTab(this); 168 169 170 NotSearchablePanel p = new NotSearchablePanel(new GridBagLayout()); 171 panel.add(p, GBC.std().fill()); 172 169 173 final JPanel txtFilterPanel = new JPanel(new GridBagLayout()); 170 174 p.add(txtFilterPanel, GBC.eol().fill(GBC.HORIZONTAL)); 171 175 txtFilter = new JosmTextField(); -
src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreference.java
54 54 import org.openstreetmap.josm.gui.preferences.PreferenceSetting; 55 55 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory; 56 56 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 57 import org.openstreetmap.josm.gui.preferences.search.NotSearchablePanel; 57 58 import org.openstreetmap.josm.gui.util.GuiHelper; 58 59 import org.openstreetmap.josm.gui.widgets.FilterField; 59 60 import org.openstreetmap.josm.plugins.PluginDownloadTask; … … 165 166 } 166 167 167 168 private JPanel buildSearchFieldPanel() { 168 JPanel pnl = new JPanel(new GridBagLayout());169 JPanel pnl = new NotSearchablePanel(new GridBagLayout()); 169 170 pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 170 171 GridBagConstraints gc = new GridBagConstraints(); 171 172 -
src/org/openstreetmap/josm/gui/preferences/search/ISearchableComponent.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.preferences.search; 3 4 import java.util.List; 5 6 /** 7 * Interface allowing components in the preferences to determine if and how they can be searched 8 * @author Bjoeni 9 */ 10 public interface ISearchableComponent { 11 /** 12 * @return whether the component can be searched<br><br> 13 * default: true 14 */ 15 default boolean isSearchable() { 16 return true; 17 } 18 19 /** 20 * @return whether the children of this component should be traversed <br><br> 21 * 22 * default: same as {@link #isSearchable()} unless explicitly overridden 23 */ 24 default boolean isChildrenSearchable() { 25 return isSearchable(); 26 } 27 28 /** 29 * @return the {@link SearchItem}s that should be used. Ignored if {@link #isSearchable()} returns {@code false}.<br> 30 * Overrides the default {@link SearchTextFinder} if returning not {@code null} (including if an empty list is returned)<br><br> 31 * default: null 32 */ 33 default List<SearchItem> getSearchItems() { 34 return null; 35 } 36 } -
src/org/openstreetmap/josm/gui/preferences/search/NotSearchablePanel.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.preferences.search; 3 4 import java.awt.LayoutManager; 5 6 import javax.swing.JPanel; 7 8 /** 9 * {@link JPanel} that disallows searching its contents 10 * @see ISearchableComponent 11 * @author Bjoeni 12 */ 13 public class NotSearchablePanel extends JPanel implements ISearchableComponent { 14 15 /** 16 * Create {@link JPanel} that disallows searching its contents 17 */ 18 public NotSearchablePanel() { 19 super(); 20 } 21 22 /** 23 * Create {@link JPanel} that disallows searching its contents 24 * @param layout 25 */ 26 public NotSearchablePanel(LayoutManager layout) { 27 super(layout); 28 } 29 30 /** 31 * Create {@link JPanel} that disallows searching its contents 32 * @param isDoubleBuffered 33 */ 34 public NotSearchablePanel(boolean isDoubleBuffered) { 35 super(isDoubleBuffered); 36 } 37 38 /** 39 * Create {@link JPanel} that disallows searching its contents 40 * @param layout 41 * @param isDoubleBuffered 42 */ 43 public NotSearchablePanel(LayoutManager layout, boolean isDoubleBuffered) { 44 super(layout, isDoubleBuffered); 45 } 46 47 /** 48 * The component can not be searched 49 * @return false 50 */ 51 @Override 52 public boolean isSearchable() { 53 return false; 54 } 55 56 } -
src/org/openstreetmap/josm/gui/preferences/search/SearchIndex.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.preferences.search; 3 4 import java.awt.Component; 5 import java.awt.Container; 6 import java.awt.GridBagConstraints; 7 import java.awt.GridBagLayout; 8 import java.awt.LayoutManager; 9 import java.util.ArrayList; 10 import java.util.Arrays; 11 import java.util.List; 12 import java.util.Stack; 13 14 import javax.swing.JComponent; 15 import javax.swing.JSeparator; 16 17 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 18 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.PreferenceTab; 19 20 /** 21 * Contains all {@link SearchItem}s 22 * @author Bjoeni 23 */ 24 public class SearchIndex { 25 Stack<SearchItem> stack = new Stack<>(); 26 List<SearchItem> parents = new ArrayList<>(); 27 PreferenceTabbedPane prefTabs; 28 GridBagConstraints lastConstraint; 29 30 public SearchIndex(PreferenceTabbedPane prefTabs) { 31 this.prefTabs = prefTabs; 32 } 33 34 void add(SearchItem item) { 35 if (stack.isEmpty()) { 36 item.setLevelInset(0, 0); 37 parents.add(item); 38 stack.push(item); 39 } else { 40 SearchItem lastItem = stack.lastElement(); 41 if (!lastItem.eol && lastItem.level == item.level) { 42 lastItem.setEOL(item.eol); 43 lastItem.addChild(item); 44 } else if (lastItem.level < item.level || (lastItem.level == item.level && lastItem.inset < item.inset)) { 45 stack.push(lastItem.addChild(item)); 46 } else { 47 stack.pop(); 48 add(item); 49 } 50 } 51 } 52 53 void addAll(List<SearchItem> items, boolean isEOL) { 54 if (items.size() > 0) { 55 items.get(items.size() - 1).setEOL(isEOL); 56 } 57 items.forEach(item -> add(item)); 58 } 59 60 void insertEOL() { 61 if (!stack.isEmpty()) { 62 stack.lastElement().setEOL(); 63 } 64 } 65 66 void insertSeparator() { 67 if (!stack.isEmpty()) { 68 stack.lastElement().maximizeInset(); 69 } 70 } 71 72 void insertNewPage() { 73 stack.clear(); 74 } 75 76 public boolean isBuilt() { 77 return !parents.isEmpty(); 78 } 79 80 public void build() { 81 parents.clear(); 82 for (int i = 0; i < prefTabs.getTabCount(); i++) { 83 Component c = prefTabs.getComponentAt(i); 84 if (c instanceof PreferenceTab) { 85 prefTabs.initializeTab(i, (PreferenceTab) c, true); 86 c = prefTabs.getComponentAt(i); 87 } 88 insertNewPage(); 89 searchComponent(c, 1); 90 } 91 } 92 93 private String lastFilterStr; 94 95 public void filter(String filterStr) { 96 if (lastFilterStr != null && filterStr.indexOf(lastFilterStr) != 0) { 97 parents.forEach(SearchItem::showAll); 98 } 99 100 if (!filterStr.isEmpty()) { 101 parents.stream().filter(SearchItem::isVisible).forEach(item -> { 102 item.filter(filterStr); 103 }); 104 } 105 106 lastFilterStr = filterStr; 107 } 108 109 private boolean searchComponent(Component comp, int level) { 110 111 final Component c = comp; 112 113 boolean isEOL = true; 114 GridBagConstraints currentConstraint = null; 115 116 Container p = c.getParent(); 117 if (p != null) { 118 LayoutManager layout = p.getLayout(); 119 if (layout != null && layout instanceof GridBagLayout) { 120 GridBagLayout grid = (GridBagLayout) layout; 121 122 currentConstraint = grid.getConstraints(c); 123 isEOL = currentConstraint.gridwidth == GridBagConstraints.REMAINDER; 124 } 125 } 126 127 if (lastConstraint != null && currentConstraint != null 128 && (((lastConstraint.fill == GridBagConstraints.HORIZONTAL 129 || lastConstraint.fill == GridBagConstraints.BOTH) 130 && currentConstraint.fill != GridBagConstraints.HORIZONTAL 131 && currentConstraint.fill != GridBagConstraints.BOTH) 132 || lastConstraint.gridy != currentConstraint.gridy)) { 133 insertEOL(); 134 } 135 136 lastConstraint = currentConstraint; 137 boolean isChildrenSearchable = true; 138 ISearchableComponent s = null; 139 if (c instanceof ISearchableComponent) { 140 s = (ISearchableComponent) c; 141 isChildrenSearchable = s.isChildrenSearchable(); 142 } 143 144 if (s == null || s.isSearchable()) { 145 146 List<SearchItem> items = null; 147 if (s != null) { 148 items = s.getSearchItems(); 149 } 150 if (items == null) { 151 List<SearchItem> itm = new ArrayList<>(); 152 SearchTextFinder.DEFAULT_SEARCH_TEXT_FINDERS.forEach(finder -> itm.addAll(finder.getSearchItems(c))); 153 items = itm; 154 } 155 if (items.size() == 0) { 156 if (isEOL) { 157 insertEOL(); 158 } 159 if (c instanceof JSeparator) { 160 insertSeparator(); 161 } 162 163 } else { 164 items.get(0).components.add(c); 165 if (c instanceof JComponent) { 166 items.get(0).tooltip = ((JComponent) c).getToolTipText(); 167 } 168 169 final int inset = currentConstraint == null ? 0 : currentConstraint.insets.left; 170 items.forEach(item -> item.setLevelInset(level, inset)); 171 isChildrenSearchable = isChildrenSearchable 172 && items.stream().allMatch(item -> item.childComponentsSearchable); 173 174 addAll(items, isEOL); 175 } 176 } 177 178 if (isChildrenSearchable && c instanceof Container) { 179 Container cont = (Container) c; 180 List<Component> components = Arrays.asList(cont.getComponents()); 181 if (components.size() > 0) { 182 insertEOL(); 183 for (Component component : components) { 184 searchComponent(component, level + 1); 185 } 186 } 187 } 188 return isEOL; 189 } 190 191 } 192 No newline at end of file -
src/org/openstreetmap/josm/gui/preferences/search/SearchItem.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.preferences.search; 3 4 import java.awt.Component; 5 import java.util.ArrayList; 6 import java.util.Arrays; 7 import java.util.List; 8 import java.util.Locale; 9 import java.util.Objects; 10 import java.util.Optional; 11 12 import org.openstreetmap.josm.tools.LanguageInfo; 13 14 /** 15 * Contains searchable items and their components 16 * @author Bjoeni 17 */ 18 public class SearchItem { 19 List<Component> components = new ArrayList<>(); 20 String text; 21 String tooltip; 22 int level; 23 int inset = 0; 24 boolean eol = true; 25 List<SearchItem> children = new ArrayList<>(); 26 boolean childComponentsSearchable = true; 27 28 private boolean visible = true; 29 private static final Locale CURRENT_LOCALE = LanguageInfo.getLocale(LanguageInfo.getJOSMLocaleCode()); 30 31 public SearchItem() { 32 } 33 34 public SearchItem(String text) { 35 this.text = text; 36 } 37 38 public SearchItem(Component component, String text, String tooltip, boolean eol, 39 boolean childComponentsSearchable) { 40 this.components.add(component); 41 this.text = text; 42 this.tooltip = tooltip; 43 this.setEOL(eol); 44 this.childComponentsSearchable = childComponentsSearchable; 45 } 46 47 public SearchItem addChild(SearchItem item) { 48 Optional<SearchItem> match = children.stream() 49 .filter(c -> Objects.equals(c.text, item.text) && c.level == item.level && c.inset == item.inset) 50 .findAny(); 51 52 if (match.isPresent()) { 53 match.get().merge(item); 54 return match.get(); 55 } else { 56 children.add(item); 57 return item; 58 } 59 } 60 61 public void merge(SearchItem item) { 62 this.components.addAll(item.components); 63 this.setEOL(this.eol || item.eol); 64 } 65 66 public boolean filter(String filterStr) { 67 visible = this.matches(filterStr); 68 for (SearchItem child : children) { 69 if (child.isVisible()) { 70 visible = child.filter(filterStr) || visible; 71 } 72 } 73 return visible; 74 } 75 76 public boolean matches(String filterStr) { 77 return Arrays.asList(filterStr.toLowerCase(CURRENT_LOCALE).split(" ")).stream() 78 .allMatch(f -> text != null && text.toLowerCase(CURRENT_LOCALE).indexOf(f) != -1 79 || (tooltip != null && tooltip.toLowerCase(CURRENT_LOCALE).indexOf(f) != -1)); 80 } 81 82 public void showAll() { 83 visible = true; 84 children.forEach(SearchItem::showAll); 85 } 86 87 @Override 88 public String toString() { 89 return text + (tooltip == null ? "" : " (Tooltip: " + tooltip + ")") + " [" + level + "." + inset + "] {" 90 + components.size() + "}"; 91 } 92 93 public boolean isVisible() { 94 return visible; 95 } 96 97 public void addTooltip(String tooltip) { 98 if (this.tooltip == null || this.tooltip.trim().isEmpty()) { 99 this.tooltip = tooltip; 100 } 101 } 102 103 public void setLevelInset(int level, int inset) { 104 this.level = level; 105 this.inset = inset; 106 } 107 108 public void setEOL() { 109 setEOL(true); 110 } 111 112 public void setEOL(boolean eol) { 113 this.eol = eol; 114 } 115 116 public void maximizeInset() { 117 this.inset = Integer.MAX_VALUE; 118 } 119 120 } 121 No newline at end of file -
src/org/openstreetmap/josm/gui/preferences/search/SearchPanel.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.preferences.search; 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.util.List; 7 import java.util.stream.Collectors; 8 9 import javax.swing.JLabel; 10 import javax.swing.JPanel; 11 import javax.swing.JScrollPane; 12 13 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 14 import org.openstreetmap.josm.tools.Logging; 15 import org.openstreetmap.josm.tools.Utils; 16 17 /** 18 * Panel displaying search results in the preferences 19 * @author Bjoeni 20 */ 21 public class SearchPanel extends JScrollPane implements ISearchableComponent { 22 23 private PreferenceTabbedPane tabs; 24 private SearchIndex searchIndex; 25 private JLabel lbl = new JLabel("search results here"); 26 private JPanel panel = new JPanel(); 27 28 public SearchPanel(PreferenceTabbedPane tabs) { 29 this.tabs = tabs; 30 searchIndex = new SearchIndex(tabs); 31 panel.add(lbl); 32 setViewportView(panel); 33 } 34 35 public PreferenceTabbedPane getTabPane() { 36 return tabs; 37 } 38 39 public void search(String text) { 40 if (!searchIndex.isBuilt() || "".equals(text)) { 41 Logging.info("Building search index..."); 42 lbl.setText(tr("Building search index...")); 43 searchIndex.build(); 44 } 45 Logging.info("searching"); 46 lbl.setText(tr("Searching...")); 47 searchIndex.filter(text); 48 Logging.info("searched"); 49 searchableSettings = new StringBuilder(); 50 printSearchItems(searchIndex.parents.stream().filter(SearchItem::isVisible).collect(Collectors.toList()), ""); 51 /*try { 52 FileUtils.writeStringToFile(new File(FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath() 53 + "/searchableSettings.txt"), searchableSettings.toString()); 54 } catch (IOException e) { 55 e.printStackTrace(); 56 }*/ 57 lbl.setText("<html><pre>" + Utils.escapeReservedCharactersHTML(searchableSettings.toString()) + "<pre><html>"); 58 } 59 60 StringBuilder searchableSettings; 61 62 private void printSearchItems(List<SearchItem> items, String indent) { 63 for (int i = 0; i < items.size(); i++) { 64 SearchItem item = items.get(i); 65 searchableSettings.append("\n" + indent + item.toString().replaceAll("\n", "<br>")); 66 List<SearchItem> c = item.children.stream().filter(SearchItem::isVisible).collect(Collectors.toList()); 67 if (c.size() > 0) { 68 searchableSettings.append("\n" + indent + ">> "); 69 printSearchItems(c, indent + " "); 70 searchableSettings.append("\n" + indent + "<<"); 71 if (indent.isEmpty()) { 72 searchableSettings.append("\n"); 73 } 74 } else if (item.eol && i != items.size() - 1) { 75 searchableSettings.append("\n" + indent + "=="); 76 } 77 } 78 79 } 80 81 @Override 82 public boolean isSearchable() { 83 return false; 84 } 85 86 } -
src/org/openstreetmap/josm/gui/preferences/search/SearchTextField.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.preferences.search; 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.awt.Dimension; 7 8 import javax.swing.event.DocumentEvent; 9 import javax.swing.event.DocumentListener; 10 11 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 12 import org.openstreetmap.josm.gui.widgets.JosmTextField; 13 14 /** 15 * TextField for searching the preferences 16 * @author Bjoeni 17 */ 18 public class SearchTextField extends JosmTextField { 19 private SearchPanel panel; 20 private PreferenceTabbedPane tabs; 21 22 public SearchTextField(SearchPanel panel) { 23 24 this.panel = panel; 25 tabs = panel.getTabPane(); 26 setHint(tr("Search...")); 27 getDocument().addDocumentListener(new DocumentListener() { 28 29 @Override 30 public void removeUpdate(DocumentEvent e) { 31 panel.getTabPane().setSelectedIndex(0); 32 panel.search(getTextContent()); 33 } 34 35 @Override 36 public void insertUpdate(DocumentEvent e) { 37 panel.getTabPane().setSelectedIndex(0); 38 panel.search(getTextContent()); 39 40 } 41 42 @Override 43 public void changedUpdate(DocumentEvent e) { 44 } 45 }); 46 } 47 48 public void adjustWidth() { 49 int width = getPreferredSize().width; 50 for (int i = 0; i < tabs.getTabCount(); i++) { 51 width = Math.max(width, tabs.getBoundsAt(i).width); 52 } 53 setPreferredSize(new Dimension(width, getPreferredSize().height)); 54 } 55 56 @Override 57 public String getText() { 58 return tr("Search"); 59 } 60 61 public String getTextContent() { 62 return super.getText(); 63 } 64 65 } -
src/org/openstreetmap/josm/gui/preferences/search/SearchTextFinder.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.preferences.search; 3 4 import java.awt.Component; 5 import java.util.ArrayList; 6 import java.util.Arrays; 7 import java.util.Collections; 8 import java.util.List; 9 import java.util.stream.Collectors; 10 11 import javax.swing.JCheckBox; 12 import javax.swing.JComboBox; 13 import javax.swing.JLabel; 14 import javax.swing.JList; 15 import javax.swing.JRadioButton; 16 import javax.swing.JTable; 17 import javax.swing.table.TableModel; 18 19 /** 20 * Class for obtaining the searchable properties of arbitrary components 21 * @param <T> type of the component 22 * @author Bjoeni 23 */ 24 public class SearchTextFinder<T extends Component> { 25 List<IComponentProperties<T>> properties = new ArrayList<>(); 26 27 @FunctionalInterface 28 private interface IComponentProperties<U extends Component> { 29 Object getFrom(U component); 30 31 default List<SearchItem> getSearchItems(U component) { 32 Object obj = getFrom(component); 33 34 if (obj == null) { 35 return new ArrayList<>(); 36 } 37 38 if (obj instanceof String) { 39 return Arrays.asList(new SearchItem((String) obj)); 40 } 41 42 if (obj instanceof String[]) { 43 return Arrays.asList((String[]) obj).stream().map(SearchItem::new).collect(Collectors.toList()); 44 } 45 46 if (obj instanceof SearchItem[]) { 47 return Arrays.asList((SearchItem[]) obj); 48 } 49 50 throw new IllegalArgumentException(); 51 } 52 } 53 54 @FunctionalInterface 55 interface ComponentProperty<U extends Component> extends IComponentProperties<U> { 56 @Override 57 String getFrom(U component); 58 } 59 60 @FunctionalInterface 61 interface ComponentPropertyArray<U extends Component> extends IComponentProperties<U> { 62 @Override 63 String[] getFrom(U component); 64 } 65 66 @FunctionalInterface 67 interface ComponentPropertyItem<U extends Component> extends IComponentProperties<U> { 68 @Override 69 SearchItem[] getFrom(U component); 70 } 71 72 /** 73 * Instantiates {@link SearchTextFinder} 74 */ 75 public SearchTextFinder() { 76 } 77 78 /** 79 * Instantiates {@link SearchTextFinder} 80 * @param prop Expression returning a searchable string for the given component, e.g. {@code JLabel::getText}. 81 * @see #add(ComponentProperty) 82 * @see #addArray(ComponentPropertyArray) 83 */ 84 public SearchTextFinder(ComponentProperty<T> prop) { 85 properties.add(prop); 86 } 87 88 /** 89 * Add another property. 90 * The compiler can't deal with generic vararg parameters properly, so just use this function instead 91 * @param prop Expression returning a searchable string for the given component, e.g. {@code JLabel::getText}. 92 * @return this (for chaining) 93 */ 94 public SearchTextFinder<T> add(ComponentProperty<T> prop) { 95 properties.add(prop); 96 return this; 97 } 98 99 /** 100 * Add a property returning a string array. 101 * The compiler can't deal with generic vararg parameters properly, so just use this function instead 102 * @param prop Expression returning an array of searchable strings for the given component 103 * @return this (for chaining) 104 */ 105 public SearchTextFinder<T> addArray(ComponentPropertyArray<T> prop) { 106 properties.add(prop); 107 return this; 108 } 109 110 /** 111 * Add a property returning a string array. 112 * The compiler can't deal with generic vararg parameters properly, so just use this function instead 113 * @param prop Expression returning an array of searchable strings for the given component 114 * @return this (for chaining) 115 */ 116 public SearchTextFinder<T> addItem(ComponentPropertyItem<T> prop) { 117 properties.add(prop); 118 return this; 119 } 120 121 /** 122 * Get the searchable texts for the given component 123 * @param c component 124 * @return {@code List<String>} or an empty list if it's not the right type. 125 */ 126 public List<SearchItem> getSearchItems(Component c) { 127 List<SearchItem> ret = new ArrayList<>(); 128 129 try { 130 @SuppressWarnings("unchecked") 131 T component = (T) c; 132 if (component != null) { 133 properties.forEach(property -> { 134 List<SearchItem> items = property.getSearchItems(component); 135 items.forEach(item -> { 136 if (item.text != null && item.text.trim().length() > 0) { 137 if (item.text.indexOf('<') != -1) { 138 item.text = stripHtml(item.text); 139 } 140 if (item.text.indexOf(':') == item.text.length() - 1) { 141 item.text = item.text.substring(0, item.text.length() - 1); 142 } 143 if (item.tooltip != null && item.tooltip.indexOf('<') != -1) { 144 item.tooltip = stripHtml(item.tooltip); 145 } 146 ret.add(item); 147 } 148 }); 149 }); 150 } 151 152 } catch (ClassCastException ex) { 153 // can't use 'instanceof' here, because the type information of T will already be stripped away at runtime 154 } 155 return ret; 156 } 157 158 private String stripHtml(String text) { 159 return text 160 .replaceAll("<br\s*/?>", "\n") 161 .replaceAll("(<style>.*</style>|<[^<>]*>)", " ") 162 .trim() 163 .replaceAll(" +", " "); 164 } 165 166 public final static List<SearchTextFinder<?>> DEFAULT_SEARCH_TEXT_FINDERS = Collections.unmodifiableList(Arrays.asList( 167 168 new SearchTextFinder<>(JLabel::getText), 169 new SearchTextFinder<>(JRadioButton::getText), 170 new SearchTextFinder<>(JCheckBox::getText), 171 172 new SearchTextFinder<JTable>().addItem(table -> { 173 List<SearchItem> lst = new ArrayList<>(); 174 TableModel tm = table.getModel(); 175 for (int row = 0; row < tm.getRowCount(); row++) { 176 for (int col = 0; col < tm.getColumnCount(); col++) { 177 Object obj = tm.getValueAt(row, col); 178 Component renderer = table.getCellRenderer(row, col) 179 .getTableCellRendererComponent(table, obj, false, false, row, col); 180 if (renderer instanceof JLabel) { 181 JLabel label = (JLabel) renderer; 182 boolean isLast = col == tm.getColumnCount() - 1; 183 lst.add(new SearchItem(label, label.getText(), label.getToolTipText(), isLast, false)); 184 } 185 } 186 } 187 return lst.toArray(new SearchItem[0]); 188 }), 189 190 new SearchTextFinder<JComboBox<Object>>().addItem(combobox -> { 191 List<SearchItem> lst = new ArrayList<>(); 192 int size = combobox.getItemCount(); 193 JList<Object> listStub = new JList<>(); 194 for (int i = 0; i < size; i++) { 195 Component renderer = combobox.getRenderer().getListCellRendererComponent(listStub, 196 combobox.getItemAt(i), i, false, false); 197 if (renderer instanceof JLabel) { 198 JLabel label = (JLabel) renderer; 199 lst.add(new SearchItem(renderer, label.getText(), label.getToolTipText(), false, false)); 200 } 201 } 202 return lst.toArray(new SearchItem[0]); 203 }))); 204 205 } 206 No newline at end of file -
src/org/openstreetmap/josm/gui/preferences/search/package-info.java
1 package org.openstreetmap.josm.gui.preferences.search; 2 No newline at end of file -
src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java
15 15 import java.awt.event.KeyEvent; 16 16 import java.awt.im.InputContext; 17 17 import java.lang.reflect.Field; 18 import java.util.ArrayList; 18 19 import java.util.LinkedHashMap; 19 20 import java.util.List; 20 21 import java.util.Map; … … 39 40 import javax.swing.table.TableColumnModel; 40 41 41 42 import org.openstreetmap.josm.data.preferences.NamedColorProperty; 43 import org.openstreetmap.josm.gui.preferences.search.SearchItem; 44 import org.openstreetmap.josm.gui.preferences.search.ISearchableComponent; 42 45 import org.openstreetmap.josm.gui.util.GuiHelper; 43 46 import org.openstreetmap.josm.gui.util.TableHelper; 44 47 import org.openstreetmap.josm.gui.widgets.FilterField; … … 50 53 /** 51 54 * This is the keyboard preferences content. 52 55 */ 53 public class PrefJPanel extends JPanel {56 public class PrefJPanel extends JPanel implements ISearchableComponent { 54 57 55 58 // table of shortcuts 56 59 private final AbstractTableModel model; … … 363 366 } 364 367 } 365 368 } 369 370 @Override 371 public boolean isChildrenSearchable() { 372 return false; 373 } 374 375 @Override 376 public List<SearchItem> getSearchItems() { 377 List<SearchItem> list = new ArrayList<>(); 378 for (int row = 0; row < model.getRowCount(); row++) { 379 list.add(new SearchItem(model.getValueAt(row, 0).toString())); 380 } 381 return list; 382 } 366 383 }