Skip to content

Commit

Permalink
For #47 - started implementation: added tab panel to the archive view…
Browse files Browse the repository at this point in the history
…, moved sorting to server side, addded several stub methods
  • Loading branch information
vitalidze committed May 5, 2015
1 parent cef5f15 commit d25ad8d
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 175 deletions.
24 changes: 9 additions & 15 deletions src/main/java/org/traccar/web/client/Application.java
Expand Up @@ -74,7 +74,6 @@ public Application() {
geoFenceController.getDeviceGeoFences(),
this);
archiveController = new ArchiveController(archiveHandler, userSettingsHandler, deviceController.getDeviceStore());
archiveController.getPositionStore().addStoreHandlers(archiveStoreHandler);

view = new ApplicationView(
deviceController.getView(), mapController.getView(), archiveController.getView());
Expand Down Expand Up @@ -110,6 +109,15 @@ public void onSelected(Position position) {
mapController.selectArchivePosition(position);
}

@Override
public void onClear(Device device) {
// TODO
}

@Override
public void onDrawTrack(Track track) {
mapController.showArchivePositions(track);
}
};

public ArchiveController getArchiveController() {
Expand All @@ -131,20 +139,6 @@ public void onRemove(StoreRemoveEvent<Device> event) {

};

private StoreHandlers<Position> archiveStoreHandler = new BaseStoreHandlers<Position>() {

@Override
public void onAnything() {
mapController.showArchivePositions(
new Track(
archiveController.getPositionStore().getAll(),
archiveController.getStyle()
)
);
}

};

private StoreHandlers<GeoFence> geoFenceStoreHandler = new BaseStoreHandlers<GeoFence>() {
@Override
public void onAdd(StoreAddEvent<GeoFence> event) {
Expand Down
6 changes: 0 additions & 6 deletions src/main/java/org/traccar/web/client/TrackSegment.java
Expand Up @@ -29,12 +29,6 @@ public TrackSegment() {

public TrackSegment(List<Position> positions, ArchiveStyle style) {
this.positions = new ArrayList<Position>(positions);
Collections.sort(this.positions, new Comparator<Position>() {
@Override
public int compare(Position o1, Position o2) {
return o1.getTime().compareTo(o2.getTime());
}
});
this.style = style;
}

Expand Down
Expand Up @@ -16,14 +16,16 @@
package org.traccar.web.client.controller;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.traccar.web.client.Application;
import org.traccar.web.client.ApplicationContext;
import org.traccar.web.client.ArchiveStyle;
import org.traccar.web.client.Track;
import org.traccar.web.client.i18n.Messages;
import org.traccar.web.client.model.BaseAsyncCallback;
import org.traccar.web.client.model.PositionProperties;
import org.traccar.web.client.view.ArchiveView;
import org.traccar.web.client.view.FilterDialog;
import org.traccar.web.shared.model.Device;
Expand All @@ -37,29 +39,26 @@
public class ArchiveController implements ContentController, ArchiveView.ArchiveHandler {

public interface ArchiveHandler {
public void onSelected(Position position);
void onSelected(Position position);
void onClear(Device device);
void onDrawTrack(Track track);
}

private final ArchiveHandler archiveHandler;

private final FilterDialog.FilterSettingsHandler filterSettingsHandler;

private ListStore<Position> positionStore;
private final Map<Long, List<Position>> positionArchives; // Device.id <-> position archive

private ArchiveView archiveView;
private final ArchiveView archiveView;

private Messages i18n = GWT.create(Messages.class);
private final Messages i18n = GWT.create(Messages.class);

public ArchiveController(ArchiveHandler archiveHandler, FilterDialog.FilterSettingsHandler filterSettingsHandler, ListStore<Device> deviceStore) {
this.archiveHandler = archiveHandler;
this.filterSettingsHandler = filterSettingsHandler;
PositionProperties positionProperties = GWT.create(PositionProperties.class);
positionStore = new ListStore<Position>(positionProperties.id());
archiveView = new ArchiveView(this, positionStore, deviceStore);
}

public ListStore<Position> getPositionStore() {
return positionStore;
this.positionArchives = new HashMap<Long, List<Position>>();
this.archiveView = new ArchiveView(this, deviceStore);
}

@Override
Expand All @@ -82,7 +81,7 @@ public void onLoad(final Device device, Date from, Date to, boolean filter, fina
Application.getDataService().getPositions(device, from, to, filter, new BaseAsyncCallback<List<Position>>(i18n) {
@Override
public void onSuccess(List<Position> result) {
positionStore.clear();
archiveHandler.onClear(device);
if (result.isEmpty()) {
new AlertMessageBox(i18n.error(), i18n.errNoResults()).show();
} else {
Expand All @@ -94,8 +93,10 @@ public void onSuccess(List<Position> result) {
position.setIconType(device.getIconType().getPositionIconType(position.getStatus()));
}
}
positionStore.addAll(result);
}
positionArchives.put(device.getId(), result);
archiveHandler.onDrawTrack(new Track(result, style));
archiveView.showPositions(device, result);
}
});
} else {
Expand All @@ -104,8 +105,9 @@ public void onSuccess(List<Position> result) {
}

@Override
public void onClear() {
positionStore.clear();
public void onClear(Device device) {
archiveHandler.onClear(device);
positionArchives.remove(device.getId());
}

@Override
Expand All @@ -120,8 +122,4 @@ public void selectPosition(Position position) {
public void selectDevice(Device device) {
archiveView.selectDevice(device);
}

public ArchiveStyle getStyle() {
return archiveView.style;
}
}
174 changes: 174 additions & 0 deletions src/main/java/org/traccar/web/client/view/ArchivePanel.java
@@ -0,0 +1,174 @@
/*
* Copyright 2015 Vitaly Litvak (vitavaque@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.view;

import com.google.gwt.cell.client.DateCell;
import com.google.gwt.core.client.Callback;
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.cell.core.client.NumberCell;
import com.sencha.gxt.core.client.Style;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.data.shared.loader.*;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
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;
import com.sencha.gxt.widget.core.client.grid.LiveGridView;
import com.sencha.gxt.widget.core.client.toolbar.LabelToolItem;
import org.traccar.web.client.ApplicationContext;
import org.traccar.web.client.i18n.Messages;
import org.traccar.web.client.model.BaseStoreHandlers;
import org.traccar.web.client.model.PositionProperties;
import org.traccar.web.client.state.GridStateHandler;
import org.traccar.web.shared.model.Position;

import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

public class ArchivePanel {
private static ArchivePanelUiBinder uiBinder = GWT.create(ArchivePanelUiBinder.class);

interface ArchivePanelUiBinder extends UiBinder<Widget, ArchivePanel> {
}

@UiField
VerticalLayoutContainer contentPanel;

@UiField(provided = true)
final ColumnModel<Position> columnModel;

@UiField(provided = true)
final ListStore<Position> positionStore;

@UiField(provided = true)
final LiveGridView<Position> view;

@UiField
Grid<Position> grid;

@UiField
LabelToolItem totalDistance;

@UiField
LabelToolItem averageSpeed;

@UiField(provided = true)
final Messages i18n = GWT.create(Messages.class);

private final PagingLoader<PagingLoadConfig, PagingLoadResult<Position>> loader;
private final PagingMemoryProxy memoryProxy;

static class PagingMemoryProxy extends MemoryProxy<PagingLoadConfig, PagingLoadResult<Position>> {
List<Position> positions = Collections.emptyList();

public PagingMemoryProxy() {
super(null); //data is useless in this case, memoryProxy only designed to hold, not to search
}
@Override
public void load(PagingLoadConfig config, Callback<PagingLoadResult<Position>, Throwable> callback) {
List<Position> results = positions.subList(config.getOffset(), Math.min(positions.size(), config.getOffset() + config.getLimit())); // Get results list based on the data the proxy was created with
callback.onSuccess(new PagingLoadResultBean<Position>(results, positions.size(), config.getOffset())); // again, data from the config
}

public void setPositions(List<Position> positions) {
this.positions = positions;
}
}

public ArchivePanel() {
PositionProperties positionProperties = GWT.create(PositionProperties.class);

this.positionStore = new ListStore<Position>(positionProperties.id());

List<ColumnConfig<Position, ?>> columnConfigList = new LinkedList<ColumnConfig<Position, ?>>();

ColumnConfig<Position, Boolean> columnConfigValid = new ColumnConfig<Position, Boolean>(positionProperties.valid(), 25, i18n.valid());
columnConfigList.add(columnConfigValid);

ColumnConfig<Position, Date> columnConfigDate = new ColumnConfig<Position, Date>(positionProperties.time(), 25, i18n.time());
columnConfigDate.setCell(new DateCell(ApplicationContext.getInstance().getFormatterUtil().getTimeFormat()));
columnConfigList.add(columnConfigDate);

ColumnConfig<Position, String> columnConfigAddress = new ColumnConfig<Position, String>(positionProperties.address(), 25, i18n.address());
columnConfigList.add(columnConfigAddress);

columnConfigList.add(new ColumnConfig<Position, Double>(positionProperties.latitude(), 25, i18n.latitude()));
columnConfigList.add(new ColumnConfig<Position, Double>(positionProperties.longitude(), 25, i18n.longitude()));
columnConfigList.add(new ColumnConfig<Position, Double>(positionProperties.altitude(), 25, i18n.altitude()));

ColumnConfig<Position, Double> columnConfigSpeed = new ColumnConfig<Position, Double>(positionProperties.speed(), 25, i18n.speed());
columnConfigSpeed.setCell(new NumberCell<Double>(ApplicationContext.getInstance().getFormatterUtil().getSpeedFormat()));
columnConfigList.add(columnConfigSpeed);

ColumnConfig<Position, Double> columnConfigDistance = new ColumnConfig<Position, Double>(positionProperties.distance(), 25, i18n.distance());
columnConfigDistance.setCell(new NumberCell<Double>(ApplicationContext.getInstance().getFormatterUtil().getDistanceFormat()));
columnConfigList.add(columnConfigDistance);

columnConfigList.add(new ColumnConfig<Position, Double>(positionProperties.course(), 25, i18n.course()));
columnConfigList.add(new ColumnConfig<Position, Double>(positionProperties.power(), 25, i18n.power()));

columnModel = new ColumnModel<Position>(columnConfigList);

view = new LiveGridView<Position>();
view.setForceFit(true);
view.setStripeRows(true);

uiBinder.createAndBindUi(this);

memoryProxy = new PagingMemoryProxy();
loader = new PagingLoader<PagingLoadConfig, PagingLoadResult<Position>>(memoryProxy);
loader.setRemoteSort(true);
grid.setLoader(loader);

new GridStateHandler<Position>(grid).loadState();

// TODO
// grid.getSelectionModel().addSelectionChangedHandler(this);
// grid.getSelectionModel().setSelectionMode(Style.SelectionMode.SINGLE);
}

void updateTotals(List<Position> positions) {
double totalDistance = 0;
double averageSpeed = 0;
for (int i = 0; i < positions.size(); i++) {
Position position = positions.get(i);
totalDistance += position.getDistance();
averageSpeed += position.getSpeed();
}
averageSpeed = averageSpeed / positions.size();
this.totalDistance.setLabel(ApplicationContext.getInstance().getFormatterUtil().getDistanceFormat().format(totalDistance));
this.averageSpeed.setLabel(ApplicationContext.getInstance().getFormatterUtil().getSpeedFormat().format(averageSpeed));
}

public VerticalLayoutContainer getContentPanel() {
return contentPanel;
}

public void setPositions(List<Position> positions) {
memoryProxy.setPositions(positions);
loader.load(0, view.getCacheSize());
updateTotals(positions);
}

public void selectPosition(Position position) {
grid.getSelectionModel().select(position, false);
}
}
43 changes: 43 additions & 0 deletions src/main/java/org/traccar/web/client/view/ArchivePanel.ui.xml
@@ -0,0 +1,43 @@
<!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"
xmlns:form="urn:import:com.sencha.gxt.widget.core.client.form"
xmlns:menu="urn:import:com.sencha.gxt.widget.core.client.menu">

<ui:with type="com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData" field="toolBarRowData">
<ui:attributes width="1" height="-1" />
</ui:with>
<ui:with type="com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData" field="layoutData">
<ui:attributes width="1" height="1" />
</ui:with>

<ui:with type="com.sencha.gxt.data.shared.ListStore" field="positionStore" />
<ui:with type="com.sencha.gxt.widget.core.client.grid.ColumnModel" field="columnModel" />

<ui:with type="com.sencha.gxt.widget.core.client.grid.LiveGridView" field="view">
<ui:attributes stripeRows="true" autoFill="true" />
</ui:with>

<ui:with field='i18n' type='org.traccar.web.client.i18n.Messages' />

<container:VerticalLayoutContainer ui:field="contentPanel">
<container:child layoutData="{layoutData}">
<grid:Grid ui:field="grid" store="{positionStore}" cm="{columnModel}" view="{view}" stateful="true" stateId="archiveGrid" />
</container:child>
<container:child layoutData="{toolBarRowData}">
<toolbar:ToolBar>
<toolbar:FillToolItem />
<toolbar:LabelToolItem label="{i18n.distance}:" />
<toolbar:LabelToolItem ui:field="totalDistance" label="0" width="80" />
<toolbar:LabelToolItem label="{i18n.speed}:" />
<toolbar:LabelToolItem ui:field="averageSpeed" label="0" width="80" />
</toolbar:ToolBar>
</container:child>
</container:VerticalLayoutContainer>
</ui:UiBinder>

0 comments on commit d25ad8d

Please sign in to comment.