// Copyright 2010 Google Inc. All Rights Reseved. // // 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.testing.testify.risk.frontend.client.view.widgets; import com.google.common.collect.Lists; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiFactory; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HasValue; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.RadioButton; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; import com.google.testing.testify.risk.frontend.client.util.NotificationUtil; import com.google.testing.testify.risk.frontend.model.AccLabel; import com.google.testing.testify.risk.frontend.model.Attribute; import com.google.testing.testify.risk.frontend.model.Capability; import com.google.testing.testify.risk.frontend.model.Component; import com.google.testing.testify.risk.frontend.model.FailureRate; import com.google.testing.testify.risk.frontend.model.UserImpact; import java.util.Collection; import java.util.List; /** * A capability widget that allows you to edit the details of the capability. Hook up * an update and delete listener to be notified of edits on this widget. * * @author jimr@google.com (Jim Reardon) */ public class EditCapabilityWidget extends Composite implements HasValue<Capability> { interface EditCapabilityWidgetUiBinder extends UiBinder<Widget, EditCapabilityWidget> {} private static final EditCapabilityWidgetUiBinder uiBinder = GWT.create(EditCapabilityWidgetUiBinder.class); private Capability capability; private final List<Attribute> attributes = Lists.newArrayList(); private final List<Component> components = Lists.newArrayList(); @UiField protected FlowPanel labelsPanel; @UiField protected HorizontalPanel failurePanel; @UiField protected HorizontalPanel impactPanel; @UiField protected ListBox attributeBox; @UiField protected ListBox componentBox; @UiField protected TextBox capabilityName; @UiField protected TextArea description; @UiField protected Label capabilityGripper; @UiField protected HorizontalPanel buttonPanel; @UiField public HorizontalPanel savedPanel; @UiField protected EasyDisclosurePanel disclosurePanel; @UiField protected Button cancelButton; @UiField protected Button saveButton; @UiField protected Image deleteImage; @UiField protected Label capabilityId; private final Label capabilityLabel = new Label(); private LabelWidget addNewLabel; private Collection<String> labelSuggestions = Lists.newArrayList(); private boolean isEditable = false; private boolean isDeletable = true; /** * Creates a widget which exposes the ability to edit the widget. * * @param capability the capability for this widget. */ public EditCapabilityWidget(Capability capability) { this.capability = capability; initWidget(uiBinder.createAndBindUi(this)); capabilityLabel.setText(capability.getName()); description.getElement().setAttribute("placeholder", "Enter description of this capability..."); refresh(); } public Widget getCapabilityGripper() { return capabilityGripper; } public void expand() { disclosurePanel.setOpen(true); } public void setAttributes(List<Attribute> attributes) { this.attributes.clear(); this.attributes.addAll(attributes); refresh(); } public void setComponents(List<Component> components) { this.components.clear(); this.components.addAll(components); refresh(); } public long getCapabilityId() { return capability.getCapabilityId(); } public void disableDelete() { isDeletable = false; deleteImage.setVisible(false); } @UiFactory public EasyDisclosurePanel createDisclosurePanel() { EasyDisclosurePanel panel = new EasyDisclosurePanel(capabilityLabel); panel.setOpen(false); return panel; } @UiHandler("deleteImage") protected void handleDelete(ClickEvent event) { String promptText = "Are you sure you want to remove " + capability.getName() + "?"; if (Window.confirm(promptText)) { setValue(null, true); } } @UiHandler("cancelButton") protected void handleCancel(ClickEvent event) { refresh(); } @UiHandler("saveButton") public void handleSave(ClickEvent event) { savedPanel.setVisible(false); long selectedAttribute; long selectedComponent; try { selectedAttribute = Long.parseLong(attributeBox.getValue(attributeBox.getSelectedIndex())); selectedComponent = Long.parseLong(componentBox.getValue(componentBox.getSelectedIndex())); } catch (NumberFormatException e) { NotificationUtil.displayErrorMessage("Couldn't save capability. The attribute or" + " component ID was invalid."); return; } // Handle updates. capability.setName(capabilityName.getValue()); capability.setDescription(description.getValue()); capability.setFailureRate( FailureRate.fromDescription(getSelectedOptionInPanel(failurePanel))); capability.setUserImpact( UserImpact.fromDescription(getSelectedOptionInPanel(impactPanel))); capability.setAttributeId(selectedAttribute); capability.setComponentId(selectedComponent); if ((capability.getComponentId() != selectedComponent) || (capability.getAttributeId() != selectedAttribute)) { Window.alert("The capability " + capability.getName() + " will disappear from the " + " currently visible list because you have changed its attribute or component."); } // Tell the world that we've updated this capability. ValueChangeEvent.fire(this, capability); } public void showSaved() { // Show saved message. savedPanel.setVisible(true); Timer timer = new Timer() { @Override public void run() { savedPanel.setVisible(false); } }; // Make the saved text disappear after 10 seconds. timer.schedule(5000); } /** * Updates the label suggestions for all labels on this view. */ public void setLabelSuggestions(Collection<String> labelSuggestions) { this.labelSuggestions.clear(); this.labelSuggestions.addAll(labelSuggestions); for (Widget w : labelsPanel) { if (w instanceof LabelWidget) { LabelWidget l = (LabelWidget) w; l.setLabelSuggestions(this.labelSuggestions); } } } private void refresh() { capabilityLabel.setText(capability.getName()); capabilityName.setText(capability.getName()); createLabelsPanel(); description.setText(capability.getDescription()); createFailureBox(); createImpactBox(); createAttributeBox(); createComponentBox(); capabilityName.setEnabled(isEditable); capabilityGripper.setVisible(isEditable); description.setEnabled(isEditable); enableOrDisableAllRadioButtons(failurePanel, isEditable); enableOrDisableAllRadioButtons(impactPanel, isEditable); attributeBox.setEnabled(isEditable); componentBox.setEnabled(isEditable); buttonPanel.setVisible(isEditable); } private void createLabelsPanel() { labelsPanel.clear(); for (AccLabel label : capability.getAccLabels()) { createLabel(label); } addBlankLabel(); } private void createLabel(final AccLabel label) { final LabelWidget widget = new LabelWidget(label.getLabelText()); widget.setLabelSuggestions(labelSuggestions); widget.setEditable(isEditable); widget.addValueChangeHandler(new ValueChangeHandler<String>() { @Override public void onValueChange(ValueChangeEvent<String> event) { if (event.getValue() == null) { labelsPanel.remove(widget); capability.removeLabel(label); } else { label.setLabelText(event.getValue()); } } }); labelsPanel.add(widget); } private void addBlankLabel() { final String newText = "new label"; addNewLabel = new LabelWidget(newText, true); addNewLabel.setLabelSuggestions(labelSuggestions); addNewLabel.setEditable(true); addNewLabel.addValueChangeHandler(new ValueChangeHandler<String>() { @Override public void onValueChange(ValueChangeEvent<String> event) { labelsPanel.remove(addNewLabel); AccLabel label = capability.addLabel(event.getValue()); createLabel(label); addBlankLabel(); } }); addNewLabel.setVisible(isEditable); labelsPanel.add(addNewLabel); } private void createFailureBox() { failurePanel.clear(); RadioButton button; for (FailureRate rate : FailureRate.values()) { button = new RadioButton("failure" + capability.getCapabilityId().toString(), rate.getDescription()); failurePanel.add(button); if (rate.equals(capability.getFailureRate())) { button.setValue(true); } } } private void createImpactBox() { impactPanel.clear(); RadioButton button; for (UserImpact impact : UserImpact.values()) { button = new RadioButton("impact" + capability.getCapabilityId().toString(), impact.getDescription()); impactPanel.add(button); if (impact.equals(capability.getUserImpact())) { button.setValue(true); } } } private void enableOrDisableAllRadioButtons(Panel panel, boolean enable) { for (Widget w : panel) { if (w instanceof RadioButton) { RadioButton b = (RadioButton) w; b.setEnabled(enable); } } } private String getSelectedOptionInPanel(Panel panel) { for (Widget w : panel) { if (w instanceof RadioButton) { RadioButton b = (RadioButton) w; if (b.getValue()) { return b.getText(); } } } return null; } private void createAttributeBox() { attributeBox.clear(); int i = 0; for (Attribute attribute : attributes) { attributeBox.addItem(attribute.getName(), attribute.getAttributeId().toString()); if (attribute.getAttributeId() == capability.getAttributeId()) { attributeBox.setSelectedIndex(i); } i++; } } private void createComponentBox() { componentBox.clear(); int i = 0; for (Component component : components) { componentBox.addItem(component.getName(), component.getComponentId().toString()); if (component.getComponentId() == capability.getComponentId()) { componentBox.setSelectedIndex(i); } i++; } } public void makeEditable() { isEditable = true; deleteImage.setVisible(isDeletable); enableOrDisableAllRadioButtons(failurePanel, true); enableOrDisableAllRadioButtons(impactPanel, true); description.setEnabled(true); attributeBox.setEnabled(true); componentBox.setEnabled(true); capabilityName.setEnabled(true); capabilityGripper.setVisible(true); buttonPanel.setVisible(true); for (Widget widget : labelsPanel) { LabelWidget label = (LabelWidget) widget; label.setEditable(true); } addNewLabel.setVisible(true); } @Override public Capability getValue() { return capability; } @Override public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Capability> handler) { return addHandler(handler, ValueChangeEvent.getType()); } @Override public void setValue(Capability capability) { this.capability = capability; } @Override public void setValue(Capability capability, boolean fireEvents) { this.capability = capability; if (fireEvents) { ValueChangeEvent.fire(this, capability); } } }