/*
* 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) {
}
});
}
}