diff --git a/extension/Documentation/Manual.rst b/extension/Documentation/Manual.rst
index 0bb933fbd4ce407233736bcc306dcc609ef183ac..e65c45daa1f6431084142defa0cc690f8c605b7a 100644
--- a/extension/Documentation/Manual.rst
+++ b/extension/Documentation/Manual.rst
@@ -2935,7 +2935,7 @@ Type: radio
 
     * *itemList* = `<attribute>` E.g.: *itemList=red,blue,orange* or *itemList=1:red,2:blue,3:orange*
     * If ':' or ',' are part of key or value, it needs to escaped by '\\'.
-        E.g.: `itemList=1:red\\: (with colon),2:blue\\, (with comma),3:orange``
+        E.g.: `itemList=1:red\\: (with colon),2:blue\\, (with comma),3:orange`
 
   3. Definition of the *enum* or *set* field (only labels, ids are not possible).
 
@@ -3137,6 +3137,8 @@ and will be processed after saving the primary record and before any action Form
 
 	 {{SELECT SUBSTRING_INDEX( '{{pathFileName:R}}', '/', -1)  }}
 
+See also `downloadButton`_ to offer a download of an uploaded file.
+
 * *FormElement.parameter*:
 
   * *capture=camera*: On a smartphone, after pressing the 'open file' button, the camera will be opened and a
@@ -3185,6 +3187,15 @@ and will be processed after saving the primary record and before any action Form
 
   * *fileReplace=always*: If `fileDestination` exist - replace it by the new one.
 
+.. _`downloadButton`:
+
+  * *downloadButton*: If given, shows a button to download the previous uploaded file - instead of the string given in
+    `fe.value`. It's important that `fe.value` points to a readable file on the server.
+
+    If `downloadButton` ist empty, just shows the regular download glyph.
+
+    Additional attributes might be given like `downloadButton='t:Download|o:check file'. Please check `download`_.
+
   * fileSplit, fileDestinationSplit, tableNameSplit: see split-pdf-upload_
 
 Immediately after the upload finished (before the user press save), the file will be checked on the server for it's
@@ -5041,23 +5052,23 @@ Parameter and (element) sources
 
 * *popupMessage*: `a:<text>` - will be displayed in the popup window during download. If the creating/download is fast, the window might disappear quickly.
 
-* *mode*: `m:<mode>`
+* *mode*: `M:<mode>`
 
   * *mode* = <file | pdf | zip> - This parameter is optional and can be skipped in most situations. Mandatory
     for 'zip'.
 
-      * If `m:file`, the mime type is derived dynamically from the specified file. In this mode, only one element source
+      * If `M:file`, the mime type is derived dynamically from the specified file. In this mode, only one element source
         is allowed per download link (no concatenation).
 
       * In case of multiple element sources, only `pdf` or `zip` is supported.
-      * If `m:zip` is used together with `p:...`, `U:...` or `u:..`, those HTML pages will be converted to PDF. Those files
+      * If `M:zip` is used together with `p:...`, `U:...` or `u:..`, those HTML pages will be converted to PDF. Those files
         get generic filenames inside the archive.
       * If not specified, the **default** 'Mode' depends on the number of specified element sources (=file or web page):
 
         * If only one `file` is specifed, the default is `file`.
         * If there is a) a page defined or b) multiple elements, the default is `pdf`.
 
-* *element sources* - for `m:pdf` or `m:zip`, all of the following three element sources might be specified multiple times. Any combination and order of the three options are allowed.
+* *element sources* - for `M:pdf` or `M:zip`, all of the following three element sources might be specified multiple times. Any combination and order of the three options are allowed.
 
   * *file*: `F:<pathFileName>` - relative or absolute pathFileName offered for a) download (single), or to be concatenated
     in a PDF or ZIP.
@@ -5093,7 +5104,7 @@ Example `_link`: ::
 	SELECT "d:file.pdf|s|t:Download|F:fileadmin/pdf/test.pdf" AS _link
 
 	# single `file`, with mode
-	SELECT "d:file.pdf|m:pdf|s|t:Download|F:fileadmin/pdf/test.pdf" AS _link
+	SELECT "d:file.pdf|M:pdf|s|t:Download|F:fileadmin/pdf/test.pdf" AS _link
 
 	# three sources: two pages and one file
 	SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1|F:fileadmin/pdf/test.pdf" AS _link
