/*
* Ext GWT 2.2.0 - Ext for GWT
* Copyright(c) 2007-2010, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
package com.extjs.gxt.ui.client.widget.form;
import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.core.XDOM;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.extjs.gxt.ui.client.util.BaseEventPreview;
import com.extjs.gxt.ui.client.util.Rectangle;
import com.extjs.gxt.ui.client.widget.ComponentHelper;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.event.ComponentEvent;
/**
* A file upload filed. When using this field, the containing form panel's
* encoding must be set to MULTIPART using @link
* {@link FormPanel#setEncoding(Encoding)}. In addition, the method should be
* set to POST using
* {@link FormPanel#setMethod(com.extjs.gxt.ui.client.widget.form.FormPanel.Method)}
*
* <p />
* You must set a name for uploads to work with Firefox.
*
*/
public class FileUploadField extends TextField<String> {
public class FileUploadFieldMessages extends TextFieldMessages {
private String browseText = GXT.MESSAGES.uploadField_browseText();
/**
* Returns the browse text.
*
* @return the browse text
*/
public String getBrowseText() {
return browseText;
}
/**
* Sets the browse text.
*
* @param browseText the browse text
*/
public void setBrowseText(String browseText) {
this.browseText = browseText;
}
}
private String accept;
private Button button;
private AbstractImagePrototype buttonIcon;
private int buttonOffset = 3;
private El file;
private BaseEventPreview focusPreview;
/**
* Creates a new file upload field.
*/
public FileUploadField() {
focusPreview = new BaseEventPreview();
focusPreview.setAutoHide(false);
messages = new FileUploadFieldMessages();
ensureVisibilityOnSizing = true;
setWidth(150);
}
/**
* A comma-separated list of content types that a server processing this form
* will handle correctly.
*
*/
public String getAccept() {
if (rendered) {
return ((InputElement) file.dom.cast()).getAccept();
}
return accept;
}
/**
* Returns the button icon class.
*/
public AbstractImagePrototype getButtonIconStyle() {
return buttonIcon;
}
/**
* Returns the button offset.
*/
public int getButtonOffset() {
return buttonOffset;
}
/**
* Returns the file input element. You should not store a reference to this.
* When resetting this field the file input will change.
*/
public InputElement getFileInput() {
return (InputElement) file.dom.cast();
}
@Override
public FileUploadFieldMessages getMessages() {
return (FileUploadFieldMessages) messages;
}
@Override
public String getName() {
if (rendered) {
String n = file.dom.getAttribute("name");
if (!n.equals("")) {
return n;
}
}
return super.getName();
}
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if ((event.getTypeInt() != Event.ONCLICK) && ((Element) event.getEventTarget().cast()).isOrHasChild(file.dom)) {
button.onBrowserEvent(event);
}
}
@Override
public void onComponentEvent(ComponentEvent ce) {
super.onComponentEvent(ce);
switch (ce.getEventTypeInt()) {
case Event.ONCHANGE:
onChange(ce);
break;
case Event.ONKEYDOWN:
if (ce.getKeyCode() != KeyCodes.KEY_TAB && GXT.isAriaEnabled()) {
file.focus();
}
break;
}
}
@Override
public void reset() {
super.reset();
createFileInput();
}
/**
* A comma-separated list of content types that a server processing this form
* will handle correctly.
*
*/
public void setAccept(String accept) {
this.accept = accept;
if (rendered) {
((InputElement) file.dom.cast()).setAccept(accept);
}
}
/**
* Sets the button icon class.
*
* @param buttonIconStyle the button icon style
*/
public void setButtonIcon(AbstractImagePrototype buttonIconStyle) {
this.buttonIcon = buttonIconStyle;
}
/**
* Sets the number of pixels between the input element and the browser button
* (defaults to 3).
*/
public void setButtonOffset(int buttonOffset) {
this.buttonOffset = buttonOffset;
}
@Override
public void setName(String name) {
this.name = name;
if (rendered) {
file.dom.removeAttribute("name");
if (name != null) {
((InputElement) file.dom.cast()).setName(name);
}
}
}
@Override
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
if (button != null) {
button.setEnabled(!readOnly);
}
if (file != null) {
file.setEnabled(!readOnly);
}
}
@Override
protected void afterRender() {
super.afterRender();
el().removeStyleName(fieldStyle);
}
protected void createFileInput() {
if (file != null) {
el().removeChild(file.dom);
}
file = new El((Element) Document.get().createFileInputElement().cast());
file.addEventsSunk(Event.ONCHANGE | Event.FOCUSEVENTS);
file.setId(XDOM.getUniqueId());
file.addStyleName("x-form-file");
file.setTabIndex(-1);
((InputElement) file.dom.cast()).setName(name);
((InputElement) file.dom.cast()).setAccept(accept);
file.insertInto(getElement(), 1);
file.setEnabled(isEnabled());
}
@Override
protected void doAttachChildren() {
super.doAttachChildren();
ComponentHelper.doAttach(button);
}
@Override
protected void doDetachChildren() {
super.doDetachChildren();
ComponentHelper.doDetach(button);
}
@Override
protected El getFocusEl() {
return input;
}
@Override
protected El getInputEl() {
return input;
}
@Override
protected El getStyleEl() {
return input;
}
@Override
protected void onBlur(ComponentEvent ce) {
Rectangle rec = button.el().getBounds();
if (rec.contains(BaseEventPreview.getLastXY())) {
ce.stopEvent();
return;
}
super.onBlur(ce);
focusPreview.remove();
}
protected void onChange(ComponentEvent ce) {
setValue(getFileInput().getValue());
}
@Override
protected void onDetach() {
super.onDetach();
if (focusPreview != null) {
focusPreview.remove();
}
}
@Override
protected void onFocus(ComponentEvent ce) {
super.onFocus(ce);
focusPreview.add();
}
@Override
protected void onRender(Element target, int index) {
El wrap = new El(DOM.createDiv());
wrap.addStyleName("x-form-field-wrap");
wrap.addStyleName("x-form-file-wrap");
input = new El(DOM.createInputText());
input.addStyleName(fieldStyle);
input.addStyleName("x-form-file-text");
input.setId(XDOM.getUniqueId());
if (GXT.isAriaEnabled()) {
input.setTitle("File upload field");
}
if (GXT.isIE && target.getTagName().equals("TD")) {
input.setStyleAttribute("position", "static");
}
wrap.appendChild(input.dom);
setElement(wrap.dom, target, index);
button = new Button(getMessages().getBrowseText());
button.getAriaSupport().setIgnore(true);
button.addStyleName("x-form-file-btn");
button.setIcon(buttonIcon);
button.render(wrap.dom);
createFileInput();
super.onRender(target, index);
super.setReadOnly(true);
}
@Override
protected void onResize(int width, int height) {
super.onResize(width, height);
input.setWidth(width - button.getWidth() - buttonOffset, true);
}
}