Ticket #17576: 17576-timezones-V2.diff

File 17576-timezones-V2.diff, 12.9 KB (added by Bjoeni, 2 months ago)
  • src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java

     
    3636import java.util.Hashtable;
    3737import java.util.List;
    3838import java.util.Objects;
    39 import java.util.Optional;
    4039import java.util.TimeZone;
    4140import java.util.concurrent.TimeUnit;
    4241
     
    540539     *
    541540     */
    542541    private class SetOffsetActionListener implements ActionListener {
     542        JCheckBox ckDst;
     543        ImageDisplay imgDisp;
     544        JLabel lbExifTime;
     545        JosmTextField tfGpsTime;
    543546
     547        class TimeZoneItem implements Comparable<TimeZoneItem> {
     548            private TimeZone tz;
     549            private String rawString;
     550            private String dstString;
     551
     552            public TimeZoneItem(TimeZone tz) {
     553                this.tz = tz;
     554            }
     555
     556            public String getFormattedString() {
     557                if (ckDst.isSelected()) {
     558                    return getDstString();
     559                } else {
     560                    return getRawString();
     561                }
     562            }
     563
     564            public String getDstString() {
     565                if (dstString == null) {
     566                    dstString = formatTimezone(tz.getRawOffset() + tz.getDSTSavings());
     567                }
     568                return dstString;
     569            }
     570
     571            public String getRawString() {
     572                if (rawString == null) {
     573                    rawString = formatTimezone(tz.getRawOffset());
     574                }
     575                return rawString;
     576            }
     577
     578            public String getID() {
     579                return tz.getID();
     580            }
     581
     582            @Override
     583            public String toString() {
     584                return getID() + " (" + getFormattedString() + ")";
     585            }
     586
     587            @Override
     588            public int compareTo(TimeZoneItem o) {
     589                return getID().compareTo(o.getID());
     590            }
     591
     592            private String formatTimezone(int offset) {
     593                return new GpxTimezone((double) offset / TimeUnit.HOURS.toMillis(1)).formatTimezone();
     594            }
     595        }
     596
    544597        @Override
    545598        public void actionPerformed(ActionEvent arg0) {
    546599            SimpleDateFormat dateFormat = (SimpleDateFormat) DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM);
     
    551604                    + "And then, simply capture the time you read on the photo and select a timezone<hr></html>")),
    552605                    BorderLayout.NORTH);
    553606
    554             ImageDisplay imgDisp = new ImageDisplay();
     607            imgDisp = new ImageDisplay();
    555608            imgDisp.setPreferredSize(new Dimension(300, 225));
    556609            panel.add(imgDisp, BorderLayout.CENTER);
    557610
     
    565618            gc.anchor = GridBagConstraints.WEST;
    566619            panelTf.add(new JLabel(tr("Photo time (from exif):")), gc);
    567620
    568             JLabel lbExifTime = new JLabel();
     621            lbExifTime = new JLabel();
    569622            gc.gridx = 1;
    570623            gc.weightx = 1.0;
    571624            gc.fill = GridBagConstraints.HORIZONTAL;
     
    580633            gc.anchor = GridBagConstraints.WEST;
    581634            panelTf.add(new JLabel(tr("Gps time (read from the above photo): ")), gc);
    582635
    583             JosmTextField tfGpsTime = new JosmTextField(12);
     636            tfGpsTime = new JosmTextField(12);
    584637            tfGpsTime.setEnabled(false);
    585638            tfGpsTime.setMinimumSize(new Dimension(155, tfGpsTime.getMinimumSize().height));
    586639            gc.gridx = 1;
     
    598651            gc.weightx = gc.weighty = 0.0;
    599652            gc.fill = GridBagConstraints.NONE;
    600653            gc.anchor = GridBagConstraints.WEST;
    601             panelTf.add(new JLabel(tr("I am in the timezone of: ")), gc);
     654            panelTf.add(new JLabel(tr("Photo taken in the timezone of: ")), gc);
    602655
     656            ckDst = new JCheckBox(tr("Use daylight saving time (where applicable)"), Config.getPref().getBoolean("geoimage.timezoneid.dst"));
     657
    603658            String[] tmp = TimeZone.getAvailableIDs();
    604             List<String> vtTimezones = new ArrayList<>(tmp.length);
     659            List<TimeZoneItem> vtTimezones = new ArrayList<>(tmp.length);
    605660
     661            String defTzStr = Config.getPref().get("geoimage.timezoneid", "");
     662            if (defTzStr.isEmpty()) {
     663                defTzStr = TimeZone.getDefault().getID();
     664            }
     665            TimeZoneItem defTzItem = null;
     666
    606667            for (String tzStr : tmp) {
    607                 TimeZone tz = TimeZone.getTimeZone(tzStr);
    608 
    609                 String tzDesc = tzStr + " (" +
    610                         new GpxTimezone(((double) tz.getRawOffset()) / TimeUnit.HOURS.toMillis(1)).formatTimezone() +
    611                         ')';
    612                 vtTimezones.add(tzDesc);
     668                TimeZoneItem tz = new TimeZoneItem(TimeZone.getTimeZone(tzStr));
     669                vtTimezones.add(tz);
     670                if (defTzStr.equals(tzStr)) {
     671                    defTzItem = tz;
     672                }
    613673            }
    614674
    615675            Collections.sort(vtTimezones);
    616676
    617             JosmComboBox<String> cbTimezones = new JosmComboBox<>(vtTimezones.toArray(new String[0]));
     677            JosmComboBox<TimeZoneItem> cbTimezones = new JosmComboBox<>(vtTimezones.toArray(new TimeZoneItem[0]));
    618678
    619             String tzId = Config.getPref().get("geoimage.timezoneid", "");
    620             TimeZone defaultTz;
    621             if (tzId.isEmpty()) {
    622                 defaultTz = TimeZone.getDefault();
    623             } else {
    624                 defaultTz = TimeZone.getTimeZone(tzId);
     679            if (defTzItem != null) {
     680                cbTimezones.setSelectedItem(defTzItem);
    625681            }
    626682
    627             cbTimezones.setSelectedItem(defaultTz.getID() + " (" +
    628                     new GpxTimezone(((double) defaultTz.getRawOffset()) / TimeUnit.HOURS.toMillis(1)).formatTimezone() +
    629                     ')');
    630 
    631683            gc.gridx = 1;
    632684            gc.weightx = 1.0;
    633685            gc.gridwidth = 2;
     
    634686            gc.fill = GridBagConstraints.HORIZONTAL;
    635687            panelTf.add(cbTimezones, gc);
    636688
     689            gc.gridy = 3;
     690            panelTf.add(ckDst, gc);
     691
     692            ckDst.addActionListener(l -> {
     693                cbTimezones.repaint();
     694            });
     695
    637696            panel.add(panelTf, BorderLayout.SOUTH);
    638697
    639698            JPanel panelLst = new JPanel(new BorderLayout());
     
    653712            imgList.getSelectionModel().addListSelectionListener(evt -> {
    654713                int index = imgList.getSelectedIndex();
    655714                ImageEntry img = yLayer.getImageData().getImages().get(index);
    656                 imgDisp.setImage(img);
    657                 Date date = img.getExifTime();
    658                 if (date != null) {
    659                     DateFormat df = DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM);
    660                     lbExifTime.setText(df.format(date));
    661                     tfGpsTime.setText(df.format(date));
    662                     tfGpsTime.setCaretPosition(tfGpsTime.getText().length());
    663                     tfGpsTime.setEnabled(true);
    664                     tfGpsTime.requestFocus();
    665                 } else {
    666                     lbExifTime.setText(tr("No date"));
    667                     tfGpsTime.setText("");
    668                     tfGpsTime.setEnabled(false);
    669                 }
     715                updateExifComponents(img);
    670716            });
    671717            panelLst.add(new JScrollPane(imgList), BorderLayout.CENTER);
    672718
     
    678724                    return;
    679725                ImageEntry entry = new ImageEntry(fc.getSelectedFile());
    680726                entry.extractExif();
    681                 imgDisp.setImage(entry);
    682 
    683                 Date date = entry.getExifTime();
    684                 if (date != null) {
    685                     lbExifTime.setText(DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM).format(date));
    686                     tfGpsTime.setText(DateUtils.getDateFormat(DateFormat.SHORT).format(date)+' ');
    687                     tfGpsTime.setEnabled(true);
    688                 } else {
    689                     lbExifTime.setText(tr("No date"));
    690                     tfGpsTime.setText("");
    691                     tfGpsTime.setEnabled(false);
    692                 }
     727                updateExifComponents(entry);
    693728            });
    694729            panelLst.add(openButton, BorderLayout.PAGE_END);
    695730
     
    718753                    continue;
    719754                }
    720755
    721                 String selectedTz = (String) cbTimezones.getSelectedItem();
    722                 int pos = selectedTz.lastIndexOf('(');
    723                 tzId = selectedTz.substring(0, pos - 1);
    724                 String tzValue = selectedTz.substring(pos + 1, selectedTz.length() - 1);
     756                TimeZoneItem selectedTz = (TimeZoneItem) cbTimezones.getSelectedItem();
    725757
    726                 Config.getPref().put("geoimage.timezoneid", tzId);
     758                Config.getPref().put("geoimage.timezoneid", selectedTz.getID());
     759                Config.getPref().putBoolean("geoimage.timezoneid.dst", ckDst.isSelected());
    727760                tfOffset.setText(GpxTimeOffset.milliseconds(delta).formatOffset());
    728                 tfTimezone.setText(tzValue);
     761                tfTimezone.setText(selectedTz.getFormattedString());
    729762
    730763                isOk = true;
    731764
     
    733766            statusBarUpdater.updateStatusBar();
    734767            yLayer.updateBufferAndRepaint();
    735768        }
     769
     770        void updateExifComponents(ImageEntry img) {
     771            imgDisp.setImage(img);
     772            Date date = img.getExifTime();
     773            if (date != null) {
     774                DateFormat df = DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM);
     775                df.setTimeZone(DateUtils.UTC); //EXIF data does not contain timezone information and is read as UTC
     776                lbExifTime.setText(df.format(date));
     777                tfGpsTime.setText(df.format(date));
     778                tfGpsTime.setCaretPosition(tfGpsTime.getText().length());
     779                tfGpsTime.setEnabled(true);
     780                tfGpsTime.requestFocus();
     781            } else {
     782                lbExifTime.setText(tr("No date"));
     783                tfGpsTime.setText("");
     784                tfGpsTime.setEnabled(false);
     785            }
     786        }
    736787    }
    737788
    738789    private class GpxLayerAddedListener implements LayerChangeListener {
     
    817868        JPanel panelTf = new JPanel(new GridBagLayout());
    818869
    819870        try {
    820             timezone = GpxTimezone.parseTimezone(Optional.ofNullable(Config.getPref().get("geoimage.timezone", "0:00")).orElse("0:00"));
     871            String tz = Config.getPref().get("geoimage.timezone");
     872            if (!tz.isEmpty()) {
     873                timezone = GpxTimezone.parseTimezone(tz);
     874            } else {
     875                timezone = new GpxTimezone(TimeUnit.MILLISECONDS.toMinutes(TimeZone.getDefault().getRawOffset()) / 60.); //hours is double
     876            }
    821877        } catch (ParseException e) {
    822878            timezone = GpxTimezone.ZERO;
    823879            Logging.trace(e);
     
    10541110            if (selGpx == null)
    10551111                return tr("No gpx selected");
    10561112
    1057             final long offsetMs = ((long) (timezone.getHours() * TimeUnit.HOURS.toMillis(-1))) + delta.getMilliseconds(); // in milliseconds
     1113            final long offsetMs = ((long) (timezone.getHours() * TimeUnit.HOURS.toMillis(1))) + delta.getMilliseconds(); // in milliseconds
    10581114            lastNumMatched = GpxImageCorrelation.matchGpxTrack(dateImgLst, selGpx.data, offsetMs, forceTags);
    10591115
    10601116            return trn("<html>Matched <b>{0}</b> of <b>{1}</b> photo to GPX track.</html>",
  • src/org/openstreetmap/josm/tools/date/DateUtils.java

     
    66import java.text.SimpleDateFormat;
    77import java.time.DateTimeException;
    88import java.time.Instant;
    9 import java.time.ZoneId;
    109import java.time.ZoneOffset;
    1110import java.time.ZonedDateTime;
    1211import java.time.format.DateTimeFormatter;
     
    10099                parsePart2(str, 14),
    101100                parsePart2(str, 17),
    102101                0,
    103                 // consider EXIF date in default timezone
    104                 checkLayout(str, "xxxx:xx:xx xx:xx:xx") ? ZoneId.systemDefault() : ZoneOffset.UTC
     102                ZoneOffset.UTC
    105103            );
    106104            if (str.length() == 22 || str.length() == 25) {
    107105                final int plusHr = parsePart2(str, 20);
     
    122120                parsePart2(str, 14),
    123121                parsePart2(str, 17),
    124122                parsePart3(str, 20) * 1_000_000,
    125                 // consider EXIF date in default timezone
    126                 checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") ? ZoneId.systemDefault() : ZoneOffset.UTC
     123                ZoneOffset.UTC
    127124            );
    128125            if (str.length() == 29) {
    129126                final int plusHr = parsePart2(str, 24);