/* * Copyright 2010 Google Inc. * * 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 com.google.gwt.sample.showcase.client.content.cell; import com.google.gwt.cell.client.AbstractEditableCell; import com.google.gwt.cell.client.ActionCell; import com.google.gwt.cell.client.ButtonCell; import com.google.gwt.cell.client.Cell; import com.google.gwt.cell.client.CheckboxCell; import com.google.gwt.cell.client.ClickableTextCell; import com.google.gwt.cell.client.DateCell; import com.google.gwt.cell.client.DatePickerCell; import com.google.gwt.cell.client.EditTextCell; import com.google.gwt.cell.client.FieldUpdater; import com.google.gwt.cell.client.IconCellDecorator; import com.google.gwt.cell.client.ImageCell; import com.google.gwt.cell.client.NumberCell; import com.google.gwt.cell.client.SelectionCell; import com.google.gwt.cell.client.TextCell; import com.google.gwt.cell.client.TextInputCell; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.RunAsyncCallback; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.i18n.client.Constants; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.sample.showcase.client.ContentWidget; import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData; import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseRaw; import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource; import com.google.gwt.sample.showcase.client.content.cell.ContactDatabase.Category; import com.google.gwt.sample.showcase.client.content.cell.ContactDatabase.ContactInfo; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.DataGrid; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.Widget; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * Example file. */ @ShowcaseRaw({"ContactDatabase.java", "CwCellSampler.ui.xml"}) public class CwCellSampler extends ContentWidget { /** * The UiBinder interface used by this example. */ @ShowcaseSource interface Binder extends UiBinder<Widget, CwCellSampler> { } /** * The constants used in this Content Widget. */ @ShowcaseSource public static interface CwConstants extends Constants { String cwCellSamplerDescription(); String cwCellSamplerName(); } /** * The images used for this example. */ @ShowcaseSource static interface Images extends ClientBundle { ImageResource contactsGroup(); } /** * Get a cell value from a record. * * @param <C> the cell type */ @ShowcaseSource private static interface GetValue<C> { C getValue(ContactInfo contact); } /** * A pending change to a {@link ContactInfo}. Changes aren't committed * immediately to illustrate that cells can remember their pending changes. * * @param <T> the data type being changed */ @ShowcaseSource private abstract static class PendingChange<T> { private final ContactInfo contact; private final T value; public PendingChange(ContactInfo contact, T value) { this.contact = contact; this.value = value; } /** * Commit the change to the contact. */ public void commit() { doCommit(contact, value); } /** * Update the appropriate field in the {@link ContactInfo}. * * @param contact the contact to update * @param value the new value */ protected abstract void doCommit(ContactInfo contact, T value); } /** * Updates the birthday. */ @ShowcaseSource private static class BirthdayChange extends PendingChange<Date> { public BirthdayChange(ContactInfo contact, Date value) { super(contact, value); } @Override protected void doCommit(ContactInfo contact, Date value) { contact.setBirthday(value); } } /** * Updates the category. */ @ShowcaseSource private static class CategoryChange extends PendingChange<Category> { public CategoryChange(ContactInfo contact, Category value) { super(contact, value); } @Override protected void doCommit(ContactInfo contact, Category value) { contact.setCategory(value); } } /** * Updates the first name. */ @ShowcaseSource private static class FirstNameChange extends PendingChange<String> { public FirstNameChange(ContactInfo contact, String value) { super(contact, value); } @Override protected void doCommit(ContactInfo contact, String value) { contact.setFirstName(value); } } /** * Updates the last name. */ @ShowcaseSource private static class LastNameChange extends PendingChange<String> { public LastNameChange(ContactInfo contact, String value) { super(contact, value); } @Override protected void doCommit(ContactInfo contact, String value) { contact.setLastName(value); } } /** * The main CellTable. */ @ShowcaseData @UiField(provided = true) DataGrid<ContactInfo> contactList; /** * The commit button. */ @ShowcaseData @UiField Button commitButton; /** * The redraw button. */ @ShowcaseData @UiField Button redrawButton; /** * The list of cells that are editable. */ @ShowcaseData private List<AbstractEditableCell<?, ?>> editableCells; /** * The list of pending changes. */ @ShowcaseData private List<PendingChange<?>> pendingChanges = new ArrayList<PendingChange<?>>(); /** * Constructor. * * @param constants the constants */ public CwCellSampler(CwConstants constants) { super(constants.cwCellSamplerName(), constants.cwCellSamplerDescription(), false, "ContactDatabase.java", "CwCellSampler.ui.xml"); } @Override public boolean hasMargins() { return false; } @Override public boolean hasScrollableContent() { return false; } /** * Initialize this example. */ @ShowcaseSource @Override public Widget onInitialize() { Images images = GWT.create(Images.class); // Create the table. editableCells = new ArrayList<AbstractEditableCell<?, ?>>(); contactList = new DataGrid<ContactInfo>(25, ContactInfo.KEY_PROVIDER); contactList.setMinimumTableWidth(140, Unit.EM); ContactDatabase.get().addDataDisplay(contactList); // CheckboxCell. final Category[] categories = ContactDatabase.get().queryCategories(); addColumn(new CheckboxCell(), "Checkbox", new GetValue<Boolean>() { @Override public Boolean getValue(ContactInfo contact) { // Checkbox indicates that the contact is a relative. // Index 0 = Family. return contact.getCategory() == categories[0]; } }, new FieldUpdater<ContactInfo, Boolean>() { @Override public void update(int index, ContactInfo object, Boolean value) { if (value) { // If a relative, use the Family Category. pendingChanges.add(new CategoryChange(object, categories[0])); } else { // If not a relative, use the Contacts Category. pendingChanges.add(new CategoryChange(object, categories[categories.length - 1])); } } }); // TextCell. addColumn(new TextCell(), "Text", new GetValue<String>() { @Override public String getValue(ContactInfo contact) { return contact.getFullName(); } }, null); // EditTextCell. Column<ContactInfo, String> editTextColumn = addColumn(new EditTextCell(), "EditText", new GetValue<String>() { @Override public String getValue(ContactInfo contact) { return contact.getFirstName(); } }, new FieldUpdater<ContactInfo, String>() { @Override public void update(int index, ContactInfo object, String value) { pendingChanges.add(new FirstNameChange(object, value)); } }); contactList.setColumnWidth(editTextColumn, 16.0, Unit.EM); // TextInputCell. Column<ContactInfo, String> textInputColumn = addColumn(new TextInputCell(), "TextInput", new GetValue<String>() { @Override public String getValue(ContactInfo contact) { return contact.getLastName(); } }, new FieldUpdater<ContactInfo, String>() { @Override public void update(int index, ContactInfo object, String value) { pendingChanges.add(new LastNameChange(object, value)); } }); contactList.setColumnWidth(textInputColumn, 16.0, Unit.EM); // ClickableTextCell. addColumn(new ClickableTextCell(), "ClickableText", new GetValue<String>() { @Override public String getValue(ContactInfo contact) { return "Click " + contact.getFirstName(); } }, new FieldUpdater<ContactInfo, String>() { @Override public void update(int index, ContactInfo object, String value) { Window.alert("You clicked " + object.getFullName()); } }); // ActionCell. addColumn(new ActionCell<ContactInfo>("Click Me", new ActionCell.Delegate<ContactInfo>() { @Override public void execute(ContactInfo contact) { Window.alert("You clicked " + contact.getFullName()); } }), "Action", new GetValue<ContactInfo>() { @Override public ContactInfo getValue(ContactInfo contact) { return contact; } }, null); // ButtonCell. addColumn(new ButtonCell(), "Button", new GetValue<String>() { @Override public String getValue(ContactInfo contact) { return "Click " + contact.getFirstName(); } }, new FieldUpdater<ContactInfo, String>() { @Override public void update(int index, ContactInfo object, String value) { Window.alert("You clicked " + object.getFullName()); } }); // DateCell. DateTimeFormat dateFormat = DateTimeFormat.getFormat(PredefinedFormat.DATE_MEDIUM); addColumn(new DateCell(dateFormat), "Date", new GetValue<Date>() { @Override public Date getValue(ContactInfo contact) { return contact.getBirthday(); } }, null); // DatePickerCell. addColumn(new DatePickerCell(dateFormat), "DatePicker", new GetValue<Date>() { @Override public Date getValue(ContactInfo contact) { return contact.getBirthday(); } }, new FieldUpdater<ContactInfo, Date>() { @Override public void update(int index, ContactInfo object, Date value) { pendingChanges.add(new BirthdayChange(object, value)); } }); // NumberCell. Column<ContactInfo, Number> numberColumn = addColumn(new NumberCell(), "Number", new GetValue<Number>() { @Override public Number getValue(ContactInfo contact) { return contact.getAge(); } }, null); numberColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LOCALE_END); // IconCellDecorator. addColumn(new IconCellDecorator<String>(images.contactsGroup(), new TextCell()), "Icon", new GetValue<String>() { @Override public String getValue(ContactInfo contact) { return contact.getCategory().getDisplayName(); } }, null); // ImageCell. addColumn(new ImageCell(), "Image", new GetValue<String>() { @Override public String getValue(ContactInfo contact) { return "contact.jpg"; } }, null); // SelectionCell. List<String> options = new ArrayList<String>(); for (Category category : categories) { options.add(category.getDisplayName()); } addColumn(new SelectionCell(options), "Selection", new GetValue<String>() { @Override public String getValue(ContactInfo contact) { return contact.getCategory().getDisplayName(); } }, new FieldUpdater<ContactInfo, String>() { @Override public void update(int index, ContactInfo object, String value) { for (Category category : categories) { if (category.getDisplayName().equals(value)) { pendingChanges.add(new CategoryChange(object, category)); break; } } } }); // Create the UiBinder. Binder uiBinder = GWT.create(Binder.class); Widget widget = uiBinder.createAndBindUi(this); // Add handlers to redraw or refresh the table. redrawButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { contactList.redraw(); } }); commitButton.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { // Commit the changes. for (PendingChange<?> pendingChange : pendingChanges) { pendingChange.commit(); } pendingChanges.clear(); // Push the changes to the views. ContactDatabase.get().refreshDisplays(); } }); return widget; } @Override protected void asyncOnInitialize(final AsyncCallback<Widget> callback) { GWT.runAsync(CwCellSampler.class, new RunAsyncCallback() { @Override public void onFailure(Throwable caught) { callback.onFailure(caught); } @Override public void onSuccess() { callback.onSuccess(onInitialize()); } }); } /** * Add a column with a header. * * @param <C> the cell type * @param cell the cell used to render the column * @param headerText the header string * @param getter the value getter for the cell */ @ShowcaseSource private <C> Column<ContactInfo, C> addColumn(Cell<C> cell, String headerText, final GetValue<C> getter, FieldUpdater<ContactInfo, C> fieldUpdater) { Column<ContactInfo, C> column = new Column<ContactInfo, C>(cell) { @Override public C getValue(ContactInfo object) { return getter.getValue(object); } }; column.setFieldUpdater(fieldUpdater); if (cell instanceof AbstractEditableCell<?, ?>) { editableCells.add((AbstractEditableCell<?, ?>) cell); } contactList.addColumn(column, headerText); return column; } }