Changeset 17714 in josm


Ignore:
Timestamp:
2021-04-07T23:41:13+02:00 (4 years ago)
Author:
simon04
Message:

fix #20583 - Filter notes in notes dialog

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/dialogs/NotesDialog.java

    r17712 r17714  
    1717import java.util.List;
    1818import java.util.Objects;
     19import java.util.function.Predicate;
     20import java.util.regex.Pattern;
    1921
    2022import javax.swing.AbstractAction;
     
    4951import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
    5052import org.openstreetmap.josm.gui.layer.NoteLayer;
     53import org.openstreetmap.josm.gui.util.DocumentAdapter;
     54import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedTextField;
     55import org.openstreetmap.josm.gui.widgets.JosmTextField;
    5156import org.openstreetmap.josm.spi.preferences.Config;
    5257import org.openstreetmap.josm.tools.ImageProvider;
     
    6469    private NoteTableModel model;
    6570    private JList<Note> displayList;
     71    private final JosmTextField filter = setupFilter();
    6672    private final AddCommentAction addCommentAction;
    6773    private final CloseAction closeAction;
     
    114120
    115121        JPanel pane = new JPanel(new BorderLayout());
     122        pane.add(filter, BorderLayout.NORTH);
    116123        pane.add(new JScrollPane(displayList), BorderLayout.CENTER);
    117124
     
    222229    public Note getSelectedNote() {
    223230        return noteData != null ? noteData.getSelectedNote() : null;
     231    }
     232
     233    private JosmTextField setupFilter() {
     234        final JosmTextField f = new DisableShortcutsOnFocusGainedTextField();
     235        f.setToolTipText(tr("Note filter"));
     236        f.getDocument().addDocumentListener(DocumentAdapter.create(ignore -> {
     237            String text = f.getText();
     238            model.setFilter(note -> matchesNote(text, note));
     239        }));
     240        return f;
     241    }
     242
     243    static boolean matchesNote(String filter, Note note) {
     244        if (filter == null || filter.isEmpty()) {
     245            return true;
     246        }
     247        return Pattern.compile("\\s+").splitAsStream(filter).allMatch(string -> {
     248            switch (string) {
     249                case "open":
     250                    return note.getState() == State.OPEN;
     251                case "closed":
     252                    return note.getState() == State.CLOSED;
     253                case "reopened":
     254                    return note.getLastComment().getNoteAction() == NoteComment.Action.REOPENED;
     255                case "new":
     256                    return note.getId() < 0;
     257                case "modified":
     258                    return note.getLastComment().isNew();
     259                default:
     260                    return note.getComments().toString().contains(string);
     261            }
     262        });
    224263    }
    225264
     
    270309
    271310    class NoteTableModel extends AbstractListModel<Note> {
    272         private final transient List<Note> data;
    273 
    274         /**
    275          * Constructs a new {@code NoteTableModel}.
    276          */
    277         NoteTableModel() {
    278             data = new ArrayList<>();
    279         }
     311        private final transient List<Note> data = new ArrayList<>();
     312        private final transient List<Note> filteredData = new ArrayList<>();
     313        private transient Predicate<Note> filter;
    280314
    281315        @Override
    282316        public int getSize() {
    283             if (data == null) {
    284                 return 0;
    285             }
    286             return data.size();
     317            return filteredData.size();
    287318        }
    288319
    289320        @Override
    290321        public Note getElementAt(int index) {
    291             return data.get(index);
     322            return filteredData.get(index);
     323        }
     324
     325        public void setFilter(Predicate<Note> filter) {
     326            this.filter = filter;
     327            filteredData.clear();
     328            if (filter == null) {
     329                filteredData.addAll(data);
     330            } else {
     331                data.stream().filter(filter).forEach(filteredData::add);
     332            }
     333            fireContentsChanged(this, 0, getSize());
     334            setTitle(data.isEmpty()
     335                    ? tr("Notes")
     336                    : tr("Notes: {0}/{1}", filteredData.size(), data.size()));
    292337        }
    293338
     
    295340            data.clear();
    296341            data.addAll(noteList);
    297             fireContentsChanged(this, 0, noteList.size());
     342            setFilter(filter);
    298343        }
    299344
     
    301346            displayList.clearSelection();
    302347            data.clear();
    303             fireIntervalRemoved(this, 0, getSize());
     348            setFilter(filter);
    304349        }
    305350    }
  • trunk/test/unit/org/openstreetmap/josm/gui/dialogs/NotesDialogTest.java

    r17712 r17714  
    33
    44import static org.junit.jupiter.api.Assertions.assertEquals;
     5import static org.junit.jupiter.api.Assertions.assertFalse;
     6import static org.junit.jupiter.api.Assertions.assertTrue;
    57
    68import java.time.Instant;
     
    3234    public JOSMTestRules josmTestRules = new JOSMTestRules().preferences();
    3335
    34     @Test
    35     void testMultiLineNoteRendering() {
     36    private Note createMultiLineNote() {
    3637        Note note = new Note(LatLon.ZERO);
    3738        note.setCreatedAt(Instant.now());
    3839        note.addComment(new NoteComment(Instant.now(), User.createLocalUser(null), "foo\nbar\n\nbaz:\nfoo", null, false));
     40        return note;
     41    }
     42
     43    /**
     44     * Unit test of {@link NoteRenderer}
     45     */
     46    @Test
     47    void testMultiLineNoteRendering() {
     48        Note note = createMultiLineNote();
    3949        assertEquals("0: foo; bar; baz: foo",
    4050                ((JLabel) new NoteRenderer().getListCellRendererComponent(new JList<>(), note, 0, false, false)).getText());
    4151    }
     52
     53    /**
     54     * Unit test of {@link NotesDialog#matchesNote}
     55     */
     56    @Test
     57    void testMatchesNote() {
     58        Note note = createMultiLineNote();
     59        assertTrue(NotesDialog.matchesNote(null, note));
     60        assertTrue(NotesDialog.matchesNote("", note));
     61        assertTrue(NotesDialog.matchesNote("foo", note));
     62        assertFalse(NotesDialog.matchesNote("xxx", note));
     63        assertFalse(NotesDialog.matchesNote("open", note));
     64        assertFalse(NotesDialog.matchesNote("new", note));
     65        assertFalse(NotesDialog.matchesNote("reopened", note));
     66    }
    4267}
Note: See TracChangeset for help on using the changeset viewer.