1 | package iodb;
|
---|
2 |
|
---|
3 | import java.awt.*;
|
---|
4 | import java.awt.event.ActionEvent;
|
---|
5 | import java.awt.event.ActionListener;
|
---|
6 | import java.awt.event.KeyEvent;
|
---|
7 | import java.util.*;
|
---|
8 | import java.util.List;
|
---|
9 | import javax.swing.*;
|
---|
10 | import javax.swing.border.CompoundBorder;
|
---|
11 | import javax.swing.border.EmptyBorder;
|
---|
12 | import org.openstreetmap.josm.Main;
|
---|
13 | import org.openstreetmap.josm.gui.JosmUserIdentityManager;
|
---|
14 | import org.openstreetmap.josm.gui.NavigatableComponent;
|
---|
15 | import org.openstreetmap.josm.gui.layer.ImageryLayer;
|
---|
16 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
17 | import org.openstreetmap.josm.tools.ImageProvider;
|
---|
18 | import org.openstreetmap.josm.tools.OpenBrowser;
|
---|
19 |
|
---|
20 | /**
|
---|
21 | * The dialog which presents a choice between imagery align options.
|
---|
22 | *
|
---|
23 | * @author zverik
|
---|
24 | */
|
---|
25 | public class OffsetDialog extends JDialog implements ActionListener, NavigatableComponent.ZoomChangeListener {
|
---|
26 | protected static final String PREF_CALIBRATION = "iodb.show.calibration";
|
---|
27 | protected static final String PREF_DEPRECATED = "iodb.show.deprecated";
|
---|
28 | private static final int MAX_OFFSETS = Main.main.pref.getInteger("iodb.max.offsets", 5);
|
---|
29 | private static final boolean MODAL = false; // modal does not work for executing actions
|
---|
30 |
|
---|
31 | private List<ImageryOffsetBase> offsets;
|
---|
32 | private ImageryOffsetBase selectedOffset;
|
---|
33 | private JPanel buttonPanel;
|
---|
34 |
|
---|
35 | public OffsetDialog( List<ImageryOffsetBase> offsets ) {
|
---|
36 | super(JOptionPane.getFrameForComponent(Main.parent), ImageryOffsetTools.DIALOG_TITLE,
|
---|
37 | MODAL ? ModalityType.DOCUMENT_MODAL : ModalityType.MODELESS);
|
---|
38 | setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
---|
39 | setResizable(false);
|
---|
40 | this.offsets = offsets;
|
---|
41 | NavigatableComponent.addZoomChangeListener(this);
|
---|
42 |
|
---|
43 | // make this dialog close on "escape"
|
---|
44 | getRootPane().registerKeyboardAction(this,
|
---|
45 | KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
|
---|
46 | JComponent.WHEN_IN_FOCUSED_WINDOW);
|
---|
47 | }
|
---|
48 |
|
---|
49 | private void prepareDialog() {
|
---|
50 | updateButtonPanel();
|
---|
51 | final JCheckBox calibrationBox = new JCheckBox(tr("Calibration geometries"));
|
---|
52 | calibrationBox.setSelected(Main.pref.getBoolean(PREF_CALIBRATION, true));
|
---|
53 | calibrationBox.addActionListener(new ActionListener() {
|
---|
54 | public void actionPerformed( ActionEvent e ) {
|
---|
55 | Main.pref.put(PREF_CALIBRATION, calibrationBox.isSelected());
|
---|
56 | updateButtonPanel();
|
---|
57 | }
|
---|
58 | });
|
---|
59 | final JCheckBox deprecatedBox = new JCheckBox(tr("Deprecated offsets"));
|
---|
60 | deprecatedBox.setSelected(Main.pref.getBoolean(PREF_DEPRECATED, false));
|
---|
61 | deprecatedBox.addActionListener(new ActionListener() {
|
---|
62 | public void actionPerformed( ActionEvent e ) {
|
---|
63 | Main.pref.put(PREF_DEPRECATED, deprecatedBox.isSelected());
|
---|
64 | updateButtonPanel();
|
---|
65 | }
|
---|
66 | });
|
---|
67 | Box checkBoxPanel = new Box(BoxLayout.X_AXIS);
|
---|
68 | checkBoxPanel.add(calibrationBox);
|
---|
69 | checkBoxPanel.add(deprecatedBox);
|
---|
70 | JButton cancelButton = new JButton(tr("Cancel"), ImageProvider.get("cancel"));
|
---|
71 | cancelButton.addActionListener(this);
|
---|
72 | JButton helpButton = new JButton(new HelpAction());
|
---|
73 | JPanel cancelPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
|
---|
74 | cancelPanel.add(cancelButton);
|
---|
75 | cancelPanel.add(helpButton);
|
---|
76 |
|
---|
77 | Box dialog = new Box(BoxLayout.Y_AXIS);
|
---|
78 | dialog.add(buttonPanel);
|
---|
79 | dialog.add(checkBoxPanel);
|
---|
80 | dialog.add(cancelPanel);
|
---|
81 |
|
---|
82 | dialog.setBorder(new CompoundBorder(dialog.getBorder(), new EmptyBorder(5, 5, 5, 5)));
|
---|
83 | setContentPane(dialog);
|
---|
84 | pack();
|
---|
85 | setLocationRelativeTo(Main.parent);
|
---|
86 | }
|
---|
87 |
|
---|
88 | private void updateButtonPanel() {
|
---|
89 | List<ImageryOffsetBase> filteredOffsets = filterOffsets();
|
---|
90 | if( buttonPanel == null )
|
---|
91 | buttonPanel = new JPanel();
|
---|
92 | buttonPanel.removeAll();
|
---|
93 | buttonPanel.setLayout(new GridLayout(filteredOffsets.size(), 1, 0, 5));
|
---|
94 | for( ImageryOffsetBase offset : filteredOffsets ) {
|
---|
95 | OffsetDialogButton button = new OffsetDialogButton(offset);
|
---|
96 | button.addActionListener(this);
|
---|
97 | JPopupMenu popupMenu = new JPopupMenu();
|
---|
98 | popupMenu.add(new OffsetInfoAction(offset));
|
---|
99 | if( !offset.isDeprecated() ) {
|
---|
100 | DeprecateOffsetAction action = new DeprecateOffsetAction(offset);
|
---|
101 | action.setListener(new DeprecateOffsetListener(offset));
|
---|
102 | popupMenu.add(action);
|
---|
103 | }
|
---|
104 | button.setComponentPopupMenu(popupMenu);
|
---|
105 | buttonPanel.add(button);
|
---|
106 | }
|
---|
107 | pack();
|
---|
108 | }
|
---|
109 |
|
---|
110 | private List<ImageryOffsetBase> filterOffsets() {
|
---|
111 | boolean showCalibration = Main.pref.getBoolean(PREF_CALIBRATION, true);
|
---|
112 | boolean showDeprecated = Main.pref.getBoolean(PREF_DEPRECATED, false);
|
---|
113 | List<ImageryOffsetBase> filteredOffsets = new ArrayList<ImageryOffsetBase>();
|
---|
114 | for( ImageryOffsetBase offset : offsets ) {
|
---|
115 | if( offset.isDeprecated() && !showDeprecated )
|
---|
116 | continue;
|
---|
117 | if( offset instanceof CalibrationObject && !showCalibration )
|
---|
118 | continue;
|
---|
119 | filteredOffsets.add(offset);
|
---|
120 | if( filteredOffsets.size() >= MAX_OFFSETS )
|
---|
121 | break;
|
---|
122 | }
|
---|
123 | return filteredOffsets;
|
---|
124 | }
|
---|
125 |
|
---|
126 | public void zoomChanged() {
|
---|
127 | for( Component c : buttonPanel.getComponents() ) {
|
---|
128 | if( c instanceof OffsetDialogButton ) {
|
---|
129 | ((OffsetDialogButton)c).updateLocation();
|
---|
130 | }
|
---|
131 | }
|
---|
132 | }
|
---|
133 |
|
---|
134 | public ImageryOffsetBase showDialog() {
|
---|
135 | selectedOffset = null;
|
---|
136 | prepareDialog();
|
---|
137 | setVisible(true);
|
---|
138 | return selectedOffset;
|
---|
139 | }
|
---|
140 |
|
---|
141 | public void applyOffset() {
|
---|
142 | if( selectedOffset instanceof ImageryOffset ) {
|
---|
143 | ImageryLayer layer = ImageryOffsetTools.getTopImageryLayer();
|
---|
144 | ImageryOffsetTools.applyLayerOffset(layer, (ImageryOffset)selectedOffset);
|
---|
145 | Main.map.repaint();
|
---|
146 | if( !Main.pref.getBoolean("iodb.offset.message", false) ) {
|
---|
147 | JOptionPane.showMessageDialog(Main.parent,
|
---|
148 | tr("The topmost imagery layer has been shifted to presumably match\n"
|
---|
149 | + "OSM data in the area. Please check that the offset is still valid\n"
|
---|
150 | + "by downloading GPS tracks and comparing them and OSM data to the imagery."),
|
---|
151 | ImageryOffsetTools.DIALOG_TITLE, JOptionPane.INFORMATION_MESSAGE);
|
---|
152 | Main.pref.put("iodb.offset.message", true);
|
---|
153 | }
|
---|
154 | } else if( selectedOffset instanceof CalibrationObject ) {
|
---|
155 | CalibrationLayer clayer = new CalibrationLayer((CalibrationObject)selectedOffset);
|
---|
156 | Main.map.mapView.addLayer(clayer);
|
---|
157 | clayer.panToCenter();
|
---|
158 | if( !Main.pref.getBoolean("iodb.calibration.message", false) ) {
|
---|
159 | JOptionPane.showMessageDialog(Main.parent,
|
---|
160 | tr("A layer has been added with a calibration geometry. Hide data layers,\n"
|
---|
161 | + "find the corresponding feature on the imagery layer and move it accordingly."),
|
---|
162 | ImageryOffsetTools.DIALOG_TITLE, JOptionPane.INFORMATION_MESSAGE);
|
---|
163 | Main.pref.put("iodb.calibration.message", true);
|
---|
164 | }
|
---|
165 | }
|
---|
166 | }
|
---|
167 |
|
---|
168 | public void actionPerformed( ActionEvent e ) {
|
---|
169 | if( e.getSource() instanceof OffsetDialogButton ) {
|
---|
170 | selectedOffset = ((OffsetDialogButton)e.getSource()).getOffset();
|
---|
171 | } else
|
---|
172 | selectedOffset = null;
|
---|
173 | NavigatableComponent.removeZoomChangeListener(this);
|
---|
174 | setVisible(false);
|
---|
175 | if( !MODAL && selectedOffset != null )
|
---|
176 | applyOffset();
|
---|
177 | }
|
---|
178 |
|
---|
179 | private class DeprecateOffsetListener implements QuerySuccessListener {
|
---|
180 | ImageryOffsetBase offset;
|
---|
181 |
|
---|
182 | public DeprecateOffsetListener( ImageryOffsetBase offset ) {
|
---|
183 | this.offset = offset;
|
---|
184 | }
|
---|
185 |
|
---|
186 | public void queryPassed() {
|
---|
187 | offset.setDeprecated(new Date(), JosmUserIdentityManager.getInstance().getUserName(), "");
|
---|
188 | updateButtonPanel();
|
---|
189 | }
|
---|
190 | }
|
---|
191 |
|
---|
192 | class HelpAction extends AbstractAction {
|
---|
193 |
|
---|
194 | public HelpAction() {
|
---|
195 | super(tr("Help"));
|
---|
196 | putValue(SMALL_ICON, ImageProvider.get("help"));
|
---|
197 | }
|
---|
198 |
|
---|
199 | public void actionPerformed( ActionEvent e ) {
|
---|
200 | String base = "http://wiki.openstreetmap.org/wiki/";
|
---|
201 | String page = "Imagery_Offset_Database";
|
---|
202 | String lang = "RU:"; // todo: determine it
|
---|
203 | OpenBrowser.displayUrl(base + lang + page);
|
---|
204 | }
|
---|
205 | }
|
---|
206 | }
|
---|