commit a79fdc43e758e52db2c182c6ddc683d88b5c5754
Author: Simon Legner <Simon.Legner@gmail.com>
Date: 2020-08-31 22:35:59 +0200
fix #19745 - Preferences: add quick filter for styles/presets/rules
diff --git a/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java b/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java
index 3ae180dbf..3dcde79fa 100644
|
a
|
b
|
|
| 8 | 8 | import java.awt.Color; |
| 9 | 9 | import java.awt.Component; |
| 10 | 10 | import java.awt.Dimension; |
| 11 | | import java.awt.Font; |
| 12 | 11 | import java.awt.GridBagConstraints; |
| 13 | 12 | import java.awt.GridBagLayout; |
| 14 | 13 | import java.awt.Insets; |
| … |
… |
|
| 39 | 38 | import java.util.regex.Pattern; |
| 40 | 39 | import java.util.stream.Collectors; |
| 41 | 40 | import java.util.stream.IntStream; |
| | 41 | import java.util.stream.Stream; |
| 42 | 42 | |
| 43 | 43 | import javax.swing.AbstractAction; |
| 44 | 44 | import javax.swing.BorderFactory; |
| 45 | 45 | import javax.swing.Box; |
| 46 | | import javax.swing.DefaultListModel; |
| 47 | 46 | import javax.swing.DefaultListSelectionModel; |
| 48 | 47 | import javax.swing.JButton; |
| 49 | 48 | import javax.swing.JCheckBox; |
| 50 | 49 | import javax.swing.JComponent; |
| 51 | 50 | import javax.swing.JFileChooser; |
| 52 | 51 | import javax.swing.JLabel; |
| 53 | | import javax.swing.JList; |
| 54 | 52 | import javax.swing.JOptionPane; |
| 55 | 53 | import javax.swing.JPanel; |
| 56 | 54 | import javax.swing.JScrollPane; |
| … |
… |
|
| 58 | 56 | import javax.swing.JTable; |
| 59 | 57 | import javax.swing.JToolBar; |
| 60 | 58 | import javax.swing.KeyStroke; |
| 61 | | import javax.swing.ListCellRenderer; |
| 62 | 59 | import javax.swing.ListSelectionModel; |
| 63 | 60 | import javax.swing.UIManager; |
| 64 | 61 | import javax.swing.event.CellEditorListener; |
| … |
… |
|
| 93 | 90 | import org.openstreetmap.josm.gui.util.TableHelper; |
| 94 | 91 | import org.openstreetmap.josm.gui.widgets.AbstractFileChooser; |
| 95 | 92 | import org.openstreetmap.josm.gui.widgets.FileChooserManager; |
| | 93 | import org.openstreetmap.josm.gui.widgets.FilterField; |
| 96 | 94 | import org.openstreetmap.josm.gui.widgets.JosmTextField; |
| 97 | 95 | import org.openstreetmap.josm.io.CachedFile; |
| 98 | 96 | import org.openstreetmap.josm.io.NetworkManager; |
| … |
… |
|
| 124 | 122 | /** the underlying model of active sources **/ |
| 125 | 123 | protected final ActiveSourcesModel activeSourcesModel; |
| 126 | 124 | /** the list of available sources **/ |
| 127 | | protected final JList<ExtendedSourceEntry> lstAvailableSources; |
| | 125 | protected final JTable tblAvailableSources; |
| 128 | 126 | /** the underlying model of available sources **/ |
| 129 | | protected final AvailableSourcesListModel availableSourcesModel; |
| | 127 | protected final AvailableSourcesModel availableSourcesModel; |
| 130 | 128 | /** the URL from which the available sources are fetched **/ |
| 131 | 129 | protected final String availableSourcesUrl; |
| 132 | 130 | /** the list of source providers **/ |
| … |
… |
protected SourceEditor(SourceType sourceType, String availableSourcesUrl, List<S
|
| 151 | 149 | this.canEnable = sourceType == SourceType.MAP_PAINT_STYLE || sourceType == SourceType.TAGCHECKER_RULE; |
| 152 | 150 | |
| 153 | 151 | DefaultListSelectionModel selectionModel = new DefaultListSelectionModel(); |
| 154 | | this.availableSourcesModel = new AvailableSourcesListModel(selectionModel); |
| 155 | | this.lstAvailableSources = new JList<>(availableSourcesModel); |
| 156 | | this.lstAvailableSources.setSelectionModel(selectionModel); |
| 157 | | final SourceEntryListCellRenderer listCellRenderer = new SourceEntryListCellRenderer(); |
| 158 | | this.lstAvailableSources.setCellRenderer(listCellRenderer); |
| 159 | | GuiHelper.extendTooltipDelay(lstAvailableSources); |
| | 152 | this.availableSourcesModel = new AvailableSourcesModel(); |
| | 153 | this.tblAvailableSources = new ScrollHackTable(availableSourcesModel); |
| | 154 | this.tblAvailableSources.setAutoCreateRowSorter(true); |
| | 155 | this.tblAvailableSources.setSelectionModel(selectionModel); |
| | 156 | final FancySourceEntryTableCellRenderer availableSourcesEntryRenderer = new FancySourceEntryTableCellRenderer(); |
| | 157 | this.tblAvailableSources.getColumnModel().getColumn(0).setCellRenderer(availableSourcesEntryRenderer); |
| | 158 | GuiHelper.extendTooltipDelay(tblAvailableSources); |
| 160 | 159 | this.availableSourcesUrl = availableSourcesUrl; |
| 161 | 160 | this.sourceProviders = sourceProviders; |
| 162 | 161 | |
| … |
… |
protected SourceEditor(SourceType sourceType, String availableSourcesUrl, List<S
|
| 165 | 164 | tblActiveSources = new ScrollHackTable(activeSourcesModel); |
| 166 | 165 | tblActiveSources.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); |
| 167 | 166 | tblActiveSources.setSelectionModel(selectionModel); |
| 168 | | tblActiveSources.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); |
| 169 | | tblActiveSources.setShowGrid(false); |
| 170 | | tblActiveSources.setIntercellSpacing(new Dimension(0, 0)); |
| 171 | | tblActiveSources.setTableHeader(null); |
| 172 | | tblActiveSources.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); |
| | 167 | Stream.of(tblAvailableSources, tblActiveSources).forEach(t -> { |
| | 168 | t.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); |
| | 169 | t.setShowGrid(false); |
| | 170 | t.setIntercellSpacing(new Dimension(0, 0)); |
| | 171 | t.setTableHeader(null); |
| | 172 | t.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); |
| | 173 | }); |
| 173 | 174 | SourceEntryTableCellRenderer sourceEntryRenderer = new SourceEntryTableCellRenderer(); |
| 174 | 175 | if (canEnable) { |
| 175 | 176 | tblActiveSources.getColumnModel().getColumn(0).setMaxWidth(1); |
| … |
… |
protected SourceEditor(SourceType sourceType, String availableSourcesUrl, List<S
|
| 180 | 181 | } |
| 181 | 182 | |
| 182 | 183 | activeSourcesModel.addTableModelListener(e -> { |
| 183 | | listCellRenderer.updateSources(activeSourcesModel.getSources()); |
| 184 | | lstAvailableSources.repaint(); |
| | 184 | availableSourcesEntryRenderer.updateSources(activeSourcesModel.getSources()); |
| | 185 | tblAvailableSources.repaint(); |
| 185 | 186 | }); |
| 186 | 187 | tblActiveSources.addPropertyChangeListener(evt -> { |
| 187 | | listCellRenderer.updateSources(activeSourcesModel.getSources()); |
| 188 | | lstAvailableSources.repaint(); |
| | 188 | availableSourcesEntryRenderer.updateSources(activeSourcesModel.getSources()); |
| | 189 | tblAvailableSources.repaint(); |
| 189 | 190 | }); |
| 190 | 191 | // Force Swing to show horizontal scrollbars for the JTable |
| 191 | 192 | // Yes, this is a little ugly, but should work |
| | 193 | availableSourcesModel.addTableModelListener(e -> TableHelper.adjustColumnWidth(tblAvailableSources, 0, 800)); |
| 192 | 194 | activeSourcesModel.addTableModelListener(e -> TableHelper.adjustColumnWidth(tblActiveSources, canEnable ? 1 : 0, 800)); |
| 193 | 195 | activeSourcesModel.setActiveSources(getInitialSourcesList()); |
| 194 | 196 | |
| … |
… |
public void mouseClicked(MouseEvent e) {
|
| 226 | 228 | } |
| 227 | 229 | |
| 228 | 230 | ActivateSourcesAction activateSourcesAction = new ActivateSourcesAction(); |
| 229 | | lstAvailableSources.addListSelectionListener(activateSourcesAction); |
| | 231 | tblAvailableSources.getSelectionModel().addListSelectionListener(activateSourcesAction); |
| 230 | 232 | JButton activate = new JButton(activateSourcesAction); |
| 231 | 233 | |
| 232 | 234 | setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); |
| … |
… |
public void mouseClicked(MouseEvent e) {
|
| 255 | 257 | gbc.anchor = GBC.CENTER; |
| 256 | 258 | gbc.insets = new Insets(0, 11, 0, 0); |
| 257 | 259 | |
| 258 | | JScrollPane sp1 = new JScrollPane(lstAvailableSources); |
| 259 | | add(sp1, gbc); |
| | 260 | FilterField availableSourcesFilter = new FilterField().filter(tblAvailableSources, availableSourcesModel); |
| | 261 | JPanel defaultPane = new JPanel(new GridBagLayout()); |
| | 262 | JScrollPane sp1 = new JScrollPane(tblAvailableSources); |
| | 263 | defaultPane.add(availableSourcesFilter, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL)); |
| | 264 | defaultPane.add(sp1, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.BOTH)); |
| | 265 | add(defaultPane, gbc); |
| 260 | 266 | |
| 261 | 267 | gbc.gridx = 1; |
| 262 | 268 | gbc.weightx = 0.0; |
| … |
… |
public void initiallyLoadAvailableSources() {
|
| 560 | 566 | /** |
| 561 | 567 | * List model of available sources. |
| 562 | 568 | */ |
| 563 | | protected static class AvailableSourcesListModel extends DefaultListModel<ExtendedSourceEntry> { |
| | 569 | protected static class AvailableSourcesModel extends AbstractTableModel { |
| 564 | 570 | private final transient List<ExtendedSourceEntry> data; |
| 565 | | private final DefaultListSelectionModel selectionModel; |
| 566 | 571 | |
| 567 | 572 | /** |
| 568 | 573 | * Constructs a new {@code AvailableSourcesListModel} |
| 569 | | * @param selectionModel selection model |
| 570 | 574 | */ |
| 571 | | public AvailableSourcesListModel(DefaultListSelectionModel selectionModel) { |
| | 575 | public AvailableSourcesModel() { |
| 572 | 576 | data = new ArrayList<>(); |
| 573 | | this.selectionModel = selectionModel; |
| 574 | 577 | } |
| 575 | 578 | |
| 576 | 579 | /** |
| … |
… |
public void setSources(List<ExtendedSourceEntry> sources) {
|
| 582 | 585 | if (sources != null) { |
| 583 | 586 | data.addAll(sources); |
| 584 | 587 | } |
| 585 | | fireContentsChanged(this, 0, data.size()); |
| | 588 | fireTableDataChanged(); |
| | 589 | } |
| | 590 | |
| | 591 | public ExtendedSourceEntry getValueAt(int rowIndex) { |
| | 592 | return data.get(rowIndex); |
| 586 | 593 | } |
| 587 | 594 | |
| 588 | 595 | @Override |
| 589 | | public ExtendedSourceEntry getElementAt(int index) { |
| 590 | | return data.get(index); |
| | 596 | public ExtendedSourceEntry getValueAt(int rowIndex, int ignored) { |
| | 597 | return getValueAt(rowIndex); |
| 591 | 598 | } |
| 592 | 599 | |
| 593 | 600 | @Override |
| 594 | | public int getSize() { |
| | 601 | public int getRowCount() { |
| 595 | 602 | if (data == null) return 0; |
| 596 | 603 | return data.size(); |
| 597 | 604 | } |
| 598 | 605 | |
| 599 | | /** |
| 600 | | * Deletes the selected sources. |
| 601 | | */ |
| 602 | | public void deleteSelected() { |
| 603 | | Iterator<ExtendedSourceEntry> it = data.iterator(); |
| 604 | | int i = 0; |
| 605 | | while (it.hasNext()) { |
| 606 | | it.next(); |
| 607 | | if (selectionModel.isSelectedIndex(i)) { |
| 608 | | it.remove(); |
| 609 | | } |
| 610 | | i++; |
| 611 | | } |
| 612 | | fireContentsChanged(this, 0, data.size()); |
| 613 | | } |
| 614 | | |
| 615 | | /** |
| 616 | | * Returns the selected sources. |
| 617 | | * @return the selected sources |
| 618 | | */ |
| 619 | | public List<ExtendedSourceEntry> getSelected() { |
| 620 | | return IntStream.range(0, data.size()) |
| 621 | | .filter(selectionModel::isSelectedIndex) |
| 622 | | .mapToObj(data::get) |
| 623 | | .collect(Collectors.toList()); |
| | 606 | @Override |
| | 607 | public int getColumnCount() { |
| | 608 | return 1; |
| 624 | 609 | } |
| 625 | 610 | } |
| 626 | 611 | |
| … |
… |
public void tableChanged(TableModelEvent e) {
|
| 1065 | 1050 | } |
| 1066 | 1051 | |
| 1067 | 1052 | protected final void updateEnabledState() { |
| 1068 | | setEnabled(lstAvailableSources.getSelectedIndices().length > 0); |
| | 1053 | setEnabled(tblAvailableSources.getSelectedRowCount() > 0); |
| 1069 | 1054 | } |
| 1070 | 1055 | |
| 1071 | 1056 | @Override |
| … |
… |
public void valueChanged(ListSelectionEvent e) {
|
| 1075 | 1060 | |
| 1076 | 1061 | @Override |
| 1077 | 1062 | public void actionPerformed(ActionEvent e) { |
| 1078 | | List<ExtendedSourceEntry> sources = availableSourcesModel.getSelected(); |
| | 1063 | List<ExtendedSourceEntry> sources = Arrays.stream(tblAvailableSources.getSelectedRows()) |
| | 1064 | .map(tblAvailableSources::convertRowIndexToModel) |
| | 1065 | .mapToObj(availableSourcesModel::getValueAt) |
| | 1066 | .collect(Collectors.toList()); |
| | 1067 | |
| 1079 | 1068 | int josmVersion = Version.getInstance().getVersion(); |
| 1080 | 1069 | if (josmVersion != Version.JOSM_UNKNOWN_VERSION) { |
| 1081 | 1070 | Collection<String> messages = new ArrayList<>(); |
| … |
… |
public void actionPerformed(ActionEvent e) {
|
| 1329 | 1318 | } |
| 1330 | 1319 | } |
| 1331 | 1320 | |
| 1332 | | static class SourceEntryListCellRenderer extends JLabel implements ListCellRenderer<ExtendedSourceEntry> { |
| | 1321 | static class FancySourceEntryTableCellRenderer extends DefaultTableCellRenderer { |
| 1333 | 1322 | |
| 1334 | 1323 | private static final NamedColorProperty SOURCE_ENTRY_ACTIVE_BACKGROUND_COLOR = new NamedColorProperty( |
| 1335 | 1324 | marktr("External resource entry: Active"), |
| … |
… |
public void actionPerformed(ActionEvent e) {
|
| 1341 | 1330 | private final Map<String, SourceEntry> entryByUrl = new HashMap<>(); |
| 1342 | 1331 | |
| 1343 | 1332 | @Override |
| 1344 | | public Component getListCellRendererComponent(JList<? extends ExtendedSourceEntry> list, ExtendedSourceEntry value, |
| 1345 | | int index, boolean isSelected, boolean cellHasFocus) { |
| | 1333 | public Component getTableCellRendererComponent(JTable list, Object object, boolean isSelected, boolean hasFocus, int row, int column) { |
| | 1334 | super.getTableCellRendererComponent(list, object, isSelected, hasFocus, row, column); |
| | 1335 | final ExtendedSourceEntry value = (ExtendedSourceEntry) object; |
| 1346 | 1336 | String s = value.toString(); |
| 1347 | 1337 | setText(s); |
| 1348 | | if (isSelected) { |
| 1349 | | setBackground(list.getSelectionBackground()); |
| 1350 | | setForeground(list.getSelectionForeground()); |
| 1351 | | } else { |
| 1352 | | setBackground(list.getBackground()); |
| 1353 | | setForeground(list.getForeground()); |
| 1354 | | } |
| 1355 | | setEnabled(list.isEnabled()); |
| 1356 | | setFont(list.getFont()); |
| 1357 | | setFont(getFont().deriveFont(Font.PLAIN)); |
| 1358 | | setOpaque(true); |
| 1359 | 1338 | setToolTipText(value.getTooltip()); |
| 1360 | 1339 | if (!isSelected) { |
| 1361 | 1340 | final SourceEntry sourceEntry = entryByUrl.get(value.url); |