Changeset 12609 in josm


Ignore:
Timestamp:
2017-08-16T22:08:22+02:00 (7 years ago)
Author:
michael2402
Message:

Apply #15057: Patch by bafonins, modified.

Location:
trunk/src/org/openstreetmap/josm
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/OverpassDownloadAction.java

    r12608 r12609  
    88import java.awt.Component;
    99import java.awt.Dimension;
     10import java.awt.GridBagLayout;
    1011import java.awt.event.ActionEvent;
    1112import java.awt.event.FocusEvent;
     
    2526import javax.swing.JPanel;
    2627import javax.swing.JScrollPane;
     28import javax.swing.event.ListSelectionEvent;
     29import javax.swing.event.ListSelectionListener;
    2730import javax.swing.plaf.basic.BasicArrowButton;
    2831
     
    4144import org.openstreetmap.josm.io.OverpassDownloadReader;
    4245import org.openstreetmap.josm.tools.GBC;
     46import org.openstreetmap.josm.tools.ImageProvider;
    4347import org.openstreetmap.josm.tools.Shortcut;
    4448
     
    159163        private static final BooleanProperty OVERPASS_QUERY_LIST_OPENED =
    160164                new BooleanProperty("download.overpass.query-list.opened", false);
     165        private static final String ACTION_IMG_SUBDIR = "dialogs";
    161166
    162167        private OverpassDownloadDialog(Component parent) {
     
    178183        @Override
    179184        protected void buildMainPanelAboveDownloadSelections(JPanel pnl) {
    180             // needed for the invisible checkboxes cbDownloadGpxData, cbDownloadNotes
    181             pnl.add(new JLabel(), GBC.eol());
    182 
    183185            DisableActionsFocusListener disableActionsFocusListener =
    184186                    new DisableActionsFocusListener(slippyMapChooser.getNavigationComponentActionMap());
     
    192194            };
    193195
    194             JButton openQueryWizard = new JButton("Query Wizard");
     196            JButton openQueryWizard = new JButton(tr("Query Wizard"));
    195197            openQueryWizard.setToolTipText(tooltip);
    196198            openQueryWizard.addActionListener(queryWizardAction);
     199
     200            // use eol() that is needed for the invisible checkboxes cbDownloadGpxData, cbDownloadNotes
     201            pnl.add(openQueryWizard, GBC.eol());
     202            pnl.add(new JLabel(tr("Overpass query:")), GBC.std().insets(5, 5, 0, 0).anchor(GBC.NORTHWEST));
    197203
    198204            // CHECKSTYLE.OFF: LineLength
     
    217223            });
    218224
     225
    219226            this.overpassQueryList = new OverpassQueryList(this, this.overpassQuery);
    220             overpassQueryList.setToolTipText(tr("Show/hide Overpass snippet list"));
    221             overpassQueryList.setVisible(OVERPASS_QUERY_LIST_OPENED.get());
    222             overpassQueryList.setPreferredSize(new Dimension(350, 300));
     227            this.overpassQueryList.setPreferredSize(new Dimension(350, 300));
     228
     229            EditSnippetAction edit = new EditSnippetAction();
     230            RemoveSnippetAction remove = new RemoveSnippetAction();
     231            this.overpassQueryList.addSelectionListener(edit);
     232            this.overpassQueryList.addSelectionListener(remove);
     233
     234            JPanel listPanel = new JPanel(new GridBagLayout());
     235            listPanel.add(new JLabel(tr("Your saved queries:")), GBC.eol().insets(2).anchor(GBC.CENTER));
     236            listPanel.add(this.overpassQueryList, GBC.eol().fill(GBC.BOTH));
     237            listPanel.add(new JButton(new AddSnippetAction()), GBC.std().fill(GBC.HORIZONTAL));
     238            listPanel.add(new JButton(edit), GBC.std().fill(GBC.HORIZONTAL));
     239            listPanel.add(new JButton(remove), GBC.std().fill(GBC.HORIZONTAL));
     240            listPanel.setVisible(OVERPASS_QUERY_LIST_OPENED.get());
     241
    223242            JScrollPane scrollPane = new JScrollPane(overpassQuery);
    224             BasicArrowButton arrowButton = new BasicArrowButton(overpassQueryList.isVisible()
     243            BasicArrowButton arrowButton = new BasicArrowButton(listPanel.isVisible()
    225244                ? BasicArrowButton.EAST
    226245                : BasicArrowButton.WEST);
     246            arrowButton.setToolTipText(tr("Show/hide Overpass snippet list"));
    227247            arrowButton.addActionListener(e -> {
    228                 if (overpassQueryList.isVisible()) {
    229                     overpassQueryList.setVisible(false);
     248                if (listPanel.isVisible()) {
     249                    listPanel.setVisible(false);
    230250                    arrowButton.setDirection(BasicArrowButton.WEST);
    231251                    OVERPASS_QUERY_LIST_OPENED.put(Boolean.FALSE);
    232252                } else {
    233                     overpassQueryList.setVisible(true);
     253                    listPanel.setVisible(true);
    234254                    arrowButton.setDirection(BasicArrowButton.EAST);
    235                     OVERPASS_QUERY_LIST_OPENED.put(Boolean.FALSE);
     255                    OVERPASS_QUERY_LIST_OPENED.put(Boolean.TRUE);
    236256                }
    237257            });
     
    243263            JPanel pane = new JPanel(new BorderLayout());
    244264            pane.add(innerPanel, BorderLayout.CENTER);
    245             pane.add(overpassQueryList, BorderLayout.EAST);
     265            pane.add(listPanel, BorderLayout.EAST);
    246266
    247267            GBC gbc = GBC.eol().fill(GBC.HORIZONTAL); gbc.ipady = 200;
    248             pnl.add(openQueryWizard, GBC.std().insets(5, 5, 5, 5));
    249268            pnl.add(pane, gbc);
    250269        }
    251270
    252         String getOverpassQuery() {
     271        public String getOverpassQuery() {
    253272            return overpassQuery.getText();
    254273        }
     
    310329            super.btnDownload.doClick();
    311330        }
     331
     332        /**
     333         * Action that delegates snippet creation to {@link OverpassQueryList#createNewItem()}.
     334         */
     335        class AddSnippetAction extends AbstractAction {
     336
     337            /**
     338             * Constructs a new {@code AddSnippetAction}.
     339             */
     340            AddSnippetAction() {
     341                super();
     342                putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "add"));
     343                putValue(SHORT_DESCRIPTION, tr("Add new snippet"));
     344            }
     345
     346            @Override
     347            public void actionPerformed(ActionEvent e) {
     348                overpassQueryList.createNewItem();
     349            }
     350        }
     351
     352        /**
     353         * Action that delegates snippet removal to {@link OverpassQueryList#removeSelectedItem()}.
     354         */
     355        class RemoveSnippetAction extends AbstractAction implements ListSelectionListener {
     356
     357            /**
     358             * Constructs a new {@code RemoveSnippetAction}.
     359             */
     360            RemoveSnippetAction() {
     361                super();
     362                putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "delete"));
     363                putValue(SHORT_DESCRIPTION, tr("Delete selected snippet"));
     364                checkEnabled();
     365            }
     366
     367            @Override
     368            public void actionPerformed(ActionEvent e) {
     369                overpassQueryList.removeSelectedItem();
     370            }
     371
     372            /**
     373             * Disables the action if no items are selected.
     374             */
     375            void checkEnabled() {
     376                setEnabled(overpassQueryList.getSelectedItem().isPresent());
     377            }
     378
     379            @Override
     380            public void valueChanged(ListSelectionEvent e) {
     381                checkEnabled();
     382            }
     383        }
     384
     385        /**
     386         * Action that delegates snippet edit to {@link OverpassQueryList#editSelectedItem()}.
     387         */
     388        class EditSnippetAction extends AbstractAction implements ListSelectionListener {
     389
     390            /**
     391             * Constructs a new {@code EditSnippetAction}.
     392             */
     393            EditSnippetAction() {
     394                super();
     395                putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "edit"));
     396                putValue(SHORT_DESCRIPTION, tr("Edit selected snippet"));
     397                checkEnabled();
     398            }
     399
     400            @Override
     401            public void actionPerformed(ActionEvent e) {
     402                overpassQueryList.editSelectedItem();
     403            }
     404
     405            /**
     406             * Disables the action if no items are selected.
     407             */
     408            void checkEnabled() {
     409                setEnabled(overpassQueryList.getSelectedItem().isPresent());
     410            }
     411
     412            @Override
     413            public void valueChanged(ListSelectionEvent e) {
     414                checkEnabled();
     415            }
     416        }
    312417    }
    313418}
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/PostDownloadHandler.java

    r12575 r12609  
    2020import org.openstreetmap.josm.gui.ExceptionDialogUtil;
    2121import org.openstreetmap.josm.gui.Notification;
     22import org.openstreetmap.josm.gui.util.GuiHelper;
    2223import org.openstreetmap.josm.tools.ExceptionUtil;
    2324import org.openstreetmap.josm.tools.Utils;
     
    6869        //
    6970        Set<Object> errors = new LinkedHashSet<>(task.getErrorObjects());
     71
    7072        if (this.errorReporter != null) {
    71             errorReporter.accept(errors);
     73            GuiHelper.runInEDT(() -> errorReporter.accept(errors));
    7274        }
    7375
  • trunk/src/org/openstreetmap/josm/gui/download/OverpassQueryList.java

    r12578 r12609  
    1616import java.time.LocalDateTime;
    1717import java.time.format.DateTimeFormatter;
     18import java.time.format.DateTimeParseException;
    1819import java.util.ArrayList;
    1920import java.util.Collection;
    2021import java.util.Collections;
    2122import java.util.HashMap;
     23import java.util.List;
    2224import java.util.Locale;
    2325import java.util.Map;
     
    7476    private static final String KEY_KEY = "key";
    7577    private static final String QUERY_KEY = "query";
    76     private static final String USE_COUNT_KEY = "useCount";
     78    private static final String LAST_EDIT_KEY = "lastEdit";
    7779    private static final String PREFERENCE_ITEMS = "download.overpass.query";
     80
     81    private static final String TRANSLATED_HISTORY = tr("history");
    7882
    7983    /**
     
    103107    public synchronized Optional<SelectorItem> getSelectedItem() {
    104108        int idx = lsResult.getSelectedIndex();
    105         if (lsResultModel.getSize() == 0 || idx == -1) {
     109        if (lsResultModel.getSize() <= idx || idx == -1) {
    106110            return Optional.empty();
    107111        }
    108112
    109113        SelectorItem item = lsResultModel.getElementAt(idx);
    110         item.increaseUsageCount();
    111 
    112         this.items.values().stream()
    113                 .filter(it -> !it.getKey().equals(item.getKey()))
    114                 .forEach(SelectorItem::decreaseUsageCount);
    115114
    116115        filterItems();
     
    128127    public synchronized void saveHistoricItem(String query) {
    129128        boolean historicExist = this.items.values().stream()
    130                 .filter(it -> it.getKey().contains("history"))
    131129                .map(SelectorItem::getQuery)
    132130                .anyMatch(q -> q.equals(query));
     
    134132        if (!historicExist) {
    135133            SelectorItem item = new SelectorItem(
    136                     "history " + LocalDateTime.now().format(FORMAT),
    137                     query);
     134                    TRANSLATED_HISTORY + " " + LocalDateTime.now().format(FORMAT), query);
    138135
    139136            this.items.put(item.getKey(), item);
     
    148145     * updates the view.
    149146     */
    150     private synchronized void removeSelectedItem() {
     147    public synchronized void removeSelectedItem() {
    151148        Optional<SelectorItem> it = this.getSelectedItem();
    152149
     
    160157        SelectorItem item = it.get();
    161158        if (this.items.remove(item.getKey(), item)) {
     159            clearSelection();
    162160            savePreferences();
    163161            filterItems();
     
    169167     * to preferences and updates the view.
    170168     */
    171     private synchronized void editSelectedItem() {
     169    public synchronized void editSelectedItem() {
    172170        Optional<SelectorItem> it = this.getSelectedItem();
    173171
     
    185183                tr("Edit item"),
    186184                item,
    187                 tr("Save"));
     185                tr("Save"), tr("Cancel"));
    188186        dialog.showDialog();
    189187
     
    202200     * and updates the view.
    203201     */
    204     private synchronized void createNewItem() {
     202    public synchronized void createNewItem() {
    205203        EditItemDialog dialog = new EditItemDialog(componentParent, tr("Add snippet"), tr("Add"));
    206204        dialog.showDialog();
     
    208206        Optional<SelectorItem> newItem = dialog.getOutputItem();
    209207        newItem.ifPresent(i -> {
    210             items.put(i.getKey(), new SelectorItem(i.getKey(), i.getQuery()));
     208            items.put(i.getKey(), i);
    211209            savePreferences();
    212210            filterItems();
     
    222220    protected void filterItems() {
    223221        String text = edSearchText.getText().toLowerCase(Locale.ENGLISH);
    224 
    225         super.lsResultModel.setItems(this.items.values().stream()
     222        List<SelectorItem> matchingItems = this.items.values().stream()
     223                .sorted((i1, i2) -> i2.getLastEdit().compareTo(i1.getLastEdit()))
    226224                .filter(item -> item.getKey().contains(text))
    227                 .collect(Collectors.toList()));
     225                .collect(Collectors.toList());
     226
     227        super.lsResultModel.setItems(matchingItems);
    228228    }
    229229
     
    248248            it.put(KEY_KEY, item.getKey());
    249249            it.put(QUERY_KEY, item.getQuery());
    250             it.put(USE_COUNT_KEY, Integer.toString(item.getUsageCount()));
     250            it.put(LAST_EDIT_KEY, item.getLastEdit().format(FORMAT));
    251251
    252252            toSave.add(it);
     
    266266
    267267        for (Map<String, String> entry : toRetrieve) {
    268             String key = entry.get(KEY_KEY);
    269             String query = entry.get(QUERY_KEY);
    270             int usageCount = Integer.parseInt(entry.get(USE_COUNT_KEY));
    271 
    272             result.put(key, new SelectorItem(key, query, usageCount));
     268            try {
     269                String key = entry.get(KEY_KEY);
     270                String query = entry.get(QUERY_KEY);
     271                String lastEditText = entry.get(LAST_EDIT_KEY);
     272                // Compatibility: Some entries may not have a last edit set.
     273                LocalDateTime lastEdit = lastEditText == null ? LocalDateTime.MIN : LocalDateTime.parse(lastEditText, FORMAT);
     274
     275                result.put(key, new SelectorItem(key, query, lastEdit));
     276            } catch (IllegalArgumentException | DateTimeParseException e) {
     277                // skip any corrupted item
     278                Main.error(e);
     279            }
    273280        }
    274281
     
    412419        private final JTextField name;
    413420        private final JosmTextArea query;
    414         private final int initialNameHash;
    415421
    416422        private final transient AbstractTextComponentValidator queryValidator;
     
    419425        private static final int SUCCESS_BTN = 0;
    420426        private static final int CANCEL_BTN = 1;
     427
     428        private final transient SelectorItem itemToEdit;
    421429
    422430        /**
     
    437445            super(parent, title, buttonTexts);
    438446
    439             String nameToEdit = itemToEdit != null ? itemToEdit.getKey() : "";
    440             String queryToEdit = itemToEdit != null ? itemToEdit.getQuery() : "";
    441             this.initialNameHash = nameToEdit.hashCode();
     447            this.itemToEdit = itemToEdit;
     448
     449            String nameToEdit = itemToEdit == null ? "" : itemToEdit.getKey();
     450            String queryToEdit = itemToEdit == null ? "" : itemToEdit.getQuery();
    442451
    443452            this.name = new JTextField(nameToEdit);
     
    458467                public boolean isValid() {
    459468                    String currentName = name.getText();
    460                     int currentHash = currentName.hashCode();
    461 
    462                     return !Utils.isStripEmpty(currentName) &&
    463                             !(currentHash != initialNameHash &&
    464                                     items.containsKey(currentName));
     469
     470                    boolean notEmpty = !Utils.isStripEmpty(currentName);
     471                    boolean exist = !currentName.equals(nameToEdit) &&
     472                                        items.containsKey(currentName);
     473
     474                    return notEmpty && !exist;
    465475                }
    466476            };
     
    478488            panel.add(queryScrollPane, constraint);
    479489
    480             setDefaultButton(SUCCESS_BTN);
    481             setCancelButton(CANCEL_BTN);
     490            setDefaultButton(SUCCESS_BTN + 1);
     491            setCancelButton(CANCEL_BTN + 1);
    482492            setPreferredSize(new Dimension(400, 400));
    483493            setContent(panel, false);
     
    501511                            tr("Warning"),
    502512                            JOptionPane.WARNING_MESSAGE);
     513
     514                    return;
    503515                } else if (!this.queryValidator.isValid()) {
    504516                    JOptionPane.showMessageDialog(
     
    507519                            tr("Warning"),
    508520                            JOptionPane.WARNING_MESSAGE);
    509                 } else {
    510                     this.outputItem = Optional.of(new SelectorItem(this.name.getText(), this.query.getText()));
    511                     super.buttonAction(buttonIndex, evt);
    512                 }
    513             } else {
    514                 super.buttonAction(buttonIndex, evt);
    515             }
     521
     522                    return;
     523                } else if (this.itemToEdit != null) { // editing the item
     524                    String newKey = this.name.getText();
     525                    String newQuery = this.query.getText();
     526
     527                    String itemKey = this.itemToEdit.getKey();
     528                    String itemQuery = this.itemToEdit.getQuery();
     529
     530                    this.outputItem = Optional.of(new SelectorItem(
     531                            this.name.getText(),
     532                            this.query.getText(),
     533                            !newKey.equals(itemKey) || !newQuery.equals(itemQuery)
     534                                ? LocalDateTime.now()
     535                                : this.itemToEdit.getLastEdit()));
     536
     537                } else { // creating new
     538                    this.outputItem = Optional.of(new SelectorItem(
     539                            this.name.getText(),
     540                            this.query.getText()));
     541                }
     542            }
     543
     544            super.buttonAction(buttonIndex, evt);
    516545        }
    517546    }
     
    524553        private final String itemKey;
    525554        private final String query;
    526         private int usageCount;
     555        private final LocalDateTime lastEdit;
    527556
    528557        /**
     
    534563         */
    535564        public SelectorItem(String key, String query) {
    536             this(key, query, 1);
     565            this(key, query, LocalDateTime.now());
    537566        }
    538567
     
    541570         * @param key The key of this item.
    542571         * @param query The query of the item.
    543          * @param usageCount The number of times this query was used.
     572         * @param lastEdit The latest when the item was
    544573         * @exception NullPointerException if any parameter is {@code null}.
    545574         * @exception IllegalArgumentException if any parameter is empty.
    546575         */
    547         public SelectorItem(String key, String query, int usageCount) {
    548             Objects.requireNonNull(key);
    549             Objects.requireNonNull(query);
     576        public SelectorItem(String key, String query, LocalDateTime lastEdit) {
     577            Objects.requireNonNull(key, "The name of the item cannot be null");
     578            Objects.requireNonNull(query, "The query of the item cannot be null");
     579            Objects.requireNonNull(lastEdit, "The last edit date time cannot be null");
    550580
    551581            if (Utils.isStripEmpty(key)) {
     
    558588            this.itemKey = key;
    559589            this.query = query;
    560             this.usageCount = usageCount;
     590            this.lastEdit = lastEdit;
    561591        }
    562592
     
    578608
    579609        /**
    580          * Gets the number of times the query was used by the user.
    581          * @return The usage count of this item.
    582          */
    583         public int getUsageCount() {
    584             return this.usageCount;
    585         }
    586 
    587         /**
    588          * Increments the {@link SelectorItem#usageCount} by one till
    589          * it reaches {@link Integer#MAX_VALUE}.
    590          */
    591         public void increaseUsageCount() {
    592             if (this.usageCount < Integer.MAX_VALUE) {
    593                 this.usageCount++;
    594             }
    595         }
    596 
    597         /**
    598          * Decrements the {@link SelectorItem#usageCount} ny one till
    599          * it reaches 0.
    600          */
    601         public void decreaseUsageCount() {
    602             if (this.usageCount > 0) {
    603                 this.usageCount--;
    604             }
     610         * Gets the latest date time when the item was created/changed.
     611         * @return The latest date time when the item was created/changed.
     612         */
     613        public LocalDateTime getLastEdit() {
     614            return lastEdit;
    605615        }
    606616
  • trunk/src/org/openstreetmap/josm/gui/download/OverpassQueryWizardDialog.java

    r12580 r12609  
    3737public final class OverpassQueryWizardDialog extends ExtendedDialog {
    3838
     39    private final HistoryComboBox queryWizard;
    3940    private static final String HEADLINE_START = "<h3>";
    4041    private static final String HEADLINE_END = "</h3>";
     
    4344    private static final String TD_START = "<td>";
    4445    private static final String TD_END = "</td>";
    45     private final HistoryComboBox queryWizard;
    46     private final OverpassTurboQueryWizard overpassQueryBuilder;
     46    private static final String SPAN_START = "<span>";
     47    private static final String SPAN_END = "</span>";
    4748    private static final CollectionProperty OVERPASS_WIZARD_HISTORY =
    4849            new CollectionProperty("download.overpass.wizard", new ArrayList<String>());
     50    private final transient OverpassTurboQueryWizard overpassQueryBuilder;
    4951
    5052    // dialog buttons
     
    200202                .append(Utils.joinAsHtmlUnorderedList(Arrays.asList("<i>type:node</i>", "<i>type:relation</i>", "<i>type:way</i>")))
    201203                .append(TD_END).append(TD_START)
    202                 .append("<span>").append(tr("Download objects of a certain type.")).append("</span>")
     204                .append(SPAN_START).append(tr("Download objects of a certain type.")).append(SPAN_END)
    203205                .append(TD_END).append(TR_END)
    204206                .append(TR_START).append(TD_START)
     
    215217                        tr("{0} all objects within the current selection that have {1} as attribute.", "<i>tourism=hotel in bbox</i> -",
    216218                                "'tourism=hotel'"))))
    217                 .append("<span>")
     219                .append(SPAN_START)
    218220                .append(tr("Instead of <i>location</i> any valid place name can be used like address, city, etc."))
    219                 .append("</span>")
     221                .append(SPAN_END)
    220222                .append(TD_END).append(TR_END)
    221223                .append(TR_START).append(TD_START)
     
    231233                        tr("<i>expression1 {0} expression2</i>", "and"))))
    232234                .append(TD_END).append(TD_START)
    233                 .append("<span>")
     235                .append(SPAN_START)
    234236                .append(tr("Basic logical operators can be used to create more sophisticated queries. Instead of \"or\" - \"|\", \"||\" " +
    235237                        "can be used, and instead of \"and\" - \"&\", \"&&\"."))
    236                 .append("</span>")
     238                .append(SPAN_END)
    237239                .append(TD_END).append(TR_END).append("</table>")
    238240                .append("</body>")
Note: See TracChangeset for help on using the changeset viewer.