Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  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 com.vaadin.v7.ui;
  17. import java.io.OutputStream;
  18. import java.io.Serializable;
  19. import java.lang.reflect.Method;
  20. import java.util.Collections;
  21. import java.util.Iterator;
  22. import java.util.LinkedHashSet;
  23. import java.util.Map;
  24. import java.util.Objects;
  25. import com.vaadin.server.NoInputStreamException;
  26. import com.vaadin.server.NoOutputStreamException;
  27. import com.vaadin.server.PaintException;
  28. import com.vaadin.server.PaintTarget;
  29. import com.vaadin.server.StreamVariable.StreamingProgressEvent;
  30. import com.vaadin.shared.EventId;
  31. import com.vaadin.shared.Registration;
  32. import com.vaadin.ui.AbstractComponent;
  33. import com.vaadin.ui.Component;
  34. import com.vaadin.ui.LegacyComponent;
  35. import com.vaadin.util.ReflectTools;
  36. import com.vaadin.v7.shared.ui.upload.UploadClientRpc;
  37. import com.vaadin.v7.shared.ui.upload.UploadServerRpc;
  38. import com.vaadin.v7.shared.ui.upload.UploadState;
  39. /**
  40. * Component for uploading files from client to server.
  41. *
  42. * <p>
  43. * The visible component consists of a file name input box and a browse button
  44. * and an upload submit button to start uploading.
  45. *
  46. * <p>
  47. * The Upload component needs a java.io.OutputStream to write the uploaded data.
  48. * You need to implement the Upload.Receiver interface and return the output
  49. * stream in the receiveUpload() method.
  50. *
  51. * <p>
  52. * You can get an event regarding starting (StartedEvent), progress
  53. * (ProgressEvent), and finishing (FinishedEvent) of upload by implementing
  54. * StartedListener, ProgressListener, and FinishedListener, respectively. The
  55. * FinishedListener is called for both failed and succeeded uploads. If you wish
  56. * to separate between these two cases, you can use SucceededListener
  57. * (SucceededEvenet) and FailedListener (FailedEvent).
  58. *
  59. * <p>
  60. * The upload component does not itself show upload progress, but you can use
  61. * the ProgressIndicator for providing progress feedback by implementing
  62. * ProgressListener and updating the indicator in updateProgress().
  63. *
  64. * <p>
  65. * Setting upload component immediate initiates the upload as soon as a file is
  66. * selected, instead of the common pattern of file selection field and upload
  67. * button.
  68. *
  69. * <p>
  70. * Note! Because of browser dependent implementations of <input type="file">
  71. * element, setting size for Upload component is not supported. For some
  72. * browsers setting size may work to some extend.
  73. *
  74. * @author Vaadin Ltd.
  75. * @since 3.0
  76. */
  77. @SuppressWarnings("serial")
  78. @Deprecated
  79. public class Upload extends AbstractComponent
  80. implements Component.Focusable, LegacyComponent {
  81. /**
  82. * Should the field be focused on next repaint?
  83. */
  84. private final boolean focus = false;
  85. /**
  86. * The tab order number of this field.
  87. */
  88. private int tabIndex = 0;
  89. /**
  90. * The output of the upload is redirected to this receiver.
  91. */
  92. private Receiver receiver;
  93. private boolean isUploading;
  94. private long contentLength = -1;
  95. private int totalBytes;
  96. private String buttonCaption = "Upload";
  97. /**
  98. * ProgressListeners to which information about progress is sent during
  99. * upload
  100. */
  101. private LinkedHashSet<ProgressListener> progressListeners;
  102. private boolean interrupted = false;
  103. private boolean notStarted;
  104. private int nextid;
  105. /**
  106. * Creates a new instance of Upload.
  107. *
  108. * The receiver must be set before performing an upload.
  109. */
  110. public Upload() {
  111. registerRpc(new UploadServerRpc() {
  112. @Override
  113. public void change(String filename) {
  114. fireEvent(new ChangeEvent(Upload.this, filename));
  115. }
  116. @Override
  117. public void poll() {
  118. // Nothing to do, called only to visit the server
  119. }
  120. });
  121. }
  122. public Upload(String caption, Receiver uploadReceiver) {
  123. this();
  124. setCaption(caption);
  125. receiver = uploadReceiver;
  126. }
  127. /**
  128. * Invoked when the value of a variable has changed.
  129. *
  130. * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object,
  131. * java.util.Map)
  132. */
  133. @Override
  134. public void changeVariables(Object source, Map<String, Object> variables) {
  135. if (variables.containsKey("pollForStart")) {
  136. int id = (Integer) variables.get("pollForStart");
  137. if (!isUploading && id == nextid) {
  138. notStarted = true;
  139. markAsDirty();
  140. } else {
  141. }
  142. }
  143. }
  144. /**
  145. * Paints the content of this component.
  146. *
  147. * @param target
  148. * Target to paint the content on.
  149. * @throws PaintException
  150. * if the paint operation failed.
  151. */
  152. @Override
  153. public void paintContent(PaintTarget target) throws PaintException {
  154. if (notStarted) {
  155. target.addAttribute("notStarted", true);
  156. notStarted = false;
  157. return;
  158. }
  159. // The field should be focused
  160. if (focus) {
  161. target.addAttribute("focus", true);
  162. }
  163. // The tab ordering number
  164. if (tabIndex >= 0) {
  165. target.addAttribute("tabindex", tabIndex);
  166. }
  167. target.addAttribute("state", isUploading);
  168. if (buttonCaption != null) {
  169. target.addAttribute("buttoncaption", buttonCaption);
  170. }
  171. target.addAttribute("nextid", nextid);
  172. // Post file to this strean variable
  173. target.addVariable(this, "action", getStreamVariable());
  174. }
  175. /**
  176. * Interface that must be implemented by the upload receivers to provide the
  177. * Upload component an output stream to write the uploaded data.
  178. *
  179. * @author Vaadin Ltd.
  180. * @since 3.0
  181. */
  182. @Deprecated
  183. public interface Receiver extends Serializable {
  184. /**
  185. * Invoked when a new upload arrives.
  186. *
  187. * @param filename
  188. * the desired filename of the upload, usually as specified
  189. * by the client.
  190. * @param mimeType
  191. * the MIME type of the uploaded file.
  192. * @return Stream to which the uploaded file should be written.
  193. */
  194. public OutputStream receiveUpload(String filename, String mimeType);
  195. }
  196. /* Upload events */
  197. private static final Method UPLOAD_FINISHED_METHOD;
  198. private static final Method UPLOAD_FAILED_METHOD;
  199. private static final Method UPLOAD_SUCCEEDED_METHOD;
  200. private static final Method UPLOAD_STARTED_METHOD;
  201. static {
  202. try {
  203. UPLOAD_FINISHED_METHOD = FinishedListener.class.getDeclaredMethod(
  204. "uploadFinished", new Class[] { FinishedEvent.class });
  205. UPLOAD_FAILED_METHOD = FailedListener.class.getDeclaredMethod(
  206. "uploadFailed", new Class[] { FailedEvent.class });
  207. UPLOAD_STARTED_METHOD = StartedListener.class.getDeclaredMethod(
  208. "uploadStarted", new Class[] { StartedEvent.class });
  209. UPLOAD_SUCCEEDED_METHOD = SucceededListener.class.getDeclaredMethod(
  210. "uploadSucceeded", new Class[] { SucceededEvent.class });
  211. } catch (final java.lang.NoSuchMethodException e) {
  212. // This should never happen
  213. throw new java.lang.RuntimeException(
  214. "Internal error finding methods in Upload");
  215. }
  216. }
  217. /**
  218. * Upload.FinishedEvent is sent when the upload receives a file, regardless
  219. * of whether the reception was successful or failed. If you wish to
  220. * distinguish between the two cases, use either SucceededEvent or
  221. * FailedEvent, which are both subclasses of the FinishedEvent.
  222. *
  223. * @author Vaadin Ltd.
  224. * @since 3.0
  225. */
  226. @Deprecated
  227. public static class FinishedEvent extends Component.Event {
  228. /**
  229. * Length of the received file.
  230. */
  231. private final long length;
  232. /**
  233. * MIME type of the received file.
  234. */
  235. private final String type;
  236. /**
  237. * Received file name.
  238. */
  239. private final String filename;
  240. /**
  241. *
  242. * @param source
  243. * the source of the file.
  244. * @param filename
  245. * the received file name.
  246. * @param MIMEType
  247. * the MIME type of the received file.
  248. * @param length
  249. * the length of the received file.
  250. */
  251. public FinishedEvent(Upload source, String filename, String MIMEType,
  252. long length) {
  253. super(source);
  254. type = MIMEType;
  255. this.filename = filename;
  256. this.length = length;
  257. }
  258. /**
  259. * Uploads where the event occurred.
  260. *
  261. * @return the Source of the event.
  262. */
  263. public Upload getUpload() {
  264. return (Upload) getSource();
  265. }
  266. /**
  267. * Gets the file name.
  268. *
  269. * @return the filename.
  270. */
  271. public String getFilename() {
  272. return filename;
  273. }
  274. /**
  275. * Gets the MIME Type of the file.
  276. *
  277. * @return the MIME type.
  278. */
  279. public String getMIMEType() {
  280. return type;
  281. }
  282. /**
  283. * Gets the length of the file.
  284. *
  285. * @return the length.
  286. */
  287. public long getLength() {
  288. return length;
  289. }
  290. }
  291. /**
  292. * Upload.FailedEvent event is sent when the upload is received, but the
  293. * reception is interrupted for some reason.
  294. *
  295. * @author Vaadin Ltd.
  296. * @since 3.0
  297. */
  298. @Deprecated
  299. public static class FailedEvent extends FinishedEvent {
  300. private Exception reason = null;
  301. /**
  302. *
  303. * @param source
  304. * @param filename
  305. * @param MIMEType
  306. * @param length
  307. * @param exception
  308. */
  309. public FailedEvent(Upload source, String filename, String MIMEType,
  310. long length, Exception reason) {
  311. this(source, filename, MIMEType, length);
  312. this.reason = reason;
  313. }
  314. /**
  315. *
  316. * @param source
  317. * @param filename
  318. * @param MIMEType
  319. * @param length
  320. * @param exception
  321. */
  322. public FailedEvent(Upload source, String filename, String MIMEType,
  323. long length) {
  324. super(source, filename, MIMEType, length);
  325. }
  326. /**
  327. * Gets the exception that caused the failure.
  328. *
  329. * @return the exception that caused the failure, null if n/a
  330. */
  331. public Exception getReason() {
  332. return reason;
  333. }
  334. }
  335. /**
  336. * FailedEvent that indicates that an output stream could not be obtained.
  337. */
  338. @Deprecated
  339. public static class NoOutputStreamEvent extends FailedEvent {
  340. /**
  341. *
  342. * @param source
  343. * @param filename
  344. * @param MIMEType
  345. * @param length
  346. */
  347. public NoOutputStreamEvent(Upload source, String filename,
  348. String MIMEType, long length) {
  349. super(source, filename, MIMEType, length);
  350. }
  351. }
  352. /**
  353. * FailedEvent that indicates that an input stream could not be obtained.
  354. */
  355. @Deprecated
  356. public static class NoInputStreamEvent extends FailedEvent {
  357. /**
  358. *
  359. * @param source
  360. * @param filename
  361. * @param MIMEType
  362. * @param length
  363. */
  364. public NoInputStreamEvent(Upload source, String filename,
  365. String MIMEType, long length) {
  366. super(source, filename, MIMEType, length);
  367. }
  368. }
  369. /**
  370. * Upload.SucceededEvent event is sent when the upload is received
  371. * successfully.
  372. *
  373. * @author Vaadin Ltd.
  374. * @since 3.0
  375. */
  376. @Deprecated
  377. public static class SucceededEvent extends FinishedEvent {
  378. /**
  379. *
  380. * @param source
  381. * @param filename
  382. * @param MIMEType
  383. * @param length
  384. */
  385. public SucceededEvent(Upload source, String filename, String MIMEType,
  386. long length) {
  387. super(source, filename, MIMEType, length);
  388. }
  389. }
  390. /**
  391. * Upload.StartedEvent event is sent when the upload is started to received.
  392. *
  393. * @author Vaadin Ltd.
  394. * @since 5.0
  395. */
  396. @Deprecated
  397. public static class StartedEvent extends Component.Event {
  398. private final String filename;
  399. private final String type;
  400. /**
  401. * Length of the received file.
  402. */
  403. private final long length;
  404. /**
  405. *
  406. * @param source
  407. * @param filename
  408. * @param MIMEType
  409. * @param length
  410. */
  411. public StartedEvent(Upload source, String filename, String MIMEType,
  412. long contentLength) {
  413. super(source);
  414. this.filename = filename;
  415. type = MIMEType;
  416. length = contentLength;
  417. }
  418. /**
  419. * Uploads where the event occurred.
  420. *
  421. * @return the Source of the event.
  422. */
  423. public Upload getUpload() {
  424. return (Upload) getSource();
  425. }
  426. /**
  427. * Gets the file name.
  428. *
  429. * @return the filename.
  430. */
  431. public String getFilename() {
  432. return filename;
  433. }
  434. /**
  435. * Gets the MIME Type of the file.
  436. *
  437. * @return the MIME type.
  438. */
  439. public String getMIMEType() {
  440. return type;
  441. }
  442. /**
  443. * @return the length of the file that is being uploaded
  444. */
  445. public long getContentLength() {
  446. return length;
  447. }
  448. }
  449. /**
  450. * Upload.ChangeEvent event is sent when the value (filename) of the upload
  451. * changes.
  452. *
  453. * @since 7.2
  454. */
  455. @Deprecated
  456. public static class ChangeEvent extends Component.Event {
  457. private final String filename;
  458. public ChangeEvent(Upload source, String filename) {
  459. super(source);
  460. this.filename = filename;
  461. }
  462. /**
  463. * Uploads where the event occurred.
  464. *
  465. * @return the Source of the event.
  466. */
  467. @Override
  468. public Upload getSource() {
  469. return (Upload) super.getSource();
  470. }
  471. /**
  472. * Gets the file name.
  473. *
  474. * @return the filename.
  475. */
  476. public String getFilename() {
  477. return filename;
  478. }
  479. }
  480. /**
  481. * Receives the events when the upload starts.
  482. *
  483. * @author Vaadin Ltd.
  484. * @since 5.0
  485. */
  486. @Deprecated
  487. public interface StartedListener extends Serializable {
  488. /**
  489. * Upload has started.
  490. *
  491. * @param event
  492. * the Upload started event.
  493. */
  494. public void uploadStarted(StartedEvent event);
  495. }
  496. /**
  497. * Receives the events when the uploads are ready.
  498. *
  499. * @author Vaadin Ltd.
  500. * @since 3.0
  501. */
  502. @Deprecated
  503. public interface FinishedListener extends Serializable {
  504. /**
  505. * Upload has finished.
  506. *
  507. * @param event
  508. * the Upload finished event.
  509. */
  510. public void uploadFinished(FinishedEvent event);
  511. }
  512. /**
  513. * Receives events when the uploads are finished, but unsuccessful.
  514. *
  515. * @author Vaadin Ltd.
  516. * @since 3.0
  517. */
  518. @Deprecated
  519. public interface FailedListener extends Serializable {
  520. /**
  521. * Upload has finished unsuccessfully.
  522. *
  523. * @param event
  524. * the Upload failed event.
  525. */
  526. public void uploadFailed(FailedEvent event);
  527. }
  528. /**
  529. * Receives events when the uploads are successfully finished.
  530. *
  531. * @author Vaadin Ltd.
  532. * @since 3.0
  533. */
  534. @Deprecated
  535. public interface SucceededListener extends Serializable {
  536. /**
  537. * Upload successfull..
  538. *
  539. * @param event
  540. * the Upload successfull event.
  541. */
  542. public void uploadSucceeded(SucceededEvent event);
  543. }
  544. /**
  545. * Listener for {@link ChangeEvent}
  546. *
  547. * @since 7.2
  548. */
  549. @Deprecated
  550. public interface ChangeListener extends Serializable {
  551. Method FILENAME_CHANGED = ReflectTools.findMethod(ChangeListener.class,
  552. "filenameChanged", ChangeEvent.class);
  553. /**
  554. * A file has been selected but upload has not yet started.
  555. *
  556. * @param event
  557. * the change event
  558. */
  559. public void filenameChanged(ChangeEvent event);
  560. }
  561. /**
  562. * Adds the upload started event listener.
  563. *
  564. * @param listener
  565. * the Listener to be added, not null
  566. */
  567. public Registration addStartedListener(StartedListener listener) {
  568. addListener(StartedEvent.class, listener, UPLOAD_STARTED_METHOD);
  569. return () -> removeListener(StartedEvent.class, listener,
  570. UPLOAD_STARTED_METHOD);
  571. }
  572. /**
  573. * Removes the upload started event listener.
  574. *
  575. * @param listener
  576. * the Listener to be removed.
  577. */
  578. @Deprecated
  579. public void removeStartedListener(StartedListener listener) {
  580. removeListener(StartedEvent.class, listener, UPLOAD_STARTED_METHOD);
  581. }
  582. /**
  583. * Adds the upload received event listener.
  584. *
  585. * @param listener
  586. * the Listener to be added, not null
  587. */
  588. public Registration addFinishedListener(FinishedListener listener) {
  589. addListener(FinishedEvent.class, listener, UPLOAD_FINISHED_METHOD);
  590. return () -> removeListener(FinishedEvent.class, listener,
  591. UPLOAD_FINISHED_METHOD);
  592. }
  593. /**
  594. * Removes the upload received event listener.
  595. *
  596. * @param listener
  597. * the Listener to be removed.
  598. */
  599. @Deprecated
  600. public void removeFinishedListener(FinishedListener listener) {
  601. removeListener(FinishedEvent.class, listener, UPLOAD_FINISHED_METHOD);
  602. }
  603. /**
  604. * Adds the upload interrupted event listener.
  605. *
  606. * @param listener
  607. * the Listener to be added, not null
  608. */
  609. public Registration addFailedListener(FailedListener listener) {
  610. addListener(FailedEvent.class, listener, UPLOAD_FAILED_METHOD);
  611. return () -> removeListener(FailedEvent.class, listener,
  612. UPLOAD_FAILED_METHOD);
  613. }
  614. /**
  615. * Removes the upload interrupted event listener.
  616. *
  617. * @param listener
  618. * the Listener to be removed.
  619. */
  620. @Deprecated
  621. public void removeFailedListener(FailedListener listener) {
  622. removeListener(FailedEvent.class, listener, UPLOAD_FAILED_METHOD);
  623. }
  624. /**
  625. * Adds the upload success event listener.
  626. *
  627. * @param listener
  628. * the Listener to be added, not null
  629. */
  630. public Registration addSucceededListener(SucceededListener listener) {
  631. addListener(SucceededEvent.class, listener, UPLOAD_SUCCEEDED_METHOD);
  632. return () -> removeListener(SucceededEvent.class, listener,
  633. UPLOAD_SUCCEEDED_METHOD);
  634. }
  635. /**
  636. * Removes the upload success event listener.
  637. *
  638. * @param listener
  639. * the Listener to be removed.
  640. */
  641. @Deprecated
  642. public void removeSucceededListener(SucceededListener listener) {
  643. removeListener(SucceededEvent.class, listener, UPLOAD_SUCCEEDED_METHOD);
  644. }
  645. /**
  646. * Adds the upload progress event listener.
  647. *
  648. * @param listener
  649. * the progress listener to be added
  650. */
  651. public Registration addProgressListener(ProgressListener listener) {
  652. Objects.requireNonNull(listener, "Listener must not be null.");
  653. if (progressListeners == null) {
  654. progressListeners = new LinkedHashSet<>();
  655. }
  656. progressListeners.add(listener);
  657. return () -> {
  658. if (progressListeners != null) {
  659. progressListeners.remove(listener);
  660. }
  661. };
  662. }
  663. /**
  664. * Removes the upload progress event listener.
  665. *
  666. * @param listener
  667. * the progress listener to be removed
  668. */
  669. @Deprecated
  670. public void removeProgressListener(ProgressListener listener) {
  671. if (progressListeners != null) {
  672. progressListeners.remove(listener);
  673. }
  674. }
  675. /**
  676. * Adds a filename change event listener
  677. *
  678. * @param listener
  679. * the Listener to add, not null
  680. */
  681. public Registration addChangeListener(ChangeListener listener) {
  682. super.addListener(EventId.CHANGE, ChangeEvent.class, listener,
  683. ChangeListener.FILENAME_CHANGED);
  684. return () -> super.removeListener(EventId.CHANGE, ChangeEvent.class,
  685. listener);
  686. }
  687. /**
  688. * Removes a filename change event listener
  689. *
  690. * @param listener
  691. * the listener to be removed
  692. */
  693. @Deprecated
  694. public void removeChangeListener(ChangeListener listener) {
  695. super.removeListener(EventId.CHANGE, ChangeEvent.class, listener);
  696. }
  697. /**
  698. * Emit upload received event.
  699. *
  700. * @param filename
  701. * @param MIMEType
  702. * @param length
  703. */
  704. protected void fireStarted(String filename, String MIMEType) {
  705. fireEvent(new Upload.StartedEvent(this, filename, MIMEType,
  706. contentLength));
  707. }
  708. /**
  709. * Emits the upload failed event.
  710. *
  711. * @param filename
  712. * @param MIMEType
  713. * @param length
  714. */
  715. protected void fireUploadInterrupted(String filename, String MIMEType,
  716. long length) {
  717. fireEvent(new Upload.FailedEvent(this, filename, MIMEType, length));
  718. }
  719. protected void fireNoInputStream(String filename, String MIMEType,
  720. long length) {
  721. fireEvent(new Upload.NoInputStreamEvent(this, filename, MIMEType,
  722. length));
  723. }
  724. protected void fireNoOutputStream(String filename, String MIMEType,
  725. long length) {
  726. fireEvent(new Upload.NoOutputStreamEvent(this, filename, MIMEType,
  727. length));
  728. }
  729. protected void fireUploadInterrupted(String filename, String MIMEType,
  730. long length, Exception e) {
  731. fireEvent(new Upload.FailedEvent(this, filename, MIMEType, length, e));
  732. }
  733. /**
  734. * Emits the upload success event.
  735. *
  736. * @param filename
  737. * @param MIMEType
  738. * @param length
  739. *
  740. */
  741. protected void fireUploadSuccess(String filename, String MIMEType,
  742. long length) {
  743. fireEvent(new Upload.SucceededEvent(this, filename, MIMEType, length));
  744. }
  745. /**
  746. * Emits the progress event.
  747. *
  748. * @param totalBytes
  749. * bytes received so far
  750. * @param contentLength
  751. * actual size of the file being uploaded, if known
  752. *
  753. */
  754. protected void fireUpdateProgress(long totalBytes, long contentLength) {
  755. // this is implemented differently than other listeners to maintain
  756. // backwards compatibility
  757. if (progressListeners != null) {
  758. for (Iterator<ProgressListener> it = progressListeners
  759. .iterator(); it.hasNext();) {
  760. ProgressListener l = it.next();
  761. l.updateProgress(totalBytes, contentLength);
  762. }
  763. }
  764. }
  765. /**
  766. * Returns the current receiver.
  767. *
  768. * @return the StreamVariable.
  769. */
  770. public Receiver getReceiver() {
  771. return receiver;
  772. }
  773. /**
  774. * Sets the receiver.
  775. *
  776. * @param receiver
  777. * the receiver to set.
  778. */
  779. public void setReceiver(Receiver receiver) {
  780. this.receiver = receiver;
  781. }
  782. /**
  783. * {@inheritDoc}
  784. */
  785. @Override
  786. public void focus() {
  787. super.focus();
  788. }
  789. /**
  790. * Gets the Tabulator index of this Focusable component.
  791. *
  792. * @see com.vaadin.ui.Component.Focusable#getTabIndex()
  793. */
  794. @Override
  795. public int getTabIndex() {
  796. return tabIndex;
  797. }
  798. /**
  799. * Sets the Tabulator index of this Focusable component.
  800. *
  801. * @see com.vaadin.ui.Component.Focusable#setTabIndex(int)
  802. */
  803. @Override
  804. public void setTabIndex(int tabIndex) {
  805. this.tabIndex = tabIndex;
  806. }
  807. /**
  808. * Go into upload state. This is to prevent double uploading on same
  809. * component.
  810. *
  811. * Warning: this is an internal method used by the framework and should not
  812. * be used by user of the Upload component. Using it results in the Upload
  813. * component going in wrong state and not working. It is currently public
  814. * because it is used by another class.
  815. */
  816. public void startUpload() {
  817. if (isUploading) {
  818. throw new IllegalStateException("uploading already started");
  819. }
  820. isUploading = true;
  821. nextid++;
  822. }
  823. /**
  824. * Interrupts the upload currently being received. The interruption will be
  825. * done by the receiving thread so this method will return immediately and
  826. * the actual interrupt will happen a bit later.
  827. */
  828. public void interruptUpload() {
  829. if (isUploading) {
  830. interrupted = true;
  831. }
  832. }
  833. /**
  834. * Go into state where new uploading can begin.
  835. *
  836. * Warning: this is an internal method used by the framework and should not
  837. * be used by user of the Upload component.
  838. */
  839. private void endUpload() {
  840. isUploading = false;
  841. contentLength = -1;
  842. interrupted = false;
  843. markAsDirty();
  844. }
  845. public boolean isUploading() {
  846. return isUploading;
  847. }
  848. /**
  849. * Gets read bytes of the file currently being uploaded.
  850. *
  851. * @return bytes
  852. */
  853. public long getBytesRead() {
  854. return totalBytes;
  855. }
  856. /**
  857. * Returns size of file currently being uploaded. Value sane only during
  858. * upload.
  859. *
  860. * @return size in bytes
  861. */
  862. public long getUploadSize() {
  863. return contentLength;
  864. }
  865. /**
  866. * ProgressListener receives events to track progress of upload.
  867. */
  868. @Deprecated
  869. public interface ProgressListener extends Serializable {
  870. /**
  871. * Updates progress to listener
  872. *
  873. * @param readBytes
  874. * bytes transferred
  875. * @param contentLength
  876. * total size of file currently being uploaded, -1 if unknown
  877. */
  878. public void updateProgress(long readBytes, long contentLength);
  879. }
  880. /**
  881. * @return String to be rendered into button that fires uploading
  882. */
  883. public String getButtonCaption() {
  884. return buttonCaption;
  885. }
  886. /**
  887. * In addition to the actual file chooser, upload components have button
  888. * that starts actual upload progress. This method is used to set text in
  889. * that button.
  890. * <p>
  891. * In case the button text is set to null, the button is hidden. In this
  892. * case developer must explicitly initiate the upload process with
  893. * {@link #submitUpload()}.
  894. * <p>
  895. * In case the Upload is used in immediate mode using
  896. * {@link #setImmediate(boolean)}, the file choose (html input with type
  897. * "file") is hidden and only the button with this text is shown.
  898. * <p>
  899. *
  900. * <p>
  901. * <strong>Note</strong> the string given is set as is to the button. HTML
  902. * formatting is not stripped. Be sure to properly validate your value
  903. * according to your needs.
  904. *
  905. * @param buttonCaption
  906. * text for upload components button.
  907. */
  908. public void setButtonCaption(String buttonCaption) {
  909. this.buttonCaption = buttonCaption;
  910. markAsDirty();
  911. }
  912. /**
  913. * Forces the upload the send selected file to the server.
  914. * <p>
  915. * In case developer wants to use this feature, he/she will most probably
  916. * want to hide the uploads internal submit button by setting its caption to
  917. * null with {@link #setButtonCaption(String)} method.
  918. * <p>
  919. * Note, that the upload runs asynchronous. Developer should use normal
  920. * upload listeners to trac the process of upload. If the field is empty
  921. * uploaded the file name will be empty string and file length 0 in the
  922. * upload finished event.
  923. * <p>
  924. * Also note, that the developer should not remove or modify the upload in
  925. * the same user transaction where the upload submit is requested. The
  926. * upload may safely be hidden or removed once the upload started event is
  927. * fired.
  928. */
  929. public void submitUpload() {
  930. markAsDirty();
  931. getRpcProxy(UploadClientRpc.class).submitUpload();
  932. }
  933. @Override
  934. public void markAsDirty() {
  935. super.markAsDirty();
  936. }
  937. /*
  938. * Handle to terminal via Upload monitors and controls the upload during it
  939. * is being streamed.
  940. */
  941. private com.vaadin.server.StreamVariable streamVariable;
  942. protected com.vaadin.server.StreamVariable getStreamVariable() {
  943. if (streamVariable == null) {
  944. streamVariable = new com.vaadin.server.StreamVariable() {
  945. private StreamingStartEvent lastStartedEvent;
  946. @Override
  947. public boolean listenProgress() {
  948. return progressListeners != null
  949. && !progressListeners.isEmpty();
  950. }
  951. @Override
  952. public void onProgress(StreamingProgressEvent event) {
  953. fireUpdateProgress(event.getBytesReceived(),
  954. event.getContentLength());
  955. }
  956. @Override
  957. public boolean isInterrupted() {
  958. return interrupted;
  959. }
  960. @Override
  961. public OutputStream getOutputStream() {
  962. if (getReceiver() == null) {
  963. throw new IllegalStateException(
  964. "Upload cannot be performed without a receiver set");
  965. }
  966. OutputStream receiveUpload = getReceiver().receiveUpload(
  967. lastStartedEvent.getFileName(),
  968. lastStartedEvent.getMimeType());
  969. lastStartedEvent = null;
  970. return receiveUpload;
  971. }
  972. @Override
  973. public void streamingStarted(StreamingStartEvent event) {
  974. startUpload();
  975. contentLength = event.getContentLength();
  976. fireStarted(event.getFileName(), event.getMimeType());
  977. lastStartedEvent = event;
  978. }
  979. @Override
  980. public void streamingFinished(StreamingEndEvent event) {
  981. fireUploadSuccess(event.getFileName(), event.getMimeType(),
  982. event.getContentLength());
  983. endUpload();
  984. }
  985. @Override
  986. public void streamingFailed(StreamingErrorEvent event) {
  987. try {
  988. Exception exception = event.getException();
  989. if (exception instanceof NoInputStreamException) {
  990. fireNoInputStream(event.getFileName(),
  991. event.getMimeType(), 0);
  992. } else if (exception instanceof NoOutputStreamException) {
  993. fireNoOutputStream(event.getFileName(),
  994. event.getMimeType(), 0);
  995. } else {
  996. fireUploadInterrupted(event.getFileName(),
  997. event.getMimeType(), 0, exception);
  998. }
  999. } finally {
  1000. endUpload();
  1001. }
  1002. }
  1003. };
  1004. }
  1005. return streamVariable;
  1006. }
  1007. @Override
  1008. public java.util.Collection<?> getListeners(java.lang.Class<?> eventType) {
  1009. if (StreamingProgressEvent.class.isAssignableFrom(eventType)) {
  1010. if (progressListeners == null) {
  1011. return Collections.EMPTY_LIST;
  1012. } else {
  1013. return Collections.unmodifiableCollection(progressListeners);
  1014. }
  1015. }
  1016. return super.getListeners(eventType);
  1017. }
  1018. /**
  1019. * Returns the immediate mode of the component.
  1020. * <p>
  1021. * An immediate mode Upload component displays the browser file choosing
  1022. * button immediately, whereas a non-immediate upload only shows a Vaadin
  1023. * button.
  1024. * <p>
  1025. * The default mode of an Upload component is non-immediate.
  1026. *
  1027. * @return true if the component is in immediate mode, false if the
  1028. * component if not in immediate mode
  1029. */
  1030. @Override
  1031. public boolean isImmediate() {
  1032. if (getExplicitImmediateValue() != null) {
  1033. return getExplicitImmediateValue();
  1034. } else {
  1035. return false;
  1036. }
  1037. }
  1038. @Override
  1039. protected UploadState getState() {
  1040. return (UploadState) super.getState();
  1041. }
  1042. }