Mercurial > hg > STI-GWT
view src/econnect/wp3_3/client/widgets/table/DynamicStiTable.java @ 69:ea856995abac trimmed_data
Allow HTML in Description field
author | Sebastian Kruse <skruse@mpiwg-berlin.mpg.de> |
---|---|
date | Thu, 10 Jan 2013 13:20:42 +0100 |
parents | 8b58d9bc0bb6 |
children | a610b45d0f90 |
line wrap: on
line source
package econnect.wp3_3.client.widgets.table; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; import com.google.gwt.user.cellview.client.SimplePager; import com.google.gwt.user.cellview.client.TextColumn; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Anchor; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FormPanel; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.Hidden; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.view.client.CellPreviewEvent; import com.google.gwt.view.client.CellPreviewEvent.Handler; import com.google.gwt.view.client.ListDataProvider; import com.google.gwt.view.client.Range; import com.google.gwt.view.client.RangeChangeEvent; import com.google.gwt.cell.client.SafeHtmlCell; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JsArrayString; import com.google.gwt.dom.client.NodeList; import com.google.gwt.dom.client.Style.BorderStyle; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.http.client.URL; import econnect.wp3_3.client.core.ApplicationConstants; import econnect.wp3_3.client.core.DataObject; import econnect.wp3_3.client.core.DataSet; import econnect.wp3_3.client.core.StiConstants; import econnect.wp3_3.client.core.StiCore; import econnect.wp3_3.client.services.ExportWriterInterface; import econnect.wp3_3.client.services.ExportWriterInterfaceAsync; /** * Implementation of a dynamic table for one dataset */ public class DynamicStiTable extends Grid { /** * The maximum number of rows of the table */ private int maxRows = 10; /** * The sti core component */ private StiCore core; /** * The index of the dataset */ private int index; /** * The dataset of this dynamic table */ private DataSet dataSet; /** * ArrayList that holds all elements that can be shown * (smaller than "dataSet" if showSelected) */ private ArrayList<DataObject> actualObjectSet; /** * Provider that hands the data to the table */ private ListDataProvider<DataObject> dataProvider; /** * CellTable which displays the data */ private CellTable<DataObject> elementsTable; /** * The dataobjects, which are presented at the actual page */ //private DataObject[][] displayedObjects; /** * The number-of-results label */ private Label results; /** * The image for show selected elements */ private Image showSelected; /** * The image for show all elements */ private Image showAll; /** * This value tells the view status: 1 for showAll, -1 for showSelected, 0 otherwise */ private int viewAll = 1; /** * Anchor that holds the URL for the KML download */ private Anchor aDownloadKML; /** * RPC Interface for writing the KML file */ private ExportWriterInterfaceAsync exportWriter; /** * Constructor for initialization of the dynamic table * * @param core object to allow interaction with all javascript components * @param id id of the dataset */ public DynamicStiTable( StiCore stiCore, final int id ){ final ApplicationConstants constants = (ApplicationConstants) GWT.create(ApplicationConstants.class); final StiConstants textConstants = (StiConstants) GWT.create(StiConstants.class); this.resize(2,1); this.addStyleName("dataTable"); this.addStyleName("center"); this.index = id; this.core = stiCore; this.dataSet = core.getDataSets().get(index); this.actualObjectSet = new ArrayList<DataObject>(); setActualObjectSet(); showAll = new Image("images/viewAll"+(core.getColorId(index))+".png"); showAll.setTitle(textConstants.showAll()); showSelected = new Image("images/viewSelected"+(core.getColorId(index))+".png"); showSelected.setTitle(textConstants.showSelected()); showAll.addStyleName("selectedView"); showAll.addStyleName("view"); showSelected.addStyleName("view"); showAll.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { if( viewAll != 1 ){ showSelected.removeStyleName("selectedView"); showAll.addStyleName("selectedView"); viewAll = 1; setActualObjectSet(); } } }); showSelected.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { if( viewAll != -1 ){ viewAll = -1; if( setActualObjectSet() ){ showAll.removeStyleName("selectedView"); showSelected.addStyleName("selectedView"); } else { viewAll = 1; } } } }); Image storeSelected = new Image("images/storeSelected"+(core.getColorId(index))+".png"); storeSelected.setTitle(textConstants.storeSelected()); storeSelected.addStyleName("view"); storeSelected.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { core.storeSelected(id); } }); Grid showOptions = new Grid(1,3); showOptions.setWidget(0,0,showAll); showOptions.setWidget(0,1,showSelected); showOptions.setWidget(0,2,storeSelected); final TextBox textualSearch = new TextBox(); final Button search = new Button("go"); final Image cancelImage = new Image(constants.cancelImage()); final Image refineImage = new Image(constants.refineImage()); final Grid buttons = new Grid(1,2); buttons.setWidget(0, 0, refineImage); buttons.setWidget(0, 1, cancelImage); final Grid refine = new Grid(1,3); refine.setWidget(0,0,textualSearch); refine.setWidget(0,1,search); search.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { if( !textualSearch.getText().equals("") ){ refineByText(textualSearch.getText()); textualSearch.setEnabled(false); refine.setWidget(0, 1, buttons); } } }); refineImage.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { core.refine(); } }); cancelImage.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { textualSearch.setEnabled(true); core.reset(); //TODO: das gibt es nun mehrfach im Code, sollte also in eine Funktion //überfuhrt werden showSelected.removeStyleName("selectedView"); showAll.addStyleName("selectedView"); viewAll = 1; setActualObjectSet(); refine.setWidget(0, 1, search); } }); this.results = new Label(); this.results.setStyleName("resultsLabel"); Label page = new Label(textConstants.page()+":"); page.setStyleName("pageLabel"); //This anchor will hold the URL of the export-file //for download from the ExportServlet aDownloadKML = new Anchor("download KML"); aDownloadKML.setVisible(false); aDownloadKML.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { aDownloadKML.setVisible(false); } }); Image export = new Image(constants.exportImage()); export.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { //create KML file createKMLFile(); } }); export.addStyleName("export"); export.setTitle(textConstants.exportDataSet()); Image delete = new Image(constants.deleteImage()); delete.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { core.deleteDataSet(index); } }); delete.addStyleName("delete"); delete.setTitle(textConstants.deleteDataSet()); Grid func = new Grid(1,3); func.setWidget(0, 0, aDownloadKML); func.setWidget(0, 1, export); func.setWidget(0, 2, delete); func.addStyleName("center"); this.elementsTable = new CellTable<DataObject>(); elementsTable.getElement().getStyle().setWidth(100, Unit.PCT); dataProvider = new ListDataProvider<DataObject>(); dataProvider.addDataDisplay(this.elementsTable); TextColumn<DataObject> nameColumn = new TextColumn<DataObject>() { @Override public String getValue(DataObject object) { return object.getName(); } }; nameColumn.setSortable(true); this.elementsTable.addColumn(nameColumn, "Name"); TextColumn<DataObject> placeColumn = new TextColumn<DataObject>() { @Override public String getValue(DataObject object) { return object.getPlace(); } }; placeColumn.setSortable(true); this.elementsTable.addColumn(placeColumn, "Place"); SafeHtmlCell descriptionCell = new SafeHtmlCell(); Column<DataObject, SafeHtml> descriptionColumn = new Column<DataObject, SafeHtml>(descriptionCell) { @Override public SafeHtml getValue(DataObject object) { SafeHtmlBuilder sb = new SafeHtmlBuilder(); sb.appendHtmlConstant(object.getDescription()); return sb.toSafeHtml(); } }; descriptionColumn.setSortable(true); this.elementsTable.addColumn(descriptionColumn, "Description"); SimplePager pager = new SimplePager(); pager.setDisplay(this.elementsTable); dataProvider.setList(this.actualObjectSet); //The actual (at this time lexicographical) sorting routine. //TODO: remove redundant code, make this more abstract ListHandler<DataObject> columnSortHandler = new ListHandler<econnect.wp3_3.client.core.DataObject>(dataProvider.getList()); JsArrayString descriptionDataColumns = this.dataSet.getDescriptionDataColumns(); for (int i = 0; i < descriptionDataColumns.length(); i++) { final String columnName = descriptionDataColumns.get(i); TextColumn<DataObject> column = new TextColumn<DataObject>() { @Override public String getValue(DataObject object) { return object.getDescriptionData(columnName); } }; column.setSortable(true); columnSortHandler.setComparator(column, new Comparator<econnect.wp3_3.client.core.DataObject>() { public int compare(econnect.wp3_3.client.core.DataObject o1, econnect.wp3_3.client.core.DataObject o2) { if (o1 == o2) return 0; if (o1 != null) return (o2 != null) ? o1.getDescriptionData(columnName).compareTo(o2.getDescriptionData(columnName)) : 1; return -1; } }); this.elementsTable.addColumn(column, columnName); } columnSortHandler.setComparator(nameColumn, new Comparator<econnect.wp3_3.client.core.DataObject>() { public int compare(econnect.wp3_3.client.core.DataObject o1, econnect.wp3_3.client.core.DataObject o2) { if (o1 == o2) return 0; if (o1 != null) return (o2 != null) ? o1.getName().compareTo(o2.getName()) : 1; return -1; } }); columnSortHandler.setComparator(placeColumn, new Comparator<econnect.wp3_3.client.core.DataObject>() { public int compare(econnect.wp3_3.client.core.DataObject o1, econnect.wp3_3.client.core.DataObject o2) { if (o1 == o2) return 0; if (o1 != null) return (o2 != null) ? o1.getPlace().compareTo(o2.getPlace()) : 1; return -1; } }); columnSortHandler.setComparator(descriptionColumn, new Comparator<econnect.wp3_3.client.core.DataObject>() { public int compare(econnect.wp3_3.client.core.DataObject o1, econnect.wp3_3.client.core.DataObject o2) { if (o1 == o2) return 0; if (o1 != null) return (o2 != null) ? o1.getDescription().compareTo(o2.getDescription()) : 1; return -1; } }); this.elementsTable.addColumnSortHandler(columnSortHandler); //Redraw row colors on page change this.elementsTable.addRangeChangeHandler(new RangeChangeEvent.Handler(){ public void onRangeChange(RangeChangeEvent event){ updateView(false); } }); this.elementsTable.setColumnWidth(nameColumn, "33%"); this.elementsTable.setColumnWidth(placeColumn, "33%"); this.elementsTable.setColumnWidth(descriptionColumn, "33%"); //This handler adds the hover-functionality to the table, //basically highlighting of rows (and in the map/timeplot) this.elementsTable.addCellPreviewHandler(new Handler<DataObject>() { //@Override public void onCellPreview( CellPreviewEvent<DataObject> event) { boolean wasChanged = false; if ("mouseover".equals(event.getNativeEvent().getType())) { DataObject hoveredObject = event.getValue(); if (!hoveredObject.getHover()){ hoveredObject.setHover(true); wasChanged = true; } } else if ("mouseout".equals(event.getNativeEvent().getType())) { DataObject hoveredObject = event.getValue(); if (hoveredObject.getHover()){ hoveredObject.setHover(false); wasChanged = true; } } else if ("click".equals(event.getNativeEvent().getType())) { DataObject clickedObject = event.getValue(); if (clickedObject.getPercentage() > 0){ clickedObject.setPercentage(0); } else { clickedObject.setPercentage(1); } wasChanged = true; } if (wasChanged) { updateView(true); core.updateTimeAndMap(); } } }); this.setWidget(1, 0, this.elementsTable); Grid tableControls = new Grid(1,5); tableControls.setWidget(0,0,showOptions); tableControls.setWidget(0,1,refine); tableControls.setWidget(0,2,this.results); tableControls.setWidget(0,3,pager); tableControls.setWidget(0,4,func); tableControls.setStyleName("tableControls"); this.setWidget(0, 0, tableControls); tableControls.getCellFormatter().setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER); this.getCellFormatter().setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER); this.getCellFormatter().setHorizontalAlignment(1, 0, HasHorizontalAlignment.ALIGN_CENTER); this.getCellFormatter().setWidth(1, 0, "100%"); } /** * Sets the actual object set; depends on the showAll and showSelected selection * * @return boolean value, if there are selected objects */ private boolean setActualObjectSet(){ boolean dataSetWasEmpty = false; if( viewAll == -1 ){ this.actualObjectSet.clear(); for( int i=0; i<this.dataSet.getObjects().length(); i++){ DataObject object = this.dataSet.getObjects().get(i); if( object.isSelected() ){ this.actualObjectSet.add(object); } } if( this.actualObjectSet.size() == 0 ){ //TODO: Wenn die derzeitige Auswahl _keine_ Elemente //enthält, werden _alle_ angezeigt. Ist das sinnvoll? dataSetWasEmpty = true; this.viewAll = 1; } } if( this.viewAll == 1 ){ this.actualObjectSet.clear(); for( int i=0; i<this.dataSet.getObjects().length(); i++){ this.actualObjectSet.add(this.dataSet.getObjects().get(i)); } } //if the dataProvider already exists, refresh the //displayed data if (this.dataProvider != null) { //refresh data this.dataProvider.refresh(); this.elementsTable.setRowCount(this.actualObjectSet.size()); this.updateView(false); } if (dataSetWasEmpty) return false; else return true; } /** * Creates a (preliminary) KML file from the data in the current data set */ private void createKMLFile(){ String kmlContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><kml xmlns=\"http://www.opengis.net/kml/2.2\"><Document>"; for( int i=0; i<this.dataSet.getObjects().length(); i++){ DataObject currentDataObject = this.dataSet.getObjects().get(i); String name = currentDataObject.getName(); String description = currentDataObject.getDescription(); String place = currentDataObject.getPlace(); String lat = currentDataObject.getLat(); String lon = currentDataObject.getLon(); String timeStamp = currentDataObject.getTimeStamp(); String timeSpanStart = currentDataObject.getTimeSpanStart(); String timeSpanEnd = currentDataObject.getTimeSpanEnd(); String kmlEntry = "<Placemark>"; kmlEntry += "<name><![CDATA[" + name + "]]></name>"; kmlEntry += "<address><![CDATA[" + place + "]]></address>"; kmlEntry += "<description><![CDATA[" + description + "]]></description>"; kmlEntry += "<Point><coordinates>" + lon + "," + lat + "</coordinates></Point>"; if ( (timeStamp != null) && (timeStamp != "undefined") ) { kmlEntry += "<TimeStamp><when>" + timeStamp + "</when></TimeStamp>"; } else { kmlEntry += "<TimeSpan><begin>" + timeSpanStart + "</begin><end>" + timeSpanEnd + "</end></TimeSpan>"; } kmlEntry += "</Placemark>"; kmlContent += kmlEntry; } kmlContent += "</Document></kml>"; exportWriter = GWT.create(ExportWriterInterface.class); exportWriter.writeKMLFile(kmlContent, new AsyncCallback<String>() { public void onFailure(Throwable caught) { //TODO: error message in layover? //there needs to be an error-window for KML parser failures anyway //this one should be used int i = 1; } public void onSuccess(String exportFileName) { String url = GWT.getModuleBaseURL(); url = url + "ExportServlet?ExportedFilename=" + URL.encode(exportFileName); aDownloadKML.setHref(url); aDownloadKML.setVisible(true); } } ); } /** * Refines the currently selected dataset (table) by the search term entered. * */ private void refineByText(String searchString){ String lowerCaseSearchString = searchString.toLowerCase(); for( int i=0; i<this.dataSet.getObjects().length(); i++){ DataObject currentDataObject = this.dataSet.getObjects().get(i); String name = currentDataObject.getName(); String description = currentDataObject.getDescription(); String place = currentDataObject.getPlace(); if ( name.toLowerCase().contains(lowerCaseSearchString) || description.toLowerCase().contains(lowerCaseSearchString) || place.toLowerCase().contains(lowerCaseSearchString) ) currentDataObject.setPercentage(1); else currentDataObject.setPercentage(0); } updateView(false); core.updateTimeAndMap(); } /** * Updates all cells of the actual page * * @param hover if there was a hover selection which caused to trigger this function */ public void updateView(boolean hover){ if( !hover && this.viewAll == -1 ){ showSelected.removeStyleName("selectedView"); this.viewAll = 0; } //redraw colors of elements (selected/unselected) int start = this.elementsTable.getVisibleRange().getStart(); for (int i=0; i<this.elementsTable.getPageSize(); i++) { if ((start+i) >= dataProvider.getList().size()) break; DataObject object = dataProvider.getList().get(start+i); boolean selected = object.isSelected(); if (hover) selected = object.getHover(); double percentage = (new Double(object.getPercentage()).doubleValue()); String borderColor = StiCore.getBorderColor(this.index,selected); String cellColor = StiCore.getCellColor(this.index,percentage); //TODO: das RowElement ist ein TR. Das hat kein Border, weswegen es //auch keine Farbe bekommt. Erst einmal allen sub-Elementen die //border-Color geben. Das sollte verbessert werden, da DOM-Iterieren //langsam ist. NodeList<TableCellElement> cells = this.elementsTable.getRowElement(i).getCells(); for (int cellIndex=0; cellIndex < cells.getLength(); cellIndex++){ cells.getItem(cellIndex).getStyle().setBorderColor(borderColor); } this.elementsTable.getRowElement(i).getStyle().setBorderColor(borderColor); this.elementsTable.getRowElement(i).getStyle().setBackgroundColor(cellColor); } } public String getTermIdentifier() { return this.dataSet.getTermIdentifier(); } }