diff --git a/extension/qfq/qfq/AbstractBuildForm.php b/extension/qfq/qfq/AbstractBuildForm.php
index 14bdb57f28afd8190621779fc4ce86d8453f0215..4cb1527719a69357bb39170779ca9d7d7ad36531 100644
--- a/extension/qfq/qfq/AbstractBuildForm.php
+++ b/extension/qfq/qfq/AbstractBuildForm.php
@@ -2891,7 +2891,16 @@ abstract class AbstractBuildForm {
         Support::setIfNotSet($formElement, FE_FILE_BUTTON_TEXT, FE_FILE_BUTTON_TEXT_DEFAULT);
         $htmlInputFile = Support::wrapTag("<label $attributeFileLabel>", $htmlInputFile . $formElement[FE_FILE_BUTTON_TEXT]);
 
-        $deleteButton = Support::wrapTag("<button type='button' class='delete-file' data-sip='$sipUpload' name='delete-$htmlFormElementName'>", $this->symbol[SYMBOL_DELETE]);
+        $deleteButton = Support::wrapTag("<button type='button' class='btn btn-default delete-file' data-sip='$sipUpload' name='delete-$htmlFormElementName'>", $this->symbol[SYMBOL_DELETE]);
+
+        if (Support::isEnabled($formElement, FE_FILE_DOWNLOAD_BUTTON)) {
+            if (is_readable($value)) {
+                $link = new Link($this->sip);
+                $value = $link->renderLink('s|M:file|d|F:' . $value . '|' . $formElement[FE_FILE_DOWNLOAD_BUTTON]);
+            } else {
+                $value .= " - file not found, please check field 'value'";
+            }
+        }
 
         $htmlFilename = Support::wrapTag("<span class='uploaded-file-name'>", $value, false);
         $htmlTextDelete = Support::wrapTag("<div class='uploaded-file $textDeleteClass'>", $htmlFilename . ' ' . $deleteButton);
diff --git a/extension/qfq/qfq/Constants.php b/extension/qfq/qfq/Constants.php
index 285e8c8345771fae54486b5392f4e212a5177bb5..ef967d7148b41053452d22f8c9f2b33ac84725fb 100644
--- a/extension/qfq/qfq/Constants.php
+++ b/extension/qfq/qfq/Constants.php
@@ -867,6 +867,7 @@ const FE_FILE_CAPTURE = 'capture'; // On a smartphone opens the camera
 const FE_FILE_SPLIT = 'fileSplit';
 const FE_FILE_SPLIT_SVG = 'svg';
 const FE_FILE_SPLIT_TABLE_NAME = 'tableNameSplit';
+const FE_FILE_DOWNLOAD_BUTTON = 'downloadButton';
 
 const FE_IMAGE_SOURCE = 'imageSource'; // Image source for a fabric element
 const FE_SQL_VALIDATE = 'sqlValidate'; // Action: Query to validate form load
diff --git a/extension/qfq/qfq/helper/Support.php b/extension/qfq/qfq/helper/Support.php
index e0522e5dc1b38dcc07da2ac72ad59a84127797b6..360ac548a279f37a9f9f54c29bfd913e3e866a43 100644
--- a/extension/qfq/qfq/helper/Support.php
+++ b/extension/qfq/qfq/helper/Support.php
@@ -930,7 +930,7 @@ class Support {
     }
 
     /**
-     * Convert 'false' and 'empty' to '0'.
+     * Convert 'false' and '<empty string>' to '0'.
      *
      * @param $val
      *
@@ -940,6 +940,25 @@ class Support {
         return ($val == '' || $val == false) ? '0' : $val;
     }
 
+    /**
+     * If there is an element $key in array $arr and if that is empty (acts as a switch) or not equal '0': return true, else false
+     *
+     * @param array $arr
+     * @param string $key
+     * @return bool  true: if $key exists and a) is empty or b) =='1'
+     */
+    public static function isEnabled(array $arr, $key) {
+        if (!array_key_exists($key, $arr)) {
+            return false;
+        }
+
+        if ($arr[$key] === '' || $arr[$key] !== '0') {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     /**
      * Check if the string starts with the comment sign - return an empty string.
      * Check if the string starts with an escaped comment sign - strip the escape character.
diff --git a/extension/qfq/tests/phpunit/SupportTest.php b/extension/qfq/tests/phpunit/SupportTest.php
index 83efd041b4d591ddb6a2d1ce8bad6566d8dd2a1a..52a38cb0ebb0636d06fc5b357f768655adf177b4 100644
--- a/extension/qfq/tests/phpunit/SupportTest.php
+++ b/extension/qfq/tests/phpunit/SupportTest.php
@@ -467,6 +467,29 @@ class SupportTest extends \PHPUnit_Framework_TestCase {
         $this->assertEquals('<div class="qfq" class="123">', $new);
     }
 
+    public function testFalseEmptyToZero() {
+        $this->assertEquals('0', Support::falseEmptyToZero(''));
+        $this->assertEquals('0', Support::falseEmptyToZero(false));
+        $this->assertEquals('false', Support::falseEmptyToZero('false'));
+        $this->assertEquals('true', Support::falseEmptyToZero('true'));
+        $this->assertEquals('123', Support::falseEmptyToZero('123'));
+    }
+
+    public function testIsEnabled() {
+        $this->assertEquals(false, Support::isEnabled(array(), ''));
+        $this->assertEquals(false, Support::isEnabled(array(), 'test'));
+        $this->assertEquals(false, Support::isEnabled(['test' => '0'], 'test'));
+
+        $this->assertEquals(true, Support::isEnabled(['test' => ''], 'test'));
+        $this->assertEquals(true, Support::isEnabled(['test' => 'val'], 'test'));
+        $this->assertEquals(true, Support::isEnabled(['test' => '1'], 'test'));
+
+        $this->assertEquals(false, Support::isEnabled(['a' => '1', 'b' => '2', 'c' => '3'], 'test'));
+        $this->assertEquals(true, Support::isEnabled(['a' => '1', 'b' => '2', 'c' => '3'], 'a'));
+        $this->assertEquals(true, Support::isEnabled(['a' => '1', 'b' => '2', 'c' => '3'], 'b'));
+        $this->assertEquals(false, Support::isEnabled(['a' => '1', 'b' => '0', 'c' => '3'], 'b'));
+    }
+
     public function testunEscapeNComment() {
 
         $this->assertEquals('', Support::handleEscapeSpaceComment(''));