teichmann@5835: package org.dive4elements.river.client.client.ui.chart; felix@1545: christian@3855: import com.google.gwt.core.client.GWT; christian@3983: import com.google.gwt.i18n.client.DateTimeFormat; christian@3855: import com.google.gwt.i18n.client.NumberFormat; felix@1545: import com.google.gwt.json.client.JSONArray; felix@1563: import com.google.gwt.json.client.JSONBoolean; felix@1545: import com.google.gwt.json.client.JSONNumber; felix@1545: import com.google.gwt.json.client.JSONParser; felix@1553: import com.google.gwt.json.client.JSONString; felix@1545: import com.google.gwt.user.client.rpc.AsyncCallback; felix@1545: christian@3855: import com.smartgwt.client.types.Alignment; christian@3855: import com.smartgwt.client.types.ListGridFieldType; felix@1545: import com.smartgwt.client.util.SC; christian@3855: import com.smartgwt.client.widgets.Button; christian@3855: import com.smartgwt.client.widgets.IButton; christian@3855: import com.smartgwt.client.widgets.Label; felix@1545: import com.smartgwt.client.widgets.Window; christian@3855: import com.smartgwt.client.widgets.events.ClickEvent; christian@3855: import com.smartgwt.client.widgets.events.ClickHandler; christian@3855: import com.smartgwt.client.widgets.grid.CellEditValueFormatter; christian@3855: import com.smartgwt.client.widgets.grid.CellEditValueParser; christian@3855: import com.smartgwt.client.widgets.grid.CellFormatter; felix@1545: import com.smartgwt.client.widgets.grid.ListGrid; felix@1545: import com.smartgwt.client.widgets.grid.ListGridField; felix@1545: import com.smartgwt.client.widgets.grid.ListGridRecord; felix@1561: import com.smartgwt.client.widgets.grid.events.RecordClickEvent; felix@1561: import com.smartgwt.client.widgets.grid.events.RecordClickHandler; christian@3855: import com.smartgwt.client.widgets.layout.HLayout; christian@3855: import com.smartgwt.client.widgets.layout.VLayout; felix@1545: teichmann@5835: import org.dive4elements.river.client.client.Config; teichmann@5835: import org.dive4elements.river.client.client.FLYSConstants; teichmann@5835: import org.dive4elements.river.client.client.event.RedrawRequestEvent; teichmann@5835: import org.dive4elements.river.client.client.event.RedrawRequestHandler; teichmann@5835: import org.dive4elements.river.client.client.services.FeedServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.services.LoadArtifactServiceAsync; teichmann@5835: import org.dive4elements.river.client.shared.model.Artifact; teichmann@5835: import org.dive4elements.river.client.shared.model.Collection; teichmann@5835: import org.dive4elements.river.client.shared.model.CollectionItem; teichmann@5835: import org.dive4elements.river.client.shared.model.Data; teichmann@5835: import org.dive4elements.river.client.shared.model.DefaultArtifact; teichmann@5835: import org.dive4elements.river.client.shared.model.DefaultData; teichmann@5835: import org.dive4elements.river.client.shared.model.Property; teichmann@5835: import org.dive4elements.river.client.shared.model.PropertyGroup; teichmann@5835: import org.dive4elements.river.client.shared.model.Recommendation; teichmann@5835: import org.dive4elements.river.client.shared.model.Settings; teichmann@5835: import org.dive4elements.river.client.shared.model.StringProperty; felix@1545: christian@3983: import java.util.Date; christian@3855: import java.util.List; felix@1549: felix@1545: felix@1545: /** felix@1545: * UI to enter point data and save it to an PointArtifact. felix@1545: */ felix@1545: public class ManualPointsEditor felix@1545: extends Window felix@1545: implements ClickHandler felix@1545: { felix@1545: /** The interface that provides i18n messages. */ felix@1545: protected FLYSConstants MSG = GWT.create(FLYSConstants.class); felix@1545: felix@2924: /** Part of name of the main data item to be fed. */ felix@1545: public static final String POINT_DATA = "manualpoints.data"; felix@1545: felix@1549: /** When we chaged something, we need a RedrawRequest(Handler). */ felix@1549: protected RedrawRequestHandler redrawRequestHandler; felix@1545: felix@1545: /** The collection */ felix@1545: protected Collection collection; felix@1545: felix@1545: /** The listGrid showing point entries. */ felix@1545: protected ListGrid listGrid; felix@1545: christian@3859: protected ListGridFieldType fieldTypeX = ListGridFieldType.FLOAT; christian@3859: felix@1545: /** Service handle to clone and add artifacts to collection. */ felix@1545: LoadArtifactServiceAsync loadArtifactService = GWT.create( teichmann@5835: org.dive4elements.river.client.client.services.LoadArtifactService.class); felix@1545: felix@1545: /** Service to feed the artifact with new point-data. */ felix@1545: FeedServiceAsync feedService = GWT.create( teichmann@5835: org.dive4elements.river.client.client.services.FeedService.class); felix@1545: felix@1545: /** UUID of artifact to feed. */ felix@1545: protected String uuid; felix@1545: felix@1568: /** Name of the outputmode, important when feeding data. */ felix@1568: protected String outputModeName; felix@1568: felix@2924: /** Name of the point data item. */ felix@2924: protected String pointDataItemName; felix@2924: felix@1545: felix@1545: /** felix@1545: * Setup editor dialog. felix@1545: * @param collection The collection to use. felix@1545: */ felix@1549: public ManualPointsEditor(Collection collection, felix@1568: RedrawRequestHandler handler, String outputModeName felix@1549: ) { felix@1545: this.collection = collection; felix@1549: this.redrawRequestHandler = handler; felix@1568: this.outputModeName = outputModeName; felix@2924: this.pointDataItemName = outputModeName + "." + POINT_DATA; felix@1545: init(); felix@1545: } felix@1545: felix@1545: felix@1545: /** Searches collection for first artifact to serve (manual) point data. */ felix@1545: public String findManualPointsUUID() { felix@1545: // TODO Need to be more picky (different points in different diagrams) felix@1545: int size = collection.getItemLength(); felix@1545: felix@1545: for (int i = 0; i < size; i++) { felix@1545: CollectionItem item = collection.getItem(i); christian@3855: String dataValue = item.getData().get(pointDataItemName); felix@1545: if (dataValue != null) { felix@1545: // Found it. felix@1545: uuid = item.identifier(); felix@1545: return uuid; felix@1545: } felix@1545: } felix@1545: felix@1545: return null; felix@1545: } felix@1545: felix@1545: felix@1545: /** felix@1545: * Initialize the editor window and its components. felix@1545: */ felix@1545: protected void init() { felix@1553: setTitle(MSG.addpoints()); felix@1545: setCanDragReposition(true); felix@1545: setCanDragResize(true); felix@1545: sascha@2905: // If no manualpoints artifact found, create it now. felix@1545: if(findManualPointsUUID() == null) { felix@1545: addArtifactCreateUI(); felix@1545: } felix@1545: else { felix@1545: createUI(); felix@1545: } felix@1545: } felix@1545: felix@1547: felix@1545: /** Create and setup/add the ui. */ felix@1545: public void createUI() { felix@1545: Button accept = new Button(MSG.label_ok()); felix@1545: Button cancel = new Button(MSG.label_cancel()); felix@1545: cancel.addClickHandler(this); felix@1561: felix@1545: accept.addClickHandler(new ClickHandler() { christian@3983: @Override felix@1545: public void onClick(ClickEvent e) { felix@1563: okClicked(); felix@1545: } felix@1545: }); felix@1545: felix@1545: HLayout buttons = new HLayout(); felix@1545: buttons.addMember(accept); felix@1545: buttons.addMember(cancel); felix@1545: buttons.setAlign(Alignment.CENTER); felix@1545: buttons.setHeight(30); felix@1545: felix@1545: VLayout layout = new VLayout(); felix@1545: listGrid = new ListGrid(); felix@1545: listGrid.setWidth100(); raimund@1570: listGrid.setHeight("*"); felix@1561: listGrid.setCanSort(false); felix@1561: listGrid.setCanEdit(true); felix@1561: listGrid.setShowHeaderContextMenu(false); felix@1561: raimund@1569: // Use X and Y as default fallback. raimund@1569: String xAxis = "X"; raimund@1569: String yAxis = "Y"; felix@1563: christian@3983: // Get header text from collection settings raimund@1569: Settings settings = this.collection.getSettings(outputModeName); raimund@1569: List axes = settings.getSettings("axes"); raimund@1569: if(axes != null) { raimund@1569: for (Property p: axes) { raimund@1569: PropertyGroup pg = (PropertyGroup)p; christian@3859: GWT.log(pg.toString()); raimund@1569: StringProperty id = raimund@1569: (StringProperty)pg.getPropertyByName("id"); raimund@1569: if(id.getValue().equals("X")) { raimund@1569: StringProperty name = raimund@1569: (StringProperty)pg.getPropertyByName("label"); raimund@1569: xAxis = name.getValue(); raimund@1569: } raimund@1569: else if (yAxis.equals("Y")) { raimund@1569: StringProperty name = raimund@1569: (StringProperty)pg.getPropertyByName("label"); raimund@1569: yAxis = name.getValue(); raimund@1569: } raimund@1569: } raimund@1569: } christian@3859: christian@3859: CellFormatter format = createCellFormatter(); christian@3859: CellEditValueParser cevp = createCellEditValueParser(); christian@3859: CellEditValueFormatter cevf = createCellEditValueFormatter(); christian@3859: raimund@1569: ListGridField xField = christian@3859: new ListGridField(PointRecord.ATTRIBUTE_X, xAxis); christian@3859: if(xAxis.equalsIgnoreCase("date") || xAxis.equalsIgnoreCase("Datum")) { christian@3983: // FIXME: This is a hack for Timeseries charts with Date types on the x axis christian@3859: xField.setType(ListGridFieldType.DATE); christian@3859: this.fieldTypeX = ListGridFieldType.DATE; christian@3859: } christian@3859: else { christian@3859: xField.setType(ListGridFieldType.FLOAT); christian@3859: xField.setCellFormatter(format); christian@3859: xField.setEditValueParser(cevp); christian@3859: xField.setEditValueFormatter(cevf); christian@3859: } felix@1563: raimund@1569: ListGridField yField = raimund@1569: new ListGridField(PointRecord.ATTRIBUTE_Y, yAxis); felix@1553: yField.setType(ListGridFieldType.FLOAT); christian@3859: yField.setCellFormatter(format); raimund@1604: yField.setEditValueParser(cevp); raimund@1604: yField.setEditValueFormatter(cevf); felix@1563: felix@1562: ListGridField nameField = new ListGridField(PointRecord.ATTRIBUTE_NAME, felix@1553: MSG.pointname()); felix@1561: final ListGridField removeField = felix@1561: new ListGridField("_removeRecord", MSG.removepoint()){{ felix@1561: setType(ListGridFieldType.ICON); felix@1561: setIcon(GWT.getHostPageBaseURL() + MSG.removeFeature()); felix@1561: setCanEdit(false); felix@1561: setCanFilter(false); felix@1561: setCanSort(false); felix@1561: setCanGroupBy(false); felix@1561: setCanFreeze(false); felix@1561: setWidth(25); felix@1561: }}; felix@1561: felix@1563: ListGridField activeField = new ListGridField( felix@1563: PointRecord.ATTRIBUTE_ACTIVE, MSG.selection()); felix@1563: activeField.setType(ListGridFieldType.BOOLEAN); felix@1564: activeField.setDefaultValue(true); felix@1563: felix@1563: listGrid.setFields(new ListGridField[] {activeField, xField, yField, felix@1553: nameField, removeField}); felix@1545: felix@1561: listGrid.addRecordClickHandler(new RecordClickHandler() { christian@3983: @Override felix@1561: public void onRecordClick(final RecordClickEvent event) { felix@1561: // Just handle remove-clicks felix@1561: if(!event.getField().getName().equals(removeField.getName())) { felix@1561: return; sascha@2905: } felix@1561: event.getViewer().removeData(event.getRecord()); felix@1561: } felix@1561: }); felix@1561: christian@3983: // Find the artifacts uuid felix@1545: findManualPointsUUID(); felix@1545: CollectionItem item = collection.getItem(uuid); felix@1545: christian@3983: // Add points to grid felix@1545: if (item != null) { felix@2924: // TODO store this from findPointUUID instead (we touched these). felix@2924: String jsonData = item.getData().get(pointDataItemName); felix@1545: JSONArray jsonArray = (JSONArray) JSONParser.parse(jsonData); felix@1545: for (int i = 0; i < jsonArray.size(); i++) { felix@1545: JSONArray point = (JSONArray) jsonArray.get(i); christian@3983: listGrid.addData(PointRecord.fromJSON(point)); felix@1545: } felix@1545: } felix@1545: else { christian@3983: GWT.log("ManualPointsEditor: No item found for " + uuid); felix@1545: } felix@1545: felix@1553: IButton button = new IButton(MSG.newpoint()); felix@1545: button.setTop(250); felix@1545: button.addClickHandler(new ClickHandler() { christian@3983: @Override felix@1545: public void onClick(ClickEvent event) { felix@1545: listGrid.startEditingNew(); felix@1545: } felix@1545: }); felix@1553: felix@1553: layout.addMember(listGrid); felix@1553: layout.addMember(button); felix@1553: felix@1553: addItem(layout); felix@1553: felix@1545: addItem(buttons); felix@1545: setWidth(380); felix@1545: setHeight(470); felix@1545: centerInPage(); felix@1545: } felix@1545: felix@1545: christian@3859: protected CellFormatter createCellFormatter() { christian@3859: return new CellFormatter() { christian@3983: @Override christian@3859: public String format(Object value, ListGridRecord record, int rowNum, int colNum) { christian@3859: if(value != null) { christian@3859: NumberFormat nf = NumberFormat.getDecimalFormat(); christian@3859: try { christian@3859: double d = Double.valueOf(value.toString()).doubleValue(); christian@3859: return nf.format(d); christian@3859: } catch (Exception e) { christian@3859: return value.toString(); christian@3859: } christian@3859: } else { christian@3859: return null; christian@3859: } christian@3859: }}; christian@3859: } christian@3859: christian@3859: christian@3859: protected CellEditValueParser createCellEditValueParser() { christian@3859: return new CellEditValueParser() { christian@3983: @Override christian@3859: public Object parse(Object value, ListGridRecord record, int rowNum, int colNum) { christian@3859: if (value == null) christian@3859: return null; christian@3859: try { christian@3859: NumberFormat nf = NumberFormat.getDecimalFormat(); christian@3859: double d = nf.parse(value.toString()); christian@3859: return (new Double(d)).toString(); christian@3859: } christian@3859: catch(NumberFormatException nfe) { christian@3859: return value; christian@3859: } christian@3859: } christian@3859: }; christian@3859: } christian@3859: christian@3859: christian@3859: protected CellEditValueFormatter createCellEditValueFormatter() { christian@3859: return new CellEditValueFormatter() { christian@3983: @Override christian@3859: public Object format(Object value, ListGridRecord record, int rowNum, int colNum) { christian@3859: if (value == null) { christian@3859: return ""; christian@3859: } christian@3859: NumberFormat nf = NumberFormat.getDecimalFormat(); christian@3859: try { christian@3859: double d = Double.valueOf(value.toString()).doubleValue(); christian@3859: return nf.format(d); christian@3859: } christian@3859: catch(NumberFormatException nfe) { christian@3859: return value; christian@3859: } christian@3859: } christian@3859: }; christian@3859: } christian@3859: christian@3983: protected String getLocaleDateFormat() { christian@3983: String loc = Config.getInstance().getLocale(); christian@3983: if ("de".equals(loc)) { christian@3983: return "yy.MM.yyyy"; christian@3983: } christian@3983: else { christian@3983: return "MM/dd/yyyy"; christian@3983: } christian@3983: } christian@3983: christian@3983: protected String formatDate(Date date) { christian@3983: DateTimeFormat dtf = DateTimeFormat.getFormat(getLocaleDateFormat()); christian@3983: return dtf.format(date); christian@3983: } christian@3859: felix@1563: /** Create JSON representation of the points present in the list grid. */ felix@1563: protected JSONArray jsonArrayFromListGrid() { felix@1563: JSONArray list = new JSONArray(); felix@1563: int idx = 0; felix@1563: felix@1563: for(ListGridRecord record : listGrid.getRecords()) { felix@1563: if (record instanceof PointRecord) { felix@1563: JSONArray data = new JSONArray(); felix@1563: felix@1563: PointRecord point = (PointRecord) record; christian@3983: if(point.isTimeseriesPoint()) { christian@3983: data.set(0, new JSONString(point.getXAsDate())); christian@3983: GWT.log("Date: " + point.getXAsDate()); christian@3983: } christian@3983: else { christian@3983: data.set(0, new JSONNumber(point.getX())); christian@3983: } felix@1563: data.set(1, new JSONNumber(point.getY())); felix@1563: data.set(2, new JSONString(point.getName())); felix@1563: data.set(3, JSONBoolean.getInstance(point.isActive())); felix@1563: felix@1563: list.set(idx, data); felix@1563: idx++; felix@1563: } felix@1563: else { felix@1563: JSONArray data = new JSONArray(); felix@1563: felix@1565: String nameString = record.getAttributeAsString(PointRecord.ATTRIBUTE_NAME); felix@1563: // Apply default name if none set. felix@1563: if (nameString == null || nameString.equals("")) { felix@1563: String xString = record.getAttributeAsString( felix@1563: PointRecord.ATTRIBUTE_X); felix@1563: String yString = record.getAttributeAsString( felix@1563: PointRecord.ATTRIBUTE_Y); felix@1563: nameString = xString + "/" + yString; felix@1563: } felix@1563: christian@3859: if(fieldTypeX.equals(ListGridFieldType.DATE)) { christian@3983: Date date = record.getAttributeAsDate(PointRecord.ATTRIBUTE_X); christian@3983: data.set(0, new JSONString(formatDate(date))); christian@3983: GWT.log("Date: " + formatDate(date)); christian@3859: } christian@3859: else { christian@3859: data.set(0, new JSONNumber(record. christian@3859: getAttributeAsDouble(PointRecord.ATTRIBUTE_X))); christian@3859: } felix@1563: data.set(1, new JSONNumber(record. felix@1563: getAttributeAsDouble(PointRecord.ATTRIBUTE_Y))); felix@1563: data.set(2, new JSONString(nameString)); felix@1563: data.set(3, JSONBoolean.getInstance(record.getAttributeAsBoolean( felix@1563: PointRecord.ATTRIBUTE_ACTIVE))); felix@1563: felix@1563: list.set(idx, data); felix@1563: idx++; felix@1563: } felix@1563: } felix@1563: return list; felix@1563: } felix@1563: felix@1563: felix@1563: /** felix@1563: * Called when OK Button was clicked. Then, if entered values are valid, felix@1563: * fire a RedrawRequest and destroy. felix@1563: */ felix@1563: protected void okClicked() { felix@1563: if(isDialogValid()) { felix@1563: // Feed JSON-encoded content of listgrid. felix@1563: JSONArray list = jsonArrayFromListGrid(); felix@1563: felix@1563: Data[] feedData = new Data[] { felix@2924: DefaultData.createSimpleStringData(pointDataItemName, felix@1563: list.toString()) felix@1563: }; felix@1563: felix@1563: feedService.feed( felix@1563: Config.getInstance().getLocale(), felix@1563: new DefaultArtifact(uuid, "TODO:hash"), felix@1563: feedData, felix@1563: new AsyncCallback() { christian@3983: @Override felix@1563: public void onFailure(Throwable caught) { felix@1563: GWT.log("Could not feed artifact with points."); felix@1563: SC.warn(MSG.getString(caught.getMessage())); felix@1563: enable(); felix@1563: } christian@3983: @Override felix@1563: public void onSuccess(Artifact fartifact) { christian@3706: GWT.log("Successfully set points"); felix@1563: redrawRequestHandler.onRedrawRequest( felix@1563: new RedrawRequestEvent()); felix@1563: destroy(); felix@1563: } felix@1563: }); felix@1563: } felix@1563: else { felix@1563: GWT.log("Dialog not valid"); felix@1563: SC.warn(MSG.error_dialog_not_valid()); felix@1563: } felix@1563: } felix@1563: felix@1563: felix@1545: /** Add a ManualPointArtifact to Collection. */ felix@1545: public void addArtifactCreateUI() { felix@1553: final Label standByLabel = new Label(MSG.standby()); felix@1545: addItem(standByLabel); felix@1545: felix@1545: setWidth(380); felix@1545: setHeight(470); felix@1545: centerInPage(); felix@1545: felix@1545: Config config = Config.getInstance(); felix@1545: String locale = config.getLocale(); sascha@2905: felix@1545: loadArtifactService.load( felix@1545: this.collection, felix@1545: new Recommendation("manualpoints", ""), felix@1545: "manualpoints", felix@1545: locale, felix@1545: new AsyncCallback() { christian@3983: @Override felix@1545: public void onFailure(Throwable caught) { felix@1545: GWT.log("Creating manualpoint artifact failed!"); felix@1545: } christian@3983: @Override felix@1545: public void onSuccess(Artifact artifact) { felix@1545: GWT.log("Successfully created artifact."); felix@1545: removeItem(standByLabel); felix@1545: uuid = artifact.getUuid(); felix@1545: createUI(); felix@1545: } felix@1545: }); felix@1545: } felix@1545: felix@1545: felix@1545: /** felix@1545: * This method is called when the user aborts point editing. felix@1545: * @param event The event. felix@1545: */ christian@3983: @Override felix@1545: public void onClick(ClickEvent event) { felix@1545: this.destroy(); felix@1545: } felix@1545: felix@1545: felix@1565: /** Return false if x or y attribute is missing. */ felix@1545: protected boolean isDialogValid() { felix@1545: boolean valid = true; felix@1565: for (ListGridRecord record : listGrid.getRecords()) { christian@3859: try { christian@3859: if (record.getAttribute(PointRecord.ATTRIBUTE_X) == null christian@3859: || record.getAttribute(PointRecord.ATTRIBUTE_Y) == null) { christian@3859: return false; christian@3859: } christian@3859: } christian@3859: catch(IllegalArgumentException ex) { christian@3859: felix@1545: } felix@1545: } raimund@1604: if (listGrid.hasErrors()) { raimund@1604: valid = false; raimund@1604: } felix@1545: return valid; felix@1545: } felix@1545: } felix@1545: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :