/*******************************************************************************
* Copyright 2011 Antti Havanko
*
* This file is part of Motiver.fi.
* Motiver.fi is licensed under one open source license and one commercial license.
*
* Commercial license: This is the appropriate option if you want to use Motiver.fi in
* commercial purposes. Contact license@motiver.fi for licensing options.
*
* Open source license: This is the appropriate option if you are creating an open source
* application with a license compatible with the GNU GPL license v3. Although the GPLv3 has
* many terms, the most important is that you must provide the source code of your application
* to your users so they can be free to modify your application for their own needs.
******************************************************************************/
package com.delect.motiver.client.view.cardio;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.ui.Widget;
import com.delect.motiver.client.AppController;
import com.delect.motiver.client.Motiver;
import com.delect.motiver.client.StringConstants;
import com.delect.motiver.client.presenter.cardio.RunPresenter;
import com.delect.motiver.client.presenter.cardio.RunPresenter.RunHandler;
import com.delect.motiver.client.res.MyResources;
import com.delect.motiver.client.view.widget.NameInputWidget;
import com.delect.motiver.client.view.widget.NameInputWidget.EnterNamePanelHandler;
import com.delect.motiver.client.view.MySpinnerField;
import com.delect.motiver.client.view.SmallNotePanel;
import com.delect.motiver.client.view.SmallNotePanelDisplay;
import com.delect.motiver.shared.util.CommonUtils;
import com.delect.motiver.shared.util.CommonUtils.MessageBoxHandler;
import com.delect.motiver.shared.Constants;
import com.delect.motiver.shared.RunModel;
import com.delect.motiver.shared.RunValueModel;
import com.extjs.gxt.ui.client.Style.SelectionMode;
import com.extjs.gxt.ui.client.Style.VerticalAlignment;
import com.extjs.gxt.ui.client.data.BasePagingLoader;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import com.extjs.gxt.ui.client.data.PagingLoader;
import com.extjs.gxt.ui.client.data.PagingModelMemoryProxy;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.util.KeyNav;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.form.NumberField;
import com.extjs.gxt.ui.client.widget.grid.CellEditor;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnData;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;
import com.extjs.gxt.ui.client.widget.grid.GridSelectionModel;
import com.extjs.gxt.ui.client.widget.layout.RowData;
import com.extjs.gxt.ui.client.widget.layout.RowLayout;
import com.extjs.gxt.ui.client.widget.layout.TableLayout;
import com.extjs.gxt.ui.client.widget.toolbar.PagingToolBar;
public class RunView extends RunPresenter.RunDisplay {
private Grid<RunValueModel> grid;
private RunHandler handler;
//panels
private SmallNotePanelDisplay panelBase = (SmallNotePanelDisplay)GWT.create(SmallNotePanel.class);
private LayoutContainer panelComments = new LayoutContainer();
private LayoutContainer panelDataOld = new LayoutContainer();
private LayoutContainer panelDates = new LayoutContainer();
private LayoutContainer panelDistance = new LayoutContainer();
private RunModel run;
private ListStore<RunValueModel> store = new ListStore<RunValueModel>();
private List<RunValueModel> values;
MessageBox box = null;
public RunView() {
try {
panelBase.setStylePrefix("panel-run");
panelBase.getPanelData().addListener(Events.Show, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
handler.valuesVisible();
}
});
this.add(panelBase);
//distance
TableLayout tl = new TableLayout(2);
tl.setCellVerticalAlign(VerticalAlignment.MIDDLE);
panelDistance.setLayout(tl);
} catch (Exception e) {
Motiver.showException(e);
}
}
@Override
public Widget asWidget() {
panelBase.getPanelData().removeAll();
try {
//if no model -> ask for name
if(run.getId() == 0) {
//add panel where user can type name
NameInputWidget panelNameInput = new NameInputWidget(new EnterNamePanelHandler() {
@Override
public void newName(String name) {
//if cancelled
if(name == null) {
handler.saveData(null);
}
else {
run.setName(name);
handler.saveData(run);
}
}
});
panelBase.getPanelData().add(panelNameInput);
panelBase.getPanelData().setVisible(true);
}
//model set
else {
panelDataOld.setStyleAttribute("min-height", "150px");
panelDataOld.setLayout(new RowLayout());
initTitlePanel();
initInfoPanel();
panelBase.getPanelData().add(panelDistance, new RowData(-1, -1, new Margins(10, 0, 10, 0)));
panelBase.getPanelData().add(panelDates, new RowData(-1, -1, new Margins(10, 0, 10, 0)));
panelBase.getPanelData().add(panelDataOld, new RowData(-1, -1, new Margins(0, 0, 5, 0)));
panelBase.getPanelData().add(panelComments, new RowData(-1, -1, new Margins(10, 0, 0, 0)));
panelBase.getPanelData().setVisible(false);
}
} catch (Exception e) {
Motiver.showException(e);
}
panelBase.getPanelData().layout();
return this;
}
@Override
public LayoutContainer getCommentsContainer() {
return panelComments;
}
@Override
public LayoutContainer getDataContainer() {
return panelDataOld;
}
@Override
public LayoutContainer getDatesContainer() {
return panelDates;
}
@Override
public void onStop() {
if(box != null && box.isVisible()) {
box.close();
}
}
@Override
public void setCollapsible(boolean isCollapsible) {
panelBase.setCollapsible(isCollapsible);
}
@Override
public void setHandler(RunHandler handler) {
this.handler = handler;
}
@Override
public void setModel(RunModel run) {
this.run = run;
}
/**
* Populates list with given values
*/
@Override
public void setValues(List<RunValueModel> values) {
try {
this.values = values;
//if null -> clear panel
if(values == null) {
panelDataOld.removeAll();
return;
}
panelDataOld.removeAll();
if(values.size() > 0) {
initList();
panelDataOld.layout();
}
} catch (Exception e) {
Motiver.showException(e);
}
}
@Override
public void showContent() {
panelBase.getPanelData().setVisible(true);
}
/**
* Initializes content panel
* - datefield
* - list
* - comments
*/
private void initInfoPanel() {
Text text = new Text(AppController.Lang.Distance() + ":");
text.setStyleAttribute("margin-right", "5px");
panelDistance.add(text);
final MySpinnerField tfDistance = new MySpinnerField();
tfDistance.setAllowBlank(false);
tfDistance.setEditable(true);
tfDistance.setMinValue(0);
tfDistance.setMaxValue(1000);
tfDistance.setValue(run.getDistance());
tfDistance.setIncrement(1);
tfDistance.setPropertyEditorType(Double.class);
tfDistance.setFormat(NumberFormat.getFormat("0.0 " + StringConstants.UNITS_DISTANCE[AppController.User.getMeasurementSystem()]));
//change when lost focus
tfDistance.addListener(Events.Valid, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
if(Double.compare(tfDistance.getValue().doubleValue(), run.getDistance()) != 0) {
run.setDistance(tfDistance.getValue().doubleValue());
handler.saveData(run);
}
}
});
panelDistance.add(tfDistance);
panelDistance.layout();
}
/**
* Inits list that shows measurements
* Parameters: unit for value column
*/
private void initList() {
//columns
//date
List<ColumnConfig> configs = new ArrayList<ColumnConfig>();
ColumnConfig column = new ColumnConfig("d", AppController.Lang.Date(), 150);
final DateTimeFormat fmt = DateTimeFormat.getFormat(StringConstants.DATEFORMATS[AppController.User.getDateFormat()] + " " + StringConstants.TIMEFORMATS[AppController.User.getTimeFormat()]);
column.setDateTimeFormat(fmt);
column.setRenderer(new GridCellRenderer<RunValueModel>() {
@Override
public Object render(RunValueModel model, String property, ColumnData config, int rowIndex, int colIndex, ListStore<RunValueModel> store, Grid<RunValueModel> grid) {
return CommonUtils.getDateTimeString(model.getDate(), false, true);
}
});
column.setMenuDisabled(true);
configs.add(column);
//duration
column = new ColumnConfig("du", AppController.Lang.Duration(), 100);
column.setRenderer(new GridCellRenderer<RunValueModel>() {
@Override
public Object render(RunValueModel model, String property, ColumnData config, int rowIndex, int colIndex, ListStore<RunValueModel> store, Grid<RunValueModel> grid) {
long value = model.getDuration();
return CommonUtils.getDurationString(value);
}
});
column.setMenuDisabled(true);
configs.add(column);
//pulse
column = new ColumnConfig("pu", AppController.Lang.Pulse(), 100);
column.setNumberFormat(NumberFormat.getFormat("0"));
column.setEditor(new CellEditor(new NumberField()));
column.setMenuDisabled(true);
configs.add(column);
//pulse max
column = new ColumnConfig("pum", AppController.Lang.MaxPulse(), 100);
column.setNumberFormat(NumberFormat.getFormat("0"));
column.setEditor(new CellEditor(new NumberField()));
column.setMenuDisabled(true);
configs.add(column);
//calories
column = new ColumnConfig("c", AppController.Lang.Calories(), 100);
column.setNumberFormat(NumberFormat.getFormat("0 kcal"));
column.setEditor(new CellEditor(new NumberField()));
column.setMenuDisabled(true);
configs.add(column);
//info
column = new ColumnConfig("i", AppController.Lang.Info(), 100);
column.setNumberFormat(NumberFormat.getFormat("0 kcal"));
column.setEditor(new CellEditor(new NumberField()));
column.setMenuDisabled(true);
configs.add(column);
final PagingToolBar toolBar = new PagingToolBar(Constants.LIMIT_LIST_RECORDS);
//set paging if more than 50 rows
if(values.size() > Constants.LIMIT_LIST_RECORDS) {
PagingModelMemoryProxy proxy = new PagingModelMemoryProxy(values);
// loader
PagingLoader<PagingLoadResult<RunValueModel>> loader = new BasePagingLoader<PagingLoadResult<RunValueModel>>(proxy);
loader.setRemoteSort(true);
store = new ListStore<RunValueModel>(loader);
toolBar.bind(loader);
loader.load(0, Constants.LIMIT_LIST_RECORDS);
}
else {
//populate store
store.removeAll();
store.add(values);
}
//grid
ColumnModel cm = new ColumnModel(configs);
grid = new Grid<RunValueModel>(store, cm);
grid.setStripeRows(true);
grid.setSelectionModel(new GridSelectionModel<RunValueModel>());
grid.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
grid.setBorders(true);
grid.getView().setEmptyText(AppController.Lang.NoValues());
grid.setAutoExpandColumn("i");
grid.setAutoWidth(true);
grid.setAutoHeight(true);
grid.setColumnResize(false);
grid.addListener(Events.OnClick, new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
grid.focus();
}
});
//remove selected rows from ALL GRIDS when delete button is pressed
new KeyNav<ComponentEvent>(grid) {
@Override
public void onDelete(ComponentEvent ce) {
deleteSelectedValues();
}
};
panelDataOld.add(grid);
if(values.size() > Constants.LIMIT_LIST_RECORDS) {
panelDataOld.add(toolBar);
}
}
/**
* Inits panel which contains the title
*/
private void initTitlePanel() {
try {
panelBase.setTitleText(run.getNameClient());
//buttons
if(run.getId() != 0) {
if(run.getUid().equals(AppController.User.getUid())) {
//add value
panelBase.addHeaderButton(AppController.Lang.AddTarget(AppController.Lang.Value().toLowerCase()),
new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
handler.newValue();
}
});
//rename run
panelBase.addHeaderImageButton(AppController.Lang.Rename(), MyResources.INSTANCE.iconBtnRename(),
new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
if(box != null && box.isVisible()) {
box.close();
}
//ask for confirm
box = CommonUtils.getMessageBoxPrompt(run.getNameClient(), new MessageBoxHandler() {
@Override
public void okPressed(String text) {
if(!run.getNameClient().equals( text )) {
run.setName(text);
panelBase.setTitleText(run.getNameClient());
handler.saveData(run);
}
}
});
box.setTitle(AppController.Lang.Name());
box.setMessage(AppController.Lang.EnterName() + ":");
box.show();
}
});
//remove run link
panelBase.addHeaderImageButton(AppController.Lang.RemoveTarget(AppController.Lang.Run().toLowerCase()), MyResources.INSTANCE.iconRemove(),
new Listener<BaseEvent>() {
@Override
public void handleEvent(BaseEvent be) {
setData("btnClick", true);
//ask for confirm
box = CommonUtils.getMessageBoxConfirm(AppController.Lang.RemoveConfirm(AppController.Lang.ThisRun().toLowerCase()), new MessageBoxHandler() {
@Override
public void okPressed(String text) {
handler.runRemoved();
}
});
box.show();
}
});
}
}
} catch (Exception e) {
Motiver.showException(e);
}
}
/**
* Deletes selected measurements from grid
*/
protected void deleteSelectedValues() {
if(grid.getSelectionModel().getSelectedItems().size() > 0) {
//ask for confirm
box = CommonUtils.getMessageBoxConfirm(AppController.Lang.RemoveConfirm(AppController.Lang.SelectedValues().toLowerCase()), new MessageBoxHandler() {
@Override
public void okPressed(String text) {
try {
//get ids of the selected items
List<RunValueModel> list = new ArrayList<RunValueModel>();
for(RunValueModel m : grid.getSelectionModel().getSelectedItems()) {
list.add(m);
//remove item from grid
store.remove(m);
}
handler.valuesRemoved(list);
} catch (Exception e) {
Motiver.showException(e);
}
}
});
box.show();
}
}
}