1 package org.simantics.maps.server.ui.prefs;
3 import java.io.IOException;
4 import java.net.URISyntaxException;
5 import java.nio.file.Files;
6 import java.nio.file.Path;
7 import java.nio.file.Paths;
10 import org.eclipse.core.runtime.preferences.InstanceScope;
11 import org.eclipse.jface.layout.GridDataFactory;
12 import org.eclipse.jface.layout.GridLayoutFactory;
13 import org.eclipse.jface.preference.BooleanFieldEditor;
14 import org.eclipse.jface.preference.ComboFieldEditor;
15 import org.eclipse.jface.preference.FieldEditorPreferencePage;
16 import org.eclipse.jface.preference.FileFieldEditor;
17 import org.eclipse.jface.preference.IPreferenceStore;
18 import org.eclipse.jface.preference.IntegerFieldEditor;
19 import org.eclipse.jface.preference.StringFieldEditor;
20 import org.eclipse.jface.util.IPropertyChangeListener;
21 import org.eclipse.jface.util.PropertyChangeEvent;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.events.SelectionAdapter;
24 import org.eclipse.swt.events.SelectionEvent;
25 import org.eclipse.swt.widgets.Button;
26 import org.eclipse.swt.widgets.Composite;
27 import org.eclipse.swt.widgets.Group;
28 import org.eclipse.swt.widgets.Label;
29 import org.eclipse.ui.IWorkbench;
30 import org.eclipse.ui.IWorkbenchPreferencePage;
31 import org.eclipse.ui.preferences.ScopedPreferenceStore;
32 import org.simantics.district.maps.server.TileserverMapnik;
33 import org.simantics.district.maps.server.TileserverMapnikInstance;
34 import org.simantics.district.maps.server.prefs.MapsServerPreferences;
35 import org.simantics.district.network.ui.DynamicComboFieldEditor;
36 import org.simantics.maps.server.ui.TileserverMapnikStartJob;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 public class MapsServerPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
42 private static final Logger LOGGER = LoggerFactory.getLogger(MapsServerPreferencePage.class);
44 private TileserverMapnik server;
46 private FileFieldEditor addNew;
48 private DynamicComboFieldEditor currentTilesSelector;
50 public MapsServerPreferencePage() {
52 setDescription("Maps server preferences");
56 public void init(IWorkbench workbench) {
58 server = TileserverMapnikInstance.get();
59 } catch (IOException | URISyntaxException e) {
60 LOGGER.error("Could not initialize " + getClass(), e);
65 protected IPreferenceStore doGetPreferenceStore() {
66 return new ScopedPreferenceStore(InstanceScope.INSTANCE, MapsServerPreferences.P_NODE);
69 private void createServerStatusField(Composite parent) {
70 Label label = new Label(parent, SWT.NONE);
71 GridDataFactory.fillDefaults().grab(true, false).applyTo(label);
73 Button b = new Button(parent, SWT.NONE);
74 GridDataFactory.fillDefaults().grab(true, false).applyTo(b);
75 updateWidgets(label, b);
76 b.addSelectionListener(new SelectionAdapter() {
79 public void widgetSelected(SelectionEvent e) {
81 if (server.isRunning()) {
83 updateWidgets(label, b);
85 new TileserverMapnikStartJob(status -> {
86 parent.getDisplay().asyncExec(() -> {
87 updateWidgets(label, b);
91 } catch (Exception ex) {
92 LOGGER.error("Could not start/stop server", ex);
98 private void updateWidgets(Label label, Button b) {
99 String labelText = "";
100 String buttonText = "";
103 if (server.isRunning()) {
105 labelText = "running";
106 labelColor = SWT.COLOR_DARK_GREEN;
108 labelText = "stopped";
109 buttonText = "Start";
111 } catch (IOException | InterruptedException e) {
112 LOGGER.error("Could not create server status field!", e);
113 labelText = "unknown";
114 labelColor = SWT.COLOR_DARK_RED;
116 label.setText("Tileserver is currently " + labelText);
117 label.setForeground(getShell().getDisplay().getSystemColor(labelColor));
119 b.setText(buttonText + " server");
122 private void createGeneralGroup() {
123 Group serverGroup = new Group(getFieldEditorParent(), SWT.NONE);
124 serverGroup.setText("General");
125 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(serverGroup);
127 createServerStatusField(serverGroup);
129 IntegerFieldEditor port = new IntegerFieldEditor(MapsServerPreferences.P_DEFAULT_PORT, "Tileserver port", serverGroup);
132 BooleanFieldEditor automatically = new BooleanFieldEditor(MapsServerPreferences.P_START_AUTOMATICALLY, "Start tileserver automatically", serverGroup);
133 addField(automatically);
135 StringFieldEditor serverFolder = new StringFieldEditor(MapsServerPreferences.P_SERVER_FOLDER, "Server folder", serverGroup);
136 serverFolder.setEnabled(false, serverGroup);
137 addField(serverFolder);
139 GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).extendedMargins(12, 12, 12, 12).spacing(5, 4).applyTo(serverGroup);
143 protected void createFieldEditors() {
144 createGeneralGroup();
151 private void createStylesGroup() {
152 Group stylesGroup = new Group(getFieldEditorParent(), SWT.NONE);
153 stylesGroup.setText("Styles");
154 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(stylesGroup);
156 createTM2StylesField(stylesGroup);
158 GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).extendedMargins(12, 12, 12, 12).spacing(5, 4).applyTo(stylesGroup);
161 private void createTM2StylesField(Composite parent) {
163 List<String> styles = server.listStyles();
165 String[][] namesAndValues = new String[styles.size()][];
166 for (int i = 0; i < styles.size(); i++) {
167 String style = styles.get(i);
168 String[] nameAndValue = new String[2];
169 nameAndValue[0] = style;
170 nameAndValue[1] = style;
171 namesAndValues[i] = nameAndValue;
174 ComboFieldEditor selector = new ComboFieldEditor(MapsServerPreferences.P_CURRENT_TM2STYLE, "Selected Style", namesAndValues, parent);
175 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(selector.getLabelControl(parent));
177 } catch (IOException e) {
182 private void createTilesGroup() {
183 Group tilesGroup = new Group(getFieldEditorParent(), SWT.NONE);
184 tilesGroup.setText("Vector Tiles");
185 GridDataFactory.fillDefaults().grab(true, false).applyTo(tilesGroup);
186 createTilesField(tilesGroup);
188 GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).extendedMargins(12, 12, 12, 12).spacing(5, 4).applyTo(tilesGroup);
191 private void createTilesField(Composite parent) {
194 String[][] namesAndValues = computeNamesAndValues();
195 currentTilesSelector = new DynamicComboFieldEditor(MapsServerPreferences.P_CURRENT_MBTILES, "Current Tiles", namesAndValues, parent);
197 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(currentTilesSelector.getLabelControl(parent));
198 addField(currentTilesSelector);
200 Composite newParent = new Composite(parent, SWT.NONE);
201 GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(newParent);
202 GridLayoutFactory.fillDefaults().numColumns(3).applyTo(newParent);
204 addNew = new FileFieldEditor("Add new tiles", "Add new tiles", newParent);
205 //GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(addNew.getTextControl(newParent));
207 addNew.setPropertyChangeListener(new IPropertyChangeListener() {
210 public void propertyChange(PropertyChangeEvent event) {
211 System.out.println(event);
215 } catch (IOException e) {
216 LOGGER.error("Could not create tiles field", e);
220 private String[][] computeNamesAndValues() throws IOException {
221 List<String> tiles = server.availableMBTiles();
222 String[][] namesAndValues = new String[tiles.size()][];
223 for (int i = 0; i < tiles.size(); i++) {
224 String style = tiles.get(i);
225 String[] nameAndValue = new String[2];
226 nameAndValue[0] = style;
227 nameAndValue[1] = style;
228 namesAndValues[i] = nameAndValue;
230 return namesAndValues;
234 protected void performApply() {
235 // Upload new mbtiles file
236 String fileLocation = addNew.getStringValue();
237 if (fileLocation != null && !fileLocation.isEmpty()) {
238 Path p = Paths.get(fileLocation);
239 Path target = server.getDataDirectory().resolve(p.getFileName());
241 Files.copy(p, target);
242 addNew.setStringValue("");
243 } catch (IOException e) {
244 String message = "Could not upload " + fileLocation + " to " + target.toAbsolutePath();
245 LOGGER.error(message, e);
246 setErrorMessage(message);
250 currentTilesSelector.updateCombo(computeNamesAndValues());
251 currentTilesSelector.load();
252 } catch (IOException e) {
255 super.performApply();
259 public boolean performOk() {
260 boolean success = super.performOk();
264 new TileserverMapnikStartJob(status -> {}).schedule();
265 } catch (Exception e) {
266 LOGGER.error("Could not restart tileserver-mapnik", e);