/* * Copyright 2008 Jeff Dwyer * * 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.apress.progwt.client.college.gui.ext; /* * Copyright 2006 Robert Hanson <iamroberthanson AT gmail.com> * * 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. */ import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.ChangeListener; import com.google.gwt.user.client.ui.ClickListener; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HasText; import com.google.gwt.user.client.ui.HasWordWrap; import com.google.gwt.user.client.ui.KeyboardListenerAdapter; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.MouseListenerAdapter; import com.google.gwt.user.client.ui.SourcesClickEvents; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; /** * Editable Label class, funcionality displays a Label UI Element until * clicked on, then if element is set to be editable (default) then an * editable area and Buttons are displayed instead. * * If the Label is not set to be word wrapped (default) then the editable * area is a Text Box and clicking the OK button or hitting return key in * the TextBox will display the Label with the updated text. * * If the Label is set to be word wrapped, using the setWordWrap(boolean) * method, then the editable area is a Text Area and clicking the OK * button will display the Label with the updated text. * * In both cases, clicking Cancel button or hitting Escape key in the * TextBox/TextArea then the Label is displayed with original text. * * @author Adam Tacy * @version 0.0.2 * * Changes since version 0.0.1 + made cancelLabelChange public [ref * request id: 1518134] + made originalText have default value of empty * string [to support ref request id: 1518134] *End* * * NOTE! This is an extension of the EditableLabel that comes with * http://gwtwidgets.blogspot.com/ The only differences with respect to * the original is that ours has a "hover" listener & associated style * change and we're using the primary/dependent stylgins. ALSO CTOR will * change "" string to "Change Me" so that there's someplace to click * @author Jeff Dwyer * */ public class EditableLabelExtension extends Composite implements HasWordWrap, HasText { protected static final String HOVER_STYLE = "hover"; /** * TextBox element to enable text to be changed if Label is not word * wrapped */ private TextBox changeText; /** * TextArea element to enable text to be changed if Label is * wordwrapped */ private TextArea changeTextArea; /** * Label element, which is initially is diplayed. */ private Label text; /** * String element that contains the original text of a Label prior to * it being edited. */ private String originalText; /** * Simple button to confirm changes */ private Widget confirmChange; /** * Simple button to cancel changes */ private Widget cancelChange; /** * Flag to indicate that Label is in editing mode. */ private boolean isEditing = false; /** * Flag to indicate that label can be edited. */ private boolean isEditable = true; /** * Local copy of the update class passed in to the constructor. */ private ChangeListener updater = null; /** * Default String value for OK button */ private String defaultOkButtonText = "OK"; /** * Default String value for Cancel button */ private String defaultCancelButtonText = "Cancel"; /** * Allows the setting of the isEditable flag, marking the label as * editable or not. * * @param flag * True or False value depending if the Label is to be * editable or not */ public void setEditable(boolean flag) { isEditable = flag; } /** * Returns the value of the isEditable flag. * * @return */ public boolean isFieldEditable() { return isEditable; } /** * Returns the value of the isEditing flag, allowing outside users to * see if the Label is being edited or not. * * @return */ public boolean isInEditingMode() { return isEditing; } /** * Change the displayed label to be a TextBox and copy label text into * the TextBox. * */ private void changeTextLabel() { if (isEditable) { // Set up the TextBox originalText = text.getText(); // Change the view from Label to TextBox and Buttons text.setVisible(false); confirmChange.setVisible(true); cancelChange.setVisible(true); if (text.getWordWrap()) { // If Label word wrapped use the TextArea to edit changeTextArea.setText(originalText); changeTextArea.setVisible(true); changeTextArea.setFocus(true); } else { // Otherwise use the TextBox to edit. changeText.setText(originalText); changeText.setVisible(true); changeText.setFocus(true); } // Set instance as being in editing mode. isEditing = true; } } /** * Restores visibility of Label and hides the TextBox and Buttons * */ private void restoreVisibility() { // Change appropriate visibilities text.setVisible(true); confirmChange.setVisible(false); cancelChange.setVisible(false); if (text.getWordWrap()) { // If Label is word wrapped hide the TextArea changeTextArea.setVisible(false); } else { // Otherwise hide the TextBox changeText.setVisible(false); } // Set isEditing flag to false as we are no longer editing isEditing = false; } /** * Sets the Label text to the new value, restores the display and * calls the update method. * */ private void setTextLabel() { if (text.getWordWrap()) { // Set the Label to be the text in the Text Box text.setText(changeTextArea.getText()); } else { // Set the Label to be the text in the Text Box text.setText(changeText.getText()); } // Set the object back to display label rather than TextBox and // Buttons restoreVisibility(); // Call the update method provided in the Constructor // (this could be anything from alerting the user through to // Making an AJAX call to store the data. updater.onChange(this); } /** * Sets the Label text to the original value, restores the display. * */ public void cancelLabelChange() { // Set the Label text back to what it was originally text.setText(originalText); // Set the object back to display Label rather than TextBox and // Buttons restoreVisibility(); } /** * Creates the Label, the TextBox and Buttons. Also associates the * update method provided in the constructor with this instance. * * @param labelText * The value of the initial Label. * @param onUpdate * The class that provides the update method called when * the Label has been updated. * @param visibleLength * The visible length (width) of the TextBox/TextArea. * @param maxLength * The maximum length of text in the TextBox. * @param maxHeight * The maximum number of visible lines of the TextArea * @param okButtonText * The text diplayed in the OK button. * @param cancelButtonText * The text displayed in the Cancel button. */ private void createEditableLabel(String labelText, ChangeListener onUpdate, String okButtonText, String cancelButtonText) { // Put everything in a VerticalPanel FlowPanel instance = new FlowPanel(); if (labelText == null || labelText.length() < 1) { labelText = "Click to edit me"; } // Create the Label element and add a ClickListener to call out // Change method when clicked text = new Label(labelText); text.setStylePrimaryName("editableLabel-label"); text.addClickListener(new ClickListener() { public void onClick(Widget sender) { changeTextLabel(); } }); text.addMouseListener(new MouseListenerAdapter() { public void onMouseEnter(Widget sender) { text.addStyleDependentName(HOVER_STYLE); } public void onMouseLeave(Widget sender) { text.removeStyleDependentName(HOVER_STYLE); } }); // Create the TextBox element used for non word wrapped Labels // and add a KeyboardListener for Return and Esc key presses changeText = new TextBox(); changeText.setStyleName("editableLabel-textBox"); changeText.addKeyboardListener(new KeyboardListenerAdapter() { public void onKeyPress(Widget sender, char keyCode, int modifiers) { // If return then save, if Esc cancel the change, // otherwise do nothing switch (keyCode) { case 13: setTextLabel(); break; case 27: cancelLabelChange(); break; } } }); // Create the TextAre element used for word-wrapped Labels // and add a KeyboardListener for Esc key presses (not return in // this case) changeTextArea = new TextArea(); changeTextArea.setStyleName("editableLabel-textArea"); changeTextArea.addKeyboardListener(new KeyboardListenerAdapter() { public void onKeyPress(Widget sender, char keyCode, int modifiers) { // If Esc then cancel the change, otherwise do nothing switch (keyCode) { case 27: cancelLabelChange(); break; } } }); // Set up Confirmation Button confirmChange = createConfirmButton(okButtonText); if (!(confirmChange instanceof SourcesClickEvents)) { throw new RuntimeException( "Confirm change button must allow for click events"); } ((SourcesClickEvents) confirmChange) .addClickListener(new ClickListener() { public void onClick(Widget sender) { setTextLabel(); } }); // Set up Cancel Button cancelChange = createCancelButton(cancelButtonText); if (!(cancelChange instanceof SourcesClickEvents)) { throw new RuntimeException( "Cancel change button must allow for click events"); } ((SourcesClickEvents) cancelChange) .addClickListener(new ClickListener() { public void onClick(Widget sender) { cancelLabelChange(); } }); // Put the buttons in a panel FlowPanel buttonPanel = new FlowPanel(); buttonPanel.setStyleName("editableLabel-buttonPanel"); buttonPanel.add(confirmChange); buttonPanel.add(cancelChange); // Add panels/widgets to the widget panel instance.add(text); instance.add(changeText); instance.add(changeTextArea); instance.add(buttonPanel); // Set initial visibilities. This needs to be after // adding the widgets to the panel because the FlowPanel // will mess them up when added. text.setVisible(true); changeText.setVisible(false); changeTextArea.setVisible(false); confirmChange.setVisible(false); cancelChange.setVisible(false); // Set the updater method. updater = onUpdate; // Assume that this is a non word wrapped Label unless explicitly // set otherwise text.setWordWrap(false); // Set the widget that this Composite represents initWidget(instance); } /** * @param cancelButtonText */ protected Widget createCancelButton(String cancelButtonText) { Button result = new Button(); result.setStyleName("editableLabel-buttons"); result.addStyleName("editableLabel-cancel"); result.setText(cancelButtonText); return result; } /** * @param okButtonText */ protected Widget createConfirmButton(String okButtonText) { Button result = new Button(); result.setStyleName("editableLabel-buttons"); result.addStyleName("editableLabel-confirm"); result.setText(okButtonText); return result; } /** * Set the word wrapping on the label (if word wrapped then the * editable field becomes a TextArea, if not then the editable field * is a TextBox. * * @param b * Boolean value, true means Label is word wrapped, false * means it is not. */ public void setWordWrap(boolean b) { text.setWordWrap(b); } /** * Return whether the Label is word wrapped or not. */ public boolean getWordWrap() { return text.getWordWrap(); } /** * Return the text value of the Label */ public String getText() { return text.getText(); } /** * Set the text value of the Label */ public void setText(String newText) { text.setText(newText); } /** * Sets the number of visible lines for a word-wrapped editable label. * * @param number * Number of visible lines. * @throws RuntimeException * if the editable label is not word-wrapped. */ public void setVisibleLines(int number) { if (text.getWordWrap()) { changeTextArea.setVisibleLines(number); } else { throw new RuntimeException( "Cannnot set number of visible lines for a non word-wrapped Editable Label"); } } /** * Get the number of Visible Lines of editable area of a word-wrapped * editable Label. * * @return Number of Visible Lines. * @throws RuntimeException * If the Label is not word-wrapped. */ public int getVisibleLines() { if (text.getWordWrap()) { return changeTextArea.getVisibleLines(); } else { throw new RuntimeException( "Editable Label that is not word-wrapped has no number of Visible Lines"); } } /** * Set maximum length of editable area. * * @param length * Length of editable area. */ public void setMaxLength(int length) { if (text.getWordWrap()) { changeTextArea.setCharacterWidth(length); } else { changeText.setMaxLength(length); } } /** * Get maximum length of editable area. * * @return maximum length of editable area. */ public int getMaxLength() { if (text.getWordWrap()) { return changeTextArea.getCharacterWidth(); } else { return changeText.getMaxLength(); } } /** * Set the visible length of the editable area. * * @throws RuntimeExcpetion * If editable label is word wrapped. */ public void setVisibleLength(int length) { if (text.getWordWrap()) { throw new RuntimeException( "Cannnot set visible length for a word-wrapped Editable Label"); } else { changeText.setVisibleLength(length); } } /** * Get the visible length of the editable area. * * @return Visible length of editable area if not a word wrapped * label. * @throws RuntimeExcpetion * If editable label is word wrapped. */ public int getVisibleLength() { if (text.getWordWrap()) { throw new RuntimeException( "Cannnot get visible length for a word-wrapped Editable Label"); } else { return changeText.getVisibleLength(); } } /** * Constructor that changes default text for buttons and allows the * setting of the wordwrap property directly. * * @param labelText * The initial text of the label. * @param onUpdate * Handler object for performing actions once label is * updated. * @param okText * Text for use in overiding the default OK button text. * @param cancelText * Text for use in overiding the default CANCEL button * text. * @param wordWrap * Boolean representing if the label should be word wrapped * or not */ public EditableLabelExtension(String labelText, ChangeListener onUpdate, String okText, String cancelText, boolean wordWrap) { createEditableLabel(labelText, onUpdate, okText, cancelText); text.setWordWrap(wordWrap); } /** * Constructor that uses default text values for buttons and sets the * word wrap property. * * @param labelText * The initial text of the label. * @param onUpdate * Handler object for performing actions once label is * updated. * @param wordWrap * Boolean representing if the label should be word wrapped * or not */ public EditableLabelExtension(String labelText, ChangeListener onUpdate, boolean wordWrap) { createEditableLabel(labelText, onUpdate, defaultOkButtonText, defaultCancelButtonText); text.setWordWrap(wordWrap); } /** * Constructor that changes default button text. * * @param labelText * The initial text of the label. * @param onUpdate * Handler object for performing actions once label is * updated. * @param okText * Text for use in overiding the default OK button text. * @param cancelText * Text for use in overiding the default CANCEL button * text. */ public EditableLabelExtension(String labelText, ChangeListener onUpdate, String okText, String cancelText) { createEditableLabel(labelText, onUpdate, okText, cancelText); } /** * Constructor that uses default text values for buttons. * * @param labelText * The initial text of the label. * @param onUpdate * Handler object for performing actions once label is * updated. */ public EditableLabelExtension(String labelText, ChangeListener onUpdate) { createEditableLabel(labelText, onUpdate, defaultOkButtonText, defaultCancelButtonText); } /** * Contrucotr with default values and no handler * * @param str */ public EditableLabelExtension(String str) { this(str, new ChangeListener() { public void onChange(Widget sender) { } }); } }