/* * Copyright (C) 2011 aki@akjava.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. */ package com.akjava.gwt.html5.client.file; import static com.google.common.base.Preconditions.checkState; import java.util.ArrayList; import java.util.List; import com.akjava.gwt.html5.client.file.webkit.DirectoryCallback; import com.akjava.gwt.html5.client.file.webkit.FileEntry; import com.akjava.gwt.html5.client.file.webkit.Item; import com.akjava.gwt.lib.client.ImageElementListener; import com.akjava.gwt.lib.client.ImageElementLoader; import com.akjava.gwt.lib.client.LogUtils; import com.akjava.gwt.lib.client.experimental.LoggingImageElementLoader; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.gwt.core.client.JsArray; import com.google.gwt.dom.client.ImageElement; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.DragLeaveEvent; import com.google.gwt.event.dom.client.DragLeaveHandler; import com.google.gwt.event.dom.client.DragOverEvent; import com.google.gwt.event.dom.client.DragOverHandler; import com.google.gwt.event.dom.client.DropEvent; import com.google.gwt.event.dom.client.DropHandler; import com.google.gwt.event.dom.client.ErrorEvent; import com.google.gwt.user.client.Timer; public class FileUtils { /* * can not shift */ public static final native JsArray<File> toFile(NativeEvent event)/*-{ return event.target.files; }-*/; public static final native JsArray<File> transferToFile(NativeEvent event)/*-{ return event.dataTransfer.files; }-*/; public static final native JsArray<Item> transferToItem(NativeEvent event)/*-{ return event.dataTransfer.items; }-*/; public static List<FileEntry> itemsToFileEntryList(JsArray<Item> items){ List<FileEntry> entrys=new ArrayList<FileEntry>(); for(int i=0;i<items.length();i++){ entrys.add(items.get(i).webkitGetAsEntry()); } return entrys; } public static FileUploadForm createSingleFileUploadForm(final DataURLListener listener){ return createSingleFileUploadForm(listener, true, true);//change default support drop } public static FileUploadForm createSingleFileUploadForm(final DataURLListener listener,final boolean reset){ return createSingleFileUploadForm(listener, reset, true);//change default support drop } //only single file & wait loading public static FileUploadForm createImageFileUploadForm(final ImageFileListener listener,final boolean reset,boolean supportOnDrop){ final FileUploadForm form=new FileUploadForm(); form.getDropPanel().addDragOverHandler(new DragOverHandler() { @Override public void onDragOver(DragOverEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(2); } } }); form.getDropPanel().addDragLeaveHandler(new DragLeaveHandler() { @Override public void onDragLeave(DragLeaveEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(0); } } }); if(supportOnDrop){ form.getDropPanel().addDropHandler(new DropHandler() { @Override public void onDrop(DropEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(0); } final FileReader reader = FileReader.createFileReader(); final JsArray<File> files = FileUtils.transferToFile(event .getNativeEvent()); if (files.length() > 0) { reader.setOnLoad(new FileHandler() { @Override public void onLoad() { new LoggingImageElementLoader(){ @Override public void onLoad(ImageElement imageElement) { listener.uploaded(files.get(0), imageElement); } }.load(reader.getResultAsString()); if(reset){ form.reset(); } } }); reader.readAsDataURL(files.get(0)); } event.stopPropagation();//maybe stop root drop,//TODO } }); } form.getFileUpload().addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { final FileReader reader=FileReader.createFileReader(); final JsArray<File> files=FileUtils.toFile(event.getNativeEvent()); final File file=files.get(0); if(files.length()>0){ reader.setOnLoad(new FileHandler() { @Override public void onLoad() { //somehow files is dead here. //LogUtils.log(files.length()+","+files.get(0)); new LoggingImageElementLoader(){ @Override public void onLoad(ImageElement imageElement) { listener.uploaded(file, imageElement); } }.load(reader.getResultAsString()); if(reset){ form.reset(); } } }); reader.readAsDataURL(file); } } }); return form; } //TODO support other case /* * why need reset because sometime you would like to re-upload modified same file.in such case it need reset though it's use change-handler. */ public static FileUploadForm createSingleFileUploadForm(final DataURLListener listener,final boolean reset,boolean supportOnDrop){ final FileUploadForm form=new FileUploadForm(); form.getDropPanel().addDragOverHandler(new DragOverHandler() { @Override public void onDragOver(DragOverEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(2); } } }); form.getDropPanel().addDragLeaveHandler(new DragLeaveHandler() { @Override public void onDragLeave(DragLeaveEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(0); } } }); if(supportOnDrop){ form.getDropPanel().addDropHandler(new DropHandler() { @Override public void onDrop(DropEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(0); } final FileReader reader = FileReader.createFileReader(); final JsArray<File> files = FileUtils.transferToFile(event .getNativeEvent()); if (files.length() > 0) { reader.setOnLoad(new FileHandler() { @Override public void onLoad() { listener.uploaded(files.get(0), reader.getResultAsString()); if(reset){ form.reset(); } } }); reader.readAsDataURL(files.get(0)); } event.stopPropagation();//maybe stop root drop,//TODO } }); } form.getFileUpload().addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { final FileReader reader=FileReader.createFileReader(); final JsArray<File> files=FileUtils.toFile(event.getNativeEvent()); if(files.length()>0){ reader.setOnLoad(new FileHandler() { @Override public void onLoad() { listener.uploaded(files.get(0), reader.getResultAsString()); if(reset){ form.reset(); } } }); reader.readAsDataURL(files.get(0)); } } }); return form; } public static final native void log(String obj)/*-{ $wnd.console.log(obj); }-*/; public static FileUploadForm createSingleFileUploadForm(final DataArrayListener listener){ return createSingleFileUploadForm(listener,true,true); } public static FileUploadForm createSingleFileUploadForm(final DataArrayListener listener,final boolean reset){ return createSingleFileUploadForm(listener,reset,true); } /** * * @param listener * @param reset * @param supportOnDrop ,if root dock catch drop nothing happen here. * @return */ public static FileUploadForm createSingleFileUploadForm(final DataArrayListener listener,final boolean reset,boolean supportOnDrop){ final FileUploadForm form=new FileUploadForm(); form.getDropPanel().addDragOverHandler(new DragOverHandler() { @Override public void onDragOver(DragOverEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(2); } } }); form.getDropPanel().addDragLeaveHandler(new DragLeaveHandler() { @Override public void onDragLeave(DragLeaveEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(0); } } }); if(supportOnDrop){ form.getDropPanel().addDropHandler(new DropHandler() { @Override public void onDrop(DropEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(0); } final FileReader reader = FileReader.createFileReader(); final JsArray<File> files = FileUtils.transferToFile(event .getNativeEvent()); if (files.length() > 0) { reader.setOnLoad(new FileHandler() { @Override public void onLoad() { listener.uploaded(files.get(0), reader.getResultAsBuffer()); if(reset){ form.reset(); } } }); reader.readAsArrayBuffer(files.get(0)); } event.stopPropagation();//maybe stop root drop,//TODO } }); } form.getFileUpload().addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { final FileReader reader=FileReader.createFileReader(); final JsArray<File> files=FileUtils.toFile(event.getNativeEvent()); if(files.length()>0){ reader.setOnLoad(new FileHandler() { @Override public void onLoad() { listener.uploaded(files.get(0), reader.getResultAsBuffer()); if(reset){ form.reset(); } } }); reader.readAsArrayBuffer(files.get(0)); } } }); return form; } public static String getExtension(String name){ int last=name.lastIndexOf("."); if(last!=-1){ return name.substring(last+1); } return null; } /** * * @param listener DataURLListener which get text-file * @param reset do reset selection file name for same file re-upload. * @return */ public static FileUploadForm createSingleTextFileUploadForm(final DataURLListener listener,final boolean reset){ return createSingleTextFileUploadForm(listener,reset,"UTF-8"); } public static FileUploadForm createSingleTextFileUploadForm(final DataURLListener listener,final boolean reset,final String textEncode){ final FileUploadForm form=new FileUploadForm(); form.getDropPanel().addDragOverHandler(new DragOverHandler() { @Override public void onDragOver(DragOverEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(2); } } }); form.getDropPanel().addDragLeaveHandler(new DragLeaveHandler() { @Override public void onDragLeave(DragLeaveEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(0); } } }); form.getDropPanel().addDropHandler(new DropHandler() { @Override public void onDrop(DropEvent event) { event.preventDefault(); if(form.isShowDragOverBorder()){ form.getDropPanel().setBorderWidth(0); } final FileReader reader = FileReader.createFileReader(); final JsArray<File> files = FileUtils.transferToFile(event .getNativeEvent()); if (files.length() > 0) { reader.setOnLoad(new FileHandler() { @Override public void onLoad() { listener.uploaded(files.get(0), reader.getResultAsString()); if(reset){ form.reset(); } } }); reader.readAsText(files.get(0),textEncode); } event.stopPropagation();//maybe stop root drop,//TODO } }); //form.getFileUpload().add form.getFileUpload().addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { //GWT.log("onChange:"); final FileReader reader=FileReader.createFileReader(); final JsArray<File> files=FileUtils.toFile(event.getNativeEvent()); if(files.length()>0){ reader.setOnLoad(new FileHandler() { @Override public void onLoad() { listener.uploaded(files.get(0), reader.getResultAsString()); if(reset){ form.reset(); } } }); reader.readAsText(files.get(0),textEncode); } } }); return form; } //TODO support drag&drop public static FileUploadForm createMultiFileUploadForm(final DataURLsListener listener,final boolean reset){ final FileUploadForm form=new FileUploadForm(); form.setMultiple(true); form.getFileUpload().addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { final FileReader reader=FileReader.createFileReader(); final JsArray<File> tmp=FileUtils.toFile(event.getNativeEvent()); @SuppressWarnings("unchecked") final JsArray<File> files=(JsArray<File>) JsArray.createArray(); for(int i=0;i<tmp.length();i++){ files.push(tmp.get(i)); } final List<File> dataFiles=new ArrayList<File>(); final List<String> values=new ArrayList<String>(); if(files.length()>0){ reader.setOnLoad(new FileHandler() { @Override public void onLoad() { dataFiles.add(files.get(0)); values.add(reader.getResultAsString()); files.shift(); if(files.length()==0){ listener.uploaded(dataFiles,values); if(reset){ form.reset(); } }else{ reader.readAsDataURL(files.get(0)); } } }); reader.readAsDataURL(files.get(0)); } } }); return form; } public interface DataArrayListener{ public void uploaded(final File file,Uint8Array array); } public interface DataURLListener{//utf-8 text or base64 public void uploaded(final File file,String text); } public interface ImageFileListener{//utf-8 text or base64 public void uploaded(final File file,ImageElement imageElement); } public interface DataURLsListener{ public void uploaded(final List<File> files,List<String> values); } public interface DirectoryFileListListener<T>{ public void onList(List<T> files); } public static void readDirectryFileNames(FileEntry directoryFile,final DirectoryFileListListener<String> listener){ readDirectryFileNames(directoryFile,Predicates.<FileEntry>alwaysTrue(),listener); } public static void readDirectryFileNames(FileEntry directoryFile,final Predicate<FileEntry> fileEntryPredicate,final DirectoryFileListListener<String> listener){ checkState(directoryFile.isDirectory(),"directoryFile is not directory"); final DirectoryReader reader=directoryFile.getReader(); final List<String> fileNames=new ArrayList<String>(); DirectoryCallback callback=new DirectoryCallback() { @Override public void callback(JsArray<FileEntry> entries) { for(int i=0;i<entries.length();i++){ FileEntry entry=entries.get(i); if(fileEntryPredicate.apply(entry)){ fileNames.add(entry.getName()); } } if(entries.length()>0){ reader.readEntries(this); }else{ listener.onList(fileNames); } } }; reader.readEntries(callback); } public static void readDirectryFileUrls(FileEntry directoryFile,final Predicate<FileEntry> fileEntryPredicate,final DirectoryFileListListener<String> listener){ checkState(directoryFile.isDirectory(),"directoryFile is not directory"); final DirectoryReader reader=directoryFile.getReader(); final List<String> fileNames=new ArrayList<String>(); DirectoryCallback callback=new DirectoryCallback() { @Override public void callback(JsArray<FileEntry> entries) { for(int i=0;i<entries.length();i++){ FileEntry entry=entries.get(i); if(fileEntryPredicate.apply(entry)){ fileNames.add(entry.toURL()); } } if(entries.length()>0){ reader.readEntries(this); }else{ listener.onList(fileNames); } } }; reader.readEntries(callback); } /* FileUtils.readDirectryFileNames(file, new Predicate<FileEntry>() { @Override public boolean apply(FileEntry input) { // TODO Auto-generated method stub return false; } }, new DirectoryFileListListener<String>() { @Override public void onList(List<String> files) { // TODO Auto-generated method stub } }); */ public static void readDirectryFileEntries(FileEntry directoryFile,final DirectoryFileListListener<FileEntry> listener){ readDirectryFileEntries(directoryFile,Predicates.<FileEntry>alwaysTrue(),listener); } public static void readDirectryFileEntries(FileEntry directoryFile,final Predicate<FileEntry> fileEntryPredicate,final DirectoryFileListListener<FileEntry> listener){ checkState(directoryFile.isDirectory(),"directoryFile is not directory"); final DirectoryReader reader=directoryFile.getReader(); final List<FileEntry> files=new ArrayList<FileEntry>(); DirectoryCallback callback=new DirectoryCallback() { @Override public void callback(JsArray<FileEntry> entries) { for(int i=0;i<entries.length();i++){ FileEntry entry=entries.get(i); if(fileEntryPredicate.apply(entry)){ files.add(entry); } } if(entries.length()>0){ reader.readEntries(this); }else{ listener.onList(files); } } }; reader.readEntries(callback); } }