├── gradle.properties ├── .dnconfig ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── .sdkmanrc ├── gwt-uploader-demo ├── src │ └── main │ │ ├── webapp │ │ ├── images │ │ │ ├── body-bg.gif │ │ │ ├── hr-content-bg.gif │ │ │ └── header-cell-selected-bg.gif │ │ ├── WEB-INF │ │ │ └── web.xml │ │ ├── index.html │ │ └── style.css │ │ └── java │ │ └── org │ │ └── docstr │ │ └── gwt │ │ └── uploader │ │ └── demo │ │ ├── client │ │ ├── cancel.png │ │ ├── view-source.png │ │ ├── upload_new_version_button.png │ │ ├── AppResources.java │ │ ├── UploaderSample.java │ │ ├── SourceCode.java │ │ ├── SourceCodePopupPanel.java │ │ ├── GwtUploaderDemo.java │ │ ├── ImageButtonAndProgressText.java │ │ ├── TextButtonAndProgressText.java │ │ ├── ImageButtonAndProgressBar.java │ │ ├── MultiUploadWithProgressBar.java │ │ └── MultiUploadWithProgressBarAndDragAndDrop.java │ │ ├── GwtUploaderDemo.gwt.xml │ │ └── shared │ │ └── HttpReq.java └── build.gradle ├── Makefile.txt ├── gwt-uploader ├── src │ └── main │ │ └── java │ │ └── org │ │ └── docstr │ │ └── gwt │ │ └── uploader │ │ ├── Uploader.gwt.xml │ │ └── client │ │ ├── UploaderClientBundle.java │ │ ├── progress │ │ ├── ResizableWidget.java │ │ ├── ResizableWidgetCollection.java │ │ └── ProgressBar.java │ │ ├── events │ │ ├── UploadEvent.java │ │ ├── FileDialogStartEvent.java │ │ ├── FileQueuedEvent.java │ │ ├── FileQueuedHandler.java │ │ ├── UploadProgressHandler.java │ │ ├── UploadStartEvent.java │ │ ├── FileDialogStartHandler.java │ │ ├── UploadCompleteEvent.java │ │ ├── UploadSuccessHandler.java │ │ ├── UploadErrorHandler.java │ │ ├── FileQueueErrorHandler.java │ │ ├── UploadStartHandler.java │ │ ├── UploadCompleteHandler.java │ │ ├── FileDialogCompleteHandler.java │ │ ├── UploadProgressEvent.java │ │ ├── UploadSuccessEvent.java │ │ ├── FileDialogCompleteEvent.java │ │ ├── FileQueueErrorEvent.java │ │ └── UploadErrorEvent.java │ │ ├── Stats.java │ │ └── File.java └── build.gradle ├── Makefile ├── .gitignore ├── .github └── workflows │ └── gradle.yml ├── gradlew.bat ├── README.md ├── gradlew └── LICENSE /gradle.properties: -------------------------------------------------------------------------------- 1 | version = 1.2.5 -------------------------------------------------------------------------------- /.dnconfig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiakuan/gwt-uploader/HEAD/.dnconfig -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiakuan/gwt-uploader/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'gwt-uploader-root' 2 | 3 | include 'gwt-uploader' 4 | include 'gwt-uploader-demo' 5 | -------------------------------------------------------------------------------- /.sdkmanrc: -------------------------------------------------------------------------------- 1 | # Enable auto-env through the sdkman_auto_env config 2 | # Add key=value pairs of SDKs to use below 3 | java=8.0.362-amzn 4 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/webapp/images/body-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiakuan/gwt-uploader/HEAD/gwt-uploader-demo/src/main/webapp/images/body-bg.gif -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/webapp/images/hr-content-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiakuan/gwt-uploader/HEAD/gwt-uploader-demo/src/main/webapp/images/hr-content-bg.gif -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/webapp/images/header-cell-selected-bg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiakuan/gwt-uploader/HEAD/gwt-uploader-demo/src/main/webapp/images/header-cell-selected-bg.gif -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiakuan/gwt-uploader/HEAD/gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/cancel.png -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/view-source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiakuan/gwt-uploader/HEAD/gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/view-source.png -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/upload_new_version_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiakuan/gwt-uploader/HEAD/gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/upload_new_version_button.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /Makefile.txt: -------------------------------------------------------------------------------- 1 | 2 | Usage: make options... 3 | 4 | Option Description 5 | ------ ----------- 6 | clean Clean build directories of projects 7 | build Build projects with tests and quality checking 8 | release Create a new release from master branch 9 | publish Publish the latest version to Maven central 10 | 11 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/Uploader.gwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | index.html 7 | 8 | 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LATEST_TAG?=`git tag|sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | tail -1` 2 | PROJECT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) 3 | 4 | help: 5 | cat Makefile.txt 6 | 7 | clean: 8 | ./gradlew clean 9 | 10 | .PHONY: build 11 | build: 12 | ./gradlew build 13 | 14 | release: 15 | ./gradlew release -Prelease.useAutomaticVersion=true 16 | 17 | publish: 18 | rm -rf $$HOME/.m2/repository/org/docstr/gwt-uploader 19 | ./gradlew build publishMavenJavaPublicationToMavenLocal publishMavenJavaPublicationToMavenRepository 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings 5 | .metadata 6 | .directory 7 | 8 | # Intellij 9 | .idea/ 10 | *.iml 11 | *.iws 12 | 13 | # Mac 14 | .DS_Store 15 | .project 16 | .classpath 17 | target 18 | *.patch 19 | 20 | *.class 21 | **/.gradle/ 22 | **/build/ 23 | /target 24 | 25 | # Mobile Tools for Java (J2ME) 26 | .mtj.tmp/ 27 | 28 | 29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 30 | hs_err_pid* 31 | /gwt-uploader-demo/war/ 32 | /gwt-uploader-demo/src/main/webapp/gwt_uploader_demo/ 33 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/AppResources.java: -------------------------------------------------------------------------------- 1 | package org.docstr.gwt.uploader.demo.client; 2 | 3 | import com.google.gwt.core.shared.GWT; 4 | import com.google.gwt.resources.client.ClientBundle; 5 | import com.google.gwt.resources.client.ImageResource; 6 | 7 | /** 8 | * @author delight.wjk@gmail.com 9 | */ 10 | public interface AppResources extends ClientBundle { 11 | 12 | AppResources INSTANCE = GWT.create(AppResources.class); 13 | 14 | @Source("cancel.png") 15 | ImageResource cancel(); 16 | 17 | @Source("upload_new_version_button.png") 18 | ImageResource upload(); 19 | } 20 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/GwtUploaderDemo.gwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Gradle 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle 3 | 4 | name: Java CI with Gradle 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up JDK 1.8 20 | uses: actions/setup-java@v1 21 | with: 22 | java-version: 1.8 23 | - name: Grant execute permission for gradlew 24 | run: chmod +x gradlew 25 | - name: Build project with Gradle 26 | run: ./gradlew build 27 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/UploaderClientBundle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.docstr.gwt.uploader.client; 18 | 19 | import com.google.gwt.core.client.GWT; 20 | 21 | /** 22 | * @author delight.wjk@gmail.com 23 | */ 24 | public interface UploaderClientBundle extends com.google.gwt.resources.client.ClientBundle { 25 | 26 | static final UploaderClientBundle INSTANCE = GWT.create(UploaderClientBundle.class); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/UploaderSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.docstr.gwt.uploader.demo.client; 18 | 19 | import com.google.gwt.user.client.ui.Widget; 20 | 21 | /** 22 | * @author delight.wjk@gmail.com 23 | */ 24 | public interface UploaderSample { 25 | // TODO: Update this URL to point to a server-side upload handler with CORS enabled. 26 | String UPLOAD_URL = "http://gwt-uploader.appspot.com/upload"; 27 | 28 | Widget getUploaderPanel(); 29 | } 30 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/SourceCode.java: -------------------------------------------------------------------------------- 1 | package org.docstr.gwt.uploader.demo.client; 2 | 3 | import elemental2.core.JsError; 4 | import elemental2.dom.Response; 5 | import org.docstr.gwt.uploader.demo.shared.HttpReq; 6 | 7 | import java.util.function.Consumer; 8 | 9 | import static elemental2.dom.DomGlobal.console; 10 | 11 | /** 12 | * @author jake 13 | */ 14 | public class SourceCode { 15 | public static void fetch(Class clazz, Consumer callback) { 16 | // org.docstr.gwt.uploader.demo.client.ImageButtonAndProgressBar 17 | String url = "https://raw.githubusercontent.com/jiakuan/gwt-uploader/master/gwt-uploader-demo/src/main/java/" + clazz.getName().replace('.', '/') + ".java"; 18 | HttpReq.create(url) 19 | .setRespHandler(new HttpReq.ResponseHandler() { 20 | @Override 21 | public void onResult(Response response) { 22 | response.text().then(text -> { 23 | console.log(text); 24 | callback.accept(text); 25 | return null; 26 | }); 27 | } 28 | 29 | @Override 30 | public void onError(JsError error) { 31 | console.error(error); 32 | callback.accept(error.message); 33 | } 34 | }) 35 | .send(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/progress/ResizableWidget.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.progress; 17 | 18 | import com.google.gwt.user.client.Element; 19 | 20 | /** 21 | * An interface that defines the methods required to support automatic resizing 22 | * of the Widget element. 23 | */ 24 | public interface ResizableWidget { 25 | 26 | /** 27 | * Get the widget's element. 28 | * 29 | * @return The widget's element. 30 | */ 31 | Element getElement(); 32 | 33 | /** 34 | * Check if this widget is attached to the page. 35 | * 36 | * @return true if the widget is attached to the page 37 | */ 38 | boolean isAttached(); 39 | 40 | /** 41 | * This method is called when the dimensions of the parent element change. 42 | * Subclasses should override this method as needed. 43 | * 44 | * @param width the new client width of the element 45 | * @param height the new client height of the element 46 | */ 47 | void onResize(int width, int height); 48 | } 49 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | import org.docstr.gwt.uploader.client.File; 19 | 20 | /** 21 | * The base class of all events that are triggered during the uploader process, 22 | * and includes methods for accessing the general state of the event, 23 | * most notably the details of the file that is being uploaded. 24 | * 25 | * @author delight.wjk@gmail.com 26 | */ 27 | public abstract class UploadEvent { 28 | 29 | private File file; 30 | 31 | /** 32 | * We can only be created by instantiating one of our sub classes. 33 | * 34 | * @param file The native javascript object containing the details of the file being uploaded. 35 | */ 36 | protected UploadEvent(File file) { 37 | this.file = file; 38 | } 39 | 40 | /** 41 | * Return the details of the file upon which the uploader event has occurred. 42 | * 43 | * @return File 44 | */ 45 | public File getFile() { 46 | return file; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/FileDialogStartEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * Provides access to the raw information provided by Uploader when a 'fileDialogStart' event 20 | * occurs. 21 | * This class should not be instantiated directly, but instead you should create a {@link 22 | * FileDialogStartHandler} and register it via the {@link org.docstr.gwt.uploader.client 23 | * .Uploader#setFileDialogStartHandler(FileDialogStartHandler)} method in order to access file 24 | * dialog start events. 25 | *

26 | * Note that the 'fileDialogStart' is fired after selectFile for selectFiles is called. This 27 | * event is fired immediately before the File Selection Dialog window is displayed. However, 28 | * the event may not execute until after the Dialog window is closed. 29 | *

