source: josm/trunk/src/org/openstreetmap/josm/gui/layer/geoimage/AdjustTimezoneAndOffsetDialog.java

Last change on this file was 19536, checked in by stoecker, 3 months ago

remove PMD ImplicitFunctionalInterface, see #24635

  • Property svn:eol-style set to native
File size: 6.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer.geoimage;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.awt.Component;
8import java.awt.Dimension;
9import java.awt.GridBagLayout;
10import java.util.Dictionary;
11import java.util.Hashtable;
12
13import javax.swing.JLabel;
14import javax.swing.JOptionPane;
15import javax.swing.JPanel;
16import javax.swing.JSlider;
17import javax.swing.event.ChangeListener;
18
19import org.openstreetmap.josm.data.gpx.GpxTimeOffset;
20import org.openstreetmap.josm.data.gpx.GpxTimezone;
21import org.openstreetmap.josm.gui.ExtendedDialog;
22import org.openstreetmap.josm.gui.MainApplication;
23import org.openstreetmap.josm.tools.GBC;
24import org.openstreetmap.josm.tools.JosmRuntimeException;
25import org.openstreetmap.josm.tools.Logging;
26
27/**
28 * Dialog used to manually adjust timezone and offset for GPX correlation.
29 * @since 18043 (extracted from {@link CorrelateGpxWithImages})
30 */
31public class AdjustTimezoneAndOffsetDialog extends ExtendedDialog {
32
33 private AdjustListener listener;
34
35 /**
36 * Constructs a new {@code AdjustTimezoneAndOffsetDialog}
37 * @param parent The parent element that will be used for position and maximum size
38 * @param tz initial timezone
39 * @param offset initial time offset
40 * @param dayOffset days offset
41 */
42 public AdjustTimezoneAndOffsetDialog(Component parent, GpxTimezone tz, GpxTimeOffset offset, int dayOffset) {
43 super(parent, tr("Adjust timezone and offset"), tr("Close"));
44 setContent(buildContent(tz, offset, dayOffset));
45 setButtonIcons("ok");
46 }
47
48 private Component buildContent(GpxTimezone a, GpxTimeOffset b, int dayOffset) {
49 // Info Labels
50 final JLabel lblMatches = new JLabel();
51
52 // Timezone Slider
53 // The slider allows to switch timezone from -12:00 to 12:00 in 30 minutes steps. Therefore the range is -24 to 24.
54 final JLabel lblTimezone = new JLabel();
55 final JSlider sldTimezone = new JSlider(-24, 24, 0);
56 sldTimezone.setPaintLabels(true);
57 Dictionary<Integer, JLabel> labelTable = new Hashtable<>();
58 // CHECKSTYLE.OFF: ParenPad
59 for (int i = -12; i <= 12; i += 6) {
60 labelTable.put(i * 2, new JLabel(new GpxTimezone(i).formatTimezone()));
61 }
62 // CHECKSTYLE.ON: ParenPad
63 sldTimezone.setLabelTable(labelTable);
64
65 // Minutes Slider
66 final JLabel lblMinutes = new JLabel();
67 final JSlider sldMinutes = new JSlider(-15, 15, 0);
68 sldMinutes.setPaintLabels(true);
69 sldMinutes.setMajorTickSpacing(5);
70
71 // Seconds slider
72 final JLabel lblSeconds = new JLabel();
73 final JSlider sldSeconds = new JSlider(-600, 600, 0);
74 sldSeconds.setPaintLabels(true);
75 labelTable = new Hashtable<>();
76 // CHECKSTYLE.OFF: ParenPad
77 for (int i = -60; i <= 60; i += 30) {
78 labelTable.put(i * 10, new JLabel(GpxTimeOffset.seconds(i).formatOffset()));
79 }
80 // CHECKSTYLE.ON: ParenPad
81 sldSeconds.setLabelTable(labelTable);
82 sldSeconds.setMajorTickSpacing(300);
83
84 // Put everything together
85 JPanel p = new JPanel(new GridBagLayout());
86 p.setPreferredSize(new Dimension(400, 230));
87 p.add(lblMatches, GBC.eol().fill());
88 p.add(lblTimezone, GBC.eol().fill());
89 p.add(sldTimezone, GBC.eol().fill().insets(0, 0, 0, 10));
90 p.add(lblMinutes, GBC.eol().fill());
91 p.add(sldMinutes, GBC.eol().fill().insets(0, 0, 0, 10));
92 p.add(lblSeconds, GBC.eol().fill());
93 p.add(sldSeconds, GBC.eol().fill());
94
95 // If there's an error in the calculation the found values
96 // will be off range for the sliders. Catch this error
97 // and inform the user about it.
98 try {
99 sldTimezone.setValue((int) (a.getHours() * 2));
100 sldMinutes.setValue((int) (b.getSeconds() / 60));
101 final long deciSeconds = b.getMilliseconds() / 100;
102 sldSeconds.setValue((int) (deciSeconds % 600));
103 } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException ex) {
104 Logging.warn(ex);
105 JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
106 tr("An error occurred while trying to match the photos to the GPX track."
107 +" You can adjust the sliders to manually match the photos."),
108 tr("Matching photos to track failed"),
109 JOptionPane.WARNING_MESSAGE);
110 }
111
112 // This is called whenever one of the sliders is moved.
113 // It updates the labels
114 ChangeListener sliderListener = x -> {
115 final GpxTimezone timezone = new GpxTimezone(sldTimezone.getValue() / 2.);
116 final int minutes = sldMinutes.getValue();
117 final int seconds = sldSeconds.getValue();
118
119 lblTimezone.setText(tr("Timezone: {0}", timezone.formatTimezone()));
120 lblMinutes.setText(tr("Minutes: {0}", minutes));
121 lblSeconds.setText(tr("Seconds: {0}", GpxTimeOffset.milliseconds(100L * seconds).formatOffset()));
122
123 StringBuilder sb = new StringBuilder("<html>");
124 if (listener != null) {
125 sb.append(listener.valuesChanged(timezone, minutes, seconds)).append("<br>");
126 }
127
128 lblMatches.setText(sb.append(trn("(Time difference of {0} day)", "Time difference of {0} days",
129 Math.abs(dayOffset), Math.abs(dayOffset))).append("</html>").toString());
130 };
131
132 // Call the sliderListener once manually so labels get adjusted
133 sliderListener.stateChanged(null);
134
135 // Listeners added here, otherwise it tries to match three times
136 // (when setting the default values)
137 sldTimezone.addChangeListener(sliderListener);
138 sldMinutes.addChangeListener(sliderListener);
139 sldSeconds.addChangeListener(sliderListener);
140
141 return p;
142 }
143
144 /**
145 * Listener called when the sliders are moved.
146 */
147 @FunctionalInterface
148 public interface AdjustListener {
149 /**
150 * Provides a textual description matching the new state after the change of values.
151 * @param timezone new timezone
152 * @param minutes new minutes offset
153 * @param seconds new seconds offset
154 * @return an HTML textual description matching the new state after the change of values
155 */
156 String valuesChanged(GpxTimezone timezone, int minutes, int seconds);
157 }
158
159 /**
160 * Sets the {@link AdjustListener}.
161 * @param listener adjust listener, can be null
162 * @return {@code this}
163 */
164 public final AdjustTimezoneAndOffsetDialog adjustListener(AdjustListener listener) {
165 this.listener = listener;
166 return this;
167 }
168}
Note: See TracBrowser for help on using the repository browser.