]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/function/settings/AddMapSourceDialog.java
Version 19, May 2018
[GpsPrune.git] / tim / prune / function / settings / AddMapSourceDialog.java
1 package tim.prune.function.settings;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.FlowLayout;
6 import java.awt.GridBagConstraints;
7 import java.awt.GridBagLayout;
8 import java.awt.Insets;
9 import java.awt.event.ActionEvent;
10 import java.awt.event.ActionListener;
11 import java.awt.event.KeyAdapter;
12 import java.awt.event.KeyEvent;
13
14 import javax.swing.BorderFactory;
15 import javax.swing.ButtonGroup;
16 import javax.swing.JButton;
17 import javax.swing.JComboBox;
18 import javax.swing.JDialog;
19 import javax.swing.JLabel;
20 import javax.swing.JPanel;
21 import javax.swing.JRadioButton;
22 import javax.swing.JTextField;
23
24 import tim.prune.I18nManager;
25 import tim.prune.gui.map.MapSource;
26 import tim.prune.gui.map.MapSourceLibrary;
27 import tim.prune.gui.map.OsmMapSource;
28
29 /**
30  * Class to handle the adding of a new map source
31  */
32 public class AddMapSourceDialog
33 {
34         private SetMapBgFunction _parent = null;
35         private JDialog _addDialog = null;
36         private MapSource _originalSource = null;
37         // controls for osm panel
38         private JTextField _oNameField = null;
39         private JTextField _baseUrlField = null, _topUrlField = null;
40         private JRadioButton[] _baseTypeRadios = null, _topTypeRadios = null;
41         private JComboBox<Integer> _oZoomCombo = null;
42         private JButton _okButton = null;
43
44         /** array of file types */
45         private static final String[] FILE_TYPES = {"png", "jpg", "gif"};
46
47
48         /**
49          * Constructor
50          * @param inParent parent dialog
51          */
52         public AddMapSourceDialog(JDialog inParentDialog, SetMapBgFunction inParentFunction)
53         {
54                 _parent = inParentFunction;
55                 _addDialog = new JDialog(inParentDialog, I18nManager.getText("dialog.addmapsource.title"), true);
56                 _addDialog.add(makeDialogComponents());
57                 _addDialog.setLocationRelativeTo(inParentDialog);
58                 _addDialog.pack();
59         }
60
61
62         /**
63          * Create dialog components
64          * @return Panel containing all gui elements in dialog
65          */
66         private Component makeDialogComponents()
67         {
68                 JPanel dialogPanel = new JPanel();
69                 dialogPanel.setLayout(new BorderLayout());
70                 // Top panel with spacer
71                 dialogPanel.add(new JLabel(" "), BorderLayout.NORTH);
72
73                 // listener
74                 KeyAdapter keyListener = new KeyAdapter() {
75                         public void keyReleased(KeyEvent e) {
76                                 super.keyReleased(e);
77                                 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
78                                         _addDialog.dispose();
79                                 }
80                                 else {
81                                         enableOK();
82                                 }
83                         }
84                 };
85                 // Listener for any gui changes (to enable ok when anything changes on an edit)
86                 ActionListener okEnabler = new ActionListener() {
87                         public void actionPerformed(ActionEvent arg0) {
88                                 enableOK();
89                         }
90                 };
91
92                 // openstreetmap panel
93                 JPanel osmPanel = new JPanel();
94                 osmPanel.setLayout(new BorderLayout());
95                 osmPanel.setBorder(BorderFactory.createEmptyBorder(6, 3, 4, 3));
96                 JPanel gbPanel = new JPanel();
97                 GridBagLayout gridbag = new GridBagLayout();
98                 GridBagConstraints c = new GridBagConstraints();
99                 gbPanel.setLayout(gridbag);
100                 c.gridx = 0; c.gridy = 0;
101                 c.gridheight = 1; c.gridwidth = 1;
102                 c.weightx = 0.0; c.weighty = 0.0;
103                 c.ipadx = 3; c.ipady = 5;
104                 c.insets = new Insets(0, 0, 5, 0);
105                 c.anchor = GridBagConstraints.FIRST_LINE_START;
106                 gbPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.sourcename")), c);
107                 _oNameField = new JTextField(18);
108                 _oNameField.addKeyListener(keyListener);
109                 c.gridx = 1; c.weightx = 1.0;
110                 gbPanel.add(_oNameField, c);
111                 // Base layer
112                 c.gridx = 0; c.gridy = 1;
113                 c.weightx = 0.0;
114                 c.insets = new Insets(0, 0, 0, 0);
115                 gbPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.layer1url")), c);
116                 _baseUrlField = new JTextField(18);
117                 _baseUrlField.addKeyListener(keyListener);
118                 c.gridx = 1; c.weightx = 1.0;
119                 gbPanel.add(_baseUrlField, c);
120                 _baseTypeRadios = new JRadioButton[3];
121                 ButtonGroup radioGroup = new ButtonGroup();
122                 for (int i=0; i<3; i++)
123                 {
124                         _baseTypeRadios[i] = new JRadioButton(FILE_TYPES[i]);
125                         radioGroup.add(_baseTypeRadios[i]);
126                         c.gridx = 2+i; c.weightx = 0.0;
127                         gbPanel.add(_baseTypeRadios[i], c);
128                         // Each type radio needs listener to call enableOk()
129                         _baseTypeRadios[i].addActionListener(okEnabler);
130                 }
131
132                 // Top layer
133                 c.gridx = 0; c.gridy = 2;
134                 gbPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.layer2url")), c);
135                 _topUrlField = new JTextField(18);
136                 _topUrlField.addKeyListener(keyListener);
137                 c.gridx = 1; c.weightx = 1.0;
138                 gbPanel.add(_topUrlField, c);
139                 _topTypeRadios = new JRadioButton[3];
140                 radioGroup = new ButtonGroup();
141                 for (int i=0; i<3; i++)
142                 {
143                         _topTypeRadios[i] = new JRadioButton(FILE_TYPES[i]);
144                         radioGroup.add(_topTypeRadios[i]);
145                         c.gridx = 2+i; c.weightx = 0.0;
146                         gbPanel.add(_topTypeRadios[i], c);
147                         // Each type radio needs listener to call enableOk()
148                         _topTypeRadios[i].addActionListener(okEnabler);
149                 }
150                 // Max zoom
151                 c.gridx = 0; c.gridy = 3;
152                 gbPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.maxzoom")), c);
153                 _oZoomCombo = new JComboBox<Integer>();
154                 for (int i=10; i<=20; i++) {
155                         _oZoomCombo.addItem(i);
156                 }
157                 // zoom dropdown needs listener to call enableOk()
158                 _oZoomCombo.addActionListener(okEnabler);
159                 c.gridx = 1;
160                 gbPanel.add(_oZoomCombo, c);
161                 osmPanel.add(gbPanel, BorderLayout.NORTH);
162
163                 // cards
164                 JPanel holderPanel = new JPanel();
165                 holderPanel.setLayout(new BorderLayout());
166                 holderPanel.add(osmPanel, BorderLayout.NORTH);
167                 dialogPanel.add(holderPanel, BorderLayout.CENTER);
168
169                 // button panel at bottom
170                 JPanel buttonPanel = new JPanel();
171                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
172                 _okButton = new JButton(I18nManager.getText("button.ok"));
173                 ActionListener okListener = new ActionListener() {
174                         public void actionPerformed(ActionEvent e)
175                         {
176                                 finish();
177                         }
178                 };
179                 _okButton.addActionListener(okListener);
180                 buttonPanel.add(_okButton);
181                 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
182                 cancelButton.addActionListener(new ActionListener() {
183                         public void actionPerformed(ActionEvent e)
184                         {
185                                 _addDialog.dispose();
186                         }
187                 });
188                 buttonPanel.add(cancelButton);
189                 dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
190                 return dialogPanel;
191         }
192
193
194         /**
195          * Init and show the dialog
196          * @param inSource source object before edit, or null to add
197          */
198         public void showDialog(MapSource inSource)
199         {
200                 _originalSource = inSource;
201                 populateFields();
202         }
203
204         /**
205          * Clear all the dialog fields to prepare for an add
206          */
207         private void clearAllFields()
208         {
209                 _oNameField.setText("");
210                 _baseUrlField.setText("");
211                 _baseTypeRadios[0].setSelected(true);
212                 _topUrlField.setText("");
213                 _topTypeRadios[0].setSelected(true);
214                 _oZoomCombo.setSelectedIndex(8);
215                 _okButton.setEnabled(false);
216                 _addDialog.setVisible(true);
217         }
218
219         /**
220          * Init the dialog fields from the given source object
221          */
222         private void populateFields()
223         {
224                 if (_originalSource == null)
225                 {
226                         clearAllFields();
227                         return;
228                 }
229
230                 // See if it's an osm source
231                 try
232                 {
233                         OsmMapSource osmSource = (OsmMapSource) _originalSource;
234                         _oNameField.setText(osmSource.getName());
235                         _baseUrlField.setText(osmSource.getBaseUrl(0));
236                         int baseType = getBaseType(osmSource.getFileExtension(0));
237                         _baseTypeRadios[baseType].setSelected(true);
238                         _topUrlField.setText(osmSource.getNumLayers()==0?"":osmSource.getBaseUrl(1));
239                         int topType = getBaseType(osmSource.getFileExtension(1));
240                         _topTypeRadios[topType].setSelected(true);
241                         _oZoomCombo.setSelectedIndex(getZoomIndex(osmSource.getMaxZoomLevel()));
242                 }
243                 catch (ClassCastException cce) {} // ignore, sourceFound flag stays false
244
245                 _okButton.setEnabled(false);
246                 _addDialog.setVisible(true);
247         }
248
249         /**
250          * Check the currently entered details and enable the OK button if it looks OK
251          */
252         private void enableOK()
253         {
254                 _okButton.setEnabled(isOsmPanelOk());
255         }
256
257         /**
258          * Check the openstreetmap panel if all details are complete
259          * @return true if details look ok
260          */
261         private boolean isOsmPanelOk()
262         {
263                 boolean ok = _oNameField.getText().trim().length() > 1;
264                 String baseUrl = null, topUrl = null;
265                 // Try to parse base url if given
266                 String baseText = _baseUrlField.getText().trim();
267                 baseUrl = MapSource.fixBaseUrl(baseText);
268                 if (baseText.length() > 0 && baseUrl == null) {ok = false;}
269                 // Same again for top url if given
270                 String topText = _topUrlField.getText().trim();
271                 topUrl = MapSource.fixBaseUrl(topText);
272                 if (topText.length() > 0 && topUrl == null) {ok = false;}
273                 // looks ok if at least one url given
274                 return (ok && (baseUrl != null || topUrl != null));
275         }
276
277         /**
278          * Finish by adding the requested source and refreshing the parent
279          */
280         private void finish()
281         {
282                 MapSource newSource = null;
283                 String origName = (_originalSource == null ? null : _originalSource.getName());
284
285                 if (isOsmPanelOk())
286                 {
287                         // Openstreetmap source
288                         String sourceName = getValidSourcename(_oNameField.getText(), origName);
289                         String url1 = _baseUrlField.getText().trim();
290                         String ext1 = getFileExtension(_baseTypeRadios);
291                         String url2 = _topUrlField.getText().trim();
292                         String ext2 = getFileExtension(_topTypeRadios);
293                         newSource = new OsmMapSource(sourceName, url1, ext1, url2, ext2, _oZoomCombo.getSelectedIndex()+10);
294                 }
295
296                 // Add new source if ok
297                 if (newSource != null)
298                 {
299                         if (_originalSource == null) {
300                                 MapSourceLibrary.addSource(newSource);
301                         }
302                         else {
303                                 MapSourceLibrary.editSource(_originalSource, newSource);
304                         }
305                         // inform setmapbg dialog
306                         _parent.updateList();
307                         _addDialog.setVisible(false);
308                 }
309         }
310
311         /**
312          * Check the given source name is valid and whether it exists in library already
313          * @param inName name to check
314          * @param inOriginalName name of source before edit (or null for new source)
315          * @return valid name for the new source
316          */
317         private static String getValidSourcename(String inName, String inOriginalName)
318         {
319                 String name = inName;
320                 if (name == null) {name = "";}
321                 else {name = name.trim();}
322                 if (name.equals("")) {
323                         name = I18nManager.getText("dialog.addmapsource.noname");
324                 }
325                 // Check there isn't already a map source with this name
326                 if (inOriginalName == null || !inOriginalName.equals(name))
327                 {
328                         if (MapSourceLibrary.hasSourceName(name))
329                         {
330                                 int suffix = 1;
331                                 while (MapSourceLibrary.hasSourceName(name + suffix)) {
332                                         suffix++;
333                                 }
334                                 name += suffix;
335                         }
336                 }
337                 return name;
338         }
339
340         /**
341          * Get the selected file extension
342          * @param inRadios array of radio buttons for selection
343          * @return selected file extension
344          */
345         private String getFileExtension(JRadioButton[] inRadios)
346         {
347                 if (inRadios != null)
348                 {
349                         for (int i=0; i<inRadios.length; i++) {
350                                 if (inRadios[i] != null && inRadios[i].isSelected()) {
351                                         return FILE_TYPES[i];
352                                 }
353                         }
354                 }
355                 return FILE_TYPES[0];
356         }
357
358         /**
359          * Get the index of the given image extension
360          * @param inExt file extension, such as "png"
361          * @return index from 0 to 2
362          */
363         private static int getBaseType(String inExt)
364         {
365                 for (int i=0; i<FILE_TYPES.length; i++) {
366                         if (FILE_TYPES[i].equals(inExt)) {
367                                 return i;
368                         }
369                 }
370                 // Not found so default to png
371                 return 0;
372         }
373
374         /**
375          * Get the dropdown index of the given zoom level
376          * @param inZoomLevel zoom level, eg 18
377          * @return index of dropdown to select
378          */
379         private static int getZoomIndex(int inZoomLevel)
380         {
381                 return Math.max(0, inZoomLevel - 10);
382         }
383 }