30 | * 31 | * @author delight.wjk@gmail.com 32 | */ 33 | public class FileDialogStartEvent { 34 | 35 | /** 36 | * This constructor is intended for internal use only. You should not create file dialog start 37 | * events directly, but instead should register a {@link FileDialogStartHandler}. 38 | */ 39 | public FileDialogStartEvent() { 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/FileQueuedEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | import org.docstr.gwt.uploader.client.File; 19 | 20 | /** 21 | * Provides access to the raw information provided by Uploader when a 'fileQueued' event occurs. 22 | * This class should not be instantiated directly, but instead you should create a {@link 23 | * FileQueuedHandler} and register it via the {@link org.docstr.gwt.uploader.client 24 | * .Uploader#setFileQueuedHandler(FileQueuedHandler)} method in order to access file queued events. 25 | *

26 | * Note that the 'fileQueued' event is fired for each file that is queued after the File 27 | * Selection Dialog window is closed. 28 | * 29 | * @author delight.wjk@gmail.com 30 | */ 31 | public class FileQueuedEvent { 32 | 33 | private File file; 34 | 35 | /** 36 | * This constructor is intended for internal use only. You should not create file queued events 37 | * directly, but instead should register a {@link FileQueuedHandler}. 38 | * 39 | * @param file The file instance that was added to the queue. 40 | */ 41 | public FileQueuedEvent(File file) { 42 | this.file = file; 43 | } 44 | 45 | /** 46 | * Return the details of the file that was added to the queue. 47 | * 48 | * @return File 49 | */ 50 | public File getFile() { 51 | return file; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/FileQueuedHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * An interface that can be used as a callback handler when file queued events are fired by 20 | * the Uploader component. General usage is as follows: 21 | *

22 |  * uploader.setFileQueuedEventHandler(new FileQueuedHandler() {
23 |  *    public boolean onFileQueued(FileQueuedEvent event) {
24 |  *       Window.alert("File with name " + event.getFile().getName() + " is ready to uploader");
25 |  *       return true;
26 |  *    }
27 |  * });
28 |  * 
29 | * Note that the 'fileQueued' event is fired for each file that is queued after the File 30 | * Selection Dialog window is closed. 31 | *

32 | * See the documentation on the {@link FileQueuedEvent} class for more details on the data 33 | * available when a file queued event occurs. 34 | * 35 | * @author delight.wjk@gmail.com 36 | */ 37 | public interface FileQueuedHandler { 38 | 39 | /** 40 | * This method is fired whenever a file queued event occurs in the Uploader component. See 41 | * the {@link FileQueuedEvent} class for more details on the data available when this event is 42 | * fired. 43 | * 44 | * @param fileQueuedEvent The details of the event that occurred. 45 | * @return The response to send back to the event handler function 46 | */ 47 | public boolean onFileQueued(FileQueuedEvent fileQueuedEvent); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /gwt-uploader/build.gradle: -------------------------------------------------------------------------------- 1 | archivesBaseName = "gwt-uploader" 2 | 3 | dependencies { 4 | } 5 | 6 | signing { 7 | sign publishing.publications 8 | } 9 | 10 | def ossrU = project.hasProperty("ossrhUsername") ? ossrhUsername : "" 11 | def ossrP = project.hasProperty("ossrhPassword") ? ossrhPassword : "" 12 | 13 | publishing { 14 | publications { 15 | mavenJava(MavenPublication) { 16 | from components.java 17 | versionMapping { 18 | usage('java-api') { 19 | fromResolutionOf('runtimeClasspath') 20 | } 21 | usage('java-runtime') { 22 | fromResolutionResult() 23 | } 24 | } 25 | pom { 26 | name = 'GWT Uploader' 27 | description = 'An API to enable sophisticated file upload capabilities within a GWT application.' 28 | url = 'https://github.com/jiakuan/gwt-uploader/' 29 | packaging = 'jar' 30 | licenses { 31 | license { 32 | name = 'The Apache License, Version 2.0' 33 | url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 34 | } 35 | } 36 | developers { 37 | developer { 38 | id = 'jiakuan' 39 | name = 'Jiakuan Wang' 40 | email = 'jake@documentnode.io' 41 | organization = 'Document Node' 42 | organizationUrl = 'https://documentnode.io' 43 | } 44 | } 45 | 46 | scm { 47 | connection = 'scm:git:git@github.com:jiakuan/gwt-uploader.git' 48 | developerConnection = 'scm:git:git@github.com:jiakuan/gwt-uploader.git' 49 | url = 'git@github.com:jiakuan/gwt-uploader.git' 50 | } 51 | } 52 | } 53 | } 54 | repositories { 55 | maven { 56 | def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" 57 | def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" 58 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl 59 | credentials { 60 | username = ossrU 61 | password = ossrP 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadProgressHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * An interface that can be used as a callback handler when uploader progress events are fired by 20 | * the Uploader component. General usage is as follows: 21 | *

22 |  * uploader.setUploadProgressHandler(new UploadProgressHandler() {
23 |  *    public boolean onUploadProgress(UploadProgressEvent event) {
24 |  *       Window.alert("Uploader progressed to " + event.getBytesTotal() + " bytes");
25 |  *       return true;
26 |  *    }
27 |  * });
28 |  * 
29 | *

30 | * Note that the 'uploadProgress' event is fired periodically by the control. This event is 31 | * useful for providing UI updates on the page. 32 | *

33 | * See the documentation on the {@link UploadProgressEvent} class for more details on the data 34 | * available when a progress event occurs. 35 | * 36 | * @author delight.wjk@gmail.com 37 | */ 38 | public interface UploadProgressHandler { 39 | 40 | /** 41 | * This method is fired whenever a progress event occurs in the Uploader component. See 42 | * the {@link UploadProgressEvent} class for more details on the data available when this event 43 | * is fired. 44 | * 45 | * @param uploadProgressEvent The details of the event that occurred. 46 | * @return The response to send back to the event handler function 47 | */ 48 | public boolean onUploadProgress(UploadProgressEvent uploadProgressEvent); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GWT Uploader Code Samples 8 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 |

21 | Your web browser must have JavaScript enabled 22 | in order for this application to display correctly. 23 |
24 | 25 | 26 |

GWT Uploader Code Examples

27 | 28 |

29 | Examples and source code that you can copy. 30 |

31 | 32 |
33 | 34 |
35 | 36 |

Simple Text and Progress Text

37 | 38 |
39 | 40 |
41 | 42 |

Upload Button and Progress Text

43 | 44 |
45 | 46 |
47 | 48 |

Upload Button and Progress Bar

49 | 50 |
51 | 52 |
53 | 54 |

Multi-File Upload with Progress Bars

55 | 56 |
57 | 58 |
59 | 60 |

Multi-File Upload with Progress Bars and Drag and Drop

61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadStartEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | import org.docstr.gwt.uploader.client.File; 19 | 20 | /** 21 | * Provides access to the raw information provided by Uploader when an 'uploader start' event 22 | * occurs. 23 | * This class should not be instantiated directly, but instead you should create a 24 | * {@link UploadStartHandler} and register it via the {@link org.docstr.gwt.uploader.client 25 | * .Uploader#setUploadStartHandler(UploadStartHandler)} method in order to access uploader start 26 | * events. 27 | *

28 | * Note that the 'uploadStart' event is called immediately before the file is uploaded. This event 29 | * provides an opportunity to perform any last minute validation, add post params or do any other 30 | * work before the file is uploaded. 31 | *

32 | * The uploader can be cancelled by returning 'false' from uploadStart in the handler. If you 33 | * return 'true' or do not return 34 | * any value then the uploader proceeds. Returning 'false' will cause an uploadError event to fired. 35 | * 36 | * @author delight.wjk@gmail.com 37 | */ 38 | public class UploadStartEvent extends UploadEvent { 39 | 40 | /** 41 | * This constructor is intended for internal use only. You should not create uploader start 42 | * events directly, but instead should register a {@link UploadStartHandler}. 43 | * 44 | * @param file The native javascript object containing the details of the file being uploaded. 45 | */ 46 | public UploadStartEvent(File file) { 47 | super(file); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/FileDialogStartHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * An interface that can be used as a callback handler when file dialog start events are fired by 20 | * the Uploader component. General usage is as follows: 21 | *

22 |  * uploader.setFileDialogStartHandler(new FileDialogStartHandler() {
23 |  *    public boolean onFileDialogStart(FileDialogStartEvent event) {
24 |  *       Window.alert("Starting the file selection dialog...");
25 |  *       return true;
26 |  *    }
27 |  * });
28 |  * 
29 | * Note that the 'fileDialogStart' is fired after selectFile for selectFiles is called. This 30 | * event is fired immediately before the File Selection Dialog window is displayed. However, 31 | * the event may not execute until after the Dialog window is closed. 32 | *

33 | * See the documentation on the {@link FileDialogStartEvent} class for more details on the data 34 | * available when a file dialog start event occurs. 35 | * 36 | * @author delight.wjk@gmail.com 37 | */ 38 | public interface FileDialogStartHandler { 39 | 40 | /** 41 | * This method is fired whenever a file dialog start event occurs in the Uploader component. See 42 | * the {@link FileDialogStartEvent} class for more details on the data available when this 43 | * event is fired. 44 | * 45 | * @param fileDialogStartEvent The details of the event that occurred. 46 | * @return The response to send back to the event handler function 47 | */ 48 | public boolean onFileDialogStartEvent(FileDialogStartEvent fileDialogStartEvent); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadCompleteEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | import org.docstr.gwt.uploader.client.File; 19 | 20 | /** 21 | * Provides access to the raw information provided by Uploader when an 'uploader complete' event 22 | * occurs. 23 | * This class should not be instantiated directly, but instead you should create a {@link 24 | * UploadCompleteHandler} and register it via the {@link org.docstr.gwt.uploader.client 25 | * .Uploader#setUploadCompleteHandler(UploadCompleteHandler)} method in order to access uploader 26 | * complete events. 27 | *

28 | * Note that the 'uploadComplete' event is always fired at the end of an uploader cycle 29 | * (after uploadError or uploadSuccess). At this point the uploader is complete and another 30 | * uploader can be started. 31 | *

32 | * If you want the next uploader to start automatically this is a good place to call this 33 | * .uploadStart(). 34 | * Use caution when calling uploadStart inside the uploadComplete event if you also have code 35 | * that cancels all the uploads in a queue. 36 | * 37 | * @author delight.wjk@gmail.com 38 | */ 39 | public class UploadCompleteEvent extends UploadEvent { 40 | 41 | /** 42 | * This constructor is intended for internal use only. You should not create uploader complete 43 | * events directly, but instead should register a {@link UploadCompleteHandler}. 44 | * 45 | * @param file The native javascript object containing the details of the file being uploaded. 46 | */ 47 | public UploadCompleteEvent(File file) { 48 | super(file); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/SourceCodePopupPanel.java: -------------------------------------------------------------------------------- 1 | package org.docstr.gwt.uploader.demo.client; 2 | 3 | import com.google.gwt.event.dom.client.ClickEvent; 4 | import com.google.gwt.event.dom.client.ClickHandler; 5 | import com.google.gwt.user.client.Window; 6 | import com.google.gwt.user.client.ui.Button; 7 | import com.google.gwt.user.client.ui.DialogBox; 8 | import com.google.gwt.user.client.ui.HTML; 9 | import com.google.gwt.user.client.ui.HasHorizontalAlignment; 10 | import com.google.gwt.user.client.ui.PopupPanel; 11 | import com.google.gwt.user.client.ui.VerticalPanel; 12 | 13 | /** 14 | * @author jiakuanwang 15 | */ 16 | public class SourceCodePopupPanel extends DialogBox { 17 | 18 | private HTML html = new HTML(); 19 | 20 | public SourceCodePopupPanel() { 21 | // PopupPanel's constructor takes 'auto-hide' as its boolean parameter. 22 | // If this is set, the panel closes itself automatically when the user 23 | // clicks outside of it. 24 | super(true); 25 | // Set the dialog box's caption. 26 | setText("Source Code"); 27 | 28 | // Enable animation. 29 | setAnimationEnabled(true); 30 | 31 | // Enable glass background. 32 | setGlassEnabled(true); 33 | Button btnClose = new Button("Close"); 34 | btnClose.addClickHandler(new ClickHandler() { 35 | @Override 36 | public void onClick(ClickEvent event) { 37 | hide(); 38 | } 39 | }); 40 | VerticalPanel panel = new VerticalPanel(); 41 | panel.add(html); 42 | panel.add(btnClose); 43 | panel.setCellHorizontalAlignment(btnClose, HasHorizontalAlignment.ALIGN_RIGHT); 44 | setWidget(panel); 45 | } 46 | 47 | public void showSourceCode(String sourceCode) { 48 | int width = (Window.getClientWidth() - 200); 49 | int height = (Window.getClientHeight() - 200); 50 | html.setHTML( 51 | "

"
52 |         + sourceCode + "
"); 53 | setPopupPositionAndShow(new PopupPanel.PositionCallback() { 54 | public void setPosition(int offsetWidth, int offsetHeight) { 55 | int left = (Window.getClientWidth() - offsetWidth) / 2; 56 | int top = (Window.getClientHeight() - offsetHeight) / 2; 57 | setPopupPosition(left, top); 58 | } 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadSuccessHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * An interface that can be used as a callback handler when uploader success events are fired by 20 | * the Uploader component. General usage is as follows: 21 | *
22 |  * uploader.setUploadSuccessHandler(new UploadSuccessHandler() {
23 |  *    public boolean onUploadSuccess(UploadSuccessEvent event) {
24 |  *       Window.alert("Successfully uploaded " + event.getFile().getName());
25 |  *       return true;
26 |  *    }
27 |  * });
28 |  * 
29 | *

30 | * Note that 'uploadSuccess' is fired when the entire uploader has been transmitted and the server 31 | * returns a HTTP 200 status code. Any data outputted by the server is available in the server 32 | * data property. 33 | *

34 | * At this point the uploader is not yet complete. Another uploader cannot be started from 35 | * uploadSuccess. 36 | *

37 | * See the documentation on the {@link UploadSuccessEvent} class for more details on the data 38 | * available when an uploader success event occurs. 39 | * 40 | * @author delight.wjk@gmail.com 41 | */ 42 | public interface UploadSuccessHandler { 43 | 44 | /** 45 | * This method is fired whenever a uploader success event occurs in the Uploader component. See 46 | * the {@link UploadSuccessEvent} class for more details on the data available when this event 47 | * is fired. 48 | * 49 | * @param uploadSuccessEvent The details of the event that occurred. 50 | * @return The response to send back to the event handler function 51 | */ 52 | public boolean onUploadSuccess(UploadSuccessEvent uploadSuccessEvent); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadErrorHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * An interface that can be used as a callback handler when uploader error events are fired by 20 | * the Uploader component. General usage is as follows: 21 | *

22 |  * uploader.setUploadErrorHandler(new UploadErrorHandler() {
23 |  *    public boolean onUploadError(UploadErrorEvent event) {
24 |  *       Window.alert("Unable to uploader file " + event.getFile().getName());
25 |  *       return true;
26 |  *    }
27 |  * });
28 |  * 
29 | *

30 | * Note that the 'uploadError' event is fired any time an uploader is interrupted or does not 31 | * complete successfully. The error code parameter indicates the type of error that occurred. 32 | *

33 | * Stopping, Cancelling or returning 'false' from uploadStart will cause uploadError to fire. 34 | * Uploader error will not fire for files that are cancelled but still waiting in the queue. 35 | *

36 | * See the documentation on the {@link UploadErrorEvent} class for more details on the data 37 | * available when an uploader error event occurs. 38 | * 39 | * @author delight.wjk@gmail.com 40 | */ 41 | public interface UploadErrorHandler { 42 | 43 | /** 44 | * This method is fired whenever a uploader error event occurs in the Uploader component. See 45 | * the {@link UploadErrorEvent} class for more details on the data available when this event is 46 | * fired. 47 | * 48 | * @param uploadErrorEvent The details of the event that occurred. 49 | * @return The response to send back to the event handler function 50 | */ 51 | public boolean onUploadError(UploadErrorEvent uploadErrorEvent); 52 | 53 | } 54 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/FileQueueErrorHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * An interface that can be used as a callback handler when file queue error events are fired by 20 | * the Uploader component. General usage is as follows: 21 | *

22 |  * uploader.setFileQueueErrorEventHandler(new FileQueueErrorHandler() {
23 |  *    public boolean onFileQueueError(FileQueueErrorEvent event) {
24 |  *       Window.alert("File with name " + event.getFile().getName() + " failed in the queue due
25 |  *       to: " + event.getErrorCode().toString());
26 |  *       return true;
27 |  *    }
28 |  * });
29 |  * 
30 | * Note that the 'fileQueueError' event is fired for each file that was not queued after the File 31 | * Selection Dialog window is closed. A file may not be queued for several reasons such as, 32 | * the file exceeds the file size, the file is empty or a file or queue limit has been exceeded. 33 | *

34 | * See the documentation on the {@link FileQueueErrorEvent} class for more details on the data 35 | * available when a file queue error event occurs. 36 | * 37 | * @author delight.wjk@gmail.com 38 | */ 39 | public interface FileQueueErrorHandler { 40 | 41 | /** 42 | * This method is fired whenever a file queue error event occurs in the Uploader component. See 43 | * the {@link org.docstr.gwt.uploader.client.events.FileQueueErrorEvent} class for more 44 | * details on the data available when this event is fired. 45 | * 46 | * @param fileQueueErrorEvent The details of the event that occurred. 47 | * @return The response to send back to the event handler function 48 | */ 49 | public boolean onFileQueueError(FileQueueErrorEvent fileQueueErrorEvent); 50 | 51 | } 52 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadStartHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * An interface that can be used as a callback handler when uploader start events are fired by 20 | * the Uploader component. General usage is as follows: 21 | *

22 |  * uploader.setUploadStartHandler(new UploadStartHandler() {
23 |  *    public boolean onUploadStart(UploadStartEvent event) {
24 |  *       Window.alert("Beginning uploader of " + event.getFile().getName());
25 |  *       return true;
26 |  *    }
27 |  * });
28 |  * 
29 | *

30 | * Note that the 'uploadStart' event is called immediately before the file is uploaded. This event 31 | * provides an opportunity to perform any last minute validation, add post params or do any other 32 | * work before the file is uploaded. 33 | *

34 | * The uploader can be cancelled by returning 'false' from uploadStart in the handler. If you return 35 | * 'true' or do not return any value then the uploader proceeds. Returning 'false' will cause an 36 | * uploadError event to fired. 37 | *

38 | * See the documentation on the {@link UploadStartEvent} class for more details on the data 39 | * available when an uploader start event occurs. 40 | * 41 | * @author delight.wjk@gmail.com 42 | */ 43 | public interface UploadStartHandler { 44 | 45 | /** 46 | * This method is fired whenever a uploader start event occurs in the Uploader component. See 47 | * the {@link UploadStartEvent} class for more details on the data available when this event is 48 | * fired. 49 | * 50 | * @param uploadStartEvent The details of the event that occurred. 51 | * @return The response to send back to the event handler function 52 | */ 53 | public boolean onUploadStart(UploadStartEvent uploadStartEvent); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadCompleteHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * An interface that can be used as a callback handler when uploader completion events are fired by 20 | * the Uploader component. General usage is as follows: 21 | *

22 |  * uploader.setUploadCompleteHandler(new UploadCompleteHandler() {
23 |  *    public boolean onUploadComplete(UploadCompleteEvent event) {
24 |  *       Window.alert("Uploader complete for file " + event.getFile().getName());
25 |  *       return true;
26 |  *    }
27 |  * });
28 |  * 
29 | *

30 | * Note that the 'uploadComplete' event is always fired at the end of an uploader cycle 31 | * (after uploadError or uploadSuccess). At this point the uploader is complete and another 32 | * uploader can be started. 33 | *

34 | * If you want the next uploader to start automatically this is a good place to call this 35 | * .uploadStart(). 36 | * Use caution when calling uploadStart inside the uploadComplete event if you also have code 37 | * that cancels all the uploads in a queue. 38 | *

39 | * See the documentation on the {@link UploadCompleteEvent} class for more details on the data 40 | * available when an uploader complete event occurs. 41 | * 42 | * @author delight.wjk@gmail.com 43 | */ 44 | public interface UploadCompleteHandler { 45 | 46 | /** 47 | * This method is fired whenever a uploader completion event occurs in the Uploader component. 48 | * See the {@link UploadCompleteEvent} class for more details on the data available when this 49 | * event is fired. 50 | * 51 | * @param uploadCompleteEvent The details of the event that occurred. 52 | * @return The response to send back to the event handler function 53 | */ 54 | public boolean onUploadComplete(UploadCompleteEvent uploadCompleteEvent); 55 | 56 | } 57 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/FileDialogCompleteHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * An interface that can be used as a callback handler when file dialog complete events are fired by 20 | * the Uploader component. General usage is as follows: 21 | *

22 |  * uploader.setFileDialogCompleteHandler(new FileDialogCompleteHandler() {
23 |  *    public boolean onFileDialogComplete(FileDialogCompleteEvent event) {
24 |  *       Window.alert(event.getTotalFilesInQueue() + " are ready to uploader");
25 |  *       return true;
26 |  *    }
27 |  * });
28 |  * 
29 | * Note that the 'fileDialogComplete' event fires after the File Selection Dialog window has been 30 | * closed and all the selected files have been processed. The 'number of files queued' property 31 | * indicates the number of files that were queued from the dialog selection (as opposed to the 32 | * number of files in the queue). 33 | *

34 | * If you want file uploading to begin automatically this is a good place to call {@link com 35 | * .jakecode.gwt.uploader.client.Uploader#startUpload()}. 36 | *

37 | * See the documentation on the {@link FileDialogCompleteEvent} class for more details on the data 38 | * available when a file dialog complete event occurs. 39 | * 40 | * @author delight.wjk@gmail.com 41 | */ 42 | public interface FileDialogCompleteHandler { 43 | 44 | /** 45 | * This method is fired whenever a file dialog complete event occurs in the Uploader component. 46 | * See the {@link FileDialogCompleteEvent} class for more details on the data available when 47 | * this event is fired. 48 | * 49 | * @param fileDialogCompleteEvent The details of the event that occurred. 50 | * @return The response to send back to the event handler function 51 | */ 52 | public boolean onFileDialogComplete(FileDialogCompleteEvent fileDialogCompleteEvent); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadProgressEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | import org.docstr.gwt.uploader.client.File; 19 | 20 | /** 21 | * Provides access to the raw information provided by Uploader when an 'uploader progress' event 22 | * occurs. 23 | * This class should not be instantiated directly, but instead you should create a 24 | * {@link UploadProgressHandler} and register it via the {@link org.docstr.gwt.uploader.client 25 | * .Uploader#setUploadProgressHandler(UploadProgressHandler)} method in order to access progress 26 | * events. 27 | *

28 | * Note that the 'uploadProgress' event is fired periodically by the control. This event is 29 | * useful for providing UI updates on the page. 30 | *

31 | * 32 | * @author delight.wjk@gmail.com 33 | */ 34 | public class UploadProgressEvent extends UploadEvent { 35 | 36 | private long bytesComplete; 37 | private long bytesTotal; 38 | 39 | /** 40 | * This constructor is intended for internal use only. You should not create progress events 41 | * directly, but instead should register a {@link UploadProgressHandler}. 42 | * 43 | * @param file The native javascript object containing the details of the file being uploaded. 44 | * @param bytesComplete Bytes transferred since the uploader process began. 45 | * @param bytesTotal Total size of the file being uploaded. 46 | */ 47 | public UploadProgressEvent(File file, long bytesComplete, long bytesTotal) { 48 | super(file); 49 | this.bytesComplete = bytesComplete; 50 | this.bytesTotal = bytesTotal; 51 | } 52 | 53 | /** 54 | * Return the bytes transferred since the uploader process began. 55 | * @return double 56 | */ 57 | public long getBytesComplete() { 58 | return bytesComplete; 59 | } 60 | 61 | /** 62 | * Return the total size of the file being uploaded. 63 | * @return long 64 | */ 65 | public long getBytesTotal() { 66 | return bytesTotal; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/GwtUploaderDemo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.docstr.gwt.uploader.demo.client; 18 | 19 | import com.google.gwt.core.client.EntryPoint; 20 | import com.google.gwt.dom.client.Style; 21 | import com.google.gwt.user.client.ui.Button; 22 | import com.google.gwt.user.client.ui.RootPanel; 23 | import com.google.gwt.user.client.ui.VerticalPanel; 24 | import com.google.gwt.user.client.ui.Widget; 25 | 26 | import java.util.HashMap; 27 | import java.util.Map; 28 | 29 | import static elemental2.dom.DomGlobal.console; 30 | 31 | /** 32 | * @author delight.wjk@gmail.com 33 | */ 34 | public class GwtUploaderDemo implements EntryPoint { 35 | 36 | private Map uploaderPanels = new HashMap<>(); 37 | private SourceCodePopupPanel sourceCodePopup = new SourceCodePopupPanel(); 38 | 39 | @Override 40 | public void onModuleLoad() { 41 | console.log("GwtUploaderDemo.onModuleLoad() - " + ImageButtonAndProgressBar.class.getName()); 42 | 43 | uploaderPanels.put("TextButtonAndProgressText", new TextButtonAndProgressText()); 44 | uploaderPanels.put("ImageButtonAndProgressText", new ImageButtonAndProgressText()); 45 | uploaderPanels.put("ImageButtonAndProgressBar", new ImageButtonAndProgressBar()); 46 | uploaderPanels.put("MultiUploadWithProgressBar", new MultiUploadWithProgressBar()); 47 | uploaderPanels.put("MultiUploadWithProgressBarAndDragAndDrop", 48 | new MultiUploadWithProgressBarAndDragAndDrop()); 49 | 50 | for (Map.Entry entry : uploaderPanels.entrySet()) { 51 | final UploaderSample sample = entry.getValue(); 52 | final Widget uploaderPanel = sample.getUploaderPanel(); 53 | final Button btnViewSource = new Button("View Source"); 54 | btnViewSource.getElement().getStyle().setMarginTop(10, Style.Unit.PX); 55 | btnViewSource.addClickHandler(event -> { 56 | sourceCodePopup.showSourceCode("Loading source code..."); 57 | SourceCode.fetch(sample.getClass(), source -> 58 | sourceCodePopup.showSourceCode(source)); 59 | }); 60 | VerticalPanel panel = new VerticalPanel(); 61 | panel.add(uploaderPanel); 62 | panel.add(btnViewSource); 63 | RootPanel.get(entry.getKey()).add(panel); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/Stats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client; 17 | 18 | import com.google.gwt.core.client.JavaScriptObject; 19 | 20 | import org.docstr.gwt.uploader.client.events.FileQueueErrorHandler; 21 | 22 | /** 23 | * A simple bean that provides access to the statistical counters managed by the Uploader 24 | * component. An instance of this object is available dynamically via the 25 | * {@link Uploader#getStats()} method. 26 | * 27 | * @author delight.wjk@gmail.com 28 | */ 29 | public final class Stats extends JavaScriptObject { 30 | 31 | /** 32 | * Instances of the Stats object can not be created directly, but should instead 33 | * be obtained via the {@link Uploader#getStats()} method. 34 | */ 35 | protected Stats() { 36 | } 37 | 38 | /** 39 | * Return a 1 or 0 indicating if a file upload is currently in progress. 40 | * 41 | * @return int 42 | */ 43 | public native int getUploadsInProgress() /*-{ 44 | return (this && this.in_progress) || 0; 45 | }-*/; 46 | 47 | /** 48 | * Return the number of files currently in the queue. 49 | * 50 | * @return int 51 | */ 52 | public native int getFilesQueued() /*-{ 53 | return (this && this.files_queued) || 0; 54 | }-*/; 55 | 56 | /** 57 | * Return the number of files that have uploaded successfully (caused uploadSuccess to be fired). 58 | * 59 | * @return int 60 | */ 61 | public native int getSuccessfulUploads() /*-{ 62 | return (this && this.successful_uploads) || 0; 63 | }-*/; 64 | 65 | /** 66 | * Return the number of files that have had errors (excluding cancelled files). 67 | * 68 | * @return int 69 | */ 70 | public native int getUploadErrors() /*-{ 71 | return (this && this.upload_errors) || 0; 72 | }-*/; 73 | 74 | /** 75 | * Return the number of files that have been cancelled. 76 | * 77 | * @return int 78 | */ 79 | public native int getUploadsCancelled() /*-{ 80 | return (this && this.upload_cancelled) || 0; 81 | }-*/; 82 | 83 | /** 84 | * Return the number of files that caused the {@link FileQueueErrorHandler} 85 | * to be fired. 86 | * 87 | * @return int 88 | */ 89 | public native int getQueueErrors() /*-{ 90 | return (this && this.queue_errors) || 0; 91 | }-*/; 92 | 93 | } 94 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadSuccessEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | import org.docstr.gwt.uploader.client.File; 19 | 20 | /** 21 | * Provides access to the raw information provided by Uploader when an 'uploader success' event 22 | * occurs. 23 | * This class should not be instantiated directly, but instead you should create a 24 | * {@link UploadSuccessHandler} and register it via the {@link org.docstr.gwt.uploader.client 25 | * .Uploader#setUploadSuccessHandler(UploadSuccessHandler)} 26 | * method in order to access uploader success events. 27 | *

28 | * Note that 'uploadSuccess' is fired when the entire uploader has been transmitted and the server 29 | * returns a HTTP 200 status code. Any data outputted by the server is available in the server 30 | * data property. 31 | *

32 | * At this point the uploader is not yet complete. Another uploader cannot be started from 33 | * uploadSuccess. 34 | * 35 | * @author delight.wjk@gmail.com 36 | */ 37 | public class UploadSuccessEvent extends UploadEvent { 38 | 39 | private String serverData; 40 | private String responseReceived; 41 | 42 | /** 43 | * This constructor is intended for internal use only. You should not create uploader success 44 | * events directly, but instead should register a {@link UploadSuccessHandler}. 45 | * 46 | * @param file The native javascript object containing the details of the file being uploaded. 47 | * @param serverData Any HTTP response data sent from the server at the completion of the 48 | * uploader. 49 | * @param responseReceived The HTTP response code sent from the server at the completion of the 50 | * uploader. 51 | */ 52 | public UploadSuccessEvent(File file, String serverData, String responseReceived) { 53 | super(file); 54 | this.serverData = serverData; 55 | this.responseReceived = responseReceived; 56 | } 57 | 58 | /** 59 | * Return any HTTP response data sent from the server at the completion of the uploader. 60 | * 61 | * @return String 62 | */ 63 | public String getServerData() { 64 | return serverData; 65 | } 66 | 67 | /** 68 | * Return the HTTP response code sent from the server at the completion of the uploader. 69 | * 70 | * @return String 71 | */ 72 | public String getResponseReceived() { 73 | return responseReceived; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/FileDialogCompleteEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | /** 19 | * Provides access to the raw information provided by Uploader when a 'fileDialogComplete' event 20 | * occurs. 21 | * This class should not be instantiated directly, but instead you should create a {@link 22 | * FileDialogCompleteHandler} and 23 | * register it via the {@link org.docstr.gwt.uploader.client 24 | * .Uploader#setFileDialogCompleteHandler(FileDialogCompleteHandler)} 25 | * method in order to access file dialog complete events. 26 | *

27 | * Note that the 'fileDialogComplete' event fires after the File Selection Dialog window has been 28 | * closed and all the selected files have been processed. The 'number of files queued' property 29 | * indicates the number of files that were queued from the dialog selection (as opposed to the 30 | * number of files in the queue). 31 | *

32 | * If you want file uploading to begin automatically this is a good place to call {@link 33 | * org.docstr.gwt.uploader.client.Uploader#startUpload()}. 34 | * 35 | * @author delight.wjk@gmail.com 36 | */ 37 | public class FileDialogCompleteEvent { 38 | 39 | private int numberOfFilesSelected; 40 | private int numberOfFilesQueued; 41 | private int totalFilesInQueue; 42 | 43 | /** 44 | * This constructor is intended for internal use only. You should not create file dialog 45 | * complete events directly, but instead should register a {@link FileDialogCompleteHandler}. 46 | * 47 | * @param numberOfFilesSelected The number of files selected in the dialog. 48 | * @param numberOfFilesQueued The number of files that were queued as a result of the dialog 49 | * selection. 50 | * @param totalFilesInQueue The total number of files now in the queue. 51 | */ 52 | public FileDialogCompleteEvent(int numberOfFilesSelected, int numberOfFilesQueued, 53 | int totalFilesInQueue) { 54 | this.numberOfFilesSelected = numberOfFilesSelected; 55 | this.numberOfFilesQueued = numberOfFilesQueued; 56 | this.totalFilesInQueue = totalFilesInQueue; 57 | } 58 | 59 | /** 60 | * Return the number of files selected in the dialog. 61 | * 62 | * @return int 63 | */ 64 | public int getNumberOfFilesQueued() { 65 | return numberOfFilesQueued; 66 | } 67 | 68 | /** 69 | * Return the number of files that were queued as a result of the dialog selection. 70 | * 71 | * @return int 72 | */ 73 | public int getNumberOfFilesSelected() { 74 | return numberOfFilesSelected; 75 | } 76 | 77 | /** 78 | * Return the total number of files now in the queue. 79 | * 80 | * @return int 81 | */ 82 | public int getTotalFilesInQueue() { 83 | return totalFilesInQueue; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/shared/HttpReq.java: -------------------------------------------------------------------------------- 1 | package org.docstr.gwt.uploader.demo.shared; 2 | 3 | import elemental2.core.JsError; 4 | import elemental2.dom.*; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import static elemental2.dom.DomGlobal.console; 10 | 11 | public class HttpReq { 12 | 13 | public enum Method { 14 | GET, 15 | POST, 16 | PUT 17 | } 18 | 19 | public interface ResponseHandler { 20 | 21 | void onResult(Response response); 22 | 23 | void onError(JsError error); 24 | } 25 | 26 | private URLSearchParams queryParams = new URLSearchParams(); 27 | private String[][] headers = new String[0][]; 28 | private RequestInit requestInit = RequestInit.create(); 29 | private ResponseHandler responseHandler; 30 | 31 | private final String url; 32 | 33 | private HttpReq(String url) { 34 | this.url = url; 35 | } 36 | 37 | public static HttpReq create(String url) { 38 | return new HttpReq(url); 39 | } 40 | 41 | public HttpReq setMethod(Method method) { 42 | requestInit.setMethod(method.name()); 43 | return this; 44 | } 45 | 46 | public HttpReq addQueryParam(String name, String value) { 47 | queryParams.append(name, value); 48 | return this; 49 | } 50 | 51 | public HttpReq addHeader(String name, String value) { 52 | headers = mergeHeaders(headers, new String[][]{{name, value}}); 53 | return this; 54 | } 55 | 56 | public HttpReq addHeaders(String[][] headers) { 57 | this.headers = mergeHeaders(this.headers, headers); 58 | return this; 59 | } 60 | 61 | public static String[][] mergeHeaders( 62 | String[][] headers1, String[][] headers2) { 63 | List mergedHeaders = new ArrayList<>(); 64 | if (headers1 != null) { 65 | for (String[] header : headers1) { 66 | mergedHeaders.add(header); 67 | } 68 | } 69 | if (headers2 != null) { 70 | for (String[] header : headers2) { 71 | mergedHeaders.add(header); 72 | } 73 | } 74 | return mergedHeaders.toArray(new String[0][]); 75 | } 76 | 77 | public HttpReq setBody(FormData body) { 78 | this.requestInit.setBody(body); 79 | return this; 80 | } 81 | 82 | public HttpReq setBody(URLSearchParams body) { 83 | this.requestInit.setBody(body); 84 | return this; 85 | } 86 | 87 | public HttpReq setBody(String body) { 88 | this.requestInit.setBody(body); 89 | return this; 90 | } 91 | 92 | public HttpReq setRespHandler(ResponseHandler responseHandler) { 93 | this.responseHandler = responseHandler; 94 | return this; 95 | } 96 | 97 | public void send() { 98 | StringBuilder fullUrl = new StringBuilder(url); 99 | String queryStr = queryParams.toString(); 100 | if (queryStr.length() > 0) { 101 | fullUrl.append(fullUrl.indexOf("?") > 0 ? "&" : "?") 102 | .append(queryStr); 103 | } 104 | 105 | requestInit.setHeaders(headers); 106 | 107 | DomGlobal.fetch(fullUrl.toString(), requestInit) 108 | .then(resp -> { 109 | if (responseHandler != null) { 110 | responseHandler.onResult(resp); 111 | } 112 | return null; 113 | }) 114 | .catch_(error -> { 115 | if (error instanceof JsError) { 116 | JsError jsError = (JsError) error; 117 | if (responseHandler != null) { 118 | responseHandler.onError(jsError); 119 | } 120 | } else { 121 | console.error("Unknown error: " + error); 122 | } 123 | return null; 124 | }); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /gwt-uploader-demo/build.gradle: -------------------------------------------------------------------------------- 1 | import org.docstr.gradle.plugins.gwt.GwtCompileOptions 2 | import org.docstr.gradle.plugins.gwt.GwtJsInteropExportsOptions 3 | 4 | /* 5 | * Copyright (c) 2022 Document Node Pty Ltd. All rights reserved. 6 | */ 7 | 8 | plugins { 9 | id 'java' 10 | id 'idea' 11 | id 'war' 12 | 13 | // https://github.com/jiakuan/gwt-gradle-plugin 14 | // https://plugins.gradle.org/plugin/org.docstr.gwt 15 | id "org.docstr.gwt" version "1.1.26" 16 | } 17 | 18 | archivesBaseName = "gwt-uploader-demo" 19 | 20 | dependencies { 21 | implementation project(':gwt-uploader') 22 | 23 | // https://github.com/google/elemental2 24 | implementation "com.google.elemental2:elemental2-dom:1.1.0" 25 | implementation "com.google.jsinterop:base:1.0.0" 26 | 27 | // test dependencies 28 | testImplementation("org.assertj:assertj-core:3.24.2") 29 | testImplementation "org.mockito:mockito-core:2.8.9" 30 | testImplementation 'org.testng:testng:7.7.0' 31 | } 32 | 33 | gwt { 34 | gwtVersion = '2.10.0' 35 | minHeapSize = "512M" 36 | maxHeapSize = "1024M" 37 | logLevel = 'INFO' 38 | modules = ["org.docstr.gwt.uploader.demo.GwtUploaderDemo"] 39 | 40 | jsInteropExports(({ 41 | shouldGenerate = true 42 | } as Closure)) 43 | 44 | compiler(({ 45 | strict = true 46 | } as Closure)) 47 | } 48 | 49 | war { 50 | classpath = classpath.filter { file -> 51 | // println file.name 52 | ( 53 | !file.name.startsWith(('gwt-dev')) && 54 | !file.name.startsWith(('gwt-user')) && 55 | !file.name.startsWith(('guava-gwt')) && 56 | !file.name.startsWith(('gwtbootstrap3')) && 57 | !file.name.startsWith(('gwtbootstrap3-extras')) && 58 | !file.name.startsWith(('servlet-api')) 59 | ) 60 | } 61 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE 62 | } 63 | 64 | //sourceSets.main.resources { srcDir file('src/main/java') exclude '*/.java' } 65 | sourceSets.main.resources.srcDir 'src/main/java' 66 | sourceSets.test.resources.srcDir 'src/test/java' 67 | 68 | configurations { 69 | runtime.exclude group: "com.google.gwt", module: "gwt-user" 70 | runtime.exclude group: "com.google.gwt", module: "gwt-dev" 71 | } 72 | 73 | clean { 74 | deleteFolder('classes') 75 | deleteFolder('war') 76 | } 77 | 78 | build.doLast { 79 | // Copy GWT module folders 80 | deleteFolder('src/main/webapp/gwt_uploader_demo') 81 | copyFilesInFolder('build/gwt/out/gwt_uploader_demo', 'src/main/webapp/gwt_uploader_demo') 82 | } 83 | 84 | private void deleteFolder(folderPath) { 85 | File folder = new File(projectDir, folderPath) 86 | if (folder.exists()) { 87 | ant.echo('Deleting folder: ' + folder.absolutePath) 88 | ant.delete(includeEmptyDirs: 'true') { 89 | fileset(dir: folder) 90 | } 91 | } 92 | } 93 | 94 | private void copyFilesInFolder(sourcePath, destPath) { 95 | File sourceDir = new File(projectDir, sourcePath) 96 | if (!sourceDir.exists()) { 97 | return 98 | } 99 | 100 | File destDir = new File(projectDir, destPath) 101 | ant.echo('Copying: ' + sourcePath + ' => ' + destPath) 102 | if (!destDir.exists()) { 103 | destDir.mkdirs() 104 | } 105 | ant.copy(todir: destDir) { 106 | fileset(dir: sourceDir) 107 | } 108 | } 109 | 110 | private void copyFile(sourcePath, destPath) { 111 | File sourceFile = new File(projectDir, sourcePath) 112 | if (!sourceFile.exists()) { 113 | return 114 | } 115 | 116 | File destFile = new File(projectDir, destPath) 117 | ant.echo('Copying: ' + sourcePath + ' => ' + destPath) 118 | if (!destFile.parentFile.exists()) { 119 | destFile.parentFile.mkdirs() 120 | } 121 | ant.copyfile(src: sourceFile, dest: destFile) 122 | } 123 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/FileQueueErrorEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | import org.docstr.gwt.uploader.client.File; 19 | 20 | /** 21 | * Provides access to the raw information provided by Uploader when a 'fileQueueError' event occurs. 22 | * This class should not be instantiated directly, but instead you should create a {@link 23 | * FileQueueErrorHandler} and register it via the {@link org.docstr.gwt.uploader.client 24 | * .Uploader#setFileQueueErrorHandler(FileQueueErrorHandler)} method in order to access file 25 | * queue error events. 26 | *

27 | * Note that the 'fileQueueError' event is fired for each file that was not queued after the File 28 | * Selection Dialog window is closed. A file may not be queued for several reasons such as, 29 | * the file exceeds the file size, the file is empty or a file or queue limit has been exceeded. 30 | *

31 | * The reason for the queue error is specified by the {@link #getErrorCode()} method. 32 | * 33 | * @author delight.wjk@gmail.com 34 | */ 35 | public class FileQueueErrorEvent { 36 | 37 | /** 38 | * An enumeration of reported file queue error code types. 39 | */ 40 | public enum ErrorCode { 41 | 42 | UNKNOWN(0), 43 | QUEUE_LIMIT_EXCEEDED(-100), 44 | FILE_EXCEEDS_SIZE_LIMIT(-110), 45 | ZERO_BYTE_FILE(-120), 46 | INVALID_FILETYPE(-130); 47 | 48 | private ErrorCode(int optionValue) { 49 | this.optionValue = optionValue; 50 | } 51 | 52 | private final int optionValue; 53 | 54 | public int toInt() { 55 | return optionValue; 56 | } 57 | } 58 | 59 | private File file; 60 | private int errorCode; 61 | private String message; 62 | 63 | /** 64 | * This constructor is intended for internal use only. You should not create file queued events 65 | * directly, but instead should register a {@link FileQueuedHandler}. 66 | * 67 | * @param file The file instance that experienced an error in the queue. 68 | * @param errorCode The error code returned by the Uploader component in the case of a file 69 | * queue failure. 70 | * @param message A human readable error message explaining the cause of the file queue failure. 71 | */ 72 | public FileQueueErrorEvent(File file, int errorCode, String message) { 73 | this.file = file; 74 | this.errorCode = errorCode; 75 | this.message = message; 76 | } 77 | 78 | /** 79 | * Return the details of the file that experienced the error in the queue. 80 | * 81 | * @return File 82 | */ 83 | public File getFile() { 84 | return file; 85 | } 86 | 87 | /** 88 | * The error code returned by the Uploader component in the case of a file queu failure, 89 | * conveniently converted to an enumeration type. 90 | * 91 | * @return ErrorCode 92 | */ 93 | public ErrorCode getErrorCode() { 94 | if (errorCode == ErrorCode.QUEUE_LIMIT_EXCEEDED.toInt()) { 95 | return ErrorCode.QUEUE_LIMIT_EXCEEDED; 96 | } else if (errorCode == ErrorCode.FILE_EXCEEDS_SIZE_LIMIT.toInt()) { 97 | return ErrorCode.FILE_EXCEEDS_SIZE_LIMIT; 98 | } else if (errorCode == ErrorCode.ZERO_BYTE_FILE.toInt()) { 99 | return ErrorCode.ZERO_BYTE_FILE; 100 | } else if (errorCode == ErrorCode.INVALID_FILETYPE.toInt()) { 101 | return ErrorCode.INVALID_FILETYPE; 102 | } else { 103 | return ErrorCode.UNKNOWN; 104 | } 105 | } 106 | 107 | /** 108 | * The original numeric error code returned by the Uploader component in the case of a file 109 | * queue failure. 110 | * 111 | * @return int 112 | */ 113 | public int getErrorCodeAsInt() { 114 | return errorCode; 115 | } 116 | 117 | /** 118 | * Return a human readable error message explaining the cause of the file queue failure. 119 | * 120 | * @return String 121 | */ 122 | public String getMessage() { 123 | return message; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GWT Uploader 2 | 3 | ![build](https://github.com/jiakuan/gwt-uploader/actions/workflows/gradle.yml/badge.svg) 4 | 5 | An API to enable sophisticated file upload capabilities within a GWT application. 6 | 7 | The source code was forked from http://www.moxiegroup.com/moxieapps/gwt-uploader/ and applied a few fixes. 8 | 9 | Please see examples with source code here: [http://gwt-uploader.appspot.com/](http://gwt-uploader.appspot.com/) 10 | 11 | * For GWT 2.7.0, please use gwt-upload 1.1.x 12 | * For GWT 2.8.0+, please use gwt-upload 1.2.x 13 | 14 | ## What is it? 15 | GWT Uploader is a freely available open source GWT library that encapsulates the file upload capabilities provided by the File and XMLHttpRequest Level 2 APIs. 16 | 17 | Using GWT Uploader allows for enhanced file upload dialogs (multiple uploads, drag and drop, queues, parallel streams, etc.) and interactive interfaces (upload progress indicators, real-time throughput display, upload cancellation, etc.) within GWT applications using pure Java code that provides a consistent experience across all browsers. 18 | 19 | If the browser is capable of handling file uploads using a modern HTML5 approach, the upload is handled using pure DOM elements and Javascript events. In the case that the browser does not support the modern approach an error is shown. 20 | 21 | ## Key Features 22 | * **Simple**: Adds consistent file upload support to all modern browsers with a single implementation, while still supporting legacy browsers automatically. 23 | * **Pure Java**: The entire set of file upload capabilities are available via GWT powered Java methods, including clean interfaces for the various runtime callbacks (no need to write any JavaScript). 24 | * **Customizable Interfaces**: GWT Uploader exposes all the file upload capabilities as a GWT Widget, making it easy to create your own aesthetic for your upload controls or leave it simple and benefit from the multiple file selection and queued uploading. Convenient methods are also provided to enable file uploads via a familiar drag and drop approach. 25 | * **Clean Syntax**: The API is built using fluent methods that allow you to manage the configuration options of the the upload control using syntax that is nearly as tight as JSON. 26 | * **Dynamic**: GWT Uploader automatically includes the necessary plugin capabilities to expose various throughput and performance metrics of the uploads during and after an upload. Each File object has the following properties: 27 | 28 | * getAverageSpeed() -- Overall average upload speed, in bytes per second 29 | * getCurrentSpeed() -- String indicating the upload speed, in bytes per second 30 | * getMovingAverageSpeed() -- Speed over averaged over the last several measurements, in bytes per second 31 | * getPercentUploaded() -- Percentage of the file uploaded (0 to 100) 32 | * getSizeUploaded() -- Formatted size uploaded so far, bytes 33 | * getTimeElapsed() -- Number of seconds passed for this upload 34 | * getTimeRemaining() -- Estimated remaining upload time in seconds 35 | These metrics allow for dynamic updates to occur in your interface, whether it's progress bars or text labels, as data is transferred for one or more files. 36 | * **Documented**: Every class and method of the API is thoroughly documented, including numerous code and syntax examples throughout. 37 | * **Examples**: The demonstration examples provide several [basic examples](http://gwt-uploader.appspot.com/) of upload interfaces that demonstrate the flexibility and integration opportunities available, with each example including a convenient "View Source" button that will allow you to see the code behind each implementation. 38 | 39 | ## Configure Maven dependency 40 | 41 | GWT Uploader is available in Maven central repository: 42 | 43 | http://search.maven.org/#search%7Cga%7C1%7Cgwt-uploader 44 | 45 | To add the dependency to your `build.gradle` (for Gradle projects) or `pom.xml` (for Maven projects), use the following configuration: 46 | 47 | For Gradle projects: 48 | 49 | ``` 50 | implementation 'org.docstr:gwt-uploader:1.2.5' 51 | ``` 52 | 53 | For Maven projects: 54 | 55 | ``` 56 | 57 | org.docstr 58 | gwt-uploader 59 | 1.2.5 60 | 61 | ``` 62 | 63 | ## How to use GWT Uploader? 64 | 65 | Please see examples with source code here: http://gwt-uploader.appspot.com/ 66 | 67 | ## How to contribute 68 | 69 | Use the following command to checkout the source code: 70 | 71 | ``` 72 | git clone git@github.com:jiakuan/gwt-uploader.git gwt-uploader-root 73 | ``` 74 | 75 | Here are the steps: 76 | 77 | * Create a new issue for things to discuss 78 | * After discussion about changes, fork the project and make changes 79 | * Run `gradle clean build` to make sure no build errors 80 | * Create a new pull request for review and discussion 81 | * After confirmation, we will merge the pull request to master 82 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/ImageButtonAndProgressText.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.docstr.gwt.uploader.demo.client; 18 | 19 | import com.google.gwt.core.client.EntryPoint; 20 | import com.google.gwt.i18n.client.NumberFormat; 21 | import com.google.gwt.user.client.Window; 22 | import com.google.gwt.user.client.ui.*; 23 | import org.docstr.gwt.uploader.client.Uploader; 24 | import org.docstr.gwt.uploader.client.events.*; 25 | 26 | /** 27 | * Uploader Image Button and Progress text label example of GWT Uploader. 28 | * 29 | * @author delight.wjk@gmail.com 30 | */ 31 | public class ImageButtonAndProgressText implements EntryPoint, UploaderSample { 32 | 33 | private final Label progressLabel = new Label(); 34 | private final Uploader uploader = new Uploader(); 35 | 36 | public void onModuleLoad() { 37 | //noinspection GwtToHtmlReferences 38 | RootPanel.get("ImageButtonAndProgressText").add(getUploaderPanel()); 39 | } 40 | 41 | @Override 42 | public Widget getUploaderPanel() { 43 | progressLabel.setStyleName("progressLabel"); 44 | uploader.setUploadURL(UPLOAD_URL) 45 | .setButtonImageURL(AppResources.INSTANCE.upload().getSafeUri().asString()) 46 | .setButtonWidth(133) 47 | .setButtonHeight(22) 48 | .setFileSizeLimit("50 MB") 49 | .setButtonCursor(Uploader.Cursor.HAND) 50 | .setButtonAction(Uploader.ButtonAction.SELECT_FILE) 51 | .setUploadProgressHandler(new UploadProgressHandler() { 52 | public boolean onUploadProgress(UploadProgressEvent uploadProgressEvent) { 53 | progressLabel.setText( 54 | NumberFormat.getPercentFormat().format( 55 | uploadProgressEvent.getBytesComplete() / uploadProgressEvent.getBytesTotal() 56 | ) 57 | ); 58 | return true; 59 | } 60 | }) 61 | .setUploadSuccessHandler(new UploadSuccessHandler() { 62 | public boolean onUploadSuccess(UploadSuccessEvent uploadSuccessEvent) { 63 | resetText(); 64 | StringBuilder sb = new StringBuilder(); 65 | sb.append("File ").append(uploadSuccessEvent.getFile().getName()) 66 | .append(" uploaded successfully at ") 67 | .append(NumberFormat.getDecimalFormat().format( 68 | uploadSuccessEvent.getFile().getAverageSpeed() / 1024 69 | )) 70 | .append(" kilobit per second"); 71 | progressLabel.setText(sb.toString()); 72 | return true; 73 | } 74 | }) 75 | .setFileDialogCompleteHandler(new FileDialogCompleteHandler() { 76 | public boolean onFileDialogComplete(FileDialogCompleteEvent fileDialogCompleteEvent) { 77 | if (fileDialogCompleteEvent.getTotalFilesInQueue() > 0 78 | && uploader.getStats().getUploadsInProgress() <= 0) { 79 | progressLabel.setText("0%"); 80 | uploader.startUpload(); 81 | } 82 | return true; 83 | } 84 | }) 85 | .setFileQueueErrorHandler(new FileQueueErrorHandler() { 86 | public boolean onFileQueueError(FileQueueErrorEvent fileQueueErrorEvent) { 87 | resetText(); 88 | Window.alert( 89 | "Upload of file " + fileQueueErrorEvent.getFile().getName() + " failed due to [" + 90 | fileQueueErrorEvent.getErrorCode().toString() + "]: " + fileQueueErrorEvent 91 | .getMessage() 92 | ); 93 | return true; 94 | } 95 | }) 96 | .setUploadErrorHandler(new UploadErrorHandler() { 97 | public boolean onUploadError(UploadErrorEvent uploadErrorEvent) { 98 | resetText(); 99 | Window 100 | .alert( 101 | "Upload of file " + uploadErrorEvent.getFile().getName() + " failed due to [" + 102 | uploadErrorEvent.getErrorCode().toString() + "]: " + uploadErrorEvent 103 | .getMessage() 104 | ); 105 | return true; 106 | } 107 | }); 108 | 109 | VerticalPanel verticalPanel = new VerticalPanel(); 110 | verticalPanel.add(uploader); 111 | verticalPanel.add(progressLabel); 112 | verticalPanel.setCellHorizontalAlignment(uploader, HorizontalPanel.ALIGN_LEFT); 113 | verticalPanel.setCellHorizontalAlignment(progressLabel, HorizontalPanel.ALIGN_LEFT); 114 | return verticalPanel; 115 | } 116 | 117 | private void resetText() { 118 | progressLabel.setText(""); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/events/UploadErrorEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.events; 17 | 18 | import org.docstr.gwt.uploader.client.File; 19 | 20 | /** 21 | * Provides access to the raw information provided by Uploader when an 'uploader error' event 22 | * occurs. 23 | * This class should not be instantiated directly, but instead you should create a 24 | * {@link UploadErrorHandler} and register it via the {@link org.docstr.gwt.uploader.client 25 | * .Uploader#setUploadErrorHandler(UploadErrorHandler)} 26 | * method in order to access uploader error events. 27 | *

28 | * Note that the 'uploadError' event is fired any time an uploader is interrupted or does not 29 | * complete successfully. The error code parameter indicates the type of error that occurred. 30 | *

31 | * Stopping, Cancelling or returning 'false' from uploadStart will cause uploadError to fire. 32 | * Uploader error will not fire for files that are cancelled but still waiting in the queue. 33 | * 34 | * @author delight.wjk@gmail.com 35 | */ 36 | public class UploadErrorEvent extends UploadEvent { 37 | 38 | /** 39 | * An enumeration of reported uploaded error code types. 40 | */ 41 | public enum ErrorCode { 42 | 43 | UNKNOWN(0), 44 | HTTP_ERROR(-200), 45 | MISSING_UPLOAD_URL(-210), 46 | IO_ERROR(-220), 47 | SECURITY_ERROR(-230), 48 | UPLOAD_LIMIT_EXCEEDED(-240), 49 | UPLOAD_FAILED(-250), 50 | SPECIFIED_FILE_ID_NOT_FOUND(-260), 51 | FILE_VALIDATION_FAILED(-270), 52 | FILE_CANCELLED(-280), 53 | UPLOAD_STOPPED(-290); 54 | 55 | private ErrorCode(int optionValue) { 56 | this.optionValue = optionValue; 57 | } 58 | 59 | private final int optionValue; 60 | 61 | public int toInt() { 62 | return optionValue; 63 | } 64 | } 65 | 66 | private int errorCode; 67 | private String message; 68 | private String serverData; 69 | 70 | /** 71 | * This constructor is intended for internal use only. You should not create uploader error 72 | * events directly, but instead should register a {@link UploadErrorHandler}. 73 | * 74 | * @param file The native javascript object containing the details of the file being 75 | * uploaded. 76 | * @param errorCode The error code returned by the Uploader component in the case of an 77 | * uploader failure. 78 | * @param message A human readable error message explaining the cause of the uploader failure. 79 | * 80 | * @param serverData Server response (if any). 81 | */ 82 | public UploadErrorEvent(File file, int errorCode, String message, String serverData) { 83 | super(file); 84 | this.errorCode = errorCode; 85 | this.message = message; 86 | this.serverData = serverData; 87 | } 88 | 89 | /** 90 | * The error code returned by the Uploader component in the case of an uploader failure, 91 | * conveniently converted to an enumeration type. 92 | * 93 | * @return ErrorCode 94 | */ 95 | public ErrorCode getErrorCode() { 96 | if (errorCode == ErrorCode.HTTP_ERROR.toInt()) { 97 | return ErrorCode.HTTP_ERROR; 98 | } else if (errorCode == ErrorCode.MISSING_UPLOAD_URL.toInt()) { 99 | return ErrorCode.MISSING_UPLOAD_URL; 100 | } else if (errorCode == ErrorCode.IO_ERROR.toInt()) { 101 | return ErrorCode.IO_ERROR; 102 | } else if (errorCode == ErrorCode.SECURITY_ERROR.toInt()) { 103 | return ErrorCode.SECURITY_ERROR; 104 | } else if (errorCode == ErrorCode.UPLOAD_LIMIT_EXCEEDED.toInt()) { 105 | return ErrorCode.UPLOAD_LIMIT_EXCEEDED; 106 | } else if (errorCode == ErrorCode.UPLOAD_FAILED.toInt()) { 107 | return ErrorCode.UPLOAD_FAILED; 108 | } else if (errorCode == ErrorCode.SPECIFIED_FILE_ID_NOT_FOUND.toInt()) { 109 | return ErrorCode.SPECIFIED_FILE_ID_NOT_FOUND; 110 | } else if (errorCode == ErrorCode.FILE_VALIDATION_FAILED.toInt()) { 111 | return ErrorCode.FILE_VALIDATION_FAILED; 112 | } else if (errorCode == ErrorCode.FILE_CANCELLED.toInt()) { 113 | return ErrorCode.FILE_CANCELLED; 114 | } else if (errorCode == ErrorCode.UPLOAD_STOPPED.toInt()) { 115 | return ErrorCode.UPLOAD_STOPPED; 116 | } else { 117 | return ErrorCode.UNKNOWN; 118 | } 119 | } 120 | 121 | /** 122 | * The original numeric error code returned by the Uploader component in the case of an 123 | * uploader failure. 124 | * 125 | * @return int 126 | */ 127 | public int getErrorCodeAsInt() { 128 | return errorCode; 129 | } 130 | 131 | /** 132 | * Return a human readable error message explaining the cause of the uploader failure. 133 | * 134 | * @return String 135 | */ 136 | public String getMessage() { 137 | return message; 138 | } 139 | 140 | /** 141 | * Return a server response (if any). 142 | * 143 | * @return String 144 | */ 145 | public String getServerData() { 146 | return serverData; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/TextButtonAndProgressText.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.docstr.gwt.uploader.demo.client; 18 | 19 | import com.google.gwt.core.client.EntryPoint; 20 | import com.google.gwt.i18n.client.NumberFormat; 21 | import com.google.gwt.user.client.Window; 22 | import com.google.gwt.user.client.ui.*; 23 | import org.docstr.gwt.uploader.client.Uploader; 24 | import org.docstr.gwt.uploader.client.events.*; 25 | 26 | /** 27 | * Simple Text Link and Progress text label example of GWT Uploader. 28 | * 29 | * @author delight.wjk@gmail.com 30 | */ 31 | public class TextButtonAndProgressText implements EntryPoint, UploaderSample { 32 | 33 | private Label progressLabel = new Label(); 34 | private Uploader uploader = new Uploader(); 35 | 36 | public void onModuleLoad() { 37 | //noinspection GwtToHtmlReferences 38 | RootPanel.get("TextButtonAndProgressText").add(getUploaderPanel()); 39 | } 40 | 41 | @Override 42 | public Widget getUploaderPanel() { 43 | progressLabel.setStyleName("progressLabel"); 44 | uploader.setUploadURL(UPLOAD_URL) 45 | .setButtonText("Click to Upload") 46 | .setButtonTextStyle( 47 | ".buttonText {font-family: Arial, sans-serif; font-size: 14px; color: #BB4B44}") 48 | .setFileSizeLimit("50 MB") 49 | .setButtonWidth(150) 50 | .setButtonHeight(22) 51 | .setButtonCursor(Uploader.Cursor.HAND) 52 | .setButtonAction(Uploader.ButtonAction.SELECT_FILE) 53 | .setUploadProgressHandler(new UploadProgressHandler() { 54 | public boolean onUploadProgress(UploadProgressEvent uploadProgressEvent) { 55 | progressLabel.setText(NumberFormat.getPercentFormat().format( 56 | (double) uploadProgressEvent.getBytesComplete() / (double) uploadProgressEvent 57 | .getBytesTotal() 58 | )); 59 | return true; 60 | } 61 | }) 62 | .setUploadSuccessHandler(new UploadSuccessHandler() { 63 | public boolean onUploadSuccess(UploadSuccessEvent uploadSuccessEvent) { 64 | resetText(); 65 | StringBuilder sb = new StringBuilder(); 66 | sb.append("File ").append(uploadSuccessEvent.getFile().getName()) 67 | .append(" (") 68 | .append(NumberFormat.getDecimalFormat() 69 | .format(uploadSuccessEvent.getFile().getSize() / 1024)) 70 | .append(" KB)") 71 | .append(" uploaded successfully at ") 72 | .append(NumberFormat.getDecimalFormat().format( 73 | uploadSuccessEvent.getFile().getAverageSpeed() / 1024 74 | )) 75 | .append(" Kb/second"); 76 | progressLabel.setText(sb.toString()); 77 | return true; 78 | } 79 | }) 80 | .setFileDialogCompleteHandler(new FileDialogCompleteHandler() { 81 | public boolean onFileDialogComplete(FileDialogCompleteEvent fileDialogCompleteEvent) { 82 | if (fileDialogCompleteEvent.getTotalFilesInQueue() > 0 83 | && uploader.getStats().getUploadsInProgress() <= 0) { 84 | progressLabel.setText("0%"); 85 | uploader.setButtonText("Uploading..."); 86 | uploader.startUpload(); 87 | } 88 | return true; 89 | } 90 | }) 91 | .setFileQueueErrorHandler(new FileQueueErrorHandler() { 92 | public boolean onFileQueueError(FileQueueErrorEvent fileQueueErrorEvent) { 93 | resetText(); 94 | Window.alert( 95 | "Upload of file " + fileQueueErrorEvent.getFile().getName() + " failed due to [" + 96 | fileQueueErrorEvent.getErrorCode().toString() + "]: " + fileQueueErrorEvent 97 | .getMessage() 98 | ); 99 | return true; 100 | } 101 | }) 102 | .setUploadErrorHandler(new UploadErrorHandler() { 103 | public boolean onUploadError(UploadErrorEvent uploadErrorEvent) { 104 | resetText(); 105 | Window.alert( 106 | "Upload of file " + uploadErrorEvent.getFile().getName() + " failed due to [" + 107 | uploadErrorEvent.getErrorCode().toString() + "]: " + uploadErrorEvent.getMessage() 108 | ); 109 | return true; 110 | } 111 | }); 112 | 113 | VerticalPanel verticalPanel = new VerticalPanel(); 114 | verticalPanel.add(uploader); 115 | verticalPanel.add(progressLabel); 116 | verticalPanel.setCellHorizontalAlignment(uploader, HorizontalPanel.ALIGN_LEFT); 117 | verticalPanel.setCellHorizontalAlignment(progressLabel, HorizontalPanel.ALIGN_LEFT); 118 | return verticalPanel; 119 | } 120 | 121 | private void resetText() { 122 | progressLabel.setText(""); 123 | uploader.setButtonText("Click to Upload"); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/ImageButtonAndProgressBar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.docstr.gwt.uploader.demo.client; 18 | 19 | import com.google.gwt.core.client.EntryPoint; 20 | import com.google.gwt.event.dom.client.ClickEvent; 21 | import com.google.gwt.event.dom.client.ClickHandler; 22 | import com.google.gwt.user.client.Window; 23 | import com.google.gwt.user.client.ui.HorizontalPanel; 24 | import com.google.gwt.user.client.ui.Image; 25 | import com.google.gwt.user.client.ui.RootPanel; 26 | import com.google.gwt.user.client.ui.Widget; 27 | import org.docstr.gwt.uploader.client.Uploader; 28 | import org.docstr.gwt.uploader.client.events.*; 29 | import org.docstr.gwt.uploader.client.progress.ProgressBar; 30 | 31 | /** 32 | * Uploader Image Button and GWT Progress Bar example of GWT Uploader. 33 | * 34 | * @author delight.wjk@gmail.com 35 | */ 36 | public class ImageButtonAndProgressBar implements EntryPoint, UploaderSample { 37 | 38 | final Uploader uploader = new Uploader(); 39 | private ProgressBar progressBar = 40 | new ProgressBar(0.0, 1.0, 0.0, new CancelProgressBarTextFormatter()); 41 | private Image cancelButton = new Image(AppResources.INSTANCE.cancel().getSafeUri().asString()); 42 | 43 | public void onModuleLoad() { 44 | //noinspection GwtToHtmlReferences 45 | RootPanel.get("ImageButtonAndProgressBar").add(getUploaderPanel()); 46 | } 47 | 48 | @Override 49 | public Widget getUploaderPanel() { 50 | final HorizontalPanel horizontalPanel = new HorizontalPanel(); 51 | 52 | uploader.setUploadURL(UPLOAD_URL) 53 | .setButtonImageURL(AppResources.INSTANCE.upload().getSafeUri().asString()) 54 | .setButtonWidth(133) 55 | .setButtonHeight(22) 56 | .setFileSizeLimit("50 MB") 57 | .setButtonCursor(Uploader.Cursor.HAND) 58 | .setButtonAction(Uploader.ButtonAction.SELECT_FILE) 59 | .setFileQueuedHandler(new FileQueuedHandler() { 60 | public boolean onFileQueued(final FileQueuedEvent fileQueuedEvent) { 61 | // Create a Progress Bar for this file 62 | progressBar.setTitle(fileQueuedEvent.getFile().getName()); 63 | progressBar.setHeight("18px"); 64 | progressBar.setWidth("200px"); 65 | 66 | // Add Cancel Button Image 67 | cancelButton.setStyleName("cancelButton"); 68 | cancelButton.addClickHandler(new ClickHandler() { 69 | public void onClick(ClickEvent event) { 70 | uploader.cancelUpload(fileQueuedEvent.getFile().getId(), false); 71 | progressBar.setProgress(-1.0d); 72 | cancelButton.removeFromParent(); 73 | } 74 | }); 75 | 76 | horizontalPanel.add(progressBar); 77 | horizontalPanel.add(cancelButton); 78 | 79 | return true; 80 | } 81 | }) 82 | .setFileDialogStartHandler(new FileDialogStartHandler() { 83 | public boolean onFileDialogStartEvent(FileDialogStartEvent fileDialogStartEvent) { 84 | if (uploader.getStats().getUploadsInProgress() <= 0) { 85 | progressBar.removeFromParent(); 86 | cancelButton.removeFromParent(); 87 | } 88 | return true; 89 | } 90 | }) 91 | .setUploadProgressHandler(new UploadProgressHandler() { 92 | public boolean onUploadProgress(UploadProgressEvent uploadProgressEvent) { 93 | progressBar.setProgress( 94 | (double) uploadProgressEvent.getBytesComplete() / uploadProgressEvent 95 | .getBytesTotal() 96 | ); 97 | return true; 98 | } 99 | }) 100 | .setUploadSuccessHandler(new UploadSuccessHandler() { 101 | public boolean onUploadSuccess(UploadSuccessEvent uploadSuccessEvent) { 102 | cancelButton.removeFromParent(); 103 | return true; 104 | } 105 | }) 106 | .setFileDialogCompleteHandler(new FileDialogCompleteHandler() { 107 | public boolean onFileDialogComplete(FileDialogCompleteEvent fileDialogCompleteEvent) { 108 | if (fileDialogCompleteEvent.getTotalFilesInQueue() > 0 109 | && uploader.getStats().getUploadsInProgress() <= 0) { 110 | progressBar.setProgress(0.0); 111 | uploader.startUpload(); 112 | } 113 | return true; 114 | } 115 | }) 116 | .setFileQueueErrorHandler(new FileQueueErrorHandler() { 117 | public boolean onFileQueueError(FileQueueErrorEvent fileQueueErrorEvent) { 118 | progressBar.setProgress(0.0); 119 | cancelButton.removeFromParent(); 120 | Window.alert( 121 | "Upload of file " + fileQueueErrorEvent.getFile().getName() + " failed due to [" + 122 | fileQueueErrorEvent.getErrorCode().toString() + "]: " + fileQueueErrorEvent 123 | .getMessage() 124 | ); 125 | return true; 126 | } 127 | }) 128 | .setUploadErrorHandler(new UploadErrorHandler() { 129 | public boolean onUploadError(UploadErrorEvent uploadErrorEvent) { 130 | progressBar.setProgress(0.0); 131 | cancelButton.removeFromParent(); 132 | Window 133 | .alert( 134 | "Upload of file " + uploadErrorEvent.getFile().getName() + " failed due to [" + 135 | uploadErrorEvent.getErrorCode().toString() + "]: " + uploadErrorEvent 136 | .getMessage() 137 | ); 138 | return true; 139 | } 140 | }); 141 | 142 | horizontalPanel.add(uploader); 143 | horizontalPanel.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE); 144 | horizontalPanel.setCellHorizontalAlignment(uploader, HorizontalPanel.ALIGN_RIGHT); 145 | return horizontalPanel; 146 | } 147 | 148 | protected class CancelProgressBarTextFormatter extends ProgressBar.TextFormatter { 149 | 150 | @Override 151 | protected String getText(ProgressBar bar, double curProgress) { 152 | if (curProgress < 0) { 153 | return "Cancelled"; 154 | } 155 | return ((int) (100 * bar.getPercent())) + "%"; 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/File.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.docstr.gwt.uploader.client; 17 | 18 | import com.google.gwt.core.client.JavaScriptObject; 19 | 20 | import org.docstr.gwt.uploader.client.events.UploadProgressEvent; 21 | 22 | import java.util.Date; 23 | 24 | /** 25 | * A logical bean that provides access to the details of a file being uploaded. An instance 26 | * of this object is available on all uploader related event handlers, such as the 27 | * {@link org.docstr.gwt.uploader.client.events.UploadProgressHandler}. 28 | *

29 | * 30 | * @author delight.wjk@gmail.com 31 | */ 32 | public final class File extends JavaScriptObject { 33 | 34 | /** 35 | * An enumeration of reported file status types, which can be determined during 36 | * any of the uploader events, such as {@link UploadProgressEvent#getFile()}. 37 | */ 38 | public enum Status { 39 | 40 | UNKNOWN(0), 41 | QUEUED(-1), 42 | IN_PROGRESS(-2), 43 | ERROR(-3), 44 | COMPLETE(-4), 45 | CANCELLED(-5); 46 | 47 | private Status(int optionValue) { 48 | this.optionValue = optionValue; 49 | } 50 | 51 | private final int optionValue; 52 | 53 | public int toInt() { 54 | return optionValue; 55 | } 56 | } 57 | 58 | /** 59 | * Instances of the File object can not be created directly, but should instead 60 | * be obtained via an event handler. 61 | * E.g. {@link org.docstr.gwt.uploader.client.events.UploadProgressEvent#getFile()}. 62 | */ 63 | protected File() { 64 | } 65 | 66 | /** 67 | * Return the unique id of the file instance as it is being maintained within the Uploader 68 | * component file queue. 69 | * 70 | * @return String 71 | */ 72 | public native String getId() /*-{ 73 | return this.id; 74 | }-*/; 75 | 76 | /** 77 | * Return the index of the file within the queue of files being uploaded by the 78 | * Uploader component. 79 | * 80 | * @return int 81 | */ 82 | public native int getIndex() /*-{ 83 | return this.index; 84 | }-*/; 85 | 86 | /** 87 | * Return the original name of the file being uploaded. 88 | * 89 | * @return String 90 | */ 91 | public native String getName() /*-{ 92 | return this.name; 93 | }-*/; 94 | 95 | /** 96 | * Return the original size of the file being uploaded (in bytes). 97 | * 98 | * @return long 99 | */ 100 | public long getSize() { 101 | return (long) nativeGetSize(); 102 | } 103 | 104 | /** 105 | * Return the mime type of the file being uploaded. 106 | * 107 | * @return String 108 | */ 109 | public native String getType() /*-{ 110 | return this.type; 111 | }-*/; 112 | 113 | /** 114 | * Return the date the file was last modified, as reported by the client machine, or null 115 | * if the browser or OS did not make the file's modification date available. 116 | * 117 | * @return Date 118 | */ 119 | public Date getModificationDate() { 120 | long date = (long) nativeGetModificationDate(); 121 | return date > 0 ? new Date(date) : null; 122 | } 123 | 124 | /** 125 | * Get the file's current status (see {@link Status} enumeration for possible values). 126 | * 127 | * @return Status 128 | */ 129 | public Status getStatus() { 130 | switch (nativeGetStatus()) { 131 | case -1: 132 | return Status.QUEUED; 133 | case -2: 134 | return Status.IN_PROGRESS; 135 | case -3: 136 | return Status.ERROR; 137 | case -4: 138 | return Status.COMPLETE; 139 | case -5: 140 | return Status.CANCELLED; 141 | default: 142 | return Status.UNKNOWN; 143 | } 144 | } 145 | 146 | /** 147 | * Return a floating point number indicating the current uploader speed of 148 | * the file, in bits per second. 149 | * 150 | * @return double 151 | */ 152 | public native double getCurrentSpeed() /*-{ 153 | return this.currentSpeed ? this.currentSpeed : 0.0; 154 | }-*/; 155 | 156 | /** 157 | * Return a floating point number indicating the overall average uploader speed, 158 | * bytes per second, in bits per second. 159 | * 160 | * @return double 161 | */ 162 | public native double getAverageSpeed() /*-{ 163 | return this.averageSpeed ? this.averageSpeed : 0.0; 164 | }-*/; 165 | 166 | /** 167 | * Return a floating point number indicating the uploader speed averaged over the 168 | * last several measurements, in bits per second. 169 | * 170 | * @return double 171 | */ 172 | public native double getMovingAverageSpeed() /*-{ 173 | return this.movingAverageSpeed ? this.movingAverageSpeed : 0.0; 174 | }-*/; 175 | 176 | /** 177 | * Return a floating point number indicating the estimated remaining 178 | * uploader time, in seconds. 179 | * 180 | * @return double 181 | */ 182 | public native double getTimeRemaining() /*-{ 183 | return this.timeRemaining ? this.timeRemaining : 0.0; 184 | }-*/; 185 | 186 | /** 187 | * Return a floating point number indicating the number of seconds 188 | * passed so far for this uploader. 189 | * 190 | * @return double 191 | */ 192 | public native double getTimeElapsed() /*-{ 193 | return this.timeElapsed ? this.timeElapsed : 0.0; 194 | }-*/; 195 | 196 | /** 197 | * Return a floating point number indicating the percentage of the 198 | * file uploaded (0 to 100). 199 | * 200 | * @return double 201 | */ 202 | public native double getPercentUploaded() /*-{ 203 | return this.percentUploaded ? this.percentUploaded : 0.0; 204 | }-*/; 205 | 206 | /** 207 | * Return a floating point number indicating the size uploaded so far, in bytes. 208 | * 209 | * @return double 210 | */ 211 | public native double getSizeUploaded() /*-{ 212 | return this.sizeUploaded ? this.sizeUploaded : 0.0; 213 | }-*/; 214 | 215 | private native double nativeGetSize() /*-{ 216 | return this.size ? this.size : 0.0; 217 | }-*/; 218 | 219 | private native double nativeGetModificationDate() /*-{ 220 | return this.modificationdate != null ? this.modificationdate.getTime() : 0; 221 | }-*/; 222 | 223 | private native int nativeGetStatus() /*-{ 224 | return this.filestatus ? this.filestatus : 0; // 0 == UNKNOWN 225 | }-*/; 226 | 227 | } 228 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/MultiUploadWithProgressBar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.docstr.gwt.uploader.demo.client; 18 | 19 | import com.google.gwt.core.client.EntryPoint; 20 | import com.google.gwt.event.dom.client.ClickEvent; 21 | import com.google.gwt.event.dom.client.ClickHandler; 22 | import com.google.gwt.user.client.Window; 23 | import com.google.gwt.user.client.ui.*; 24 | import org.docstr.gwt.uploader.client.Uploader; 25 | import org.docstr.gwt.uploader.client.events.*; 26 | import org.docstr.gwt.uploader.client.progress.ProgressBar; 27 | 28 | import java.util.LinkedHashMap; 29 | import java.util.Map; 30 | 31 | /** 32 | * Uploader Image Button with multiple file selection and GWT Progress Bars example of 33 | * GWT Uploader. 34 | * 35 | * @author delight.wjk@gmail.com 36 | */ 37 | public class MultiUploadWithProgressBar implements EntryPoint, UploaderSample { 38 | 39 | private final Uploader uploader = new Uploader(); 40 | 41 | public void onModuleLoad() { 42 | //noinspection GwtToHtmlReferences 43 | RootPanel.get("MultiUploadWithProgressBar").add(getUploaderPanel()); 44 | } 45 | 46 | @Override 47 | public Widget getUploaderPanel() { 48 | final VerticalPanel progressBarPanel = new VerticalPanel(); 49 | final Map progressBars = new LinkedHashMap(); 50 | final Map cancelButtons = new LinkedHashMap(); 51 | uploader.setUploadURL(UPLOAD_URL) 52 | .setButtonImageURL(AppResources.INSTANCE.upload().getSafeUri().asString()) 53 | .setButtonWidth(133) 54 | .setButtonHeight(22) 55 | .setFileSizeLimit("50 MB") 56 | .setButtonCursor(Uploader.Cursor.HAND) 57 | .setButtonAction(Uploader.ButtonAction.SELECT_FILES) 58 | .setFileQueuedHandler(new FileQueuedHandler() { 59 | public boolean onFileQueued(final FileQueuedEvent fileQueuedEvent) { 60 | // Create a Progress Bar for this file 61 | final ProgressBar progressBar = 62 | new ProgressBar(0.0, 1.0, 0.0, new CancelProgressBarTextFormatter()); 63 | progressBar.setTitle(fileQueuedEvent.getFile().getName()); 64 | progressBar.setHeight("18px"); 65 | progressBar.setWidth("200px"); 66 | progressBars.put(fileQueuedEvent.getFile().getId(), progressBar); 67 | 68 | // Add Cancel Button Image 69 | final Image cancelButton = 70 | new Image(AppResources.INSTANCE.cancel().getSafeUri().asString()); 71 | cancelButton.setStyleName("cancelButton"); 72 | cancelButton.addClickHandler(new ClickHandler() { 73 | public void onClick(ClickEvent event) { 74 | uploader.cancelUpload(fileQueuedEvent.getFile().getId(), false); 75 | progressBars.get(fileQueuedEvent.getFile().getId()).setProgress(-1.0d); 76 | cancelButton.removeFromParent(); 77 | } 78 | }); 79 | cancelButtons.put(fileQueuedEvent.getFile().getId(), cancelButton); 80 | 81 | // Add the Bar and Button to the interface 82 | HorizontalPanel progressBarAndButtonPanel = new HorizontalPanel(); 83 | progressBarAndButtonPanel.add(progressBar); 84 | progressBarAndButtonPanel.add(cancelButton); 85 | progressBarPanel.add(progressBarAndButtonPanel); 86 | 87 | return true; 88 | } 89 | }) 90 | .setUploadProgressHandler(new UploadProgressHandler() { 91 | public boolean onUploadProgress(UploadProgressEvent uploadProgressEvent) { 92 | ProgressBar progressBar = progressBars.get(uploadProgressEvent.getFile().getId()); 93 | progressBar.setProgress( 94 | (double) uploadProgressEvent.getBytesComplete() / uploadProgressEvent 95 | .getBytesTotal() 96 | ); 97 | return true; 98 | } 99 | }) 100 | .setUploadCompleteHandler(new UploadCompleteHandler() { 101 | public boolean onUploadComplete(UploadCompleteEvent uploadCompleteEvent) { 102 | cancelButtons.get(uploadCompleteEvent.getFile().getId()).removeFromParent(); 103 | // Call upload to see if any additional files are queued 104 | uploader.startUpload(); 105 | return true; 106 | } 107 | }) 108 | .setFileDialogStartHandler(new FileDialogStartHandler() { 109 | public boolean onFileDialogStartEvent(FileDialogStartEvent fileDialogStartEvent) { 110 | if (uploader.getStats().getUploadsInProgress() <= 0) { 111 | // Clear the uploads that have completed, if none are in process 112 | progressBarPanel.clear(); 113 | progressBars.clear(); 114 | cancelButtons.clear(); 115 | } 116 | return true; 117 | } 118 | }) 119 | .setFileDialogCompleteHandler(new FileDialogCompleteHandler() { 120 | public boolean onFileDialogComplete(FileDialogCompleteEvent fileDialogCompleteEvent) { 121 | if (uploader.getStats().getUploadsInProgress() <= 0) { 122 | uploader.startUpload(); 123 | } 124 | return true; 125 | } 126 | }) 127 | .setFileQueueErrorHandler(new FileQueueErrorHandler() { 128 | public boolean onFileQueueError(FileQueueErrorEvent fileQueueErrorEvent) { 129 | Window.alert( 130 | "Upload of file " + fileQueueErrorEvent.getFile().getName() + " failed due to [" + 131 | fileQueueErrorEvent.getErrorCode().toString() + "]: " + fileQueueErrorEvent 132 | .getMessage() 133 | ); 134 | return true; 135 | } 136 | }) 137 | .setUploadErrorHandler(new UploadErrorHandler() { 138 | public boolean onUploadError(UploadErrorEvent uploadErrorEvent) { 139 | cancelButtons.get(uploadErrorEvent.getFile().getId()).removeFromParent(); 140 | Window.alert( 141 | "Upload of file " + uploadErrorEvent.getFile().getName() + " failed due to [" + 142 | uploadErrorEvent.getErrorCode().toString() + "]: " + uploadErrorEvent.getMessage() 143 | ); 144 | return true; 145 | } 146 | }); 147 | HorizontalPanel horizontalPanel = new HorizontalPanel(); 148 | horizontalPanel.add(uploader); 149 | horizontalPanel.add(progressBarPanel); 150 | horizontalPanel.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE); 151 | horizontalPanel.setCellHorizontalAlignment(uploader, HorizontalPanel.ALIGN_LEFT); 152 | horizontalPanel.setCellHorizontalAlignment(progressBarPanel, HorizontalPanel.ALIGN_RIGHT); 153 | return horizontalPanel; 154 | } 155 | 156 | protected class CancelProgressBarTextFormatter extends ProgressBar.TextFormatter { 157 | 158 | @Override 159 | protected String getText(ProgressBar bar, double curProgress) { 160 | if (curProgress < 0) { 161 | return "Cancelled"; 162 | } 163 | return ((int) (100 * bar.getPercent())) + "%"; 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/java/org/docstr/gwt/uploader/demo/client/MultiUploadWithProgressBarAndDragAndDrop.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Document Node Pty Ltd 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.docstr.gwt.uploader.demo.client; 18 | 19 | import com.google.gwt.core.client.EntryPoint; 20 | import com.google.gwt.event.dom.client.*; 21 | import com.google.gwt.user.client.Window; 22 | import com.google.gwt.user.client.ui.*; 23 | import org.docstr.gwt.uploader.client.Uploader; 24 | import org.docstr.gwt.uploader.client.events.*; 25 | import org.docstr.gwt.uploader.client.progress.ProgressBar; 26 | 27 | import java.util.LinkedHashMap; 28 | import java.util.Map; 29 | 30 | /** 31 | * Uploader Image Button with multiple file selection, drag and drop support, and GWT Progress 32 | * Bars example of GWT Uploader. 33 | * 34 | * @author delight.wjk@gmail.com 35 | */ 36 | public class MultiUploadWithProgressBarAndDragAndDrop implements EntryPoint, UploaderSample { 37 | 38 | private final Uploader uploader = new Uploader(); 39 | 40 | public void onModuleLoad() { 41 | //noinspection GwtToHtmlReferences 42 | RootPanel.get("MultiUploadWithProgressBarAndDragAndDrop").add(getUploaderPanel()); 43 | } 44 | 45 | @Override 46 | public Widget getUploaderPanel() { 47 | final VerticalPanel progressBarPanel = new VerticalPanel(); 48 | final Map progressBars = new LinkedHashMap(); 49 | final Map cancelButtons = new LinkedHashMap(); 50 | uploader.setUploadURL(UPLOAD_URL) 51 | .setButtonImageURL(AppResources.INSTANCE.upload().getSafeUri().asString()) 52 | .setButtonWidth(133) 53 | .setButtonHeight(22) 54 | .setFileSizeLimit("50 MB") 55 | .setButtonCursor(Uploader.Cursor.HAND) 56 | .setButtonAction(Uploader.ButtonAction.SELECT_FILES) 57 | .setFileQueuedHandler(new FileQueuedHandler() { 58 | public boolean onFileQueued(final FileQueuedEvent fileQueuedEvent) { 59 | // Create a Progress Bar for this file 60 | final ProgressBar progressBar = 61 | new ProgressBar(0.0, 1.0, 0.0, new CancelProgressBarTextFormatter()); 62 | progressBar.setTitle(fileQueuedEvent.getFile().getName()); 63 | progressBar.setHeight("18px"); 64 | progressBar.setWidth("200px"); 65 | progressBars.put(fileQueuedEvent.getFile().getId(), progressBar); 66 | 67 | // Add Cancel Button Image 68 | final Image cancelButton = 69 | new Image(AppResources.INSTANCE.cancel().getSafeUri().asString()); 70 | cancelButton.setStyleName("cancelButton"); 71 | cancelButton.addClickHandler(new ClickHandler() { 72 | public void onClick(ClickEvent event) { 73 | uploader.cancelUpload(fileQueuedEvent.getFile().getId(), false); 74 | progressBars.get(fileQueuedEvent.getFile().getId()).setProgress(-1.0d); 75 | cancelButton.removeFromParent(); 76 | } 77 | }); 78 | cancelButtons.put(fileQueuedEvent.getFile().getId(), cancelButton); 79 | 80 | // Add the Bar and Button to the interface 81 | HorizontalPanel progressBarAndButtonPanel = new HorizontalPanel(); 82 | progressBarAndButtonPanel.add(progressBar); 83 | progressBarAndButtonPanel.add(cancelButton); 84 | progressBarPanel.add(progressBarAndButtonPanel); 85 | 86 | return true; 87 | } 88 | }) 89 | .setUploadProgressHandler(new UploadProgressHandler() { 90 | public boolean onUploadProgress(UploadProgressEvent uploadProgressEvent) { 91 | ProgressBar progressBar = progressBars.get(uploadProgressEvent.getFile().getId()); 92 | progressBar.setProgress( 93 | (double) uploadProgressEvent.getBytesComplete() / uploadProgressEvent 94 | .getBytesTotal() 95 | ); 96 | return true; 97 | } 98 | }) 99 | .setUploadCompleteHandler(new UploadCompleteHandler() { 100 | public boolean onUploadComplete(UploadCompleteEvent uploadCompleteEvent) { 101 | cancelButtons.get(uploadCompleteEvent.getFile().getId()).removeFromParent(); 102 | uploader.startUpload(); 103 | return true; 104 | } 105 | }) 106 | .setFileDialogStartHandler(new FileDialogStartHandler() { 107 | public boolean onFileDialogStartEvent(FileDialogStartEvent fileDialogStartEvent) { 108 | if (uploader.getStats().getUploadsInProgress() <= 0) { 109 | // Clear the uploads that have completed, if none are in process 110 | progressBarPanel.clear(); 111 | progressBars.clear(); 112 | cancelButtons.clear(); 113 | } 114 | return true; 115 | } 116 | }) 117 | .setFileDialogCompleteHandler(new FileDialogCompleteHandler() { 118 | public boolean onFileDialogComplete(FileDialogCompleteEvent fileDialogCompleteEvent) { 119 | if (fileDialogCompleteEvent.getTotalFilesInQueue() > 0) { 120 | if (uploader.getStats().getUploadsInProgress() <= 0) { 121 | uploader.startUpload(); 122 | } 123 | } 124 | return true; 125 | } 126 | }) 127 | .setFileQueueErrorHandler(new FileQueueErrorHandler() { 128 | public boolean onFileQueueError(FileQueueErrorEvent fileQueueErrorEvent) { 129 | Window.alert( 130 | "Upload of file " + fileQueueErrorEvent.getFile().getName() + " failed due to [" + 131 | fileQueueErrorEvent.getErrorCode().toString() + "]: " + fileQueueErrorEvent 132 | .getMessage() 133 | ); 134 | return true; 135 | } 136 | }) 137 | .setUploadErrorHandler(new UploadErrorHandler() { 138 | public boolean onUploadError(UploadErrorEvent uploadErrorEvent) { 139 | cancelButtons.get(uploadErrorEvent.getFile().getId()).removeFromParent(); 140 | Window.alert( 141 | "Upload of file " + uploadErrorEvent.getFile().getName() + " failed due to [" + 142 | uploadErrorEvent.getErrorCode().toString() + "]: " + uploadErrorEvent.getMessage() 143 | ); 144 | return true; 145 | } 146 | }); 147 | 148 | VerticalPanel verticalPanel = new VerticalPanel(); 149 | verticalPanel.add(uploader); 150 | 151 | if (Uploader.isAjaxUploadWithProgressEventsSupported()) { 152 | final Label dropFilesLabel = new Label("Drop Files Here"); 153 | dropFilesLabel.setStyleName("dropFilesLabel"); 154 | dropFilesLabel.addDragOverHandler(new DragOverHandler() { 155 | public void onDragOver(DragOverEvent event) { 156 | if (!uploader.getButtonDisabled()) { 157 | dropFilesLabel.addStyleName("dropFilesLabelHover"); 158 | } 159 | } 160 | }); 161 | dropFilesLabel.addDragLeaveHandler(new DragLeaveHandler() { 162 | public void onDragLeave(DragLeaveEvent event) { 163 | dropFilesLabel.removeStyleName("dropFilesLabelHover"); 164 | } 165 | }); 166 | dropFilesLabel.addDropHandler(new DropHandler() { 167 | public void onDrop(DropEvent event) { 168 | dropFilesLabel.removeStyleName("dropFilesLabelHover"); 169 | 170 | if (uploader.getStats().getUploadsInProgress() <= 0) { 171 | progressBarPanel.clear(); 172 | progressBars.clear(); 173 | cancelButtons.clear(); 174 | } 175 | 176 | uploader.addFilesToQueue(Uploader.getDroppedFiles(event.getNativeEvent())); 177 | event.preventDefault(); 178 | } 179 | }); 180 | verticalPanel.add(dropFilesLabel); 181 | } 182 | 183 | HorizontalPanel horizontalPanel = new HorizontalPanel(); 184 | horizontalPanel.add(verticalPanel); 185 | horizontalPanel.add(progressBarPanel); 186 | horizontalPanel.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE); 187 | horizontalPanel.setCellHorizontalAlignment(uploader, HorizontalPanel.ALIGN_LEFT); 188 | horizontalPanel.setCellHorizontalAlignment(progressBarPanel, HorizontalPanel.ALIGN_RIGHT); 189 | return horizontalPanel; 190 | } 191 | 192 | protected class CancelProgressBarTextFormatter extends ProgressBar.TextFormatter { 193 | 194 | @Override 195 | protected String getText(ProgressBar bar, double curProgress) { 196 | if (curProgress < 0) { 197 | return "Cancelled"; 198 | } 199 | return ((int) (100 * bar.getPercent())) + "%"; 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | -------------------------------------------------------------------------------- /gwt-uploader-demo/src/main/webapp/style.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin: 20px 50px; 3 | font-family: Arial, sans-serif; 4 | font-weight: normal; 5 | font-size: 12px; 6 | color: #454545; 7 | } 8 | 9 | h1 { 10 | font-size: 20px; 11 | font-weight: normal; 12 | color: #bb4b44; 13 | margin-top: 7px; 14 | margin-bottom: 7px; 15 | padding-left:2px; 16 | } 17 | 18 | h2 { 19 | font-size: 18px; 20 | font-weight: normal; 21 | color: #bb4b44; 22 | margin-top: 5px; 23 | margin-bottom: 5px; 24 | padding-left:2px; 25 | } 26 | 27 | h3 { 28 | font-size: 16px; 29 | font-weight: normal; 30 | color: #bb4b44; 31 | margin-top: 5px; 32 | margin-bottom: 5px; 33 | padding-left:2px; 34 | } 35 | 36 | h4 { 37 | font-size: 16px; 38 | font-weight: normal; 39 | color: #bb4b44; 40 | margin-top: 5px; 41 | margin-bottom: 5px; 42 | } 43 | 44 | p { 45 | margin-top: 12px; 46 | margin-bottom: 12px; 47 | } 48 | 49 | a { 50 | font-weight: bold; 51 | text-decoration: underline; 52 | color: #bb4b44; 53 | } 54 | 55 | a:visited { 56 | color: #BB4B44; 57 | } 58 | 59 | .anchor { 60 | font-weight: normal; 61 | text-decoration: none; 62 | } 63 | 64 | .headingParagraph { 65 | font-style: italic; 66 | color: #a7b5c4; 67 | font-size: 17px; 68 | margin-top: 0; 69 | margin-bottom: 0; 70 | } 71 | 72 | img.centered { 73 | margin-left: auto; 74 | margin-right: auto; 75 | display: block; 76 | } 77 | 78 | #scrollableArea { 79 | position: absolute; 80 | width: 100%; 81 | top: 0; 82 | bottom: 26px; 83 | min-width: 1001px; 84 | overflow-y: auto; 85 | overflow-x: hidden; 86 | background: #ededed url("images/body-bg.gif") repeat-y center; 87 | text-align: center; 88 | } 89 | 90 | #headerBackground { 91 | position: absolute; 92 | height: 145px; 93 | width: 100%; 94 | } 95 | 96 | #headerContainer { 97 | height: 145px; 98 | width: 100%; 99 | position: relative; 100 | z-index: 1000; 101 | } 102 | 103 | #header { 104 | position: relative; 105 | margin-left: auto; 106 | margin-right: auto; 107 | height: 145px; 108 | width: 1001px; 109 | text-align: left; 110 | } 111 | 112 | #headerNav { 113 | position: relative; 114 | width: 700px; 115 | height: 40px; 116 | left: 300px; 117 | top: 97px; 118 | } 119 | 120 | .headerCell { 121 | padding-top: 3px; 122 | padding-left: 17px; 123 | text-align: left; 124 | vertical-align: top; 125 | width: 20%; 126 | height: 40px; 127 | white-space: nowrap; 128 | } 129 | 130 | .headerCellSelected { 131 | background: url("images/header-cell-selected-bg.gif") repeat-x; 132 | } 133 | 134 | .headerMainLink, .headerMainLink:visited { 135 | color: #dcdcdc; 136 | font-size: 15px; 137 | line-height: 18px; 138 | text-decoration: none; 139 | font-weight: normal; 140 | display: block; 141 | } 142 | 143 | .headerMainLink:hover { 144 | color: white; 145 | } 146 | 147 | .headerSubLink, .headerSubLink:visited { 148 | color: #a7b5c4; 149 | font-size: 11px; 150 | line-height: 13px; 151 | text-decoration: none; 152 | font-weight: normal; 153 | display: block; 154 | } 155 | 156 | .headerCellSelected .headerSubLink, .headerCellSelected .headerSubLink:visited { 157 | color: black; 158 | } 159 | 160 | #content > table > tbody > tr > td > div > span { 161 | display: block; 162 | padding-bottom: 20px; 163 | text-align: center; 164 | } 165 | 166 | #searchField { 167 | position: relative; 168 | width: 100px; 169 | height: 14px; 170 | background-color: black; 171 | color: #dcdcdc; 172 | font-size: 11px; 173 | line-height: 11px; 174 | margin: 0; 175 | padding: 0; 176 | border: 0; 177 | left: 0; 178 | top: -2px; 179 | } 180 | 181 | #bodyContainer { 182 | top: 145px; 183 | width: 100%; 184 | background: #ededed url("images/body-bg.gif") repeat-y center; 185 | /*min-height: 1160px;*/ 186 | /*height: 100%;*/ 187 | } 188 | 189 | .ajaxContent { 190 | padding-top: 35px; 191 | } 192 | 193 | .picture-left { 194 | padding-right: 15px; 195 | } 196 | 197 | .homeLink { 198 | height: 75px; 199 | width: 300px; 200 | top: 63px; 201 | left: -41px; 202 | position: absolute; 203 | } 204 | 205 | #body { 206 | position: relative; 207 | margin-left: auto; 208 | margin-right: auto; 209 | width: 1001px; 210 | } 211 | 212 | #contentContainer { 213 | width: 739px; 214 | } 215 | 216 | #content { 217 | padding: 22px 26px 40px 46px; 218 | text-align: left; 219 | } 220 | 221 | .contentColumnLeft { 222 | padding-right: 33px; 223 | font-size: 12px; 224 | vertical-align: top; 225 | width: 311px; 226 | } 227 | 228 | .contentColumnRight { 229 | font-size: 12px; 230 | vertical-align: top; 231 | 232 | } 233 | 234 | .contentPictureLeft { 235 | /*padding-left: 33px;*/ 236 | width: 175px; 237 | } 238 | 239 | .contentPictureMid { 240 | width: 175px; 241 | } 242 | 243 | .contentPictureRight { 244 | width: 175px; 245 | } 246 | 247 | .contentTextRight { 248 | padding-left: 35px; 249 | } 250 | 251 | #rightNavContainer { 252 | position: absolute; 253 | width: 260px; 254 | top: 0; 255 | right: 0; 256 | } 257 | 258 | #rightNav { 259 | padding: 54px 18px 18px; 260 | text-align: left; 261 | } 262 | 263 | .contentRule { 264 | background: url("images/hr-content-bg.gif") repeat-x center; 265 | height: 19px; 266 | width: 100%; 267 | } 268 | 269 | .kibuyePic { 270 | padding-top: 58px; 271 | } 272 | 273 | .mobile { 274 | margin: 0 auto; 275 | } 276 | 277 | .moreInfo { 278 | color: #bb4b44; 279 | font-weight: bold; 280 | } 281 | 282 | .moreInfoLink { 283 | font-style: italic; 284 | } 285 | 286 | .quoteContainer { 287 | border: 2px solid #576e9a; 288 | } 289 | 290 | .quote { 291 | padding: 0 25px; 292 | font-style: italic; 293 | } 294 | 295 | .partnerLink { 296 | font-size: 18px; 297 | font-weight: normal; 298 | color: #bb4b44; 299 | padding-left: 2px; 300 | text-decoration: none; 301 | width: 168px; 302 | height: 35px; 303 | } 304 | 305 | .partnerLink.active { 306 | font-size: 18px; 307 | font-weight: normal; 308 | color: #ffffff; 309 | padding-left: 2px; 310 | text-decoration: none; 311 | background-color:#bb4b44; 312 | width: 168px; 313 | height: 35px; 314 | } 315 | 316 | .partnerLink.active > a { 317 | color: #ffffff; 318 | } 319 | 320 | .partnerName { 321 | position: relative; 322 | bottom: -10px; 323 | left: 5px; 324 | } 325 | 326 | #photo { 327 | text-align: center; 328 | width: 166px; 329 | height: 249px; 330 | } 331 | 332 | .photo { 333 | text-align: center; 334 | height: 249px; 335 | width: 166px; 336 | border: 2px solid #BB4B44; 337 | margin-bottom: 0; 338 | } 339 | 340 | .rightNavHeader { 341 | font-weight: bold; 342 | font-size: 13px; 343 | color: #393a3a; 344 | margin-bottom: 8px; 345 | } 346 | 347 | .rightNavHeader a { 348 | font-size: 16px; 349 | font-variant: small-caps; 350 | text-decoration: none; 351 | font-weight: normal; 352 | color: #bb4b44; 353 | } 354 | 355 | .rightNavHeaderSelected a { 356 | font-size: 16px; 357 | font-weight: bold; 358 | color: #393a3a; 359 | } 360 | 361 | .rightNavMessage { 362 | color: #393a3a; 363 | } 364 | 365 | .form-label { 366 | padding-bottom: 6px; 367 | padding-right: 16px; 368 | padding-top: 6px; 369 | vertical-align: top; 370 | } 371 | 372 | .form-input-select { 373 | font-size: 12px; 374 | } 375 | 376 | .form-input-submit { 377 | font-size: 12px; 378 | margin-bottom: 24px; 379 | margin-top: 18px; 380 | } 381 | 382 | .form-input-radio { 383 | position: relative; 384 | top: 2px; 385 | } 386 | 387 | .form-label-radio { 388 | cursor: pointer; 389 | font-weight: bold; 390 | } 391 | 392 | .form-error { 393 | color: #CC0000; 394 | } 395 | 396 | .infoTable, .featuresTable { 397 | border: 1px solid #dcdcdc; 398 | } 399 | 400 | .infoTable th, .infoTable td { 401 | border: 1px solid #dcdcdc; 402 | padding: 6px; 403 | } 404 | 405 | .infoTable th { 406 | background-color: #dcdcdc; 407 | } 408 | 409 | .featuresTable td { 410 | border: 1px solid #dcdcdc; 411 | padding: 10px; 412 | } 413 | 414 | .featuresTable td.label { 415 | width: 100px; 416 | font-size: 13px; 417 | font-weight: bold; 418 | vertical-align: top; 419 | text-align: left; 420 | } 421 | 422 | .code { 423 | font-family: Courier,serif; 424 | background-color: #EEEEEE; 425 | color: black; 426 | padding-left: 30px; 427 | padding-top: 8px; 428 | padding-bottom: 8px; 429 | padding-right: 8px; 430 | margin-top: 10px; 431 | margin-bottom: 10px; 432 | } 433 | 434 | .demo { 435 | overflow: auto; 436 | height: auto; 437 | border: 1px solid #ccc; 438 | background: #ffffff; 439 | border-radius: 5px; 440 | padding: 15px; 441 | text-align: left; 442 | } 443 | 444 | .viewSourceBtn { 445 | margin-top: 10px; 446 | cursor: pointer; 447 | } 448 | 449 | .gwt-ProgressBar-shell { 450 | border: 2px solid #848280; 451 | background-color: #454545; 452 | height: 16px; 453 | width: 50%; 454 | margin-left: 10px; 455 | } 456 | 457 | .gwt-ProgressBar-shell .gwt-ProgressBar-bar { 458 | background-color: #BB4B44; 459 | } 460 | 461 | .gwt-ProgressBar-shell .gwt-ProgressBar-text { 462 | padding: 0; 463 | margin: 0; 464 | color: white; 465 | } 466 | 467 | .progressLabel { 468 | font-family: Arial, sans-serif; 469 | font-size: 12px; 470 | } 471 | 472 | .dropFilesLabel { 473 | margin-top: 6px; 474 | padding-top: 28px; 475 | padding-bottom: 28px; 476 | font-family: verdana, arial, sans-serif; 477 | font-size: 12px; 478 | color: #2d4b6d; 479 | font-weight: bold; 480 | text-align: center; 481 | display: block; 482 | border: 2px dashed #888888; 483 | border-radius: 7px; 484 | } 485 | 486 | .dropFilesLabelHover { 487 | border: 2px solid #444444; 488 | color: #7c9647; 489 | } 490 | 491 | .btnbarpanel { 492 | } 493 | 494 | .demoPanel { 495 | 496 | } 497 | 498 | .viewSourceBtn { 499 | margin-top: 6px; 500 | cursor: pointer; 501 | } 502 | 503 | .viewSourceBtn-up { 504 | 505 | } 506 | 507 | .viewSourceBtn-up-hovering { 508 | 509 | } 510 | 511 | .viewSourceBtn-up-disabled { 512 | 513 | } 514 | 515 | .viewSourceBtn-down { 516 | 517 | } 518 | 519 | .cancelButton { 520 | margin: 3px 0 -1px 2px; 521 | cursor: pointer; 522 | } 523 | 524 | 525 | 526 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/progress/ResizableWidgetCollection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.progress; 17 | 18 | import com.google.gwt.event.logical.shared.ResizeEvent; 19 | import com.google.gwt.event.logical.shared.ResizeHandler; 20 | import com.google.gwt.event.shared.HandlerRegistration; 21 | import com.google.gwt.user.client.Timer; 22 | import com.google.gwt.user.client.Window; 23 | import com.google.gwt.user.client.WindowResizeListener; 24 | 25 | import java.util.HashMap; 26 | import java.util.Iterator; 27 | import java.util.Map; 28 | 29 | /** 30 | * A collection of {@link ResizableWidget} that periodically checks the outer 31 | * dimensions of a widget and redraws it as necessary. Every 32 | * {@link ResizableWidgetCollection} uses a timer, so consider the cost when 33 | * adding one. 34 | * 35 | * Typically, a {@link ResizableWidgetCollection} is only needed if you expect 36 | * your widgets to resize based on window resizing or other events. Fixed sized 37 | * Widgets do not need to be added to a {@link ResizableWidgetCollection} as 38 | * they cannot be resized. 39 | */ 40 | public class ResizableWidgetCollection 41 | implements WindowResizeListener, Iterable { 42 | 43 | /** 44 | * Information about a widgets size. 45 | */ 46 | static class ResizableWidgetInfo { 47 | 48 | private ResizableWidget widget; 49 | private int curOffsetHeight = 0; 50 | private int curOffsetWidth = 0; 51 | private int curClientHeight = 0; 52 | private int curClientWidth = 0; 53 | 54 | /** 55 | * Constructor. 56 | * 57 | * @param widget the widget that will be monitored 58 | */ 59 | public ResizableWidgetInfo(ResizableWidget widget) { 60 | this.widget = widget; 61 | updateSizes(); 62 | } 63 | 64 | public int getClientHeight() { 65 | return curClientHeight; 66 | } 67 | 68 | public int getClientWidth() { 69 | return curClientWidth; 70 | } 71 | 72 | public int getOffsetHeight() { 73 | return curOffsetHeight; 74 | } 75 | 76 | public int getOffsetWidth() { 77 | return curOffsetWidth; 78 | } 79 | 80 | /** 81 | * Update the current sizes. 82 | * 83 | * @return true if the sizes changed, false if not. 84 | */ 85 | public boolean updateSizes() { 86 | int offsetWidth = widget.getElement().getOffsetWidth(); 87 | int offsetHeight = widget.getElement().getOffsetHeight(); 88 | int clientWidth = widget.getElement().getClientWidth(); 89 | int clientHeight = widget.getElement().getClientHeight(); 90 | if (offsetWidth != curOffsetWidth || offsetHeight != curOffsetHeight 91 | || clientWidth != curClientWidth || clientHeight != curClientHeight) { 92 | this.curOffsetWidth = offsetWidth; 93 | this.curOffsetHeight = offsetHeight; 94 | this.curClientWidth = clientWidth; 95 | this.curClientHeight = clientHeight; 96 | return true; 97 | } 98 | 99 | return false; 100 | } 101 | } 102 | 103 | /** 104 | * The default delay between resize checks in milliseconds. 105 | */ 106 | private static final int DEFAULT_RESIZE_CHECK_DELAY = 400; 107 | 108 | /** 109 | * A static {@link ResizableWidgetCollection} that can be used in most cases. 110 | */ 111 | private static ResizableWidgetCollection staticCollection = null; 112 | 113 | /** 114 | * Get the globally accessible {@link ResizableWidgetCollection}. In most 115 | * cases, the global collection can be used for all {@link ResizableWidget}s. 116 | * 117 | * @return the global {@link ResizableWidgetCollection} 118 | */ 119 | public static ResizableWidgetCollection get() { 120 | if (staticCollection == null) { 121 | staticCollection = new ResizableWidgetCollection(); 122 | } 123 | return staticCollection; 124 | } 125 | 126 | /** 127 | * The timer used to periodically compare the dimensions of elements to their 128 | * old dimensions. 129 | */ 130 | private Timer resizeCheckTimer = new Timer() { 131 | @Override 132 | public void run() { 133 | // Ignore changes that result from window resize events 134 | if (windowHeight != Window.getClientHeight() 135 | || windowWidth != Window.getClientWidth()) { 136 | windowHeight = Window.getClientHeight(); 137 | windowWidth = Window.getClientWidth(); 138 | schedule(resizeCheckDelay); 139 | return; 140 | } 141 | 142 | // Look for elements that have new dimensions 143 | checkWidgetSize(); 144 | 145 | // Start checking again 146 | if (resizeCheckingEnabled) { 147 | schedule(resizeCheckDelay); 148 | } 149 | } 150 | }; 151 | 152 | /** 153 | * A hash map of the resizable widgets this collection is checking. 154 | */ 155 | private Map 156 | widgets = 157 | new HashMap(); 158 | 159 | /** 160 | * The current window height. 161 | */ 162 | private int windowHeight = 0; 163 | 164 | /** 165 | * The current window width. 166 | */ 167 | private int windowWidth = 0; 168 | 169 | /** 170 | * The hook used to remove the window handler. 171 | */ 172 | private HandlerRegistration windowHandler; 173 | 174 | /** 175 | * The delay between resize checks. 176 | */ 177 | private int resizeCheckDelay = DEFAULT_RESIZE_CHECK_DELAY; 178 | 179 | /** 180 | * A boolean indicating that resize checking should run. 181 | */ 182 | private boolean resizeCheckingEnabled; 183 | 184 | /** 185 | * Create a ResizableWidget. 186 | */ 187 | public ResizableWidgetCollection() { 188 | this(DEFAULT_RESIZE_CHECK_DELAY); 189 | } 190 | 191 | /** 192 | * Constructor. 193 | * 194 | * @param resizeCheckingEnabled false to disable resize checking 195 | */ 196 | public ResizableWidgetCollection(boolean resizeCheckingEnabled) { 197 | this(DEFAULT_RESIZE_CHECK_DELAY, resizeCheckingEnabled); 198 | } 199 | 200 | /** 201 | * Constructor. 202 | * 203 | * @param resizeCheckDelay the delay between checks in milliseconds 204 | */ 205 | public ResizableWidgetCollection(int resizeCheckDelay) { 206 | this(resizeCheckDelay, true); 207 | } 208 | 209 | /** 210 | * Constructor. 211 | * 212 | * @param resizeCheckDelay The resize check delay. 213 | * @param resizeCheckingEnabled If the resize checking is enabled or not. 214 | */ 215 | protected ResizableWidgetCollection(int resizeCheckDelay, boolean resizeCheckingEnabled) { 216 | setResizeCheckDelay(resizeCheckDelay); 217 | setResizeCheckingEnabled(resizeCheckingEnabled); 218 | } 219 | 220 | /** 221 | * Add a resizable widget to the collection. 222 | * 223 | * @param widget the resizable widget to add 224 | */ 225 | public void add(ResizableWidget widget) { 226 | widgets.put(widget, new ResizableWidgetInfo(widget)); 227 | } 228 | 229 | /** 230 | * Check to see if any Widgets have been resized and call their handlers 231 | * appropriately. 232 | */ 233 | public void checkWidgetSize() { 234 | for (Map.Entry entry : widgets.entrySet()) { 235 | ResizableWidget widget = entry.getKey(); 236 | ResizableWidgetInfo info = entry.getValue(); 237 | 238 | // Call the onResize method only if the widget is attached 239 | if (info.updateSizes()) { 240 | // Check that the offset width and height are greater than 0. 241 | if (info.getOffsetWidth() > 0 && info.getOffsetHeight() > 0 242 | && widget.isAttached()) { 243 | // Send the client dimensions, which is the space available for 244 | // rendering. 245 | widget.onResize(info.getOffsetWidth(), info.getOffsetHeight()); 246 | } 247 | } 248 | } 249 | } 250 | 251 | /** 252 | * Get the delay between resize checks in milliseconds. 253 | * 254 | * @return the resize check delay 255 | */ 256 | public int getResizeCheckDelay() { 257 | return resizeCheckDelay; 258 | } 259 | 260 | /** 261 | * Check whether or not resize checking is enabled. 262 | * 263 | * @return true is resize checking is enabled 264 | */ 265 | public boolean isResizeCheckingEnabled() { 266 | return resizeCheckingEnabled; 267 | } 268 | 269 | public Iterator iterator() { 270 | return widgets.keySet().iterator(); 271 | } 272 | 273 | /** 274 | * Called when the browser window is resized. 275 | * 276 | * @param width the width of the window's client area. 277 | * @param height the height of the window's client area. 278 | */ 279 | @Deprecated 280 | public void onWindowResized(int width, int height) { 281 | checkWidgetSize(); 282 | } 283 | 284 | /** 285 | * Remove a {@link ResizableWidget} from the collection. 286 | * 287 | * @param widget the widget to remove 288 | */ 289 | public void remove(ResizableWidget widget) { 290 | widgets.remove(widget); 291 | } 292 | 293 | /** 294 | * Set the delay between resize checks in milliseconds. 295 | * 296 | * @param resizeCheckDelay the new delay 297 | */ 298 | public void setResizeCheckDelay(int resizeCheckDelay) { 299 | this.resizeCheckDelay = resizeCheckDelay; 300 | } 301 | 302 | /** 303 | * Set whether or not resize checking is enabled. If disabled, elements will 304 | * still be resized on window events, but the timer will not check their 305 | * dimensions periodically. 306 | * 307 | * @param enabled true to enable the resize checking timer 308 | */ 309 | public void setResizeCheckingEnabled(boolean enabled) { 310 | if (enabled && !resizeCheckingEnabled) { 311 | resizeCheckingEnabled = true; 312 | if (windowHandler == null) { 313 | windowHandler = Window.addResizeHandler(new ResizeHandler() { 314 | public void onResize(ResizeEvent event) { 315 | onWindowResized(event.getWidth(), event.getHeight()); 316 | } 317 | }); 318 | } 319 | resizeCheckTimer.schedule(resizeCheckDelay); 320 | } else if (!enabled && resizeCheckingEnabled) { 321 | resizeCheckingEnabled = false; 322 | if (windowHandler != null) { 323 | windowHandler.removeHandler(); 324 | windowHandler = null; 325 | } 326 | resizeCheckTimer.cancel(); 327 | } 328 | } 329 | 330 | /** 331 | * Inform the {@link ResizableWidgetCollection} that the size of a widget has 332 | * changed and already been redrawn. This will prevent the widget from being 333 | * redrawn on the next loop. 334 | * 335 | * @param widget the widget's size that changed 336 | */ 337 | public void updateWidgetSize(ResizableWidget widget) { 338 | if (!widget.isAttached()) { 339 | return; 340 | } 341 | 342 | ResizableWidgetInfo info = widgets.get(widget); 343 | if (info != null) { 344 | info.updateSizes(); 345 | } 346 | } 347 | 348 | } 349 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /gwt-uploader/src/main/java/org/docstr/gwt/uploader/client/progress/ProgressBar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | package org.docstr.gwt.uploader.client.progress; 17 | 18 | import com.google.gwt.user.client.DOM; 19 | import com.google.gwt.user.client.Element; 20 | import com.google.gwt.user.client.ui.Widget; 21 | 22 | /** 23 | * A widget that displays progress on an arbitrary scale. 24 | * 25 | *

CSS Style Rules

26 | * 36 | */ 37 | public class ProgressBar extends Widget implements ResizableWidget { 38 | 39 | private static final String DEFAULT_TEXT_CLASS_NAME = 40 | "gwt-ProgressBar-text"; 41 | 42 | private String textClassName = DEFAULT_TEXT_CLASS_NAME; 43 | private String textFirstHalfClassName = DEFAULT_TEXT_CLASS_NAME + "-firstHalf"; 44 | private String textSecondHalfClassName = DEFAULT_TEXT_CLASS_NAME + "-secondHalf"; 45 | 46 | /** 47 | * A formatter used to format the text displayed in the progress bar widget. 48 | */ 49 | public abstract static class TextFormatter { 50 | 51 | /** 52 | * Generate the text to display in the ProgressBar based on the current 53 | * value. 54 | * 55 | * Override this method to change the text displayed within the ProgressBar. 56 | * 57 | * @param bar the progress bar 58 | * @param curProgress the current progress 59 | * @return the text to display in the progress bar 60 | */ 61 | protected abstract String getText(ProgressBar bar, double curProgress); 62 | } 63 | 64 | /** 65 | * The bar element that displays the progress. 66 | */ 67 | private Element barElement; 68 | 69 | /** 70 | * The current progress. 71 | */ 72 | private double curProgress; 73 | 74 | /** 75 | * The maximum progress. 76 | */ 77 | private double maxProgress; 78 | 79 | /** 80 | * The minimum progress. 81 | */ 82 | private double minProgress; 83 | 84 | /** 85 | * A boolean that determines if the text is visible. 86 | */ 87 | private boolean textVisible = true; 88 | 89 | /** 90 | * The element that displays text on the page. 91 | */ 92 | private Element textElement; 93 | 94 | /** 95 | * The current text formatter. 96 | */ 97 | private TextFormatter textFormatter; 98 | 99 | /** 100 | * Create a progress bar with default range of 0 to 100. 101 | */ 102 | public ProgressBar() { 103 | this(0.0, 100.0, 0.0); 104 | } 105 | 106 | /** 107 | * Create a progress bar with an initial progress and a default range of 0 to 108 | * 100. 109 | * 110 | * @param curProgress the current progress 111 | */ 112 | public ProgressBar(double curProgress) { 113 | this(0.0, 100.0, curProgress); 114 | } 115 | 116 | /** 117 | * Create a progress bar within the given range. 118 | * 119 | * @param minProgress the minimum progress 120 | * @param maxProgress the maximum progress 121 | */ 122 | public ProgressBar(double minProgress, double maxProgress) { 123 | this(minProgress, maxProgress, 0.0); 124 | } 125 | 126 | /** 127 | * Create a progress bar within the given range starting at the specified 128 | * progress amount. 129 | * 130 | * @param minProgress the minimum progress 131 | * @param maxProgress the maximum progress 132 | * @param curProgress the current progress 133 | */ 134 | public ProgressBar(double minProgress, double maxProgress, double curProgress) { 135 | this(minProgress, maxProgress, curProgress, null); 136 | } 137 | 138 | /** 139 | * Create a progress bar within the given range starting at the specified 140 | * progress amount. 141 | * 142 | * @param minProgress the minimum progress 143 | * @param maxProgress the maximum progress 144 | * @param curProgress the current progress 145 | * @param textFormatter the text formatter 146 | */ 147 | public ProgressBar(double minProgress, double maxProgress, 148 | double curProgress, TextFormatter textFormatter) { 149 | this.minProgress = minProgress; 150 | this.maxProgress = maxProgress; 151 | this.curProgress = curProgress; 152 | setTextFormatter(textFormatter); 153 | 154 | // Create the outer shell 155 | setElement(DOM.createDiv()); 156 | DOM.setStyleAttribute(getElement(), "position", "relative"); 157 | setStyleName("gwt-ProgressBar-shell"); 158 | 159 | // Create the bar element 160 | barElement = DOM.createDiv(); 161 | DOM.appendChild(getElement(), barElement); 162 | DOM.setStyleAttribute(barElement, "height", "100%"); 163 | setBarStyleName("gwt-ProgressBar-bar"); 164 | 165 | // Create the text element 166 | textElement = DOM.createDiv(); 167 | DOM.appendChild(getElement(), textElement); 168 | DOM.setStyleAttribute(textElement, "position", "absolute"); 169 | DOM.setStyleAttribute(textElement, "top", "0px"); 170 | 171 | // Set the current progress 172 | setProgress(curProgress); 173 | } 174 | 175 | /** 176 | * Get the maximum progress. 177 | * 178 | * @return the maximum progress 179 | */ 180 | public double getMaxProgress() { 181 | return maxProgress; 182 | } 183 | 184 | /** 185 | * Get the minimum progress. 186 | * 187 | * @return the minimum progress 188 | */ 189 | public double getMinProgress() { 190 | return minProgress; 191 | } 192 | 193 | /** 194 | * Get the current percent complete, relative to the minimum and maximum 195 | * values. The percent will always be between 0.0 - 1.0. 196 | * 197 | * @return the current percent complete 198 | */ 199 | public double getPercent() { 200 | // If we have no range 201 | if (maxProgress <= minProgress) { 202 | return 0.0; 203 | } 204 | 205 | // Calculate the relative progress 206 | double percent = (curProgress - minProgress) / (maxProgress - minProgress); 207 | return Math.max(0.0, Math.min(1.0, percent)); 208 | } 209 | 210 | /** 211 | * Get the current progress. 212 | * 213 | * @return the current progress 214 | */ 215 | public double getProgress() { 216 | return curProgress; 217 | } 218 | 219 | /** 220 | * Get the text formatter. 221 | * 222 | * @return the text formatter 223 | */ 224 | public TextFormatter getTextFormatter() { 225 | return textFormatter; 226 | } 227 | 228 | /** 229 | * Check whether the text is visible or not. 230 | * 231 | * @return true if the text is visible 232 | */ 233 | public boolean isTextVisible() { 234 | return textVisible; 235 | } 236 | 237 | /** 238 | * This method is called when the dimensions of the parent element change. 239 | * Subclasses should override this method as needed. 240 | * 241 | * Move the text to the center of the progress bar. 242 | * 243 | * @param width the new client width of the element 244 | * @param height the new client height of the element 245 | */ 246 | public void onResize(int width, int height) { 247 | if (textVisible) { 248 | int textWidth = DOM.getElementPropertyInt(textElement, "offsetWidth"); 249 | int left = (width / 2) - (textWidth / 2); 250 | DOM.setStyleAttribute(textElement, "left", left + "px"); 251 | } 252 | } 253 | 254 | /** 255 | * Redraw the progress bar when something changes the layout. 256 | */ 257 | public void redraw() { 258 | if (isAttached()) { 259 | int width = DOM.getElementPropertyInt(getElement(), "clientWidth"); 260 | int height = DOM.getElementPropertyInt(getElement(), "clientHeight"); 261 | onResize(width, height); 262 | } 263 | } 264 | 265 | public void setBarStyleName(String barClassName) { 266 | DOM.setElementProperty(barElement, "className", barClassName); 267 | } 268 | 269 | /** 270 | * Set the maximum progress. If the minimum progress is more than the current 271 | * progress, the current progress is adjusted to be within the new range. 272 | * 273 | * @param maxProgress the maximum progress 274 | */ 275 | public void setMaxProgress(double maxProgress) { 276 | this.maxProgress = maxProgress; 277 | curProgress = Math.min(curProgress, maxProgress); 278 | resetProgress(); 279 | } 280 | 281 | /** 282 | * Set the minimum progress. If the minimum progress is more than the current 283 | * progress, the current progress is adjusted to be within the new range. 284 | * 285 | * @param minProgress the minimum progress 286 | */ 287 | public void setMinProgress(double minProgress) { 288 | this.minProgress = minProgress; 289 | curProgress = Math.max(curProgress, minProgress); 290 | resetProgress(); 291 | } 292 | 293 | /** 294 | * Set the current progress. 295 | * 296 | * @param curProgress the current progress 297 | */ 298 | public void setProgress(double curProgress) { 299 | this.curProgress = Math.max(minProgress, Math.min(maxProgress, curProgress)); 300 | 301 | // Calculate percent complete 302 | int percent = (int) (100 * getPercent()); 303 | DOM.setStyleAttribute(barElement, "width", percent + "%"); 304 | DOM.setElementProperty(textElement, "innerHTML", generateText(curProgress)); 305 | updateTextStyle(percent); 306 | 307 | // Realign the text 308 | redraw(); 309 | } 310 | 311 | public void setTextFirstHalfStyleName(String textFirstHalfClassName) { 312 | this.textFirstHalfClassName = textFirstHalfClassName; 313 | onTextStyleChange(); 314 | } 315 | 316 | /** 317 | * Set the text formatter. 318 | * 319 | * @param textFormatter the text formatter 320 | */ 321 | public void setTextFormatter(TextFormatter textFormatter) { 322 | this.textFormatter = textFormatter; 323 | } 324 | 325 | public void setTextSecondHalfStyleName(String textSecondHalfClassName) { 326 | this.textSecondHalfClassName = textSecondHalfClassName; 327 | onTextStyleChange(); 328 | } 329 | 330 | public void setTextStyleName(String textClassName) { 331 | this.textClassName = textClassName; 332 | onTextStyleChange(); 333 | } 334 | 335 | /** 336 | * Sets whether the text is visible over the bar. 337 | * 338 | * @param textVisible True to show text, false to hide it 339 | */ 340 | public void setTextVisible(boolean textVisible) { 341 | this.textVisible = textVisible; 342 | if (this.textVisible) { 343 | DOM.setStyleAttribute(textElement, "display", ""); 344 | redraw(); 345 | } else { 346 | DOM.setStyleAttribute(textElement, "display", "none"); 347 | } 348 | } 349 | 350 | /** 351 | * Generate the text to display within the progress bar. Override this 352 | * function to change the default progress percent to a more informative 353 | * message, such as the number of kilobytes downloaded. 354 | * 355 | * @param curProgress the current progress 356 | * @return the text to display in the progress bar 357 | */ 358 | protected String generateText(double curProgress) { 359 | if (textFormatter != null) { 360 | return textFormatter.getText(this, curProgress); 361 | } else { 362 | return (int) (100 * getPercent()) + "%"; 363 | } 364 | } 365 | 366 | /** 367 | * Get the bar element. 368 | * 369 | * @return the bar element 370 | */ 371 | protected Element getBarElement() { 372 | return barElement; 373 | } 374 | 375 | /** 376 | * Get the text element. 377 | * 378 | * @return the text element 379 | */ 380 | protected Element getTextElement() { 381 | return textElement; 382 | } 383 | 384 | /** 385 | * This method is called immediately after a widget becomes attached to the 386 | * browser's document. 387 | */ 388 | @Override 389 | protected void onLoad() { 390 | // Reset the position attribute of the parent element 391 | DOM.setStyleAttribute(getElement(), "position", "relative"); 392 | ResizableWidgetCollection.get().add(this); 393 | redraw(); 394 | } 395 | 396 | @Override 397 | protected void onUnload() { 398 | ResizableWidgetCollection.get().remove(this); 399 | } 400 | 401 | /** 402 | * Reset the progress text based on the current min and max progress range. 403 | */ 404 | protected void resetProgress() { 405 | setProgress(getProgress()); 406 | } 407 | 408 | private void onTextStyleChange() { 409 | int percent = (int) (100 * getPercent()); 410 | updateTextStyle(percent); 411 | } 412 | 413 | private void updateTextStyle(int percent) { 414 | // Set the style depending on the size of the bar 415 | if (percent < 50) { 416 | DOM.setElementProperty(textElement, "className", 417 | textClassName + " " + textFirstHalfClassName); 418 | } else { 419 | DOM.setElementProperty(textElement, "className", 420 | textClassName + " " + textSecondHalfClassName); 421 | } 422 | } 423 | } 424 | --------------------------------------------------------------------------------