aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar/web
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/traccar/web')
-rw-r--r--src/org/traccar/web/client/Application.java40
-rw-r--r--src/org/traccar/web/client/controller/ArchiveController.java4
-rw-r--r--src/org/traccar/web/client/controller/DeviceController.java4
-rw-r--r--src/org/traccar/web/client/controller/MapController.java50
-rw-r--r--src/org/traccar/web/client/controller/StateController.java57
-rw-r--r--src/org/traccar/web/client/model/StateItem.java31
-rw-r--r--src/org/traccar/web/client/model/StateItemProperties.java17
-rw-r--r--src/org/traccar/web/client/model/StateReader.java43
-rw-r--r--src/org/traccar/web/client/view/ApplicationView.java6
-rw-r--r--src/org/traccar/web/client/view/ApplicationView.ui.xml18
-rw-r--r--src/org/traccar/web/client/view/ArchiveView.java4
-rw-r--r--src/org/traccar/web/client/view/DeviceView.java4
-rw-r--r--src/org/traccar/web/client/view/MapPositionRenderer.java42
-rw-r--r--src/org/traccar/web/client/view/MapView.java48
-rw-r--r--src/org/traccar/web/client/view/StateView.java58
-rw-r--r--src/org/traccar/web/client/view/StateView.ui.xml22
-rw-r--r--src/org/traccar/web/server/model/DataServiceImpl.java2
-rw-r--r--src/org/traccar/web/shared/model/Device.java2
18 files changed, 431 insertions, 21 deletions
diff --git a/src/org/traccar/web/client/Application.java b/src/org/traccar/web/client/Application.java
index c802995..07e2586 100644
--- a/src/org/traccar/web/client/Application.java
+++ b/src/org/traccar/web/client/Application.java
@@ -20,6 +20,7 @@ import java.util.logging.Logger;
import org.traccar.web.client.controller.ArchiveController;
import org.traccar.web.client.controller.DeviceController;
import org.traccar.web.client.controller.MapController;
+import org.traccar.web.client.controller.StateController;
import org.traccar.web.client.model.BaseStoreHandlers;
import org.traccar.web.client.model.DataService;
import org.traccar.web.client.model.DataServiceAsync;
@@ -48,6 +49,7 @@ public class Application {
}
private final DeviceController deviceController;
+ private final StateController stateController;
private final MapController mapController;
private final ArchiveController archiveController;
@@ -56,31 +58,65 @@ public class Application {
public Application() {
deviceController = new DeviceController(deviceHandler);
deviceController.getDeviceStore().addStoreHandlers(deviceStoreHandler);
- mapController = new MapController();
+ stateController = new StateController();
+ mapController = new MapController(mapHandler);
archiveController = new ArchiveController(archiveHanlder, deviceController.getDeviceStore());
archiveController.getPositionStore().addStoreHandlers(archiveStoreHandler);
view = new ApplicationView(
- deviceController.getView(), mapController.getView(), archiveController.getView());
+ deviceController.getView(), stateController.getView(), mapController.getView(), archiveController.getView());
}
public void run() {
RootPanel.get().add(view);
deviceController.run();
+ stateController.run();
mapController.run();
archiveController.run();
}
private DeviceController.DeviceHandler deviceHandler = new DeviceController.DeviceHandler() {
+ private Device selected;
+
@Override
public void onSelected(Device device) {
+ if (selected != null) {
+ mapController.unregisterPositionUpdate(selected);
+ }
+ if (device != null) {
+ mapController.registerPositionUpdate(device, positionUpdateHandler);
+ }
+ selected = device;
mapController.selectDevice(device);
}
};
+ private MapController.PositionUpdateHandler positionUpdateHandler = new MapController.PositionUpdateHandler() {
+
+ @Override
+ public void onUpdate(Position position) {
+ stateController.showState(position);
+ }
+
+ };
+
+ private MapController.MapHandler mapHandler = new MapController.MapHandler() {
+
+ @Override
+ public void onDeviceSelected(Device device) {
+ deviceController.selectDevice(device);
+ }
+
+ @Override
+ public void onArchivePositionSelected(Position position) {
+ archiveController.selectPosition(position);
+ }
+
+ };
+
private ArchiveController.ArchiveHandler archiveHanlder = new ArchiveController.ArchiveHandler() {
@Override
diff --git a/src/org/traccar/web/client/controller/ArchiveController.java b/src/org/traccar/web/client/controller/ArchiveController.java
index 1146252..553e674 100644
--- a/src/org/traccar/web/client/controller/ArchiveController.java
+++ b/src/org/traccar/web/client/controller/ArchiveController.java
@@ -87,4 +87,8 @@ public class ArchiveController implements ContentController, ArchiveView.Archive
positionStore.clear();
}
+ public void selectPosition(Position position) {
+ archiveView.selectPosition(position);
+ }
+
}
diff --git a/src/org/traccar/web/client/controller/DeviceController.java b/src/org/traccar/web/client/controller/DeviceController.java
index 24ed2a1..75aa76f 100644
--- a/src/org/traccar/web/client/controller/DeviceController.java
+++ b/src/org/traccar/web/client/controller/DeviceController.java
@@ -124,4 +124,8 @@ public class DeviceController implements ContentController, DeviceView.DeviceHan
dialog.show();
}
+ public void selectDevice(Device device) {
+ deviceView.selectDevice(device);
+ }
+
}
diff --git a/src/org/traccar/web/client/controller/MapController.java b/src/org/traccar/web/client/controller/MapController.java
index 44094f7..13c736f 100644
--- a/src/org/traccar/web/client/controller/MapController.java
+++ b/src/org/traccar/web/client/controller/MapController.java
@@ -17,8 +17,10 @@ package org.traccar.web.client.controller;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import org.traccar.web.client.Application;
import org.traccar.web.client.view.MapView;
@@ -29,14 +31,22 @@ import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sencha.gxt.widget.core.client.ContentPanel;
-public class MapController implements ContentController {
+public class MapController implements ContentController, MapView.MapHandler {
private static final int UPDATE_INTERVAL = 15000;
+ public interface MapHandler {
+ public void onDeviceSelected(Device device);
+ public void onArchivePositionSelected(Position position);
+ }
+
+ private MapHandler mapHandler;
+
private MapView mapView;
- public MapController() {
- mapView = new MapView();
+ public MapController(MapHandler mapHandler) {
+ this.mapHandler = mapHandler;
+ mapView = new MapView(this);
}
@Override
@@ -57,12 +67,20 @@ public class MapController implements ContentController {
update();
}
+ private Map<Long, Position> latestPositionMap = new HashMap<Long, Position>();
+
public void update() {
updateTimer.cancel();
Application.getDataService().getLatestPositions(new AsyncCallback<List<Position>>() {
@Override
public void onSuccess(List<Position> result) {
mapView.showLatestPositions(result);
+ for (Position position : result) {
+ latestPositionMap.put(position.getDevice().getId(), position);
+ }
+ for (Map.Entry<Long, PositionUpdateHandler> entry : positionUpdateMap.entrySet()) {
+ entry.getValue().onUpdate(latestPositionMap.get(entry.getKey()));
+ }
updateTimer.schedule(UPDATE_INTERVAL);
}
@Override
@@ -91,4 +109,30 @@ public class MapController implements ContentController {
mapView.selectArchivePosition(position);
}
+ public interface PositionUpdateHandler {
+ public void onUpdate(Position position);
+ }
+
+ private Map<Long, PositionUpdateHandler> positionUpdateMap = new HashMap<Long, PositionUpdateHandler>();
+
+
+ public void registerPositionUpdate(Device device, PositionUpdateHandler handler) {
+ positionUpdateMap.put(device.getId(), handler);
+ handler.onUpdate(latestPositionMap.get(device.getId()));
+ }
+
+ public void unregisterPositionUpdate(Device device) {
+ positionUpdateMap.remove(device.getId());
+ }
+
+ @Override
+ public void onPositionSelected(Position position) {
+ mapHandler.onDeviceSelected(position.getDevice());
+ }
+
+ @Override
+ public void onArchivePositionSelected(Position position) {
+ mapHandler.onArchivePositionSelected(position);
+ }
+
}
diff --git a/src/org/traccar/web/client/controller/StateController.java b/src/org/traccar/web/client/controller/StateController.java
new file mode 100644
index 0000000..a19bec8
--- /dev/null
+++ b/src/org/traccar/web/client/controller/StateController.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.traccar.web.client.controller;
+
+import org.traccar.web.client.model.StateItem;
+import org.traccar.web.client.model.StateItemProperties;
+import org.traccar.web.client.model.StateReader;
+import org.traccar.web.client.view.StateView;
+import org.traccar.web.shared.model.Position;
+
+import com.google.gwt.core.client.GWT;
+import com.sencha.gxt.data.shared.ListStore;
+import com.sencha.gxt.widget.core.client.ContentPanel;
+
+public class StateController implements ContentController {
+
+ private ListStore<StateItem> stateStore;
+
+ private StateView stateView;
+
+ public StateController() {
+ StateItemProperties stateItemProperties = GWT.create(StateItemProperties.class);
+ stateStore = new ListStore<StateItem>(stateItemProperties.id());
+ stateView = new StateView(stateStore);
+ }
+
+ @Override
+ public ContentPanel getView() {
+ return stateView.getView();
+ }
+
+ @Override
+ public void run() {
+ }
+
+ public void showState(Position position) {
+ if (position != null) {
+ stateStore.replaceAll(StateReader.getState(position));
+ } else {
+ stateStore.clear();
+ }
+ }
+
+}
diff --git a/src/org/traccar/web/client/model/StateItem.java b/src/org/traccar/web/client/model/StateItem.java
new file mode 100644
index 0000000..651d2a2
--- /dev/null
+++ b/src/org/traccar/web/client/model/StateItem.java
@@ -0,0 +1,31 @@
+package org.traccar.web.client.model;
+
+
+public class StateItem {
+
+ public StateItem(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+}
diff --git a/src/org/traccar/web/client/model/StateItemProperties.java b/src/org/traccar/web/client/model/StateItemProperties.java
new file mode 100644
index 0000000..e3700a5
--- /dev/null
+++ b/src/org/traccar/web/client/model/StateItemProperties.java
@@ -0,0 +1,17 @@
+package org.traccar.web.client.model;
+
+import com.google.gwt.editor.client.Editor.Path;
+import com.sencha.gxt.core.client.ValueProvider;
+import com.sencha.gxt.data.shared.ModelKeyProvider;
+import com.sencha.gxt.data.shared.PropertyAccess;
+
+public interface StateItemProperties extends PropertyAccess<StateItem> {
+
+ @Path("name")
+ ModelKeyProvider<StateItem> id();
+
+ ValueProvider<StateItem, String> name();
+
+ ValueProvider<StateItem, String> value();
+
+}
diff --git a/src/org/traccar/web/client/model/StateReader.java b/src/org/traccar/web/client/model/StateReader.java
new file mode 100644
index 0000000..a354917
--- /dev/null
+++ b/src/org/traccar/web/client/model/StateReader.java
@@ -0,0 +1,43 @@
+package org.traccar.web.client.model;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.traccar.web.shared.model.Position;
+import org.traccar.web.shared.model.XmlParser;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+
+public class StateReader {
+
+ private static String toString(Object object) {
+ if (object != null) {
+ return object.toString();
+ }
+ return null;
+ }
+
+ public static List<StateItem> getState(Position position) {
+ List<StateItem> state = new LinkedList<StateItem>();
+
+ state.add(new StateItem("valid", toString(position.getValid())));
+ state.add(new StateItem("time", DateTimeFormat.getFormat("yyyy-MM-dd HH:mm:ss").format(position.getTime())));
+ state.add(new StateItem("latitude", toString(position.getLatitude())));
+ state.add(new StateItem("longitude", toString(position.getLongitude())));
+ state.add(new StateItem("altitude", toString(position.getAltitude())));
+ state.add(new StateItem("speed", toString(position.getSpeed())));
+ state.add(new StateItem("course", toString(position.getCourse())));
+ state.add(new StateItem("power", toString(position.getPower())));
+ state.add(new StateItem("address", position.getAddress()));
+
+ String other = position.getOther();
+ if (other != null) {
+ for (String key : XmlParser.enumerateElements(other)) {
+ state.add(new StateItem(key, XmlParser.getElement(other, key)));
+ }
+ }
+
+ return state;
+ }
+
+}
diff --git a/src/org/traccar/web/client/view/ApplicationView.java b/src/org/traccar/web/client/view/ApplicationView.java
index f4c42e5..dfa5335 100644
--- a/src/org/traccar/web/client/view/ApplicationView.java
+++ b/src/org/traccar/web/client/view/ApplicationView.java
@@ -33,13 +33,17 @@ public class ApplicationView extends Composite {
ContentPanel devicePanel;
@UiField(provided = true)
+ ContentPanel statePanel;
+
+ @UiField(provided = true)
ContentPanel mapPanel;
@UiField(provided = true)
ContentPanel archivePanel;
- public ApplicationView(ContentPanel deviceView, ContentPanel mapView, ContentPanel archiveView) {
+ public ApplicationView(ContentPanel deviceView, ContentPanel stateView, ContentPanel mapView, ContentPanel archiveView) {
devicePanel = deviceView;
+ statePanel = stateView;
mapPanel = mapView;
archivePanel = archiveView;
initWidget(uiBinder.createAndBindUi(this));
diff --git a/src/org/traccar/web/client/view/ApplicationView.ui.xml b/src/org/traccar/web/client/view/ApplicationView.ui.xml
index 2faae1e..0b05ab9 100644
--- a/src/org/traccar/web/client/view/ApplicationView.ui.xml
+++ b/src/org/traccar/web/client/view/ApplicationView.ui.xml
@@ -5,7 +5,10 @@
xmlns:container="urn:import:com.sencha.gxt.widget.core.client.container"
xmlns:gxt="urn:import:com.sencha.gxt.widget.core.client">
- <ui:with type="com.sencha.gxt.core.client.util.Margins" field="westMargins">
+ <ui:with type="com.sencha.gxt.core.client.util.Margins" field="topMargins">
+ <ui:attributes top="5" right="0" bottom="0" left="0" />
+ </ui:with>
+ <ui:with type="com.sencha.gxt.core.client.util.Margins" field="westMargins">
<ui:attributes top="5" right="5" bottom="0" left="5" />
</ui:with>
<ui:with type="com.sencha.gxt.core.client.util.Margins" field="centerMargins">
@@ -25,10 +28,21 @@
<ui:attributes size="0.25" maxSize="2147483647" margins="{southMargins}" split="true" />
</ui:with>
+ <ui:with type="com.sencha.gxt.widget.core.client.container.BorderLayoutContainer.BorderLayoutData" field="bottomData">
+ <ui:attributes size="0.5" maxSize="2147483647" margins="{topMargins}" split="true" />
+ </ui:with>
+
<container:Viewport>
<container:BorderLayoutContainer>
<container:west layoutData="{westData}">
- <gxt:ContentPanel ui:field="devicePanel" />
+ <container:BorderLayoutContainer>
+ <container:center>
+ <gxt:ContentPanel ui:field="devicePanel" />
+ </container:center>
+ <container:south layoutData="{bottomData}">
+ <gxt:ContentPanel ui:field="statePanel" />
+ </container:south>
+ </container:BorderLayoutContainer>
</container:west>
<container:center layoutData="{centerData}">
<gxt:ContentPanel ui:field="mapPanel" />
diff --git a/src/org/traccar/web/client/view/ArchiveView.java b/src/org/traccar/web/client/view/ArchiveView.java
index 67b5750..32e569e 100644
--- a/src/org/traccar/web/client/view/ArchiveView.java
+++ b/src/org/traccar/web/client/view/ArchiveView.java
@@ -181,4 +181,8 @@ public class ArchiveView implements SelectionChangedEvent.SelectionChangedHandle
};
+ public void selectPosition(Position position) {
+ grid.getSelectionModel().select(positionStore.findModel(position), false);
+ }
+
}
diff --git a/src/org/traccar/web/client/view/DeviceView.java b/src/org/traccar/web/client/view/DeviceView.java
index 5f6441b..c3f3f7a 100644
--- a/src/org/traccar/web/client/view/DeviceView.java
+++ b/src/org/traccar/web/client/view/DeviceView.java
@@ -134,4 +134,8 @@ public class DeviceView implements SelectionChangedEvent.SelectionChangedHandler
});
}
+ public void selectDevice(Device device) {
+ grid.getSelectionModel().select(deviceStore.findModel(device), false);
+ }
+
}
diff --git a/src/org/traccar/web/client/view/MapPositionRenderer.java b/src/org/traccar/web/client/view/MapPositionRenderer.java
index f1bf57c..15ba082 100644
--- a/src/org/traccar/web/client/view/MapPositionRenderer.java
+++ b/src/org/traccar/web/client/view/MapPositionRenderer.java
@@ -21,6 +21,8 @@ import java.util.Map;
import org.gwtopenmaps.openlayers.client.Icon;
import org.gwtopenmaps.openlayers.client.Marker;
+import org.gwtopenmaps.openlayers.client.event.EventHandler;
+import org.gwtopenmaps.openlayers.client.event.EventObject;
import org.gwtopenmaps.openlayers.client.feature.VectorFeature;
import org.gwtopenmaps.openlayers.client.geometry.LineString;
import org.gwtopenmaps.openlayers.client.geometry.Point;
@@ -29,9 +31,16 @@ import org.gwtopenmaps.openlayers.client.layer.Vector;
import org.traccar.web.shared.model.Device;
import org.traccar.web.shared.model.Position;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.user.client.ui.RootPanel;
+
public class MapPositionRenderer {
+ public interface SelectHandler {
+ public void onSelected(Position position);
+ }
+
private final MapView mapView;
private final MarkerIconFactory.IconType iconType;
@@ -43,14 +52,41 @@ public class MapPositionRenderer {
return mapView.getMarkerLayer();
}
- public MapPositionRenderer(MapView mapView, MarkerIconFactory.IconType iconType) {
+ private SelectHandler selectHandler;
+
+ public MapPositionRenderer(MapView mapView, MarkerIconFactory.IconType iconType, SelectHandler selectHandler) {
this.mapView = mapView;
this.iconType = iconType;
+ this.selectHandler = selectHandler;
+ }
+
+ private void addSelectEvent(Marker marker, final Position position) {
+ if (selectHandler != null) {
+ marker.getEvents().register("click", marker, new EventHandler() {
+ @Override
+ public void onHandle(EventObject eventObject) {
+ selectHandler.onSelected(position);
+ }
+ });
+ marker.getEvents().register("mouseover", marker, new EventHandler() {
+ @Override
+ public void onHandle(EventObject eventObject) {
+ RootPanel.get().getElement().getStyle().setCursor(Style.Cursor.SE_RESIZE);
+ }
+ });
+ marker.getEvents().register("mouseout", marker, new EventHandler() {
+ @Override
+ public void onHandle(EventObject eventObject) {
+ RootPanel.get().getElement().getStyle().setCursor(Style.Cursor.AUTO);
+ }
+ });
+ }
}
private void changeMarkerIcon(Long positionId, Icon icon) {
Marker oldMarker = markerMap.get(positionId);
Marker newMarker = new Marker(oldMarker.getLonLat(), icon);
+ addSelectEvent(newMarker, positionMap.get(positionId));
markerMap.put(positionId, newMarker);
getMarkerLayer().addMarker(newMarker);
getMarkerLayer().removeMarker(oldMarker);
@@ -58,6 +94,7 @@ public class MapPositionRenderer {
private Map<Long, Marker> markerMap = new HashMap<Long, Marker>(); // Position.id -> Marker
private Map<Long, Long> deviceMap = new HashMap<Long, Long>(); // Device.id -> Position.id
+ private Map<Long, Position> positionMap = new HashMap<Long, Position>(); // Position.id -> Position
private Long selectedPositionId;
private Long selectedDeviceId;
@@ -68,6 +105,7 @@ public class MapPositionRenderer {
}
markerMap.clear();
deviceMap.clear();
+ positionMap.clear();
for (Position position : positions) {
Marker marker = new Marker(
@@ -75,6 +113,8 @@ public class MapPositionRenderer {
MarkerIconFactory.getIcon(iconType, false));
markerMap.put(position.getId(), marker);
deviceMap.put(position.getDevice().getId(), position.getId());
+ positionMap.put(position.getId(), position);
+ addSelectEvent(marker, position);
getMarkerLayer().addMarker(marker);
}
diff --git a/src/org/traccar/web/client/view/MapView.java b/src/org/traccar/web/client/view/MapView.java
index f57ec65..e54381d 100644
--- a/src/org/traccar/web/client/view/MapView.java
+++ b/src/org/traccar/web/client/view/MapView.java
@@ -47,6 +47,13 @@ import com.sencha.gxt.widget.core.client.ContentPanel;
public class MapView {
+ public interface MapHandler {
+ public void onPositionSelected(Position position);
+ public void onArchivePositionSelected(Position position);
+ }
+
+ private MapHandler mapHandler;
+
private ContentPanel contentPanel;
public ContentPanel getView() {
@@ -81,33 +88,34 @@ public class MapView {
point.transform(new Projection("EPSG:4326"), new Projection(map.getProjection()));
return point;
}
-
+
private void initMapLayers(Map map) {
map.addLayer(OSM.Mapnik("OpenStreetMap"));
-
+
GoogleV3Options gHybridOptions = new GoogleV3Options();
gHybridOptions.setType(GoogleV3MapType.G_HYBRID_MAP);
map.addLayer(new GoogleV3("Google Hybrid", gHybridOptions));
-
+
GoogleV3Options gNormalOptions = new GoogleV3Options();
gNormalOptions.setType(GoogleV3MapType.G_NORMAL_MAP);
map.addLayer(new GoogleV3("Google Normal", gNormalOptions));
-
+
GoogleV3Options gSatelliteOptions = new GoogleV3Options();
gSatelliteOptions.setType(GoogleV3MapType.G_SATELLITE_MAP);
map.addLayer(new GoogleV3("Google Satellite", gSatelliteOptions));
-
+
GoogleV3Options gTerrainOptions = new GoogleV3Options();
gTerrainOptions.setType(GoogleV3MapType.G_TERRAIN_MAP);
- map.addLayer(new GoogleV3("Google Terrain", gTerrainOptions));
-
+ map.addLayer(new GoogleV3("Google Terrain", gTerrainOptions));
+
final String bingKey = "AseEs0DLJhLlTNoxbNXu7DGsnnH4UoWuGue7-irwKkE3fffaClwc9q_Mr6AyHY8F";
map.addLayer(new Bing(new BingOptions("Bing Road", bingKey, BingType.ROAD)));
map.addLayer(new Bing(new BingOptions("Bing Hybrid", bingKey, BingType.HYBRID)));
map.addLayer(new Bing(new BingOptions("Bing Aerial", bingKey, BingType.AERIAL)));
}
- public MapView() {
+ public MapView(MapHandler mapHandler) {
+ this.mapHandler = mapHandler;
contentPanel = new ContentPanel();
contentPanel.setHeadingText("Map");
@@ -124,7 +132,7 @@ public class MapView {
markerLayer = new Markers("Markers", markersOptions);
initMapLayers(map);
-
+
map.addLayer(vectorLayer);
map.addLayer(markerLayer);
@@ -147,8 +155,8 @@ public class MapView {
}
});
- latestPositionRenderer = new MapPositionRenderer(this, MarkerIconFactory.IconType.iconLatest);
- archivePositionRenderer = new MapPositionRenderer(this, MarkerIconFactory.IconType.iconArchive);
+ latestPositionRenderer = new MapPositionRenderer(this, MarkerIconFactory.IconType.iconLatest, latestPositionSelectHandler);
+ archivePositionRenderer = new MapPositionRenderer(this, MarkerIconFactory.IconType.iconArchive, archivePositionSelectHandler);
}
private final MapPositionRenderer latestPositionRenderer;
@@ -172,4 +180,22 @@ public class MapView {
archivePositionRenderer.selectPosition(position, true);
}
+ private MapPositionRenderer.SelectHandler latestPositionSelectHandler = new MapPositionRenderer.SelectHandler() {
+
+ @Override
+ public void onSelected(Position position) {
+ mapHandler.onPositionSelected(position);
+ }
+
+ };
+
+ private MapPositionRenderer.SelectHandler archivePositionSelectHandler = new MapPositionRenderer.SelectHandler() {
+
+ @Override
+ public void onSelected(Position position) {
+ mapHandler.onArchivePositionSelected(position);
+ }
+
+ };
+
}
diff --git a/src/org/traccar/web/client/view/StateView.java b/src/org/traccar/web/client/view/StateView.java
new file mode 100644
index 0000000..700d55a
--- /dev/null
+++ b/src/org/traccar/web/client/view/StateView.java
@@ -0,0 +1,58 @@
+package org.traccar.web.client.view;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.traccar.web.client.model.StateItem;
+import org.traccar.web.client.model.StateItemProperties;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Widget;
+import com.sencha.gxt.data.shared.ListStore;
+import com.sencha.gxt.widget.core.client.ContentPanel;
+import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
+import com.sencha.gxt.widget.core.client.grid.ColumnModel;
+import com.sencha.gxt.widget.core.client.grid.Grid;
+
+public class StateView {
+
+ private static StateViewUiBinder uiBinder = GWT.create(StateViewUiBinder.class);
+
+ interface StateViewUiBinder extends UiBinder<Widget, StateView> {
+ }
+
+ @UiField
+ ContentPanel contentPanel;
+
+ public ContentPanel getView() {
+ return contentPanel;
+ }
+
+ @UiField(provided = true)
+ ColumnModel<StateItem> columnModel;
+
+ @UiField(provided = true)
+ ListStore<StateItem> stateStore;
+
+ @UiField
+ Grid<StateItem> grid;
+
+ public StateView(ListStore<StateItem> stateStore) {
+ this.stateStore = stateStore;
+
+ StateItemProperties stateItemProperties = GWT.create(StateItemProperties.class);
+
+ List<ColumnConfig<StateItem, ?>> columnConfigList = new LinkedList<ColumnConfig<StateItem, ?>>();
+ columnConfigList.add(new ColumnConfig<StateItem, String>(stateItemProperties.name(), 0, "Attribute"));
+ columnConfigList.add(new ColumnConfig<StateItem, String>(stateItemProperties.value(), 0, "Value"));
+ columnModel = new ColumnModel<StateItem>(columnConfigList);
+
+ uiBinder.createAndBindUi(this);
+
+ grid.getSelectionModel().setLocked(true);
+ }
+
+}
+
diff --git a/src/org/traccar/web/client/view/StateView.ui.xml b/src/org/traccar/web/client/view/StateView.ui.xml
new file mode 100644
index 0000000..2a7c2ac
--- /dev/null
+++ b/src/org/traccar/web/client/view/StateView.ui.xml
@@ -0,0 +1,22 @@
+<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
+<ui:UiBinder
+ xmlns:ui="urn:ui:com.google.gwt.uibinder"
+ xmlns:g="urn:import:com.google.gwt.user.client.ui"
+ xmlns:container="urn:import:com.sencha.gxt.widget.core.client.container"
+ xmlns:gxt="urn:import:com.sencha.gxt.widget.core.client"
+ xmlns:toolbar="urn:import:com.sencha.gxt.widget.core.client.toolbar"
+ xmlns:grid="urn:import:com.sencha.gxt.widget.core.client.grid"
+ xmlns:button="urn:import:com.sencha.gxt.widget.core.client.button">
+
+ <ui:with type="com.sencha.gxt.data.shared.ListStore" field="stateStore" />
+ <ui:with type="com.sencha.gxt.widget.core.client.grid.ColumnModel" field="columnModel" />
+
+ <ui:with type="com.sencha.gxt.widget.core.client.grid.GridView" field="view">
+ <ui:attributes stripeRows="true" autoFill="true" />
+ </ui:with>
+
+ <gxt:ContentPanel ui:field="contentPanel" headingText="State">
+ <grid:Grid ui:field="grid" store="{stateStore}" cm="{columnModel}" view="{view}" />
+ </gxt:ContentPanel>
+
+</ui:UiBinder>
diff --git a/src/org/traccar/web/server/model/DataServiceImpl.java b/src/org/traccar/web/server/model/DataServiceImpl.java
index e48fa73..287a568 100644
--- a/src/org/traccar/web/server/model/DataServiceImpl.java
+++ b/src/org/traccar/web/server/model/DataServiceImpl.java
@@ -152,6 +152,7 @@ public class DataServiceImpl extends RemoteServiceServlet implements DataService
try {
entityManager.persist(device);
user.getDevices().add(device);
+ entityManager.merge(user);
entityManager.getTransaction().commit();
return device;
} catch (RuntimeException e) {
@@ -191,6 +192,7 @@ public class DataServiceImpl extends RemoteServiceServlet implements DataService
device = entityManager.merge(device);
user.getDevices().remove(device);
entityManager.remove(device);
+ entityManager.merge(user);
entityManager.getTransaction().commit();
return device;
} catch (RuntimeException e) {
diff --git a/src/org/traccar/web/shared/model/Device.java b/src/org/traccar/web/shared/model/Device.java
index ede3c5f..324bad8 100644
--- a/src/org/traccar/web/shared/model/Device.java
+++ b/src/org/traccar/web/shared/model/Device.java
@@ -49,7 +49,7 @@ public class Device implements Serializable {
return id;
}
- @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
+ @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Position latestPosition;
public Position getLatestPosition() {