title: Downloads with JavaFX WebView
body: <p>my web application offers a download. Javascript creats at the click the url (it depends on the user input) and the browser should open it, so that the page isn't reloaded.</p>
  
  <p>For that, I think I have to alternatives:</p>
  
  <pre><code>// Alt1:
  window.open(pathToFile);
  
  // Alt2:
  var downloadFrame = document.getElementById('downloads');
  if (downloadFrame === null) {
    downloadFrame = document.createElement('iframe');
    downloadFrame.id = 'downloads';
    downloadFrame.style.display = 'none';
    document.body.appendChild(downloadFrame);
  }
  downloadFrame.src = pathToFile;
  </code></pre>
  
  <p>Both works under Firefox. Problem with open new window method: If the creation of the file at the server needs more time, the new empty tab will be closed late.
  Problem with iframe: If there is an error at the server, no feedback is given.</p>
  
  <p>I think at firefox the iframe is the better solution. But the web application must run with an JavaFX WebView, too. JavaFX haven't a download feature, I have to write it. One possible way is to listen on the location property:</p>
  
  <pre><code>final WebView webView = new WebView();
  
  webView.getEngine().locationProperty().addListener(new ChangeListener&lt;String&gt;() {
      @Override public void changed(ObservableValue&lt;? extends String&gt; observableValue, String oldLoc, String newLoc) {
          if (newLoc.cotains("/download")) {
              FileChooser chooser = new FileChooser();
              chooser.setTitle("Save " + newLoc);
              File saveFile = chooser.showSaveDialog(webView.getEngine().getScene().getWindow());
  
              if (saveFile != null) {
                  BufferedInputStream  is = null;
                  BufferedOutputStream os = null;
                  try {
                      is = new BufferedInputStream(new URL(newLoc).openStream());
                      os = new BufferedOutputStream(new FileOutputStream(saveFile));
  
                      while ((readBytes = is.read()) != -1) {
                        os.write(b);
                      }
                  } finally {
                      try { if (is != null) is.close(); } catch (IOException e) {}
                      try { if (os != null) os.close(); } catch (IOException e) {}
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>There are some problems:</p>
  
  <ol>
  <li>The download start depends on a part of the url, because JafaFX supports no access to the http headers (that is bearable)</li>
  <li>If the user starts the download with the same url two times, only the first download works (the change event only fires, if the url is new). I can crate unique urls (with #1, #2 and so on at the end). But this is ugly.</li>
  <li>Only the "window.open(pathToFile);" method works. Loading an iframe don't fire the change location event of the website. That is expectable but I haven't found the right Listener.</li>
  </ol>
  
  <p>Can someone help me to solve 2. or 3.? </p>
  
  <p>Thank you!</p>
  
  <p>PS: Sorry for my bad english.</p>
  
  <p>edit:
  For 2. I found a way. I don't know if it is a good one, if it is performant, if the new webview is deleted or is in the cache after download, ....
  And the user don't get an feedback, when some a problem is raised:</p>
  
  <pre><code>webView.getEngine().setCreatePopupHandler(new Callback&lt;PopupFeatures, WebEngine&gt;() {
      @Override public WebEngine call(PopupFeatures config) {
          final WebView downloader = new WebView();
          downloader.getEngine().locationProperty().addListener(/* The Listener from above */);
          return downloader.getEngine();
      }
  }
  </code></pre>