Ticket #20795: 20795.patch

File 20795.patch, 14.3 KB (added by Bjoeni, 5 years ago)
  • src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java

    ### Eclipse Workspace Patch 1.0
    #P josm
     
    168168                }
    169169            }
    170170        }
    171         if (trkTag) {
     171        if (trkTag && prevWp != null) {
    172172            ret += matchPoints(images, prevWp, prevWpTime, prevWp, prevWpTime, offset, false, trkTagTime, true);
    173173        }
    174174        return ret;
  • src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java

     
    2121import java.awt.event.ItemListener;
    2222import java.awt.event.WindowAdapter;
    2323import java.awt.event.WindowEvent;
     24import java.beans.PropertyChangeEvent;
     25import java.beans.PropertyChangeListener;
    2426import java.io.File;
    2527import java.io.IOException;
    2628import java.io.InputStream;
     
    115117 */
    116118public class CorrelateGpxWithImages extends AbstractAction {
    117119
    118     private static final List<GpxData> loadedGpxData = new ArrayList<>();
     120    private static MutableComboBoxModel<GpxDataWrapper> gpxModel;
     121    private static List<CorrelateGpxWithImages> instances = new ArrayList<>();
    119122
     123    private static boolean forceTags;
     124
    120125    private final transient GeoImageLayer yLayer;
    121126    private transient GpxTimezone timezone;
    122127    private transient GpxTimeOffset delta;
    123     private static boolean forceTags;
    124128
    125129    /**
    126130     * Constructs a new {@code CorrelateGpxWithImages} action.
     
    130134        super(tr("Correlate to GPX"));
    131135        new ImageProvider("dialogs/geoimage/gpx2img").getResource().attachImageIcon(this, true);
    132136        this.yLayer = layer;
    133         MainApplication.getLayerManager().addLayerChangeListener(new GpxLayerAddedListener());
     137        instances.add(this);
    134138    }
    135139
    136140    private final class SyncDialogWindowListener extends WindowAdapter {
     
    233237    }
    234238
    235239    private static class GpxDataWrapper {
    236         private final String name;
     240        private String name;
    237241        private final GpxData data;
    238242        private final File file;
    239243
     
    243247            this.file = file;
    244248        }
    245249
     250        void setName(String name) {
     251            this.name = name;
     252            instances.forEach(CorrelateGpxWithImages::repaintCombobox);
     253        }
     254
    246255        @Override
    247256        public String toString() {
    248257            return name;
     
    249258        }
    250259    }
    251260
     261    private static class NoGpxDataWrapper extends GpxDataWrapper {
     262        NoGpxDataWrapper() {
     263            super(null, null, null);
     264        }
     265
     266        @Override
     267        public String toString() {
     268            return tr("<No GPX track loaded yet>");
     269        }
     270    }
     271
    252272    private ExtendedDialog syncDialog;
    253     private MutableComboBoxModel<GpxDataWrapper> gpxModel;
    254273    private JPanel outerPanel;
    255274    private JosmComboBox<GpxDataWrapper> cbGpx;
    256275    private JosmTextField tfTimezone;
     
    280299
    281300            try {
    282301                outerPanel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    283                 for (int i = gpxModel.getSize() - 1; i >= 0; i--) {
    284                     GpxDataWrapper wrapper = gpxModel.getElementAt(i);
    285                     if (sel.equals(wrapper.file)) {
    286                         gpxModel.setSelectedItem(wrapper);
    287                         if (!sel.getName().equals(wrapper.name)) {
    288                             JOptionPane.showMessageDialog(
    289                                     MainApplication.getMainFrame(),
    290                                     tr("File {0} is loaded yet under the name \"{1}\"", sel.getName(), wrapper.name),
    291                                     tr("Error"),
    292                                     JOptionPane.ERROR_MESSAGE
    293                             );
    294                         }
    295                         return;
    296                     }
    297                 }
     302                removeDuplicates(sel);
    298303                GpxData data = null;
    299304                try (InputStream iStream = Compression.getUncompressedFileInputStream(sel)) {
    300305                    IGpxReader reader = gpxFilter.accept(sel) ? new GpxReader(iStream) : new NmeaReader(iStream);
     
    322327                    return;
    323328                }
    324329
    325                 loadedGpxData.add(data);
    326                 if (gpxModel.getElementAt(0).file == null) {
    327                     gpxModel.removeElementAt(0);
    328                 }
    329330                GpxDataWrapper elem = new GpxDataWrapper(sel.getName(), data, sel);
    330331                gpxModel.addElement(elem);
    331332                gpxModel.setSelectedItem(elem);
     333                statusBarUpdater.matchAndUpdateStatusBar();
    332334            } finally {
    333335                outerPanel.setCursor(Cursor.getDefaultCursor());
    334336            }
     
    527529
    528530                forceTags = cForce.isSelected(); // This setting is not supposed to be saved permanently
    529531
    530                 statusBarUpdater.updateStatusBar();
     532                statusBarUpdater.matchAndUpdateStatusBar();
    531533                yLayer.updateBufferAndRepaint();
    532534            }
    533535        }
     
    764766                isOk = true;
    765767
    766768            }
    767             statusBarUpdater.updateStatusBar();
     769            statusBarUpdater.matchAndUpdateStatusBar();
    768770            yLayer.updateBufferAndRepaint();
    769771        }
    770772
     
    787789        }
    788790    }
    789791
    790     private class GpxLayerAddedListener implements LayerChangeListener {
     792    private static class GpxLayerAddedListener implements LayerChangeListener {
    791793        @Override
    792794        public void layerAdded(LayerAddEvent e) {
    793             if (syncDialog != null && syncDialog.isVisible()) {
    794                 Layer layer = e.getAddedLayer();
    795                 if (layer instanceof GpxLayer) {
    796                     GpxLayer gpx = (GpxLayer) layer;
    797                     GpxDataWrapper gdw = new GpxDataWrapper(gpx.getName(), gpx.data, gpx.data.storageFile);
    798                     if (gpxModel.getElementAt(0).file == null) {
    799                         gpxModel.removeElementAt(0);
    800                     }
    801                     gpxModel.addElement(gdw);
    802                 }
     795            Layer layer = e.getAddedLayer();
     796            if (layer instanceof GpxLayer) {
     797                GpxLayer gpx = (GpxLayer) layer;
     798                File file = gpx.data.storageFile;
     799                removeDuplicates(file);
     800                GpxDataWrapper gdw = new GpxDataWrapper(gpx.getName(), gpx.data, file);
     801                gpx.addPropertyChangeListener(new GpxLayerRenamedListener(gdw));
     802                gpxModel.addElement(gdw);
     803                instances.forEach(CorrelateGpxWithImages::repaintCombobox);
    803804            }
    804805        }
    805806
     
    814815        }
    815816    }
    816817
     818    private static class GpxLayerRenamedListener implements PropertyChangeListener {
     819        private GpxDataWrapper gdw;
     820        GpxLayerRenamedListener(GpxDataWrapper gdw) {
     821            this.gdw = gdw;
     822        }
     823
     824        @Override
     825        public void propertyChange(PropertyChangeEvent e) {
     826            if (Layer.NAME_PROP.equals(e.getPropertyName())) {
     827                gdw.setName(e.getNewValue().toString());
     828            }
     829        }
     830    }
     831
    817832    @Override
    818833    public void actionPerformed(ActionEvent ae) {
    819         // Construct the list of loaded GPX tracks
    820         gpxModel = new DefaultComboBoxModel<>();
    821         GpxDataWrapper defaultItem = null;
    822         for (GpxLayer cur : MainApplication.getLayerManager().getLayersOfType(GpxLayer.class).stream()
    823                 .filter(GpxLayer::isLocalFile).collect(Collectors.toList())) {
    824             GpxDataWrapper gdw = new GpxDataWrapper(cur.getName(), cur.data, cur.data.storageFile);
    825             gpxModel.addElement(gdw);
    826             if (cur == yLayer.gpxLayer || (defaultItem == null && gdw.file != null)) {
    827                 defaultItem = gdw;
     834        NoGpxDataWrapper nogdw = new NoGpxDataWrapper();
     835        if (gpxModel == null) {
     836            // Construct the list of loaded GPX tracks
     837            gpxModel = new DefaultComboBoxModel<>();
     838            GpxDataWrapper defaultItem = null;
     839            for (GpxLayer cur : MainApplication.getLayerManager().getLayersOfType(GpxLayer.class)) {
     840                GpxDataWrapper gdw = new GpxDataWrapper(cur.getName(), cur.data, cur.data.storageFile);
     841                cur.addPropertyChangeListener(new GpxLayerRenamedListener(gdw));
     842                gpxModel.addElement(gdw);
     843                if (cur == yLayer.gpxLayer || defaultItem == null) {
     844                    defaultItem = gdw;
     845                }
    828846            }
    829         }
    830         for (GpxData data : loadedGpxData) {
    831             GpxDataWrapper gdw = new GpxDataWrapper(data.storageFile.getName(), data, data.storageFile);
    832             gpxModel.addElement(gdw);
    833             if (defaultItem == null && gdw.file != null) { // select first GPX track associated to a file
    834                 defaultItem = gdw;
     847
     848            if (gpxModel.getSize() == 0) {
     849                gpxModel.addElement(nogdw);
     850            } else if (defaultItem != null) {
     851                gpxModel.setSelectedItem(defaultItem);
    835852            }
     853            MainApplication.getLayerManager().addLayerChangeListener(new GpxLayerAddedListener());
    836854        }
    837855
    838         GpxDataWrapper nogdw = new GpxDataWrapper(tr("<No GPX track loaded yet>"), null, null);
    839         if (gpxModel.getSize() == 0) {
    840             gpxModel.addElement(nogdw);
    841         } else if (defaultItem != null) {
    842             gpxModel.setSelectedItem(defaultItem);
    843         }
    844 
    845856        JPanel panelCb = new JPanel();
    846857
    847858        panelCb.add(new JLabel(tr("GPX track: ")));
     
    10071018        cbExifImg.addItemListener(statusBarUpdaterWithRepaint);
    10081019        cbTaggedImg.addItemListener(statusBarUpdaterWithRepaint);
    10091020
    1010         statusBarUpdater.updateStatusBar();
     1021        statusBarUpdater.matchAndUpdateStatusBar();
    10111022        yLayer.updateBufferAndRepaint();
    10121023
    10131024        outerPanel = new JPanel(new BorderLayout());
     
    10141025        outerPanel.add(statusBar, BorderLayout.PAGE_END);
    10151026
    10161027        if (!GraphicsEnvironment.isHeadless()) {
     1028            instances.forEach(CorrelateGpxWithImages::closeDialog);
    10171029            syncDialog = new ExtendedDialog(
    10181030                    MainApplication.getMainFrame(),
    10191031                    tr("Correlate images with GPX track"),
     
    10311043        }
    10321044    }
    10331045
     1046    private static void removeDuplicates(File file) {
     1047        for (int i = gpxModel.getSize() - 1; i >= 0; i--) {
     1048            GpxDataWrapper wrapper = gpxModel.getElementAt(i);
     1049            if (wrapper instanceof NoGpxDataWrapper || (file != null && file.equals(wrapper.file))) {
     1050                gpxModel.removeElement(wrapper);
     1051            }
     1052        }
     1053    }
     1054
    10341055    private final transient StatusBarUpdater statusBarUpdater = new StatusBarUpdater(false);
    10351056    private final transient StatusBarUpdater statusBarUpdaterWithRepaint = new StatusBarUpdater(true);
    10361057
     
    10431064
    10441065        @Override
    10451066        public void insertUpdate(DocumentEvent ev) {
    1046             updateStatusBar();
     1067            matchAndUpdateStatusBar();
    10471068        }
    10481069
    10491070        @Override
    10501071        public void removeUpdate(DocumentEvent ev) {
    1051             updateStatusBar();
     1072            matchAndUpdateStatusBar();
    10521073        }
    10531074
    10541075        @Override
     
    10581079
    10591080        @Override
    10601081        public void itemStateChanged(ItemEvent e) {
    1061             updateStatusBar();
     1082            matchAndUpdateStatusBar();
    10621083        }
    10631084
    10641085        @Override
    10651086        public void actionPerformed(ActionEvent e) {
    1066             updateStatusBar();
     1087            matchAndUpdateStatusBar();
    10671088        }
    10681089
    1069         public void updateStatusBar() {
    1070             statusBarText.setText(statusText());
    1071             if (doRepaint) {
    1072                 yLayer.updateBufferAndRepaint();
     1090        public void matchAndUpdateStatusBar() {
     1091            if (syncDialog != null && syncDialog.isVisible()) {
     1092                statusBarText.setText(matchAndGetStatusText());
     1093                if (doRepaint) {
     1094                    yLayer.updateBufferAndRepaint();
     1095                }
    10731096            }
    10741097        }
    10751098
    1076         private String statusText() {
     1099        private String matchAndGetStatusText() {
    10771100            try {
    10781101                timezone = GpxTimezone.parseTimezone(tfTimezone.getText().trim());
    10791102                delta = GpxTimeOffset.parseOffset(tfOffset.getText().trim());
     
    11961219                    lblMatches.setText(statusBarText.getText() + "<br>" + trn("(Time difference of {0} day)",
    11971220                            "Time difference of {0} days", Math.abs(dayOffset), Math.abs(dayOffset)));
    11981221
    1199                     statusBarUpdater.updateStatusBar();
     1222                    statusBarUpdater.matchAndUpdateStatusBar();
    12001223                    yLayer.updateBufferAndRepaint();
    12011224                }
    12021225            }
     
    12501273    static class NoGpxTimestamps extends Exception {
    12511274    }
    12521275
     1276    void closeDialog() {
     1277        if (syncDialog != null) {
     1278            syncDialog.setVisible(false);
     1279            new SyncDialogWindowListener().windowDeactivated(null);
     1280            syncDialog.dispose();
     1281            syncDialog = null;
     1282        }
     1283    }
     1284
     1285    void repaintCombobox() {
     1286        if (cbGpx != null) {
     1287            cbGpx.repaint();
     1288        }
     1289    }
     1290
    12531291    /**
    12541292     * Tries to auto-guess the timezone and offset.
    12551293     *
     
    13151353            tfTimezone.getDocument().addDocumentListener(statusBarUpdater);
    13161354            tfOffset.getDocument().addDocumentListener(statusBarUpdater);
    13171355
    1318             statusBarUpdater.updateStatusBar();
     1356            statusBarUpdater.matchAndUpdateStatusBar();
    13191357            yLayer.updateBufferAndRepaint();
    13201358        }
    13211359    }
     
    13431381    private GpxDataWrapper selectedGPX(boolean complain) {
    13441382        Object item = gpxModel.getSelectedItem();
    13451383
    1346         if (item == null || ((GpxDataWrapper) item).file == null) {
     1384        if (item == null || ((GpxDataWrapper) item).data == null) {
    13471385            if (complain) {
    13481386                JOptionPane.showMessageDialog(MainApplication.getMainFrame(), tr("You should select a GPX track"),
    13491387                        tr("No selected GPX track"), JOptionPane.ERROR_MESSAGE);