Merge "Omaha #4354: Support GeoJSON Feature objects in damage path tool." into omaha_16.1.1
Former-commit-id: 76a49d774debae6e378fa70485ac3d3568d637f7
This commit is contained in:
commit
6d9456783c
10 changed files with 686 additions and 38 deletions
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Damage Path
|
||||
Bundle-SymbolicName: com.raytheon.uf.viz.damagepath;singleton:=true
|
||||
Bundle-Version: 1.15.1.qualifier
|
||||
Bundle-Version: 1.15.2.qualifier
|
||||
Bundle-Vendor: RAYTHEON
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
Require-Bundle: com.raytheon.uf.viz.core;bundle-version="1.14.6",
|
||||
|
@ -14,5 +14,6 @@ Require-Bundle: com.raytheon.uf.viz.core;bundle-version="1.14.6",
|
|||
com.raytheon.viz.ui;bundle-version="1.14.1",
|
||||
com.raytheon.viz.awipstools;bundle-version="1.14.0",
|
||||
com.raytheon.viz.radar;bundle-version="1.14.0",
|
||||
javax.measure;bundle-version="1.0.0"
|
||||
javax.measure;bundle-version="1.0.0",
|
||||
com.raytheon.uf.common.util;bundle-version="1.14.1"
|
||||
Export-Package: com.raytheon.uf.viz.damagepath
|
||||
|
|
|
@ -3,23 +3,29 @@
|
|||
<plugin>
|
||||
<extension
|
||||
point="com.raytheon.viz.ui.contextualMenu">
|
||||
<contextualMenu
|
||||
actionClass="com.raytheon.uf.viz.damagepath.OpenGeoJsonPropertiesDlgAction"
|
||||
capabilityClass="com.raytheon.uf.viz.damagepath.DamagePathLayer"
|
||||
name="Set GeoJSON Properties"
|
||||
sortID="3">
|
||||
</contextualMenu>
|
||||
<contextualMenu
|
||||
actionClass="com.raytheon.uf.viz.damagepath.ExportDamagePathAction"
|
||||
capabilityClass="com.raytheon.uf.viz.damagepath.DamagePathLayer"
|
||||
name="Export GeoJSON"
|
||||
sortID="3">
|
||||
sortID="4">
|
||||
</contextualMenu>
|
||||
<contextualMenu
|
||||
actionClass="com.raytheon.uf.viz.damagepath.ImportDamagePathAction"
|
||||
capabilityClass="com.raytheon.uf.viz.damagepath.DamagePathLayer"
|
||||
name="Import GeoJSON"
|
||||
sortID="4">
|
||||
sortID="5">
|
||||
</contextualMenu>
|
||||
<contextualMenu
|
||||
actionClass="com.raytheon.uf.viz.damagepath.ImportFromDistanceSpeedAction"
|
||||
capabilityClass="com.raytheon.uf.viz.damagepath.DamagePathLayer"
|
||||
name="Import from Distance Speed Tool"
|
||||
sortID="5">
|
||||
sortID="6">
|
||||
</contextualMenu>
|
||||
</extension>
|
||||
</plugin>
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
package com.raytheon.uf.viz.damagepath;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.ModifyEvent;
|
||||
import org.eclipse.swt.events.ModifyListener;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Layout;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
import com.raytheon.uf.common.util.Pair;
|
||||
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
|
||||
|
||||
/**
|
||||
* Dialog to add new property key/value pairs for the
|
||||
* {@code EditGeoJsonPropertiesDlg}.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Apr 23, 2015 #4354 dgilling Initial creation based on dialog from
|
||||
* lvenable.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author lvenable
|
||||
* @version 1.0
|
||||
*/
|
||||
public class AddKeyValueDlg extends CaveSWTDialog {
|
||||
|
||||
private static final String EMPTY_STRING = "";
|
||||
|
||||
private static final String EMPTY_KEY_MSG = "Enter a key.";
|
||||
|
||||
private static final String USED_KEY_MSG = "Key %s is already in use.";
|
||||
|
||||
private Text keyTF;
|
||||
|
||||
private Text valueTF;
|
||||
|
||||
private Button okBtn;
|
||||
|
||||
private Label verificationLbl;
|
||||
|
||||
private final Collection<String> reservedKeys;
|
||||
|
||||
public AddKeyValueDlg(Shell parentShell, Collection<String> reservedKeys) {
|
||||
super(parentShell, SWT.DIALOG_TRIM, CAVE.DO_NOT_BLOCK
|
||||
| CAVE.MODE_INDEPENDENT);
|
||||
this.reservedKeys = reservedKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Layout constructShellLayout() {
|
||||
GridLayout mainLayout = new GridLayout(1, false);
|
||||
return mainLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object constructShellLayoutData() {
|
||||
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||
return gd;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeComponents(Shell shell) {
|
||||
setText("Add GeoJSON Property");
|
||||
|
||||
createKeyValueControls();
|
||||
createBottomButtons();
|
||||
}
|
||||
|
||||
private void createKeyValueControls() {
|
||||
Composite keyValueComp = new Composite(shell, SWT.NONE);
|
||||
keyValueComp.setLayout(new GridLayout(2, false));
|
||||
keyValueComp.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true,
|
||||
false));
|
||||
|
||||
Label keyLbl = new Label(keyValueComp, SWT.NONE);
|
||||
keyLbl.setText("Key:");
|
||||
|
||||
GridData gd = new GridData(130, SWT.DEFAULT);
|
||||
keyTF = new Text(keyValueComp, SWT.BORDER);
|
||||
keyTF.setLayoutData(gd);
|
||||
keyTF.addModifyListener(new ModifyListener() {
|
||||
|
||||
@Override
|
||||
public void modifyText(ModifyEvent e) {
|
||||
String newKey = keyTF.getText().trim();
|
||||
if (reservedKeys.contains(newKey)) {
|
||||
verificationLbl.setText(String.format(USED_KEY_MSG, newKey));
|
||||
okBtn.setEnabled(false);
|
||||
} else if (newKey.isEmpty()) {
|
||||
verificationLbl.setText(EMPTY_KEY_MSG);
|
||||
okBtn.setEnabled(false);
|
||||
} else {
|
||||
verificationLbl.setText(EMPTY_STRING);
|
||||
okBtn.setEnabled(true);
|
||||
}
|
||||
|
||||
getShell().pack();
|
||||
getShell().layout();
|
||||
}
|
||||
});
|
||||
|
||||
Label valueLbl = new Label(keyValueComp, SWT.NONE);
|
||||
valueLbl.setText("Value:");
|
||||
|
||||
gd = new GridData(130, SWT.DEFAULT);
|
||||
valueTF = new Text(keyValueComp, SWT.BORDER);
|
||||
valueTF.setLayoutData(gd);
|
||||
|
||||
verificationLbl = new Label(keyValueComp, SWT.NONE);
|
||||
verificationLbl.setText(EMPTY_KEY_MSG);
|
||||
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, true);
|
||||
gd.horizontalSpan = 2;
|
||||
verificationLbl.setLayoutData(gd);
|
||||
|
||||
}
|
||||
|
||||
private void createBottomButtons() {
|
||||
Composite buttonComp = new Composite(shell, SWT.NONE);
|
||||
buttonComp.setLayout(new GridLayout(2, false));
|
||||
buttonComp.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true,
|
||||
false));
|
||||
|
||||
int buttonWidth = 70;
|
||||
|
||||
GridData gd = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false);
|
||||
gd.widthHint = buttonWidth;
|
||||
okBtn = new Button(buttonComp, SWT.PUSH);
|
||||
okBtn.setText(" OK ");
|
||||
okBtn.setLayoutData(gd);
|
||||
okBtn.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
handleOkAction();
|
||||
}
|
||||
});
|
||||
okBtn.setEnabled(false);
|
||||
|
||||
gd = new GridData(SWT.LEFT, SWT.DEFAULT, true, false);
|
||||
gd.widthHint = buttonWidth;
|
||||
Button cancelBtn = new Button(buttonComp, SWT.PUSH);
|
||||
cancelBtn.setText(" Cancel ");
|
||||
cancelBtn.setLayoutData(gd);
|
||||
cancelBtn.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
setReturnValue(null);
|
||||
close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleOkAction() {
|
||||
Pair<String, String> pair = new Pair<>(keyTF.getText().trim(), valueTF
|
||||
.getText().trim());
|
||||
setReturnValue(pair);
|
||||
close();
|
||||
}
|
||||
}
|
|
@ -22,14 +22,31 @@ package com.raytheon.uf.viz.damagepath;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
import org.geotools.feature.simple.SimpleFeatureBuilder;
|
||||
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
|
||||
import org.opengis.feature.Property;
|
||||
import org.opengis.feature.simple.SimpleFeature;
|
||||
import org.opengis.feature.simple.SimpleFeatureType;
|
||||
import org.opengis.feature.type.Name;
|
||||
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonUtil;
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonUtilSimpleImpl;
|
||||
import com.raytheon.uf.common.json.JsonException;
|
||||
import com.raytheon.uf.common.json.geo.BasicJsonService;
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonMapUtil;
|
||||
import com.raytheon.uf.common.json.geo.IGeoJsonService;
|
||||
import com.raytheon.uf.common.json.geo.SimpleGeoJsonService;
|
||||
import com.raytheon.uf.common.localization.FileUpdatedMessage;
|
||||
import com.raytheon.uf.common.localization.ILocalizationFileObserver;
|
||||
import com.raytheon.uf.common.localization.IPathManager;
|
||||
|
@ -45,23 +62,25 @@ import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
|||
import com.raytheon.uf.viz.drawing.polygon.PolygonLayer;
|
||||
import com.raytheon.uf.viz.drawing.polygon.PolygonUtil;
|
||||
import com.vividsolutions.jts.geom.Coordinate;
|
||||
import com.vividsolutions.jts.geom.Geometry;
|
||||
import com.vividsolutions.jts.geom.Polygon;
|
||||
|
||||
/**
|
||||
* A layer for displaying and customizing a weather event's damage path.
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Jan 19, 2015 3974 njensen Initial creation
|
||||
* Mar 31, 2015 3977 nabowle Reset polygon when initializing from the
|
||||
* localization file fails.
|
||||
*
|
||||
* Apr 23, 2015 4354 dgilling Support GeoJSON Feature properties.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
@ -77,6 +96,8 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
|
|||
|
||||
private static final String PATH = DIR + IPathManager.SEPARATOR + FILE;
|
||||
|
||||
private Map<String, String> featureProperties = Collections.emptyMap();
|
||||
|
||||
/**
|
||||
* JVM property to specify the localization level to attempt to save/load
|
||||
* with. Falls back to USER if not defined.
|
||||
|
@ -181,7 +202,7 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
|
|||
* TODO create a new InputAdapter that takes highest priority and blocks
|
||||
* other inputs. left clicking adds vertices, right click indicates the
|
||||
* last point on the polygon, then connect the first and last point.
|
||||
*
|
||||
*
|
||||
* afterwards, remove and dispose of that input adapter
|
||||
*/
|
||||
return null;
|
||||
|
@ -226,8 +247,46 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
|
|||
|
||||
protected void loadDamagePath(LocalizationFile file) {
|
||||
try (InputStream is = file.openInputStream()) {
|
||||
GeoJsonUtil json = new GeoJsonUtilSimpleImpl();
|
||||
Polygon geometry = (Polygon) json.deserializeGeom(is);
|
||||
Geometry deserializedGeom = null;
|
||||
Map<String, String> deserializedProps = Collections.emptyMap();
|
||||
GeoJsonMapUtil geoJsonUtil = new GeoJsonMapUtil();
|
||||
|
||||
/*
|
||||
* For compatibility with any users that may have an autosaved
|
||||
* damage path file from build 15.1, we'll support deserializing
|
||||
* both Geometry and Feature GeoJSON types.
|
||||
*
|
||||
* TODO: remove this code for code that just expects the file to
|
||||
* always be a Feature.
|
||||
*/
|
||||
Map<String, Object> jsonObject = (Map<String, Object>) new BasicJsonService()
|
||||
.deserialize(is, LinkedHashMap.class);
|
||||
String geoJsonType = jsonObject.get(GeoJsonMapUtil.TYPE_KEY)
|
||||
.toString();
|
||||
if (geoJsonType.equals(GeoJsonMapUtil.FEATURE_TYPE)) {
|
||||
SimpleFeature feature = geoJsonUtil.populateFeature(jsonObject);
|
||||
deserializedGeom = (Geometry) feature.getDefaultGeometry();
|
||||
|
||||
Name defaultGeomAttrib = feature.getDefaultGeometryProperty()
|
||||
.getName();
|
||||
deserializedProps = new LinkedHashMap<>();
|
||||
deserializedProps.put(GeoJsonMapUtil.ID_KEY, feature.getID());
|
||||
for (Property p : feature.getProperties()) {
|
||||
if (!defaultGeomAttrib.equals(p.getName())) {
|
||||
deserializedProps.put(p.getName().toString(), p
|
||||
.getValue().toString());
|
||||
}
|
||||
}
|
||||
} else if (isGeometryType(geoJsonType)) {
|
||||
deserializedGeom = geoJsonUtil.populateGeometry(jsonObject);
|
||||
} else {
|
||||
String message = "Unexpected GeoJSON object type "
|
||||
+ geoJsonType
|
||||
+ ". This tool only supports Feature and Geometry objects.";
|
||||
throw new JsonException(message);
|
||||
}
|
||||
|
||||
Polygon geometry = (Polygon) deserializedGeom;
|
||||
/*
|
||||
* specifically call super.resetPolygon() cause this.resetPolygon()
|
||||
* will save the file and we don't want to do that or we could
|
||||
|
@ -237,6 +296,8 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
|
|||
if (current == null || !current.equals(geometry)) {
|
||||
super.resetPolygon(geometry.getExteriorRing().getCoordinates());
|
||||
}
|
||||
|
||||
featureProperties = deserializedProps;
|
||||
} catch (Exception e) {
|
||||
statusHandler.error(
|
||||
"Error loading damage path file " + file.getName(), e);
|
||||
|
@ -247,8 +308,9 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
|
|||
LocalizationFileOutputStream fos = null;
|
||||
try {
|
||||
fos = file.openOutputStream();
|
||||
GeoJsonUtil json = new GeoJsonUtilSimpleImpl();
|
||||
json.serialize(this.getPolygon(), fos);
|
||||
IGeoJsonService json = new SimpleGeoJsonService();
|
||||
SimpleFeature feature = buildFeature();
|
||||
json.serialize(feature, fos);
|
||||
fos.closeAndSave();
|
||||
} catch (Throwable t) {
|
||||
if (fos != null) {
|
||||
|
@ -262,4 +324,55 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
|
|||
"Error saving damage path file " + file.getName(), t);
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleFeature buildFeature() {
|
||||
Map<String, String> jsonProps = getFeatureProperties();
|
||||
|
||||
String id = jsonProps.get(GeoJsonMapUtil.ID_KEY);
|
||||
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
|
||||
typeBuilder.setName("feature");
|
||||
Geometry geom = getPolygon();
|
||||
if (geom != null) {
|
||||
typeBuilder.setDefaultGeometry("the_geom");
|
||||
typeBuilder.add("the_geom", geom.getClass());
|
||||
}
|
||||
|
||||
Collection<String> keysToIgnore = Arrays.asList(GeoJsonMapUtil.ID_KEY);
|
||||
Set<String> keySet = jsonProps.keySet();
|
||||
List<Object> values = new ArrayList<Object>(keySet.size());
|
||||
for (String key : keySet) {
|
||||
if (!keysToIgnore.contains(key)) {
|
||||
Object val = jsonProps.get(key);
|
||||
typeBuilder.add(key, val.getClass());
|
||||
values.add(val);
|
||||
}
|
||||
}
|
||||
|
||||
SimpleFeatureType type = typeBuilder.buildFeatureType();
|
||||
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(type);
|
||||
if (geom != null) {
|
||||
featureBuilder.add(geom);
|
||||
}
|
||||
featureBuilder.addAll(values);
|
||||
return featureBuilder.buildFeature(id);
|
||||
}
|
||||
|
||||
public Map<String, String> getFeatureProperties() {
|
||||
return featureProperties;
|
||||
}
|
||||
|
||||
public void setFeatureProperties(Map<String, String> featureProperties) {
|
||||
this.featureProperties = featureProperties;
|
||||
saveJob.schedule();
|
||||
}
|
||||
|
||||
public boolean isGeometryType(String geoJsonType) {
|
||||
return ((GeoJsonMapUtil.GEOM_COLL_TYPE.equals(geoJsonType))
|
||||
|| (GeoJsonMapUtil.LINE_STR_TYPE.equals(geoJsonType))
|
||||
|| (GeoJsonMapUtil.MULT_LINE_STR_TYPE.equals(geoJsonType))
|
||||
|| (GeoJsonMapUtil.MULT_POINT_TYPE.equals(geoJsonType))
|
||||
|| (GeoJsonMapUtil.MULT_POLY_TYPE.equals(geoJsonType))
|
||||
|| (GeoJsonMapUtil.POINT_TYPE.equals(geoJsonType)) || (GeoJsonMapUtil.POLY_TYPE
|
||||
.equals(geoJsonType)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
package com.raytheon.uf.viz.damagepath;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.events.SelectionEvent;
|
||||
import org.eclipse.swt.events.ShellAdapter;
|
||||
import org.eclipse.swt.events.ShellEvent;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Layout;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
|
||||
import com.raytheon.uf.common.util.Pair;
|
||||
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
|
||||
import com.raytheon.viz.ui.dialogs.ICloseCallback;
|
||||
|
||||
/**
|
||||
* Dialog to add/remove the key/value pairs that are part of the "properties"
|
||||
* member object in GeoJSON Feature objects.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Apr 23, 2015 #4354 dgilling Initial creation based on dialog from
|
||||
* lvenable.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author lvenable
|
||||
* @version 1.0
|
||||
*/
|
||||
public class EditGeoJsonPropertiesDlg extends CaveSWTDialog {
|
||||
|
||||
private Table table;
|
||||
|
||||
private Button deleteBtn;
|
||||
|
||||
private Map<String, String> properties;
|
||||
|
||||
public EditGeoJsonPropertiesDlg(Shell parentShell,
|
||||
Map<String, String> properties) {
|
||||
super(parentShell, SWT.DIALOG_TRIM, CAVE.DO_NOT_BLOCK);
|
||||
|
||||
this.properties = new LinkedHashMap<>(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Layout constructShellLayout() {
|
||||
// Create the main layout for the shell.
|
||||
GridLayout mainLayout = new GridLayout(1, false);
|
||||
mainLayout.marginHeight = 2;
|
||||
mainLayout.marginWidth = 2;
|
||||
|
||||
return mainLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object constructShellLayoutData() {
|
||||
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||
return gd;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeComponents(Shell shell) {
|
||||
setText("GeoJSON Properties Editor");
|
||||
|
||||
shell.addShellListener(new ShellAdapter() {
|
||||
|
||||
@Override
|
||||
public void shellClosed(ShellEvent e) {
|
||||
setReturnValue(properties);
|
||||
}
|
||||
});
|
||||
|
||||
createTableComp();
|
||||
createAddDeleteButtons();
|
||||
addSeparator(shell, SWT.HORIZONTAL);
|
||||
createBottomButtons();
|
||||
|
||||
populateTable();
|
||||
}
|
||||
|
||||
private void createTableComp() {
|
||||
int columnWidth = 150;
|
||||
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||
gd.heightHint = 250;
|
||||
gd.widthHint = columnWidth * 2;
|
||||
|
||||
table = new Table(shell, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL
|
||||
| SWT.SINGLE);
|
||||
table.setLayoutData(gd);
|
||||
table.setHeaderVisible(true);
|
||||
table.setLinesVisible(true);
|
||||
|
||||
TableColumn column = new TableColumn(table, SWT.NONE);
|
||||
column.setText("Key");
|
||||
column = new TableColumn(table, SWT.NONE);
|
||||
column.setText("Value");
|
||||
|
||||
for (int i = 0; i < table.getColumnCount(); i++) {
|
||||
table.getColumn(i).setWidth(columnWidth);
|
||||
}
|
||||
}
|
||||
|
||||
private void createAddDeleteButtons() {
|
||||
Composite buttonComp = new Composite(shell, SWT.NONE);
|
||||
buttonComp.setLayout(new GridLayout(2, false));
|
||||
buttonComp.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true,
|
||||
false));
|
||||
|
||||
int buttonWidth = 70;
|
||||
|
||||
GridData gd = new GridData(SWT.RIGHT, SWT.DEFAULT, true, false);
|
||||
gd.widthHint = buttonWidth;
|
||||
Button addBtn = new Button(buttonComp, SWT.PUSH);
|
||||
addBtn.setText(" Add ");
|
||||
addBtn.setLayoutData(gd);
|
||||
addBtn.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
AddKeyValueDlg akvd = new AddKeyValueDlg(shell, properties
|
||||
.keySet());
|
||||
akvd.setCloseCallback(new ICloseCallback() {
|
||||
@Override
|
||||
public void dialogClosed(Object returnValue) {
|
||||
if (returnValue == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (returnValue instanceof Pair) {
|
||||
Pair<String, String> newProperty = (Pair<String, String>) returnValue;
|
||||
properties.put(newProperty.getFirst(),
|
||||
newProperty.getSecond());
|
||||
populateTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
akvd.open();
|
||||
}
|
||||
});
|
||||
|
||||
gd = new GridData(SWT.LEFT, SWT.DEFAULT, true, false);
|
||||
gd.widthHint = buttonWidth;
|
||||
deleteBtn = new Button(buttonComp, SWT.PUSH);
|
||||
deleteBtn.setText(" Delete ");
|
||||
deleteBtn.setLayoutData(gd);
|
||||
deleteBtn.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
handleDeleteAction();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createBottomButtons() {
|
||||
Composite buttonComp = new Composite(shell, SWT.NONE);
|
||||
buttonComp.setLayout(new GridLayout(1, false));
|
||||
buttonComp.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true,
|
||||
false));
|
||||
|
||||
int buttonWidth = 70;
|
||||
|
||||
GridData gd = new GridData(SWT.CENTER, SWT.DEFAULT, true, false);
|
||||
gd.widthHint = buttonWidth;
|
||||
Button okBtn = new Button(buttonComp, SWT.PUSH);
|
||||
okBtn.setText(" Close ");
|
||||
okBtn.setLayoutData(gd);
|
||||
okBtn.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
setReturnValue(properties);
|
||||
close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addSeparator(Composite comp, int orientation) {
|
||||
GridData gd;
|
||||
|
||||
if (orientation == SWT.HORIZONTAL) {
|
||||
gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
||||
|
||||
if (comp.getLayout() instanceof GridLayout) {
|
||||
int columns = ((GridLayout) comp.getLayout()).numColumns;
|
||||
gd.horizontalSpan = columns;
|
||||
}
|
||||
} else {
|
||||
gd = new GridData(SWT.DEFAULT, SWT.FILL, false, true);
|
||||
}
|
||||
|
||||
Label sepLbl = new Label(comp, SWT.SEPARATOR | orientation);
|
||||
sepLbl.setLayoutData(gd);
|
||||
}
|
||||
|
||||
private void populateTable() {
|
||||
table.removeAll();
|
||||
for (Entry<String, String> entry : properties.entrySet()) {
|
||||
TableItem ti = new TableItem(table, SWT.NONE);
|
||||
ti.setText(0, entry.getKey());
|
||||
ti.setText(1, entry.getValue());
|
||||
}
|
||||
|
||||
if (table.getItemCount() > 0) {
|
||||
table.select(0);
|
||||
}
|
||||
|
||||
enableDeleteButton();
|
||||
}
|
||||
|
||||
private void handleDeleteAction() {
|
||||
int index = table.getSelectionIndex();
|
||||
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
properties.remove(table.getItem(index).getText(0));
|
||||
populateTable();
|
||||
|
||||
if (index < table.getItemCount()) {
|
||||
table.select(index);
|
||||
} else if (table.getItemCount() > 0) {
|
||||
table.select(table.getItemCount() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void enableDeleteButton() {
|
||||
if ((table.getItemCount() > 0) && (table.getSelectionIndex() >= 0)) {
|
||||
deleteBtn.setEnabled(true);
|
||||
} else {
|
||||
deleteBtn.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,9 +24,10 @@ import java.io.FileOutputStream;
|
|||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.FileDialog;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.opengis.feature.simple.SimpleFeature;
|
||||
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonUtil;
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonUtilSimpleImpl;
|
||||
import com.raytheon.uf.common.json.geo.IGeoJsonService;
|
||||
import com.raytheon.uf.common.json.geo.SimpleGeoJsonService;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.viz.core.VizApp;
|
||||
|
@ -42,7 +43,8 @@ import com.raytheon.viz.ui.cmenu.AbstractRightClickAction;
|
|||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Feb 9, 2015 3975 njensen Initial creation
|
||||
* Feb 09, 2015 3975 njensen Initial creation
|
||||
* Apr 23, 2015 4354 dgilling Export as GeoJSON Feature object.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -75,8 +77,9 @@ public class ExportDamagePathAction extends AbstractRightClickAction {
|
|||
if (filename != null) {
|
||||
DamagePathLayer<?> layer = (DamagePathLayer<?>) getSelectedRsc();
|
||||
try (FileOutputStream fos = new FileOutputStream(filename)) {
|
||||
GeoJsonUtil json = new GeoJsonUtilSimpleImpl();
|
||||
json.serialize(layer.getPolygon(), fos);
|
||||
IGeoJsonService json = new SimpleGeoJsonService();
|
||||
SimpleFeature feature = layer.buildFeature();
|
||||
json.serialize(feature, fos);
|
||||
} catch (Exception e) {
|
||||
statusHandler.error(
|
||||
"Error exporting damage path file to "
|
||||
|
|
|
@ -20,14 +20,20 @@
|
|||
package com.raytheon.uf.viz.damagepath;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.FileDialog;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.opengis.feature.Property;
|
||||
import org.opengis.feature.simple.SimpleFeature;
|
||||
import org.opengis.feature.type.Name;
|
||||
|
||||
import com.raytheon.uf.common.json.JsonException;
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonUtil;
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonUtilSimpleImpl;
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonMapUtil;
|
||||
import com.raytheon.uf.common.json.geo.IGeoJsonService;
|
||||
import com.raytheon.uf.common.json.geo.SimpleGeoJsonService;
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.viz.core.VizApp;
|
||||
|
@ -38,18 +44,19 @@ import com.vividsolutions.jts.geom.Polygon;
|
|||
|
||||
/**
|
||||
* Action to import a damage path from a GeoJSON file specified by the user.
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Feb 12, 2015 3975 njensen Initial creation
|
||||
* Mar 31, 2015 3977 nabowle Make sure the polygon is not empty.
|
||||
*
|
||||
* Apr 23, 2015 4354 dgilling Support GeoJSON Feature objects.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @author njensen
|
||||
* @version 1.0
|
||||
*/
|
||||
|
@ -77,15 +84,28 @@ public class ImportDamagePathAction extends AbstractRightClickAction {
|
|||
if (filename != null) {
|
||||
DamagePathLayer<?> layer = (DamagePathLayer<?>) getSelectedRsc();
|
||||
try (FileInputStream fis = new FileInputStream(filename)) {
|
||||
GeoJsonUtil json = new GeoJsonUtilSimpleImpl();
|
||||
Geometry geom = json.deserializeGeom(fis);
|
||||
if (geom instanceof Polygon
|
||||
&& geom.getCoordinates().length > 0) {
|
||||
IGeoJsonService json = new SimpleGeoJsonService();
|
||||
SimpleFeature feature = json.deserializeFeature(fis);
|
||||
Geometry geom = (Geometry) feature.getDefaultGeometry();
|
||||
if ((geom instanceof Polygon)
|
||||
&& (geom.getCoordinates().length > 0)) {
|
||||
layer.setPolygon((Polygon) geom);
|
||||
} else {
|
||||
throw new JsonException("Damage path file "
|
||||
+ filename + " must contain a Polygon!");
|
||||
}
|
||||
|
||||
Name defaultGeomAttrib = feature
|
||||
.getDefaultGeometryProperty().getName();
|
||||
Map<String, String> featureProps = new LinkedHashMap<>();
|
||||
featureProps.put(GeoJsonMapUtil.ID_KEY, feature.getID());
|
||||
for (Property p : feature.getProperties()) {
|
||||
if (!defaultGeomAttrib.equals(p.getName())) {
|
||||
featureProps.put(p.getName().toString(), p
|
||||
.getValue().toString());
|
||||
}
|
||||
}
|
||||
layer.setFeatureProperties(featureProps);
|
||||
} catch (Exception e) {
|
||||
statusHandler.error("Error importing damage path from "
|
||||
+ filename, e);
|
||||
|
@ -94,5 +114,4 @@ public class ImportDamagePathAction extends AbstractRightClickAction {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.viz.damagepath;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import com.raytheon.uf.viz.core.VizApp;
|
||||
import com.raytheon.viz.ui.VizWorkbenchManager;
|
||||
import com.raytheon.viz.ui.cmenu.AbstractRightClickAction;
|
||||
import com.raytheon.viz.ui.dialogs.ICloseCallback;
|
||||
|
||||
/**
|
||||
* {@code Action} class to launch the {@code EditGeoJsonPropertiesDlg}.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Apr 23, 2015 #4354 dgilling Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author dgilling
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class OpenGeoJsonPropertiesDlgAction extends AbstractRightClickAction {
|
||||
|
||||
public OpenGeoJsonPropertiesDlgAction() {
|
||||
super("Set GeoJSON Properties...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
VizApp.runSync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Shell shell = VizWorkbenchManager.getInstance()
|
||||
.getCurrentWindow().getShell();
|
||||
final DamagePathLayer<?> layer = (DamagePathLayer<?>) getSelectedRsc();
|
||||
final Map<String, String> geoJsonProps = layer
|
||||
.getFeatureProperties();
|
||||
|
||||
EditGeoJsonPropertiesDlg dlg = new EditGeoJsonPropertiesDlg(
|
||||
shell, geoJsonProps);
|
||||
dlg.setCloseCallback(new ICloseCallback() {
|
||||
|
||||
@Override
|
||||
public void dialogClosed(Object returnValue) {
|
||||
if ((returnValue != null)
|
||||
&& (!geoJsonProps.equals(returnValue))) {
|
||||
Map<String, String> updatedProperties = (Map<String, String>) returnValue;
|
||||
layer.setFeatureProperties(updatedProperties);
|
||||
}
|
||||
}
|
||||
});
|
||||
dlg.open();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -185,7 +185,7 @@
|
|||
id="com.raytheon.uf.viz.aviation.advisory.feature"
|
||||
version="0.0.0"/>
|
||||
|
||||
<includes
|
||||
<includes
|
||||
id="com.raytheon.uf.viz.datadelivery.feature"
|
||||
version="0.0.0"/>
|
||||
|
||||
|
@ -197,6 +197,10 @@
|
|||
id="com.raytheon.uf.viz.d2d.damagepath.feature"
|
||||
version="0.0.0"/>
|
||||
|
||||
<includes
|
||||
id="gov.noaa.gsd.viz.hazards.feature"
|
||||
version="0.0.0"/>
|
||||
|
||||
<requires>
|
||||
<import feature="com.raytheon.uf.viz.application.feature" version="1.0.0.qualifier"/>
|
||||
</requires>
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.opengis.feature.simple.SimpleFeature;
|
|||
import org.opengis.feature.simple.SimpleFeatureType;
|
||||
|
||||
import com.raytheon.uf.common.http.MimeType;
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonUtil;
|
||||
import com.raytheon.uf.common.json.geo.GeoJsonUtilSimpleImpl;
|
||||
import com.raytheon.uf.common.json.geo.IGeoJsonService;
|
||||
import com.raytheon.uf.common.json.geo.SimpleGeoJsonService;
|
||||
import com.raytheon.uf.common.json.geo.MixedFeatureCollection;
|
||||
import com.raytheon.uf.edex.ogc.common.OgcResponse;
|
||||
import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE;
|
||||
|
@ -56,7 +56,7 @@ public class JsonFeatureFormatter implements SimpleFeatureFormatter {
|
|||
|
||||
public static MimeType mimeType = new MimeType("application/json");
|
||||
|
||||
protected GeoJsonUtil jsonUtil = new GeoJsonUtilSimpleImpl();
|
||||
protected IGeoJsonService jsonUtil = new SimpleGeoJsonService();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
|
Loading…
Add table
Reference in a new issue